Skip to content

Commit

Permalink
import pub key from did:key for signature verification
Browse files Browse the repository at this point in the history
  • Loading branch information
severinstampler committed Dec 2, 2021
1 parent 2fa99a4 commit 4ed0b4c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 33 deletions.
75 changes: 44 additions & 31 deletions src/main/kotlin/id/walt/services/did/DidService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import id.walt.crypto.*
import id.walt.crypto.KeyAlgorithm.ECDSA_Secp256k1
import id.walt.crypto.KeyAlgorithm.EdDSA_Ed25519
import id.walt.model.*
import id.walt.services.CryptoProvider
import id.walt.services.WaltIdServices
import id.walt.services.context.ContextManager
import id.walt.services.crypto.CryptoService
import id.walt.services.hkvstore.HKVKey
import id.walt.services.key.KeyService
import id.walt.services.keystore.KeyStoreService
import id.walt.services.vc.JsonLdCredentialService
import id.walt.signatory.ProofConfig
import io.ktor.client.features.*
Expand All @@ -18,6 +20,14 @@ import kotlinx.coroutines.runBlocking
import mu.KotlinLogging
import org.bouncycastle.asn1.ASN1BitString
import org.bouncycastle.asn1.ASN1Sequence
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
import java.util.*

private val log = KotlinLogging.logger {}
Expand Down Expand Up @@ -357,53 +367,56 @@ object DidService {
fun importKey(didUrl: String) {
val did = loadOrResolveAnyDid(didUrl) ?: throw Exception("Could not load or resolve $didUrl")

val verificationMethod = when (did) {
is DidEbsi -> did.verificationMethod
is Did -> did.verificationMethod
else -> throw Exception("Did not supported")
} ?: throw Exception("Could not import key as no verification method was found")

verificationMethod.forEach { vm ->
if (!booleanArrayOf(
importJwk(didUrl, vm.publicKeyJwk),
importKeyBase58(didUrl, vm.publicKeyBase58),
importKeyPem(didUrl, vm.publicKeyPem)
).contains(true)
) {
throw Exception("Could not import any key")
}
kotlin.runCatching { KeyService.getService().load(didUrl) }
.getOrNull()?.let { throw Exception("Could not import key, as key alias \"${didUrl}\" is already existing.") }

if(did.verificationMethod?.flatMap { vm ->
listOf(
tryImportJwk(didUrl, vm),
tryImportKeyBase58(didUrl, vm),
tryImportKeyPem(didUrl, vm)
)
}?.reduce { acc, b -> acc || b } != true) {
throw Exception("Could not import any key")
}
}

private fun importKeyPem(keyAlias: String, keyPem: String?): Boolean {
private fun tryImportKeyPem(did: String, vm: VerificationMethod): Boolean {

keyPem ?: return false
vm.publicKeyPem ?: return false

// TODO implement

return false
}

private fun importKeyBase58(keyAlias: String, keyBase58: String?): Boolean {
private fun tryImportKeyBase58(did: String, vm: VerificationMethod): Boolean {

keyBase58 ?: return false
vm.publicKeyBase58 ?: return false
if (vm.type != "Ed25519VerificationKey2018") {
return false
}

// TODO implement
val keyFactory = KeyFactory.getInstance("Ed25519")

return false
}
val pubKeyInfo = SubjectPublicKeyInfo(AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), vm.publicKeyBase58.decodeBase58())
val x509KeySpec = X509EncodedKeySpec(pubKeyInfo.encoded)

private fun importJwk(keyAlias: String, publicKeyJwk: Jwk?): Boolean {
val pubKey = keyFactory.generatePublic(x509KeySpec)
val keyId = KeyId(vm.id)
ContextManager.keyStore.store(Key(keyId, EdDSA_Ed25519, CryptoProvider.SUN, KeyPair(pubKey, null)))
ContextManager.keyStore.addAlias(keyId, did)

publicKeyJwk ?: return false
return true
}

kotlin.runCatching { KeyService.getService().load(keyAlias) }
.getOrNull()?.let { throw Exception("Could not import key, as key alias \"$keyAlias\" is already existing.") }
private fun tryImportJwk(did: String, vm: VerificationMethod): Boolean {

publicKeyJwk.kid = keyAlias
log.debug { "Importing key: ${publicKeyJwk.kid}" }
val keyId = KeyService.getService().importKey(Klaxon().toJsonString(publicKeyJwk))
ContextManager.keyStore.addAlias(keyId, keyAlias)
vm.publicKeyJwk ?: return false

log.debug { "Importing key: ${vm.id}" }
val keyId = KeyService.getService().importKey(Klaxon().toJsonString(vm.publicKeyJwk))
ContextManager.keyStore.addAlias(keyId, did)
return true
}

Expand All @@ -417,7 +430,7 @@ object DidService {
// "web" -> resolveDidWebDummy(didUrl)
// else -> TODO("did:${didUrl.method} implemented yet")
// }
// }
// }String

// TODO: include once working
// internal fun resolveDidWeb(didUrl: DidUrl): DidWeb {
Expand Down
26 changes: 24 additions & 2 deletions src/test/kotlin/id/walt/context/WaltContextTest.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package id.walt.context

import id.walt.auditor.Auditor
import id.walt.auditor.SignaturePolicy
import id.walt.model.DidMethod
import id.walt.servicematrix.ServiceMatrix
import id.walt.services.context.ContextManager
import id.walt.services.did.DidService
import id.walt.signatory.ProofConfig
import id.walt.signatory.Signatory
import id.walt.test.RESOURCES_PATH
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.collections.shouldHaveSize
Expand All @@ -24,10 +28,11 @@ class WaltContextTest: AnnotationSpec() {
File(TEST_CONTEXT_DATA_ROOT).deleteRecursively()
}

val userAContext = TestContext("userA")
val userBContext = TestContext("userB")

@Test
fun testContext() {
val userAContext = TestContext("userA")
val userBContext = TestContext("userB")

var did1: String? = null
ContextManager.runWith(userAContext) {
Expand All @@ -48,4 +53,21 @@ class WaltContextTest: AnnotationSpec() {
didList1.first() shouldBe did1
}
}

@Test
fun testDidKeyImport() {
var cred: String = ""
ContextManager.runWith(userAContext) {
// create did:key with new key in user A context
val did = DidService.create(DidMethod.key)
// issue credential using created did
cred = Signatory.getService().issue("VerifiableId", ProofConfig(did, did))
}

ContextManager.runWith(userBContext) {
// verify credential in user B context, importing key from did on the fly
val result = Auditor.getService().verify(cred, listOf(SignaturePolicy()))
result.valid shouldBe true
}
}
}

0 comments on commit 4ed0b4c

Please sign in to comment.