diff --git a/waltid-libraries/waltid-did/README.md b/waltid-libraries/waltid-did/README.md index b940603dd..6fb4f7caf 100644 --- a/waltid-libraries/waltid-did/README.md +++ b/waltid-libraries/waltid-did/README.md @@ -182,7 +182,7 @@ represented as **_walt.id crypto_** `Key`. rsa ✓ ‐ - ✗ + ✓ @@ -214,7 +214,7 @@ represented as **_walt.id crypto_** `Key`. rsa ✓ ‐ - ✗ + ✓ @@ -246,7 +246,7 @@ represented as **_walt.id crypto_** `Key`. rsa ✓ ✗ - ✗ + ✓ @@ -263,11 +263,17 @@ represented as **_walt.id crypto_** `Key`. - ebsi + ebsi secp256r1 ✗ ✗ + ✓ + + + secp256k1 + ✗ ✗ + ✓ @@ -286,7 +292,7 @@ represented as **_walt.id crypto_** `Key`. (*) The did:key implementation defaults to W3C CCG https://w3c-ccg.github.io/did-method-key/. By setting _useJwkJcsPub_ to `true` the EBSI implementation (jwk_jcs-pub encoding) according https://hub.ebsi.eu/tools/libraries/key-did-resolver is performed. -## Remote DID operations by 3d party services (fallback) +## Remote DID operations by 3rd party services (fallback) According Universal Resolver: https://github.com/decentralized-identity/universal-resolver/ diff --git a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/document/DidEbsiDocument.kt b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/document/DidEbsiDocument.kt new file mode 100644 index 000000000..3e1d9bdda --- /dev/null +++ b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/document/DidEbsiDocument.kt @@ -0,0 +1,72 @@ +package id.walt.did.dids.document + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlin.js.ExperimentalJsExport +import kotlin.js.JsExport +import kotlin.js.JsName + +@JsExport +@OptIn(ExperimentalSerializationApi::class, ExperimentalJsExport::class) +@Serializable +data class DidEbsiDocument( + @EncodeDefault @SerialName("@context") val context: List = DEFAULT_CONTEXT, + val id: String, // did:ebsi: + val controller: List?, + val verificationMethod: List?, + val authentication: List?, + val assertionMethod: List?, + val capabilityInvocation: List?, + val capabilityDelegation: List?, + val keyAgreement: List?, +) { + companion object { + private val DEFAULT_CONTEXT = + listOf("https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1") + private val json = Json { + explicitNulls = false + } + } + + @Serializable + data class VerificationMethod( + val id: String, // did:ebsi: + val type: String, // JsonWebKey2020 + val controller: String, // did:ebsi: + val publicKeyJwk: JsonObject // jwk + ) + + fun toMap() = json.encodeToJsonElement(this).jsonObject.toMap() + + @JsName("secondaryConstructor") + constructor(didDoc: DidDocument) : this( + context = DEFAULT_CONTEXT, + id = didDoc["id"]!!.jsonPrimitive.content, + controller = didDoc["controller"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + verificationMethod = didDoc["verificationMethod"]?.jsonArray?.map { + val verificationMethod = it.jsonObject + val id = verificationMethod["id"]!!.jsonPrimitive.content + val type = verificationMethod["type"]!!.jsonPrimitive.content + val controller = verificationMethod["controller"]!!.jsonPrimitive.content + val publicKeyJwk = verificationMethod["publicKeyJwk"]!!.jsonObject + VerificationMethod(id, type, controller, publicKeyJwk) + }, + authentication = didDoc["authentication"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + assertionMethod = didDoc["assertionMethod"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + capabilityInvocation = didDoc["capabilityInvocation"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + capabilityDelegation = didDoc["capabilityDelegation"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + keyAgreement = didDoc["keyAgreement"]?.jsonArray?.map { + it.jsonPrimitive.content + }, + ) +} \ No newline at end of file diff --git a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/LocalResolver.kt b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/LocalResolver.kt index 82448c663..56106f972 100644 --- a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/LocalResolver.kt +++ b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/LocalResolver.kt @@ -27,7 +27,7 @@ class LocalResolver : DidResolver { DidJwkResolver(), DidWebResolver(http), DidKeyResolver(), - DidEbsiResolver() + DidEbsiResolver(http) ).associateBy { it.method }.toMutableMap() fun deactivateMethod(method: String) { diff --git a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidEbsiResolver.kt b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidEbsiResolver.kt index a03b9c7a6..b654f5bd0 100644 --- a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidEbsiResolver.kt +++ b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidEbsiResolver.kt @@ -3,11 +3,13 @@ package id.walt.did.dids.resolver.local import id.walt.crypto.keys.Key import id.walt.crypto.keys.jwk.JWKKey import id.walt.did.dids.document.DidDocument +import id.walt.did.dids.document.DidEbsiDocument import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.client.request.* +import io.ktor.client.statement.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -22,36 +24,33 @@ import kotlin.js.JsExport @OptIn(ExperimentalJsExport::class) @JsExport -class DidEbsiResolver : LocalResolverMethod("ebsi") { +class DidEbsiResolver( + private val client: HttpClient, +) : LocalResolverMethod("ebsi") { val httpLogging = false + private val didRegistryUrlBaseURL = "https://api-conformance.ebsi.eu/did-registry/v5/identifiers/" + private val json = Json { ignoreUnknownKeys = true } @JvmBlocking @JvmAsync @JsPromise @JsExport.Ignore - override suspend fun resolve(did: String): Result { - val url = "https://api-conformance.ebsi.eu/did-registry/v5/identifiers/${did}" - - val httpClient = HttpClient { - install(ContentNegotiation) { - json(Json { ignoreUnknownKeys = true }) - } - if (httpLogging) { - install(Logging) { - logger = Logger.SIMPLE - level = LogLevel.HEADERS - } - } - } + override suspend fun resolve(did: String): Result = runCatching { + resolveDid(did) + } - val response = runCatching { + private suspend fun resolveDid(did: String): DidDocument { + val url = didRegistryUrlBaseURL + did + return client.get(url).bodyAsText().let { DidDocument( - jsonObject = httpClient.get(url).body() + DidEbsiDocument( + DidDocument( + jsonObject = Json.parseToJsonElement(it).jsonObject + ) + ).toMap() ) } - - return response } @JvmBlocking @@ -73,6 +72,13 @@ class DidEbsiResolver : LocalResolverMethod("ebsi") { return tryConvertAnyPublicKeyJwkToKey(publicKeyJwks) } + /* + Note from Christos: + There exist cases of EBSI DID Documents that only have secp256k1. There is nothing invalid + in not having a secp256r1 key. Hence, this function was changed to prioritize secp256r1 keys, + but not to return a failure result otherwise. + * NOTE: + * */ @JvmBlocking @JvmAsync @JsPromise @@ -82,6 +88,6 @@ class DidEbsiResolver : LocalResolverMethod("ebsi") { val result = JWKKey.importJWK(publicKeyJwk) if (result.isSuccess && publicKeyJwk.contains("P-256")) return result } - return Result.failure(NoSuchElementException("No key could be imported")) + return JWKKey.importJWK(publicKeyJwks.first()) } } diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidJwkConsistencyTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidJwkConsistencyTest.kt new file mode 100644 index 000000000..d0d05cc7e --- /dev/null +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidJwkConsistencyTest.kt @@ -0,0 +1,24 @@ +import id.walt.crypto.keys.KeyType +import id.walt.crypto.keys.jwk.JWKKey +import id.walt.did.dids.registrar.dids.DidJwkCreateOptions +import id.walt.did.dids.registrar.local.jwk.DidJwkRegistrar +import id.walt.did.dids.resolver.local.DidJwkResolver +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class LocalDidJwkConsistencyTest { + + private val localResolver = DidJwkResolver() + private val localRegistrar = DidJwkRegistrar() + + @Test + fun testDidJwkCreateAndResolveConsistency() = runTest{ + val keyList: List = KeyType.entries.map { JWKKey.generate(it) } + for (key in keyList) { + val didResult = localRegistrar.registerByKey(key, DidJwkCreateOptions(keyType = key.keyType)) + val resolvedKey = localResolver.resolveToKey(didResult.did).getOrThrow() + assertEquals(key.getThumbprint(),resolvedKey.getThumbprint()) + } + } +} \ No newline at end of file diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidKeyConsistencyTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidKeyConsistencyTest.kt new file mode 100644 index 000000000..0e69fe85e --- /dev/null +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidKeyConsistencyTest.kt @@ -0,0 +1,35 @@ +import id.walt.crypto.keys.KeyType +import id.walt.crypto.keys.jwk.JWKKey +import id.walt.did.dids.registrar.dids.DidKeyCreateOptions +import id.walt.did.dids.registrar.local.key.DidKeyRegistrar +import id.walt.did.dids.resolver.local.DidKeyResolver +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class LocalDidKeyConsistencyTest { + + private val localResolver = DidKeyResolver() + private val localRegistrar = DidKeyRegistrar() + + @Test + fun testDidKeyCreateAndResolveConsistency() = runTest{ + val keyList: List = KeyType.entries.map { JWKKey.generate(it) } + for (key in keyList) { + val didResult = localRegistrar.registerByKey(key, DidKeyCreateOptions(keyType = key.keyType)) + val resolvedKey = localResolver.resolveToKey(didResult.did).getOrThrow() + assertEquals(key.getThumbprint(),resolvedKey.getThumbprint()) + } + } + + @Test + fun testDidKeyCreateAndResolveJwkJcsPubConsistency() = runTest { + val keyList: List = KeyType.entries.map { JWKKey.generate(it) } + for (key in keyList) { + val didResult = localRegistrar.registerByKey(key, DidKeyCreateOptions(keyType = key.keyType, useJwkJcsPub = true)) + localResolver.resolveToKey(didResult.did) + val resolvedKey = localResolver.resolveToKey(didResult.did).getOrThrow() + assertEquals(key.getThumbprint(),resolvedKey.getThumbprint()) + } + } +} \ No newline at end of file diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidWebConsistencyTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidWebConsistencyTest.kt new file mode 100644 index 000000000..8bbe1a80f --- /dev/null +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/LocalDidWebConsistencyTest.kt @@ -0,0 +1,159 @@ +import id.walt.crypto.keys.Key +import id.walt.crypto.keys.KeyType +import id.walt.crypto.keys.jwk.JWKKey +import id.walt.did.dids.document.DidDocument +import id.walt.did.dids.registrar.dids.DidWebCreateOptions +import id.walt.did.dids.registrar.local.web.DidWebRegistrar +import id.walt.did.dids.resolver.local.DidWebResolver +import io.ktor.client.* +import io.ktor.client.engine.cio.* +import io.ktor.http.* +import io.ktor.network.tls.* +import io.ktor.network.tls.certificates.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.application.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import kotlinx.serialization.json.Json +import java.io.File +import java.security.cert.X509Certificate +import javax.net.ssl.X509TrustManager +import javax.security.auth.x500.X500Principal +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class LocalDidWebConsistencyTest { + + private val localResolver = DidWebResolver(DidWebTestHttpClient.http) + private val localRegistrar = DidWebRegistrar() + + private data class TestEntry( + val did: String, + val key: Key, + val doc: DidDocument, + val domain: String, + val path: String, + ) + + private val didWebTestEntryList: List + private val didWebPathToDocMap = mutableMapOf() + private val didWebTestServer: NettyApplicationEngine + + private val keyStoreFile = File(this.javaClass.classLoader.getResource("")!!.path.plus("keystore.jks")) + private val keyStore = buildKeyStore { + certificate("test") { + password = "test123" + domains = listOf("localhost", "127.0.0.1", "0.0.0.0") + subject = X500Principal("CN=localhost, OU=walt.id, O=walt.id, C=AT") + } + }.also { it.saveToFile(keyStoreFile, "test123") } + private val environment = applicationEngineEnvironment { + envConfig() + } + + init { + didWebTestEntryList = populateTestData() + didWebTestServer = embeddedServer( + Netty, + environment, + ).start(false) + } + + @AfterTest + fun cleanUp() { + didWebTestServer.stop() + } + + @Test + fun testDidWebCreateAndResolveConsistency() = runTest { + for (entry in didWebTestEntryList) { + val resolvedKey = localResolver.resolveToKey(entry.did).getOrThrow() + assertEquals(entry.key.getThumbprint(), resolvedKey.getThumbprint()) + } + } + + private fun populateTestData(): List = runBlocking { + val keyList: List = KeyType.entries.map { JWKKey.generate(it) } + val domain = "localhost:3021" + keyList.map { + val path = it.keyType.toString().lowercase() + val didResult = localRegistrar.registerByKey( + it, + DidWebCreateOptions( + domain = domain, + path = path, + it.keyType + ) + ) + didWebPathToDocMap[path] = didResult.didDocument + TestEntry( + didResult.did, + it, + didResult.didDocument, + domain, + path, + ) + } + } + + private fun ApplicationEngineEnvironmentBuilder.envConfig() { + module { + module() + } + connector { + port = 8000 + } + sslConnector( + keyStore = keyStore, + keyAlias = "test", + keyStorePassword = { "test123".toCharArray() }, + privateKeyPassword = { "test123".toCharArray() }) { + port = 3021 + keyStorePath = keyStoreFile + } + } + + private fun Application.module() { + install(ContentNegotiation) { + json(Json { ignoreUnknownKeys = true }) + } + routing { + get("/{path}/did.json") { + if (call.parameters["path"] != null && call.parameters["path"] != "") { + val doc = didWebPathToDocMap[call.parameters["path"]] + call.respondText(doc!!.toJsonObject().toString(), ContentType.Application.Json) + } + call.response.status(HttpStatusCode.NotFound) + } + } + } + + private object DidWebTestHttpClient { + + val http = HttpClient(CIO) { + install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { + json(DidWebResolver.json) + } + engine { + https { + trustManager = TrustAllManager(this) + } + } + } + + private class TrustAllManager(config: TLSConfigBuilder) : X509TrustManager { + private val delegate = config.build().trustManager + override fun checkClientTrusted(certificates: Array?, authType: String?) {} + override fun checkServerTrusted(certificates: Array?, authType: String?) {} + override fun getAcceptedIssuers(): Array = delegate.acceptedIssuers + } + } + +} + diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/registrars/DidKeyRegistrarTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/registrars/DidKeyRegistrarTest.kt index 6c34c25b8..b37e790d0 100644 --- a/waltid-libraries/waltid-did/src/jvmTest/kotlin/registrars/DidKeyRegistrarTest.kt +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/registrars/DidKeyRegistrarTest.kt @@ -39,40 +39,67 @@ class DidKeyRegistrarTest : DidRegistrarTestBase(DidKeyRegistrar()) { @JvmStatic fun `given did options with no key when register then returns a valid did result`(): Stream = Stream.of( - arguments(DidKeyCreateOptions(useJwkJcsPub = true), ed25519DidAssertions), arguments(DidKeyCreateOptions(KeyType.Ed25519), ed25519DidAssertions), + arguments(DidKeyCreateOptions(KeyType.Ed25519, useJwkJcsPub = true), ed25519DidAssertions), arguments(DidKeyCreateOptions(KeyType.RSA), rsaDidAssertions), + arguments(DidKeyCreateOptions(KeyType.RSA, useJwkJcsPub = true), rsaDidAssertions), arguments(DidKeyCreateOptions(KeyType.secp256k1), secp256DidAssertions), + arguments(DidKeyCreateOptions(KeyType.secp256k1, useJwkJcsPub = true), secp256DidAssertions), arguments(DidKeyCreateOptions(KeyType.secp256r1), secp256DidAssertions), + arguments(DidKeyCreateOptions(KeyType.secp256r1, useJwkJcsPub = true), secp256DidAssertions), ) @JvmStatic fun `given did options and key when register with key then returns a valid did result`(): Stream = Stream.of( - //ed25519 + //ed25519 without jwk jcs pub encoding + arguments( + runBlocking { JWKKey.generate(KeyType.Ed25519) }, + DidKeyCreateOptions(), + ed25519KeyAssertions + ), + //ed25519 with jwk jcs pub encoding arguments( runBlocking { JWKKey.generate(KeyType.Ed25519) }, DidKeyCreateOptions(useJwkJcsPub = true), ed25519KeyAssertions ), - //rsa + //rsa without jwk jcs pub encoding arguments( runBlocking { JWKKey.generate(KeyType.RSA) }, DidKeyCreateOptions(), rsaKeyAssertions ), - //secp256k1 + //rsa with jwk jcs pub encoding + arguments( + runBlocking { JWKKey.generate(KeyType.RSA) }, + DidKeyCreateOptions(useJwkJcsPub = true), + rsaKeyAssertions + ), + //secp256k1 without jwk jcs pub encoding arguments( runBlocking { JWKKey.generate(KeyType.secp256k1) }, DidKeyCreateOptions(), secp256KeyAssertions ), - //secp256r1 + //secp256k1 with jwk jcs pub encoding + arguments( + runBlocking { JWKKey.generate(KeyType.secp256k1) }, + DidKeyCreateOptions(useJwkJcsPub = true), + secp256KeyAssertions + ), + //secp256r1 without jwk jcs pub encoding arguments( runBlocking { JWKKey.generate(KeyType.secp256r1) }, DidKeyCreateOptions(), secp256KeyAssertions ), + //secp256r1 with jwk jcs pub encoding + arguments( + runBlocking { JWKKey.generate(KeyType.secp256r1) }, + DidKeyCreateOptions(useJwkJcsPub = true), + secp256KeyAssertions + ), ) } } diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidEbsiResolverTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidEbsiResolverTest.kt new file mode 100644 index 000000000..6ef0109c5 --- /dev/null +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidEbsiResolverTest.kt @@ -0,0 +1,261 @@ +package resolvers + +import id.walt.crypto.keys.Key +import id.walt.did.dids.document.DidDocument +import id.walt.did.dids.resolver.local.DidEbsiResolver +import id.walt.did.dids.resolver.local.LocalResolverMethod +import io.ktor.client.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.Arguments.arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +class DidEbsiResolverTest : DidResolverTestBase() { + override val resolver: LocalResolverMethod = DidEbsiResolver(HttpClient()) + + @ParameterizedTest + @MethodSource + override fun `given a did String, when calling resolve, then the result is a valid did document`( + did: String, key: JsonObject, assert: resolverAssertion + ) { + super.`given a did String, when calling resolve, then the result is a valid did document`(did, key, assert) + } + + @ParameterizedTest + @MethodSource + override fun `given a did String, when calling resolveToKey, then the result is valid key`( + did: String, + key: JsonObject, + assert: resolverAssertion + ) { + super.`given a did String, when calling resolveToKey, then the result is valid key`(did, key, assert) + } + + companion object { + + @JvmStatic + fun `given a did String, when calling resolve, then the result is a valid did document`(): Stream = + katiList.stream().flatMap { + val curDid = it.did + it.expectedDocValidAssertionList.map { innerIt -> + arguments(curDid, innerIt.first, innerIt.second) + }.stream() + } + + @JvmStatic + fun `given a did String, when calling resolveToKey, then the result is valid key`(): Stream = + katiList.stream() + .map { arguments(it.did, it.expectedKeyValidAssertion.first, it.expectedKeyValidAssertion.second) } + + data class TestEntry( + val did: String, + val expectedDidDoc: JsonObject, + val expectedDocValidAssertionList: List>>, + val expectedKeyValidAssertion: Pair>, + ) + + + private val katiList: List = listOf( + TestEntry( + "did:ebsi:z21Bs13TqhZV7RY727hX22XF", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:z21Bs13TqhZV7RY727hX22XF\",\"controller\":[\"did:ebsi:z21Bs13TqhZV7RY727hX22XF\"],\"verificationMethod\":[{\"id\":\"did:ebsi:z21Bs13TqhZV7RY727hX22XF#_bQu28sgqr1qnjSjJEKBGnRDilhlz7AtYYp5mMg83r0\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z21Bs13TqhZV7RY727hX22XF\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"dHVH5LYmdPKXb0o9CqgUJIaqHe0qC1OWQKXb_6jg2Dg\",\"y\":\"BDsY_JM9UGaTfuHcXR9wD4j8ExEnh3J4_MFIuTyOyHU\"}}],\"authentication\":[\"did:ebsi:z21Bs13TqhZV7RY727hX22XF#_bQu28sgqr1qnjSjJEKBGnRDilhlz7AtYYp5mMg83r0\"],\"capabilityInvocation\":[\"did:ebsi:z21Bs13TqhZV7RY727hX22XF#_bQu28sgqr1qnjSjJEKBGnRDilhlz7AtYYp5mMg83r0\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"dHVH5LYmdPKXb0o9CqgUJIaqHe0qC1OWQKXb_6jg2Dg\",\"y\":\"BDsY_JM9UGaTfuHcXR9wD4j8ExEnh3J4_MFIuTyOyHU\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"dHVH5LYmdPKXb0o9CqgUJIaqHe0qC1OWQKXb_6jg2Dg\",\"y\":\"BDsY_JM9UGaTfuHcXR9wD4j8ExEnh3J4_MFIuTyOyHU\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zj46t2gXPgmdriraZG6mb5A", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zj46t2gXPgmdriraZG6mb5A\",\"controller\":[\"did:ebsi:zj46t2gXPgmdriraZG6mb5A\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#7-1eNcG4MFkxahS1m85zcyu9ey_zOAl_fxvSPtI5Q2k\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zj46t2gXPgmdriraZG6mb5A\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"u0LAULtFwOQwusN8esicYCz579culZW5htoPC_ADha4\",\"y\":\"mYnbYZH4iyvlyMWuXE-X2ssebVE7VC9aW3wPxkU9wdQ\"}},{\"id\":\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#awSc2nG7WGNGw9YDtnVZ5HPOjeIhC8eb8UDOr3QV1Fc\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zj46t2gXPgmdriraZG6mb5A\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mDX7h2ZIOL1993wj4H83_jg67d_TaYk3dvVL447rRC0\",\"y\":\"Lr-efgLN1QPv-rb2sk-4gv7cVwXpzTY6FE8kdNHUUwU\"}}],\"authentication\":[\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#7-1eNcG4MFkxahS1m85zcyu9ey_zOAl_fxvSPtI5Q2k\",\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#awSc2nG7WGNGw9YDtnVZ5HPOjeIhC8eb8UDOr3QV1Fc\"],\"assertionMethod\":[\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#awSc2nG7WGNGw9YDtnVZ5HPOjeIhC8eb8UDOr3QV1Fc\",\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#7-1eNcG4MFkxahS1m85zcyu9ey_zOAl_fxvSPtI5Q2k\"],\"capabilityInvocation\":[\"did:ebsi:zj46t2gXPgmdriraZG6mb5A#7-1eNcG4MFkxahS1m85zcyu9ey_zOAl_fxvSPtI5Q2k\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"u0LAULtFwOQwusN8esicYCz579culZW5htoPC_ADha4\",\"y\":\"mYnbYZH4iyvlyMWuXE-X2ssebVE7VC9aW3wPxkU9wdQ\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mDX7h2ZIOL1993wj4H83_jg67d_TaYk3dvVL447rRC0\",\"y\":\"Lr-efgLN1QPv-rb2sk-4gv7cVwXpzTY6FE8kdNHUUwU\"}"), + secp256DidAssertions + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mDX7h2ZIOL1993wj4H83_jg67d_TaYk3dvVL447rRC0\",\"y\":\"Lr-efgLN1QPv-rb2sk-4gv7cVwXpzTY6FE8kdNHUUwU\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD\",\"controller\":[\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#zWNYsdkpxcq6wMfNGhsB7ns3sSOT5yCtrc4gBxHG-Mc\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"4TgiV8Fk3nG4At4ija1KQU_1N_DrI7STwyHBYnXxk7U\",\"y\":\"8wrHJAN1hdVGmXIoGnuqOIhnFC4PzKgCsHIWM50Jxwc\"}},{\"id\":\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#T6iPMW-k8O4uwZid29GwLe-Njg40E6jNT7hdLpJ3ZSg\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"AvOFLJgwIftVMBmW0Adfw1vZ6_f5rKz2Q9Il8tMyYv4\",\"y\":\"ZGynk89Jz8qKKP3qTlVm-w6LWc895B6__JbS4ldAQio\"}}],\"authentication\":[\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#zWNYsdkpxcq6wMfNGhsB7ns3sSOT5yCtrc4gBxHG-Mc\",\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#T6iPMW-k8O4uwZid29GwLe-Njg40E6jNT7hdLpJ3ZSg\"],\"assertionMethod\":[\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#T6iPMW-k8O4uwZid29GwLe-Njg40E6jNT7hdLpJ3ZSg\"],\"capabilityInvocation\":[\"did:ebsi:zjHZjJ4Sy7r92BxXzFGs7qD#zWNYsdkpxcq6wMfNGhsB7ns3sSOT5yCtrc4gBxHG-Mc\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"4TgiV8Fk3nG4At4ija1KQU_1N_DrI7STwyHBYnXxk7U\",\"y\":\"8wrHJAN1hdVGmXIoGnuqOIhnFC4PzKgCsHIWM50Jxwc\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"AvOFLJgwIftVMBmW0Adfw1vZ6_f5rKz2Q9Il8tMyYv4\",\"y\":\"ZGynk89Jz8qKKP3qTlVm-w6LWc895B6__JbS4ldAQio\"}"), + secp256DidAssertions + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"AvOFLJgwIftVMBmW0Adfw1vZ6_f5rKz2Q9Il8tMyYv4\",\"y\":\"ZGynk89Jz8qKKP3qTlVm-w6LWc895B6__JbS4ldAQio\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD\",\"controller\":[\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#pABLTNzSQAsmp_o9o-fHsZFDTdHg4qI7zIotD0q4BuM\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"cKWH4GgY2T4veJJZOgvu1AQo8ZtyXCyqelmoJLMD7tE\",\"y\":\"qasRE5xIHWhNSO0kQWG2ZGxc7NYMhuIMIF7kXACC-zQ\"}},{\"id\":\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#05tX5S5X6_tHSIBgBQQheNCWsqg16Pp9waiz4IdSCKI\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mtkBFqZiXcm1qNyTfcATB5gjlhFUK42ElVw9ho1F5Rc\",\"y\":\"qc3QRI1_Jb1i_jQPk8rlJbtZHtcvZg6PNL6v_C9IucQ\"}}],\"authentication\":[\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#pABLTNzSQAsmp_o9o-fHsZFDTdHg4qI7zIotD0q4BuM\",\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#05tX5S5X6_tHSIBgBQQheNCWsqg16Pp9waiz4IdSCKI\"],\"assertionMethod\":[\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#05tX5S5X6_tHSIBgBQQheNCWsqg16Pp9waiz4IdSCKI\",\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#pABLTNzSQAsmp_o9o-fHsZFDTdHg4qI7zIotD0q4BuM\"],\"capabilityInvocation\":[\"did:ebsi:zuzDMJqHyxtCEE6FRuCPTgD#pABLTNzSQAsmp_o9o-fHsZFDTdHg4qI7zIotD0q4BuM\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"cKWH4GgY2T4veJJZOgvu1AQo8ZtyXCyqelmoJLMD7tE\",\"y\":\"qasRE5xIHWhNSO0kQWG2ZGxc7NYMhuIMIF7kXACC-zQ\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mtkBFqZiXcm1qNyTfcATB5gjlhFUK42ElVw9ho1F5Rc\",\"y\":\"qc3QRI1_Jb1i_jQPk8rlJbtZHtcvZg6PNL6v_C9IucQ\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"mtkBFqZiXcm1qNyTfcATB5gjlhFUK42ElVw9ho1F5Rc\",\"y\":\"qc3QRI1_Jb1i_jQPk8rlJbtZHtcvZg6PNL6v_C9IucQ\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd\",\"controller\":[\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#GCocFFVY5IKotB3Gae70EveOa2XsVYorfOeRF9QMdkY\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"TZmvrZc0oFEuZskm-M2yQLqdcjXQgoiWBIB6LUtUG4s\",\"y\":\"p6JdZyx81QoYAPNSLIiR0hWGBzFejs-GnKt6kKzBk9I\"}},{\"id\":\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#q9YqiPX_jrQy8dIDLa9yzeuJQiTdjudD9sgbMAfqB2Q\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"juTV0do_XCbGfOu9DyPbaXVv-_HfnQwv6rBRo1uLX00\",\"y\":\"Xn3GCn5H9SdP5r0zbGTE1JXVoporSw23CU0To3tibAk\"}}],\"authentication\":[\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#GCocFFVY5IKotB3Gae70EveOa2XsVYorfOeRF9QMdkY\",\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#q9YqiPX_jrQy8dIDLa9yzeuJQiTdjudD9sgbMAfqB2Q\"],\"assertionMethod\":[\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#q9YqiPX_jrQy8dIDLa9yzeuJQiTdjudD9sgbMAfqB2Q\",\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#GCocFFVY5IKotB3Gae70EveOa2XsVYorfOeRF9QMdkY\"],\"capabilityInvocation\":[\"did:ebsi:zaA9cXrqiCD4n3AqX4yD7Gd#GCocFFVY5IKotB3Gae70EveOa2XsVYorfOeRF9QMdkY\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"TZmvrZc0oFEuZskm-M2yQLqdcjXQgoiWBIB6LUtUG4s\",\"y\":\"p6JdZyx81QoYAPNSLIiR0hWGBzFejs-GnKt6kKzBk9I\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"juTV0do_XCbGfOu9DyPbaXVv-_HfnQwv6rBRo1uLX00\",\"y\":\"Xn3GCn5H9SdP5r0zbGTE1JXVoporSw23CU0To3tibAk\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"juTV0do_XCbGfOu9DyPbaXVv-_HfnQwv6rBRo1uLX00\",\"y\":\"Xn3GCn5H9SdP5r0zbGTE1JXVoporSw23CU0To3tibAk\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P\",\"controller\":[\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P\"],\"verificationMethod\":[{\"id\":\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#p4k-BPfU08EvNJAfm3IL2SOXCnwG-zZY4BFKVWVoRog\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"AfUb92zIDYfTQnBt4WWTu5C1_Br42R4nV2L65w-beRQ\",\"y\":\"D-iXTeL0-ib-eHmgIftHhoCfuyQUZwHpaug8zdoJwy8\"}},{\"id\":\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#syImaaEUN-qism4UnsDaKEFZ1OiyR_R5TuY7fW4LXZ8\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"-Nspjw4dCEGcxE5JeG-DCRmtoui3TiWPB9ijTXgRQTc\",\"y\":\"hY0P4EH_0IxjAcksz-9jHKU_SdadUqnpiwSFce4wSg0\"}}],\"authentication\":[\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#p4k-BPfU08EvNJAfm3IL2SOXCnwG-zZY4BFKVWVoRog\",\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#syImaaEUN-qism4UnsDaKEFZ1OiyR_R5TuY7fW4LXZ8\"],\"assertionMethod\":[\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#syImaaEUN-qism4UnsDaKEFZ1OiyR_R5TuY7fW4LXZ8\"],\"capabilityInvocation\":[\"did:ebsi:z24Qnyqxd6cX5LeGRPdfZf3P#p4k-BPfU08EvNJAfm3IL2SOXCnwG-zZY4BFKVWVoRog\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"AfUb92zIDYfTQnBt4WWTu5C1_Br42R4nV2L65w-beRQ\",\"y\":\"D-iXTeL0-ib-eHmgIftHhoCfuyQUZwHpaug8zdoJwy8\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"-Nspjw4dCEGcxE5JeG-DCRmtoui3TiWPB9ijTXgRQTc\",\"y\":\"hY0P4EH_0IxjAcksz-9jHKU_SdadUqnpiwSFce4wSg0\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"-Nspjw4dCEGcxE5JeG-DCRmtoui3TiWPB9ijTXgRQTc\",\"y\":\"hY0P4EH_0IxjAcksz-9jHKU_SdadUqnpiwSFce4wSg0\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zwPFzwurMARpaw7KfCWY3qK", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK\",\"controller\":[\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#WHg1oqWFmR7L7YrVozU0TVGb68_19yW_-c4Yw7DMLO0\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"eO7RXSY1A2iiyhvf7i2InIQFfZjT8izOIn0TMt0BptE\",\"y\":\"sLL8kmzPRFh9TLrQdj18rzkrZN4--R-gNkzrIjbRr-k\"}},{\"id\":\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#JRM0Eu1MTpADnpCvEcz7Nj0-Qpy4-lctgsOPBncBZ9c\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"0IFKfGudFz02SR0S-kYY_soqK5FLuWrjsU_L7nc1DNs\",\"y\":\"D-EpehGuos8W7qyV77t4w847T24s6Rez71lWuqihU2c\"}}],\"authentication\":[\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#WHg1oqWFmR7L7YrVozU0TVGb68_19yW_-c4Yw7DMLO0\",\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#JRM0Eu1MTpADnpCvEcz7Nj0-Qpy4-lctgsOPBncBZ9c\"],\"assertionMethod\":[\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#JRM0Eu1MTpADnpCvEcz7Nj0-Qpy4-lctgsOPBncBZ9c\"],\"capabilityInvocation\":[\"did:ebsi:zwPFzwurMARpaw7KfCWY3qK#WHg1oqWFmR7L7YrVozU0TVGb68_19yW_-c4Yw7DMLO0\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"eO7RXSY1A2iiyhvf7i2InIQFfZjT8izOIn0TMt0BptE\",\"y\":\"sLL8kmzPRFh9TLrQdj18rzkrZN4--R-gNkzrIjbRr-k\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"0IFKfGudFz02SR0S-kYY_soqK5FLuWrjsU_L7nc1DNs\",\"y\":\"D-EpehGuos8W7qyV77t4w847T24s6Rez71lWuqihU2c\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"0IFKfGudFz02SR0S-kYY_soqK5FLuWrjsU_L7nc1DNs\",\"y\":\"D-EpehGuos8W7qyV77t4w847T24s6Rez71lWuqihU2c\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\",\"controller\":[\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\"],\"verificationMethod\":[{\"id\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#vut3AiXz8I-8MiMDNzJg3fBwrLiGPGHqIkFf11dLSrM\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"fcKROMFjLeVbBqC85a8CqdW0SuaFcjKo30ZQ3oc4g7Q\",\"y\":\"hmdWyHYSiJBHKpyrfXTuReNgNx8zBzNOJ05uld-0CwA\"}},{\"id\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#qnzNkpKXrn5B2TNFfqV28H50ai5NI9NeoTJgYQQyJkw\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"RSa9erH7Pe8eReZOzDk21lMo7900xTSo5XNrW5XxL9E\",\"y\":\"8Jpf0RmLngsz5ynDmIERV8PM61zK-U0l1scum9GgBJM\"}},{\"id\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#ZzZast3tPsTS9Avg1t21Et3d-4_j14sUR1bQg1tNH2s\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\",\"publicKeyJwk\":{\"kty\":\"RSA\",\"n\":\"v35Qi_SQ40YZOSa9Ruzh_c1JP4OQXxnFYaDPCSNhu6sbNWVsAc4LWR2mS3wDGQ1G93E6pg96aZR4JqiHoDoXs6qYbcNm1lZtdg2mpX1kGazO7PXgp7KuN4AEJmWAGyAqfjeb4jGevBCJondnBNtqmr_rvQa3Rqnij8KIzqn9Wr4Zu8d6qKbgUlZxYiZPIr8OVdopX5dgodtIagkW7IMLBsW4l22-2TYeD9hz4XQmHVyhvemKhwN4mWIgSgXF19jiD_wcAtKUgn5uokX45mi8H3_f0-WvRuu6Dl0q1ZnoPiyT07FjdBuLSNu7vxRPQWUtaqum9fEoqdyOrZKZNE7ooQ\",\"e\":\"AQAB\"}},{\"id\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#08upLhRl50l-A2XQ2L1ZQVWkArOHpAQviqSpwp4InEA\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge\",\"publicKeyJwk\":{\"crv\":\"Ed25519\",\"x\":\"dQJ74l6r97Wo4Nuxwptv_EztdCgMkPcl6Lia8l6avzU\",\"kty\":\"OKP\"}}],\"authentication\":[\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#vut3AiXz8I-8MiMDNzJg3fBwrLiGPGHqIkFf11dLSrM\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#qnzNkpKXrn5B2TNFfqV28H50ai5NI9NeoTJgYQQyJkw\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#ZzZast3tPsTS9Avg1t21Et3d-4_j14sUR1bQg1tNH2s\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#08upLhRl50l-A2XQ2L1ZQVWkArOHpAQviqSpwp4InEA\"],\"assertionMethod\":[\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#qnzNkpKXrn5B2TNFfqV28H50ai5NI9NeoTJgYQQyJkw\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#vut3AiXz8I-8MiMDNzJg3fBwrLiGPGHqIkFf11dLSrM\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#ZzZast3tPsTS9Avg1t21Et3d-4_j14sUR1bQg1tNH2s\",\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#08upLhRl50l-A2XQ2L1ZQVWkArOHpAQviqSpwp4InEA\"],\"capabilityInvocation\":[\"did:ebsi:z24AVGY1vsRLc6ZcGUH6r2Ge#vut3AiXz8I-8MiMDNzJg3fBwrLiGPGHqIkFf11dLSrM\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"fcKROMFjLeVbBqC85a8CqdW0SuaFcjKo30ZQ3oc4g7Q\",\"y\":\"hmdWyHYSiJBHKpyrfXTuReNgNx8zBzNOJ05uld-0CwA\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"RSa9erH7Pe8eReZOzDk21lMo7900xTSo5XNrW5XxL9E\",\"y\":\"8Jpf0RmLngsz5ynDmIERV8PM61zK-U0l1scum9GgBJM\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"RSa9erH7Pe8eReZOzDk21lMo7900xTSo5XNrW5XxL9E\",\"y\":\"8Jpf0RmLngsz5ynDmIERV8PM61zK-U0l1scum9GgBJM\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zbiABMoKYdMDcu56oXizxxB", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zbiABMoKYdMDcu56oXizxxB\",\"controller\":[\"did:ebsi:zbiABMoKYdMDcu56oXizxxB\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#UWfgOq5Q1lt6HJlY-LrVlbl9S9k538_NYpx6rip_Mp0\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zbiABMoKYdMDcu56oXizxxB\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"NpYbgWTX6TpeN3TC2tl49ULEk_qflBJ3THY1EladubI\",\"y\":\"AGocDIS_gpJN5zQBBFtgGvM2pKwopSjxZ2sBOqWzDxQ\"}},{\"id\":\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#imFjgN0RrHNIQdudOCqrq_Y-7xkPZa53UtNQvMTm_6Y\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zbiABMoKYdMDcu56oXizxxB\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"flk7PEpPB_D8HInoWUgL4fgh52iBGQ-H35qNL42lQ6U\",\"y\":\"ho4J0JQtKWOAVPtEyzb4LNWNPfEbrNtCPAiHUzOWgEQ\"}}],\"authentication\":[\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#UWfgOq5Q1lt6HJlY-LrVlbl9S9k538_NYpx6rip_Mp0\",\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#imFjgN0RrHNIQdudOCqrq_Y-7xkPZa53UtNQvMTm_6Y\"],\"assertionMethod\":[\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#imFjgN0RrHNIQdudOCqrq_Y-7xkPZa53UtNQvMTm_6Y\"],\"capabilityInvocation\":[\"did:ebsi:zbiABMoKYdMDcu56oXizxxB#UWfgOq5Q1lt6HJlY-LrVlbl9S9k538_NYpx6rip_Mp0\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"NpYbgWTX6TpeN3TC2tl49ULEk_qflBJ3THY1EladubI\",\"y\":\"AGocDIS_gpJN5zQBBFtgGvM2pKwopSjxZ2sBOqWzDxQ\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"flk7PEpPB_D8HInoWUgL4fgh52iBGQ-H35qNL42lQ6U\",\"y\":\"ho4J0JQtKWOAVPtEyzb4LNWNPfEbrNtCPAiHUzOWgEQ\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"flk7PEpPB_D8HInoWUgL4fgh52iBGQ-H35qNL42lQ6U\",\"y\":\"ho4J0JQtKWOAVPtEyzb4LNWNPfEbrNtCPAiHUzOWgEQ\"}"), + secp256KeyAssertions, + ), + ), + TestEntry( + "did:ebsi:zr4QYv94jLekTJ5d3k2nVz1", + Json.decodeFromString( + "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"],\"id\":\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1\",\"controller\":[\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1\"],\"verificationMethod\":[{\"id\":\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#o2UCggyx3GBstYsYEg5fjnlyc1a0Lfw4gth83dDZcDY\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"FzuNuBO4ThY6JcxiGlOqA7pysycp-JggEbsY3VTs7iA\",\"y\":\"mPh3a6N8-lwoCwUzpFIQQ0iHhhXrSyS5BQ-dymLg66E\"}},{\"id\":\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#V1SMDlhcShsWDv-TB7oJTMjoRp0gJML_0Dh0mMgUvgc\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1\",\"publicKeyJwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"GDLvQXUiZNkT2ZtywzsLYdxaS7_VBAsJ_gAma87dwRw\",\"y\":\"KWMKMjTpUVGtfDSe_bgOEPisA_gpDJFRR-GAl0EuS_M\"}}],\"authentication\":[\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#o2UCggyx3GBstYsYEg5fjnlyc1a0Lfw4gth83dDZcDY\",\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#V1SMDlhcShsWDv-TB7oJTMjoRp0gJML_0Dh0mMgUvgc\"],\"assertionMethod\":[\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#V1SMDlhcShsWDv-TB7oJTMjoRp0gJML_0Dh0mMgUvgc\"],\"capabilityInvocation\":[\"did:ebsi:zr4QYv94jLekTJ5d3k2nVz1#o2UCggyx3GBstYsYEg5fjnlyc1a0Lfw4gth83dDZcDY\"]}" + ), + listOf( + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"secp256k1\",\"x\":\"FzuNuBO4ThY6JcxiGlOqA7pysycp-JggEbsY3VTs7iA\",\"y\":\"mPh3a6N8-lwoCwUzpFIQQ0iHhhXrSyS5BQ-dymLg66E\"}"), + secp256DidAssertions, + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"GDLvQXUiZNkT2ZtywzsLYdxaS7_VBAsJ_gAma87dwRw\",\"y\":\"KWMKMjTpUVGtfDSe_bgOEPisA_gpDJFRR-GAl0EuS_M\"}"), + secp256DidAssertions, + ), + ), + Pair( + Json.decodeFromString("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"GDLvQXUiZNkT2ZtywzsLYdxaS7_VBAsJ_gAma87dwRw\",\"y\":\"KWMKMjTpUVGtfDSe_bgOEPisA_gpDJFRR-GAl0EuS_M\"}"), + secp256KeyAssertions, + ), + ), + ) + } + +} \ No newline at end of file diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidJwkResolverTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidJwkResolverTest.kt index aa30cabbc..8eacb34fe 100644 --- a/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidJwkResolverTest.kt +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidJwkResolverTest.kt @@ -72,12 +72,12 @@ class DidJwkResolverTest : DidResolverTestBase() { Json.decodeFromString("{\"kty\":\"OKP\",\"use\":\"sig\",\"crv\":\"Ed25519\",\"kid\":\"151df6ec01714883b812f26f2d63e584\",\"x\":\"qBDsYw3k62mUT8UmEx99Xz3yckiSRmTsL6aa21ZcAVM\",\"alg\":\"EdDSA\"}"), ed25519Assertions ), -// //rsa -// arguments( -// "", -// Json.decodeFromString(""), -// rsaAssertions -// ),//not implemented core-crypto + //rsa + arguments( + "did:jwk:eyJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsImtpZCI6Im1FRDVFTk91c19ZSkVsWi0tM2VKMk9OUzMteVMtbHFUMWgxU216NlJMNmciLCJuIjoibUxRR3gtRmZXUkZURjdtdlZuaVVoX1F0UkhRWDUxUVJZZnN3ZWNJUlhuZ1JXU2lmZjJQZEpTRmdHbS1CRlJsQ1NhbmJTVm1ONVg0RXNqdnhmaUdGcFVmLWFUdUNMbzJDVWdqRzdILXk0c2JQYW9ieXNaaG8zWWowV0ZKQU9IczBSUE0teG1YSW91cXpCLVExYjF0TDh2QjJpd2Y2TnJsVWFuNGxIQXR6LVFKS0JnbThWUTVuOGVIaG5Fa1hoRlkxREFTcXpQMzRvTTBmaDhYSmtIN0gyckduME5hLWRxR2Z6WVFkMWJyQUk5ZTlwVnN4WVNUSExieFhxMDRfQThiQVhDUkdVMkx2TURIVVR5V2JvSGhBZm9pd245VjI1MmRKYXBfWUxQYldtNzFjNmdyb0lQcXB6d2pxaS1HTHhxRmI1ZExMYUQ0aDRPbnB2NlhCc29DbXdRIn0", + Json.decodeFromString("{\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"mED5ENOus_YJElZ--3eJ2ONS3-yS-lqT1h1Smz6RL6g\",\"n\":\"mLQGx-FfWRFTF7mvVniUh_QtRHQX51QRYfswecIRXngRWSiff2PdJSFgGm-BFRlCSanbSVmN5X4EsjvxfiGFpUf-aTuCLo2CUgjG7H-y4sbPaobysZho3Yj0WFJAOHs0RPM-xmXIouqzB-Q1b1tL8vB2iwf6NrlUan4lHAtz-QJKBgm8VQ5n8eHhnEkXhFY1DASqzP34oM0fh8XJkH7H2rGn0Na-dqGfzYQd1brAI9e9pVsxYSTHLbxXq04_A8bAXCRGU2LvMDHUTyWboHhAfoiwn9V252dJap_YLPbWm71c6groIPqpzwjqi-GLxqFb5dLLaD4h4Onpv6XBsoCmwQ\"}"), + rsaAssertions + ), ) } } diff --git a/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidWebResolverTest.kt b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidWebResolverTest.kt index 303176024..80d79b9ce 100644 --- a/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidWebResolverTest.kt +++ b/waltid-libraries/waltid-did/src/jvmTest/kotlin/resolvers/DidWebResolverTest.kt @@ -91,12 +91,12 @@ class DidWebResolverTest : DidResolverTestBase() { Json.decodeFromString("{\"alg\":\"EdDSA\",\"crv\":\"Ed25519\",\"kid\":\"151df6ec01714883b812f26f2d63e584\",\"kty\":\"OKP\",\"use\":\"sig\",\"x\":\"qBDsYw3k62mUT8UmEx99Xz3yckiSRmTsL6aa21ZcAVM\"}"), ed25519Assertions ), -// //rsa -// arguments( -// "did:web:localhost%3A8080:rsa", -// Json.decodeFromString("{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"ab269ce10ce94b7c9565e30c034b5692\",\"kty\":\"RSA\",\"n\":\"0qbslQ5uMXL1Wk4dUD5ftrGWLhgaQENQn8AaPVREg12H_Mfr2GEL0IkBd7EQPeRFzRzngF2kWpij_nyueYKGQ3um_hione72pozP76etXNk4imTzmg3RsHcfPC5JBJAGpb5htnUQ5-VsuqbzlCUTOWNK4kIDWzbU0o-neglLAwU846_h6lTRI7xE1kh0iZyseAdx7sZ8Cd5eSYuvwQVxnNn0w-m9Bwd30g-s8xmqn9-7LBa0-UdumMLwtan4IGXltMJGYU9br1wsmz9vlG-TvfmxlgXzilJOJQMvlMKGXRmbUJRaNSYdrVJciEQEWK0tkaT45r3_LJw7dwx4DnNxzw\",\"use\":\"sig\"}"), -// rsaAssertions -// ),//not implemented crypto-core + //rsa + arguments( + "did:web:localhost%3A8080:rsa", + Json.decodeFromString("{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"ab269ce10ce94b7c9565e30c034b5692\",\"kty\":\"RSA\",\"n\":\"0qbslQ5uMXL1Wk4dUD5ftrGWLhgaQENQn8AaPVREg12H_Mfr2GEL0IkBd7EQPeRFzRzngF2kWpij_nyueYKGQ3um_hione72pozP76etXNk4imTzmg3RsHcfPC5JBJAGpb5htnUQ5-VsuqbzlCUTOWNK4kIDWzbU0o-neglLAwU846_h6lTRI7xE1kh0iZyseAdx7sZ8Cd5eSYuvwQVxnNn0w-m9Bwd30g-s8xmqn9-7LBa0-UdumMLwtan4IGXltMJGYU9br1wsmz9vlG-TvfmxlgXzilJOJQMvlMKGXRmbUJRaNSYdrVJciEQEWK0tkaT45r3_LJw7dwx4DnNxzw\",\"use\":\"sig\"}"), + rsaAssertions + ), ) } } diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/SSIKit2WalletService.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/SSIKit2WalletService.kt index 7af8ad63b..eb99632c6 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/SSIKit2WalletService.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/SSIKit2WalletService.kt @@ -339,7 +339,7 @@ class SSIKit2WalletService( return result.did } - override suspend fun listDids() = transaction { DidsService.list(walletId) } + override suspend fun listDids() = DidsService.list(walletId) override suspend fun loadDid(did: String): JsonObject = DidsService.get(walletId, did)?.let { Json.parseToJsonElement(it.document).jsonObject } diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/dids/DidService.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/dids/DidService.kt index a9422614d..df5b6debf 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/dids/DidService.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/dids/DidService.kt @@ -15,7 +15,8 @@ object DidsService { .singleOrNull()?.let { WalletDid(it) } } - fun list(wallet: UUID): List = WalletDids.selectAll().where { WalletDids.wallet eq wallet }.map { WalletDid(it) } + fun list(wallet: UUID): List = + transaction { WalletDids.selectAll().where { WalletDids.wallet eq wallet }.map { WalletDid(it) } } fun getWalletsForDid(did: String): List = transaction { WalletDids.selectAll().where { WalletDids.did eq did }.map { diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/DidController.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/DidController.kt index db5e579e5..b722e48e8 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/DidController.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/DidController.kt @@ -11,7 +11,6 @@ import io.ktor.server.application.* import io.ktor.server.response.* import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.JsonObject -import org.jetbrains.exposed.sql.transactions.transaction fun Application.dids() = walletRoute { route("dids", { @@ -26,7 +25,7 @@ fun Application.dids() = walletRoute { } } }) { - context.respond(getWalletService().run { transaction { runBlocking { listDids() } } }) + context.respond(getWalletService().run { runBlocking { listDids() } }) } route("{did}", {