Skip to content

Commit

Permalink
312 implement didkey for ebsi jwk jcs pub (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeplotean authored Jun 14, 2023
1 parent 2b60242 commit 367b5a5
Show file tree
Hide file tree
Showing 37 changed files with 815 additions and 464 deletions.
1 change: 1 addition & 0 deletions src/main/kotlin/id/walt/cli/did/DidCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class CreateDidCommand : CliktCommand(
is WebMethodOption -> DidService.create(web, keyId, DidWebCreateOptions((method as WebMethodOption).domain, (method as WebMethodOption).path))
is EbsiMethodOption -> DidService.create(ebsi, keyId, DidEbsiCreateOptions((method as EbsiMethodOption).version))
is CheqdMethodOption -> DidService.create(cheqd, keyId, DidCheqdCreateOptions((method as CheqdMethodOption).network))
is KeyMethodOption -> DidService.create(key, keyId, DidKeyCreateOptions((method as KeyMethodOption).isJwk))
else -> DidService.create(DidMethod.valueOf(method.method), keyId)
}

Expand Down
5 changes: 4 additions & 1 deletion src/main/kotlin/id/walt/cli/did/DidMethodOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package id.walt.cli.did

import com.github.ajalt.clikt.parameters.groups.OptionGroup
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parameters.types.int

sealed class DidMethodOption(val method: String) : OptionGroup()
class KeyMethodOption : DidMethodOption("key")
class WebMethodOption : DidMethodOption("web") {
val domain: String by option("-d", "--domain", help = "did:web - Domain for did:web").default("walt.id")
val path: String? by option("-p", "--path", help = "did:web - Path for did:web")
Expand All @@ -22,3 +22,6 @@ class JwkMethodOption : DidMethodOption("jwk")
class CheqdMethodOption : DidMethodOption("cheqd") {
val network: String by option("-n", "--network", help = "did:cheqd - Specify the network [testnet]").choice("mainnet", "testnet").default("testnet")
}
class KeyMethodOption : DidMethodOption("key") {
val isJwk: Boolean by option("-j", "--is-jwk", help = "did:key - is jwk_jcs-pub").flag(default = false)
}
48 changes: 48 additions & 0 deletions src/main/kotlin/id/walt/common/CommonUtils.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package id.walt.common

import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.jwk.OctetKeyPair
import com.nimbusds.jose.jwk.RSAKey
import id.walt.crypto.KeyAlgorithm
import id.walt.model.Jwk
import id.walt.services.WaltIdServices.httpNoAuth
import io.ktor.client.request.*
import io.ktor.client.statement.*
Expand Down Expand Up @@ -106,3 +112,45 @@ inline fun <reified T : Any> T.asMap() : Map<String, Any?> {
val props = T::class.memberProperties.associateBy { it.name }
return props.keys.associateWith { props[it]?.get(this) }
}

/**
* Converts the JWK public key to a required-only members JSON string
* @param - the JWK key
* @return - the JSON string representing the public key having only the required members
*/
fun convertToRequiredMembersJsonString(jwk: JWK): Jwk = when (getKeyAlgorithm(jwk)) {
KeyAlgorithm.ECDSA_Secp256k1, KeyAlgorithm.ECDSA_Secp256r1 -> EcPublicKeyRequiredMembers(jwk.toECKey())
KeyAlgorithm.EdDSA_Ed25519 -> OkpPublicKeyRequiredMembers(jwk.toOctetKeyPair())
KeyAlgorithm.RSA -> RsaPublicKeyRequiredMembers(jwk.toPublicJWK().toRSAKey())
}

fun getKeyAlgorithm(jwk: JWK): KeyAlgorithm = when (jwk.keyType.value.lowercase()) {
"rsa" -> KeyAlgorithm.RSA
"ec" -> when (jwk.toECKey().curve.stdName.lowercase()) {
"secp256k1" -> KeyAlgorithm.ECDSA_Secp256k1
"secp256r1" -> KeyAlgorithm.ECDSA_Secp256r1
else -> throw IllegalArgumentException("Curve ${jwk.toECKey().curve.stdName} for EC algorithm not supported.")
}

"okp" -> KeyAlgorithm.EdDSA_Ed25519
else -> throw IllegalArgumentException("Key algorithm ${jwk.keyType.value} not supported.")
}

private fun OkpPublicKeyRequiredMembers(okp: OctetKeyPair) = Jwk(
crv = okp.curve.name,
kty = okp.keyType.value,
x = okp.x.toString()
)

private fun EcPublicKeyRequiredMembers(ec: ECKey) = Jwk(
crv = ec.curve.name,
kty = ec.keyType.value,
x = ec.x.toString(),
y = ec.y.toString()
)

private fun RsaPublicKeyRequiredMembers(rsa: RSAKey) = Jwk(
e = rsa.publicExponent.toString(),
kty = rsa.algorithm.name,
n = rsa.modulus.toString()
)
31 changes: 16 additions & 15 deletions src/main/kotlin/id/walt/crypto/CryptFun.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ enum class KeyAlgorithm {
ECDSA_Secp256r1;

companion object {
fun fromString(algorithm: String): KeyAlgorithm = when (algorithm) {
"EdDSA", "Ed25519", "EdDSA_Ed25519" -> EdDSA_Ed25519
"ECDSA", "Secp256k1", "ECDSA_Secp256k1" -> ECDSA_Secp256k1
"RSA" -> RSA
"Secp256r1", "ECDSA_Secp256r1" -> ECDSA_Secp256r1
fun fromString(algorithm: String): KeyAlgorithm = when (algorithm.lowercase()) {
"eddsa", "ed25519", "eddsa_ed25519" -> EdDSA_Ed25519
"ecdsa", "secp256k1", "ecdsa_secp256k1" -> ECDSA_Secp256k1
"rsa" -> RSA
"secp256r1", "ecdsa_secp256r1" -> ECDSA_Secp256r1
else -> throw IllegalArgumentException("Algorithm not supported")
}
}
Expand Down Expand Up @@ -251,6 +251,9 @@ fun convertX25519PublicKeyFromMultibase58Btc(mbase58: String): ByteArray {
// 0x1205 rsa-pub
// 0xed ed25519-pub
// 0xe7 secp256k1-pub
// 0xeb51 jwk_jcs-pub

const val JwkJcsPubMultiCodecKeyCode = 0xeb51u

@Suppress("REDUNDANT_ELSE_IN_WHEN")
fun getMulticodecKeyCode(algorithm: KeyAlgorithm) = when (algorithm) {
Expand All @@ -261,16 +264,14 @@ fun getMulticodecKeyCode(algorithm: KeyAlgorithm) = when (algorithm) {
else -> throw IllegalArgumentException("No multicodec for algorithm $algorithm")
}

fun getKeyAlgorithmFromMultibase(mb: String): KeyAlgorithm {
val decoded = mb.decodeMultiBase58Btc()
val code = UVarInt.fromBytes(decoded)
return when (code.value) {
0xEDu -> KeyAlgorithm.EdDSA_Ed25519
0xE7u -> KeyAlgorithm.ECDSA_Secp256k1
0x1205u -> KeyAlgorithm.RSA
0x1200u -> KeyAlgorithm.ECDSA_Secp256r1
else -> throw IllegalArgumentException("No multicodec algorithm for code $code")
}
fun getMultiCodecKeyCode(mb: String): UInt = UVarInt.fromBytes(mb.decodeMultiBase58Btc()).value

fun getKeyAlgorithmFromKeyCode(keyCode: UInt): KeyAlgorithm = when (keyCode) {
0xEDu -> KeyAlgorithm.EdDSA_Ed25519
0xE7u -> KeyAlgorithm.ECDSA_Secp256k1
0x1205u -> KeyAlgorithm.RSA
0x1200u -> KeyAlgorithm.ECDSA_Secp256r1
else -> throw IllegalArgumentException("No multicodec algorithm for code $keyCode")
}

fun convertRawKeyToMultiBase58Btc(key: ByteArray, code: UInt): String {
Expand Down
6 changes: 2 additions & 4 deletions src/main/kotlin/id/walt/rest/core/DidController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import id.walt.common.KlaxonWithConverters
import id.walt.common.prettyPrint
import id.walt.crypto.KeyAlgorithm
import id.walt.model.DidMethod
import id.walt.rest.core.requests.did.CheqdCreateDidRequest
import id.walt.rest.core.requests.did.CreateDidRequest
import id.walt.rest.core.requests.did.EbsiCreateDidRequest
import id.walt.rest.core.requests.did.WebCreateDidRequest
import id.walt.rest.core.requests.did.*
import id.walt.services.did.*
import io.javalin.http.Context
import io.javalin.http.HttpCode
Expand Down Expand Up @@ -82,6 +79,7 @@ object DidController {
is WebCreateDidRequest -> DidWebCreateOptions(request.domain ?: "walt.id", request.path)
is EbsiCreateDidRequest -> DidEbsiCreateOptions(request.version)
is CheqdCreateDidRequest -> DidCheqdCreateOptions(request.network)
is KeyCreateDidRequest -> DidKeyCreateOptions(request.isJwk)
else -> null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ class CreateDidRequestMethodAdapter : TypeAdapter<CreateDidRequest> {


@Serializable
class KeyCreateDidRequest(override val keyAlias: String? = null) : CreateDidRequest("key")
class KeyCreateDidRequest(
override val keyAlias: String? = null,
val isJwk: Boolean = false,
) : CreateDidRequest("key")
@Serializable
class WebCreateDidRequest(
val domain: String? = null,
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/id/walt/services/did/DidOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ sealed class DidOptions
data class DidWebCreateOptions(val domain: String?, val path: String? = null) : DidOptions()
data class DidEbsiCreateOptions(val version: Int) : DidOptions()
data class DidCheqdCreateOptions(val network: String) : DidOptions()
data class DidKeyCreateOptions(val isJwk: Boolean) : DidOptions()

data class DidEbsiResolveOptions(val isRaw: Boolean) : DidOptions()
Loading

0 comments on commit 367b5a5

Please sign in to comment.