From b8099fcbc7783b59534f62f923c82c01b3ce561b Mon Sep 17 00:00:00 2001 From: mikeplotean Date: Wed, 13 Sep 2023 18:52:40 +0300 Subject: [PATCH] refactor key-import, keystores --- src/main/kotlin/id/walt/cli/did/DidCommand.kt | 12 +- src/main/kotlin/id/walt/crypto/CryptFun.kt | 25 +-- .../walt/services/key/import/JwkKeyImport.kt | 63 +++++++ .../services/key/import/KeyImportStrategy.kt | 160 +----------------- .../walt/services/key/import/PemKeyImport.kt | 136 +++++++++++++++ .../services/keystore/EncryptedKeyStore.kt | 45 +++-- .../keystore/FileSystemKeyStoreService.kt | 38 ++--- .../services/keystore/HKVKeyStoreService.kt | 42 ++--- .../services/keystore/SqlKeyStoreService.kt | 2 +- 9 files changed, 288 insertions(+), 235 deletions(-) create mode 100644 src/main/kotlin/id/walt/services/key/import/JwkKeyImport.kt create mode 100644 src/main/kotlin/id/walt/services/key/import/PemKeyImport.kt diff --git a/src/main/kotlin/id/walt/cli/did/DidCommand.kt b/src/main/kotlin/id/walt/cli/did/DidCommand.kt index 5e6b300e9..b9cc04962 100644 --- a/src/main/kotlin/id/walt/cli/did/DidCommand.kt +++ b/src/main/kotlin/id/walt/cli/did/DidCommand.kt @@ -65,11 +65,13 @@ class CreateDidCommand : CliktCommand( echo("Creating did:${method.method} (key: ${keyId})") val did = when (method) { - 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).useJwkJcsPubMulticodec)) - else -> DidService.create(DidMethod.valueOf(method.method), keyId) + is WebMethodOption -> DidWebCreateOptions((method as WebMethodOption).domain, (method as WebMethodOption).path) + is EbsiMethodOption -> DidEbsiCreateOptions((method as EbsiMethodOption).version) + is CheqdMethodOption -> DidCheqdCreateOptions((method as CheqdMethodOption).network) + is KeyMethodOption -> DidKeyCreateOptions((method as KeyMethodOption).useJwkJcsPubMulticodec) + else -> null + }.let{ + DidService.create(DidMethod.valueOf(method.method), keyId, it) } echo("\nResults:\n") diff --git a/src/main/kotlin/id/walt/crypto/CryptFun.kt b/src/main/kotlin/id/walt/crypto/CryptFun.kt index 91a070682..602246145 100644 --- a/src/main/kotlin/id/walt/crypto/CryptFun.kt +++ b/src/main/kotlin/id/walt/crypto/CryptFun.kt @@ -91,6 +91,12 @@ fun java.security.Key.toPEM(): String = when (this) { else -> throw IllegalArgumentException() } +fun java.security.Key.toBase64(): String = when (this) { + is PublicKey -> this.toBase64() + is PrivateKey -> this.toBase64() + else -> throw IllegalArgumentException() +} + fun PrivateKey.toPEM(): String = "-----BEGIN PRIVATE KEY-----" + System.lineSeparator() + @@ -104,6 +110,8 @@ fun PrivateKey.toPEM(): String = fun PrivateKey.toBase64(): String = String(Base64.getEncoder().encode(PKCS8EncodedKeySpec(this.encoded).encoded)) +fun PublicKey.toBase64(): String = encBase64(X509EncodedKeySpec(this.encoded).encoded) + fun PublicKey.toPEM(): String = "-----BEGIN PUBLIC KEY-----" + System.lineSeparator() + @@ -124,9 +132,6 @@ fun decBase64(base64: String): ByteArray = Base64.getDecoder().decode(base64) fun toBase64Url(base64: String) = base64.replace("+", "-").replace("/", "_").replace("=", "") - -fun PublicKey.toBase64(): String = encBase64(X509EncodedKeySpec(this.encoded).encoded) - fun decodePubKeyBase64(base64: String, kf: KeyFactory): PublicKey = kf.generatePublic(X509EncodedKeySpec(decBase64(base64))) @@ -162,7 +167,7 @@ fun buildKey( keyId: String, algorithm: String, provider: String, - publicPart: String, + publicPart: String?, privatePart: String?, format: KeyFormat = KeyFormat.PEM ): Key { @@ -174,16 +179,16 @@ fun buildKey( } val keyPair = when (format) { KeyFormat.PEM -> KeyPair( - decodePubKeyPem(publicPart, keyFactory), - privatePart?.let { decodePrivKeyPem(privatePart, keyFactory) }) + publicPart?.let { decodePubKeyPem(it, keyFactory) }, + privatePart?.let { decodePrivKeyPem(it, keyFactory) }) KeyFormat.BASE64_DER -> KeyPair( - decodePubKeyBase64(publicPart, keyFactory), - privatePart?.let { decodePrivKeyBase64(privatePart, keyFactory) }) + publicPart?.let { decodePubKeyBase64(it, keyFactory) }, + privatePart?.let { decodePrivKeyBase64(it, keyFactory) }) KeyFormat.BASE64_RAW -> KeyPair( - decodeRawPubKeyBase64(publicPart, keyFactory), - privatePart?.let { decodeRawPrivKey(privatePart, keyFactory) }) + publicPart?.let { decodeRawPubKeyBase64(it, keyFactory) }, + privatePart?.let { decodeRawPrivKey(it, keyFactory) }) } return Key(KeyId(keyId), KeyAlgorithm.valueOf(algorithm), CryptoProvider.valueOf(provider), keyPair) diff --git a/src/main/kotlin/id/walt/services/key/import/JwkKeyImport.kt b/src/main/kotlin/id/walt/services/key/import/JwkKeyImport.kt new file mode 100644 index 000000000..3738d915d --- /dev/null +++ b/src/main/kotlin/id/walt/services/key/import/JwkKeyImport.kt @@ -0,0 +1,63 @@ +package id.walt.services.key.import + +import com.nimbusds.jose.jwk.Curve +import com.nimbusds.jose.jwk.JWK +import com.nimbusds.jose.jwk.KeyType +import id.walt.crypto.* +import id.walt.services.CryptoProvider +import id.walt.services.keystore.KeyStoreService + +class JwkKeyImport(private val keyString: String) : KeyImportStrategy { + + override fun import(keyStore: KeyStoreService): KeyId { + val key = parseJwkKey(keyString) + keyStore.store(key) + return key.keyId + } + + private fun parseJwkKey(jwkKeyStr: String): Key { + val jwk = JWK.parse(jwkKeyStr) + + val key = when (jwk.keyType) { + KeyType.RSA -> Key( + keyId = KeyId(jwk.keyID ?: newKeyId().id), + algorithm = KeyAlgorithm.RSA, + cryptoProvider = CryptoProvider.SUN, + keyPair = jwk.toRSAKey().toKeyPair() + ) + + KeyType.EC -> { + val alg = when (jwk.toECKey().curve) { + Curve.P_256 -> KeyAlgorithm.ECDSA_Secp256r1 + Curve.SECP256K1 -> KeyAlgorithm.ECDSA_Secp256k1 + else -> throw IllegalArgumentException("EC key with curve ${jwk.toECKey().curve} not suppoerted") + } + Key( + keyId = KeyId(jwk.keyID ?: newKeyId().id), + algorithm = alg, + cryptoProvider = CryptoProvider.SUN, + keyPair = jwk.toECKey().toKeyPair() + ) + } + + KeyType.OKP -> { + val alg = when (jwk.toOctetKeyPair().curve) { + Curve.Ed25519 -> KeyAlgorithm.EdDSA_Ed25519 + else -> throw IllegalArgumentException("OKP key with curve ${jwk.toOctetKeyPair().curve} not supported") + } + buildKey( + keyId = jwk.keyID ?: newKeyId().id, + algorithm = alg.name, + provider = CryptoProvider.SUN.name, + publicPart = jwk.toOctetKeyPair().x.toString(), + privatePart = jwk.toOctetKeyPair().d?.let { jwk.toOctetKeyPair().d.toString() }, + format = KeyFormat.BASE64_RAW + ) + } + + else -> throw IllegalArgumentException("KeyType ${jwk.keyType} / Algorithm ${jwk.algorithm} not supported") + } + return key + } + +} diff --git a/src/main/kotlin/id/walt/services/key/import/KeyImportStrategy.kt b/src/main/kotlin/id/walt/services/key/import/KeyImportStrategy.kt index 3508db773..7ede99699 100644 --- a/src/main/kotlin/id/walt/services/key/import/KeyImportStrategy.kt +++ b/src/main/kotlin/id/walt/services/key/import/KeyImportStrategy.kt @@ -1,25 +1,7 @@ package id.walt.services.key.import -import com.nimbusds.jose.jwk.Curve -import com.nimbusds.jose.jwk.JWK -import com.nimbusds.jose.jwk.KeyType -import id.walt.crypto.* -import id.walt.services.CryptoProvider +import id.walt.crypto.KeyId import id.walt.services.keystore.KeyStoreService -import mu.KotlinLogging -import org.bouncycastle.asn1.ASN1ObjectIdentifier -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo -import org.bouncycastle.openssl.PEMKeyPair -import org.bouncycastle.openssl.PEMParser -import java.io.StringReader -import java.security.KeyFactory -import java.security.KeyPair -import java.security.PrivateKey -import java.security.PublicKey -import java.security.spec.PKCS8EncodedKeySpec -import java.security.spec.X509EncodedKeySpec interface KeyImportStrategy { fun import(keyStore: KeyStoreService): KeyId @@ -28,146 +10,10 @@ interface KeyImportStrategy { abstract class KeyImportFactory { companion object { fun create(keyString: String) = when (isPEM(keyString)) { - true -> PEMImportImpl(keyString) - false -> JWKImportImpl(keyString) + true -> PemKeyImport(keyString) + false -> JwkKeyImport(keyString) } private fun isPEM(keyString: String) = keyString.startsWith("-----") } } - -class PEMImportImpl(val keyString: String) : KeyImportStrategy { - - private val log = KotlinLogging.logger {} - - override fun import(keyStore: KeyStoreService) = importPem(keyString, keyStore) - - /** - * Imports the given PEM encoded key string - * @param keyStr the key string - * - * - for RSA keys: the PEM private key file - * - for other key types: concatenated public and private key in PEM format - * @return the imported key id - */ - private fun importPem(keyStr: String, keyStore: KeyStoreService): KeyId { - val parser = PEMParser(StringReader(keyStr)) - val parsedPemObject = mutableListOf() - try { - var currentPEMObject: Any? - do { - currentPEMObject = parser.readObject() - log.debug { "PEM parser next object: $currentPEMObject" } - if (currentPEMObject != null) { - parsedPemObject.add(currentPEMObject) - } - } while (currentPEMObject != null) - } catch (e: Exception) { - log.error(e) { "Error while importing PEM key!" } - } - - val kid = newKeyId() - val keyPair = getKeyPair(parsedPemObject) - keyStore.store(Key(kid, KeyAlgorithm.fromString(keyPair.public.algorithm), CryptoProvider.SUN, keyPair)) - - return kid - } - - /** - * Parses a keypair out of a one or multiple objects - */ - private fun getKeyPair(objs: List): KeyPair { - lateinit var pubKey: PublicKey - lateinit var privKey: PrivateKey - - objs.toList() - - log.debug { "Searching key pair in: $objs" } - for (obj in objs) { - if (obj is SubjectPublicKeyInfo) { - pubKey = getPublicKey(obj) - } - if (obj is PrivateKeyInfo) { - privKey = getPrivateKey(obj) - } - if (obj is PEMKeyPair) { - pubKey = getPublicKey(obj.publicKeyInfo) - privKey = getPrivateKey(obj.privateKeyInfo) - break - } - } - return KeyPair(pubKey, privKey) - } - - private fun getPublicKey(key: SubjectPublicKeyInfo): PublicKey { - val kf = getKeyFactory(key.algorithm.algorithm) - return kf.generatePublic(X509EncodedKeySpec(key.encoded)) - } - - private fun getPrivateKey(key: PrivateKeyInfo): PrivateKey { - val kf = getKeyFactory(key.privateKeyAlgorithm.algorithm) - return kf.generatePrivate(PKCS8EncodedKeySpec(key.encoded)) - } - - private fun getKeyFactory(alg: ASN1ObjectIdentifier): KeyFactory = when (alg) { - PKCSObjectIdentifiers.rsaEncryption -> KeyFactory.getInstance("RSA") - ASN1ObjectIdentifier("1.3.101.112") -> KeyFactory.getInstance("Ed25519") - ASN1ObjectIdentifier("1.2.840.10045.2.1") -> KeyFactory.getInstance("ECDSA") - else -> throw IllegalArgumentException("Algorithm not supported") - } -} - -class JWKImportImpl(val keyString: String) : KeyImportStrategy { - - override fun import(keyStore: KeyStoreService): KeyId { - val key = parseJwkKey(keyString) - keyStore.store(key) - return key.keyId - } - - private fun parseJwkKey(jwkKeyStr: String): Key { - val jwk = JWK.parse(jwkKeyStr) - - val key = when (jwk.keyType) { - KeyType.RSA -> Key( - keyId = KeyId(jwk.keyID ?: newKeyId().id), - algorithm = KeyAlgorithm.RSA, - cryptoProvider = CryptoProvider.SUN, - keyPair = jwk.toRSAKey().toKeyPair() - ) - - KeyType.EC -> { - val alg = when (jwk.toECKey().curve) { - Curve.P_256 -> KeyAlgorithm.ECDSA_Secp256r1 - Curve.SECP256K1 -> KeyAlgorithm.ECDSA_Secp256k1 - else -> throw IllegalArgumentException("EC key with curve ${jwk.toECKey().curve} not suppoerted") - } - Key( - keyId = KeyId(jwk.keyID ?: newKeyId().id), - algorithm = alg, - cryptoProvider = CryptoProvider.SUN, - keyPair = jwk.toECKey().toKeyPair() - ) - } - - KeyType.OKP -> { - val alg = when (jwk.toOctetKeyPair().curve) { - Curve.Ed25519 -> KeyAlgorithm.EdDSA_Ed25519 - else -> throw IllegalArgumentException("OKP key with curve ${jwk.toOctetKeyPair().curve} not supported") - } - buildKey( - keyId = jwk.keyID ?: newKeyId().id, - algorithm = alg.name, - provider = CryptoProvider.SUN.name, - publicPart = jwk.toOctetKeyPair().x.toString(), - privatePart = jwk.toOctetKeyPair().d?.let { jwk.toOctetKeyPair().d.toString() }, - format = KeyFormat.BASE64_RAW - ) - } - - else -> throw IllegalArgumentException("KeyType ${jwk.keyType} / Algorithm ${jwk.algorithm} not supported") - } - return key - } - -} diff --git a/src/main/kotlin/id/walt/services/key/import/PemKeyImport.kt b/src/main/kotlin/id/walt/services/key/import/PemKeyImport.kt new file mode 100644 index 000000000..81004c2fc --- /dev/null +++ b/src/main/kotlin/id/walt/services/key/import/PemKeyImport.kt @@ -0,0 +1,136 @@ +package id.walt.services.key.import + +import id.walt.crypto.Key +import id.walt.crypto.KeyAlgorithm +import id.walt.crypto.KeyId +import id.walt.crypto.newKeyId +import id.walt.services.CryptoProvider +import id.walt.services.keystore.KeyStoreService +import mu.KotlinLogging +import org.bouncycastle.asn1.ASN1ObjectIdentifier +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo +import org.bouncycastle.crypto.params.* +import org.bouncycastle.openssl.PEMKeyPair +import org.bouncycastle.openssl.PEMParser +import java.io.StringReader +import java.math.BigInteger +import java.security.KeyFactory +import java.security.KeyPair +import java.security.PrivateKey +import java.security.PublicKey +import java.security.spec.PKCS8EncodedKeySpec +import java.security.spec.RSAPrivateKeySpec +import java.security.spec.RSAPublicKeySpec +import java.security.spec.X509EncodedKeySpec + +class PemKeyImport(private val keyString: String) : KeyImportStrategy { + + private val log = KotlinLogging.logger {} + + override fun import(keyStore: KeyStoreService) = importPem(keyString, keyStore) + + /** + * Imports the given PEM encoded key string + * @param keyStr the key string + * - for RSA keys: the PEM private key file + * - for other key types: concatenated public and private key in PEM format + * @return the imported key id + */ + private fun importPem(keyStr: String, keyStore: KeyStoreService): KeyId { + val parser = PEMParser(StringReader(keyStr)) + val parsedPemObject = mutableListOf() + try { + var currentPEMObject: Any? + do { + currentPEMObject = parser.readObject() + log.debug { "PEM parser next object: $currentPEMObject" } + if (currentPEMObject != null) { + parsedPemObject.add(currentPEMObject) + } + } while (currentPEMObject != null) + } catch (e: Exception) { + log.error(e) { "Error while importing PEM key!" } + } + + val kid = newKeyId() + val keyPair = getKeyPair(parsedPemObject) + keyStore.store(Key(kid, getKeyAlgorithm(keyPair), CryptoProvider.SUN, keyPair)) + + return kid + } + + private fun getKeyAlgorithm(keyPair: KeyPair): KeyAlgorithm = (keyPair.public ?: keyPair.private).let { + KeyAlgorithm.fromString(it.algorithm) + } + + /** + * Parses a keypair out of a one or multiple objects + */ + private fun getKeyPair(objs: List): KeyPair { + var pubKey: PublicKey? = null + var privKey: PrivateKey? = null + + objs.toList() + + log.debug { "Searching key pair in: $objs" } + for (obj in objs) { + if (obj is SubjectPublicKeyInfo) { + pubKey = getPublicKey(obj) + } + if (obj is PrivateKeyInfo) { + privKey = getPrivateKey(obj) + } + if (obj is PEMKeyPair) { + pubKey = getPublicKey(obj.publicKeyInfo) + privKey = getPrivateKey(obj.privateKeyInfo) + break + } + } +// pubKey = pubKey ?: computePublicKeyFromPrivate(privKey as AsymmetricKeyParameter) + pubKey = pubKey ?: computeRSAPublicKeyFromPrivate(privKey!!) + return KeyPair(pubKey, privKey) + } + + private fun computeRSAPublicKeyFromPrivate(privateKey: PrivateKey): PublicKey? = when(KeyAlgorithm.fromString(privateKey.algorithm)) { + KeyAlgorithm.RSA -> { + val kf = KeyFactory.getInstance("RSA") + val privateSpec = kf.getKeySpec(privateKey, RSAPrivateKeySpec::class.java) + val publicSpec = RSAPublicKeySpec(privateSpec.modulus, BigInteger.valueOf(65537)) + kf.generatePublic(publicSpec) + } + else -> null + } + + private fun computePublicKeyFromPrivate(privateKey: AsymmetricKeyParameter): AsymmetricKeyParameter = when (privateKey) { + is RSAPrivateCrtKeyParameters -> { + RSAKeyParameters(false, privateKey.modulus, privateKey.publicExponent) + } + is Ed25519PrivateKeyParameters -> { + privateKey.generatePublicKey() + } + is ECPrivateKeyParameters -> { + val q = privateKey.parameters.g.multiply(privateKey.d) + ECPublicKeyParameters(q, privateKey.parameters) + } + else -> throw IllegalArgumentException("Key type not supported.") + } + + private fun getPublicKey(key: SubjectPublicKeyInfo): PublicKey { + val kf = getKeyFactory(key.algorithm.algorithm) + return kf.generatePublic(X509EncodedKeySpec(key.encoded)) + } + + private fun getPrivateKey(key: PrivateKeyInfo): PrivateKey { + val kf = getKeyFactory(key.privateKeyAlgorithm.algorithm) + return kf.generatePrivate(PKCS8EncodedKeySpec(key.encoded)) + } + + private fun getKeyFactory(alg: ASN1ObjectIdentifier): KeyFactory = when (alg) { + PKCSObjectIdentifiers.rsaEncryption -> KeyFactory.getInstance("RSA") + ASN1ObjectIdentifier("1.3.101.112") -> KeyFactory.getInstance("Ed25519") + ASN1ObjectIdentifier("1.2.840.10045.2.1") -> KeyFactory.getInstance("ECDSA") + else -> throw IllegalArgumentException("Algorithm not supported") + } +} diff --git a/src/main/kotlin/id/walt/services/keystore/EncryptedKeyStore.kt b/src/main/kotlin/id/walt/services/keystore/EncryptedKeyStore.kt index f08514e06..17d604b08 100644 --- a/src/main/kotlin/id/walt/services/keystore/EncryptedKeyStore.kt +++ b/src/main/kotlin/id/walt/services/keystore/EncryptedKeyStore.kt @@ -4,6 +4,8 @@ package id.walt.services.keystore import id.walt.crypto.* import id.walt.servicematrix.ServiceConfiguration import id.walt.services.hkvstore.enc.EncryptedHKVStore +import java.security.PrivateKey +import java.security.PublicKey import java.util.* import kotlin.io.path.Path import kotlin.io.path.name @@ -65,8 +67,7 @@ class EncryptedKeyStore(configurationPath: String) : KeyStoreService() { // log.debug { "Storing key \"${key.keyId}\"." } addAlias(key.keyId, key.keyId.id) storeKeyMetaData(key) - storePublicKey(key) - storePrivateKeyWhenExisting(key) + storeAvailableKeys(key) } override fun getKeyId(alias: String) = @@ -81,36 +82,34 @@ class EncryptedKeyStore(configurationPath: String) : KeyStoreService() { hkvs.deleteDocument(Path(keysRoot.name, keyId)) } - private fun storePublicKey(key: Key) = + private fun storeAvailableKeys(key: Key) = run { + key.keyPair?.run { + this.private?.run { saveKey(key.keyId, this) } +// this.public?.run { saveKey(key.keyId, this) } + } + runCatching { key.getPublicKey() }.onSuccess { saveKey(key.keyId, it) } + } + + private fun saveKey(keyId: KeyId, key: java.security.Key) = when (key) { + is PrivateKey -> "enc-privkey" + is PublicKey -> "enc-pubkey" + else -> throw IllegalArgumentException() + }.run { saveKeyData( - key = key, - suffix = "enc-pubkey", - data = when (keyFormat) { - KeyFormat.PEM -> key.getPublicKey().toPEM() - else -> key.getPublicKey().toBase64() + keyId, this, when (keyFormat) { + KeyFormat.PEM -> key.toPEM() + else -> key.toBase64() }.encodeToByteArray() ) - - private fun storePrivateKeyWhenExisting(key: Key) { - if (key.keyPair != null && key.keyPair!!.private != null) { - saveKeyData( - key = key, - suffix = "enc-privkey", - data = when (keyFormat) { - KeyFormat.PEM -> key.keyPair!!.private.toPEM() - else -> key.keyPair!!.private.toBase64() - }.encodeToByteArray() - ) - } } private fun storeKeyMetaData(key: Key) { - saveKeyData(key, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).encodeToByteArray()) + saveKeyData(key.keyId, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).encodeToByteArray()) } - private fun saveKeyData(key: Key, suffix: String, data: ByteArray): Unit = + private fun saveKeyData(keyId: KeyId, suffix: String, data: ByteArray): Unit = hkvs.storeDocument( - path = Path(keysRoot.name, key.keyId.id, suffix), + path = Path(keysRoot.name, keyId.id, suffix), text = Base64.getEncoder().encodeToString(data) ) diff --git a/src/main/kotlin/id/walt/services/keystore/FileSystemKeyStoreService.kt b/src/main/kotlin/id/walt/services/keystore/FileSystemKeyStoreService.kt index ccc350b8f..1cb815616 100644 --- a/src/main/kotlin/id/walt/services/keystore/FileSystemKeyStoreService.kt +++ b/src/main/kotlin/id/walt/services/keystore/FileSystemKeyStoreService.kt @@ -63,8 +63,7 @@ open class FileSystemKeyStoreService : KeyStoreService() { override fun store(key: Key) { addAlias(key.keyId, key.keyId.id) storeKeyMetaData(key) - storePublicKey(key) - storePrivateKeyWhenExisting(key) + storeAvailableKeys(key) // saveEncPublicKey(key.keyId.id, key.keyPair!!.public) // saveEncPrivateKey(key.keyId.id, key.keyPair!!.private) @@ -81,31 +80,32 @@ open class FileSystemKeyStoreService : KeyStoreService() { deleteKeyAlias(alias) } - private fun storePublicKey(key: Key) = + private fun storeAvailableKeys(key: Key) = run { + key.keyPair?.run { + this.private?.run { saveKey(key.keyId, this) } +// this.public?.run { saveKey(key.keyId, this) } + } + runCatching { key.getPublicKey() }.onSuccess { saveKey(key.keyId, it) } + } + + private fun saveKey(keyId: KeyId, key: java.security.Key) = when (key) { + is PrivateKey -> "enc-privkey" + is PublicKey -> "enc-pubkey" + else -> throw IllegalArgumentException() + }.run { saveKeyData( - key, "enc-pubkey", - when (KEY_FORMAT) { - KeyFormat.PEM -> key.getPublicKey().toPEM() - else -> key.getPublicKey().toBase64() + keyId, this, when (KEY_FORMAT) { + KeyFormat.PEM -> key.toPEM() + else -> key.toBase64() }.toByteArray() ) - - private fun storePrivateKeyWhenExisting(key: Key) { - if (key.keyPair != null && key.keyPair!!.private != null) { - saveKeyData( - key, "enc-privkey", when (KEY_FORMAT) { - KeyFormat.PEM -> key.keyPair!!.private.toPEM() - else -> key.keyPair!!.private.toBase64() - }.toByteArray() - ) - } } private fun storeKeyMetaData(key: Key) { - saveKeyData(key, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).toByteArray()) + saveKeyData(key.keyId, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).toByteArray()) } - private fun saveKeyData(key: Key, suffix: String, data: ByteArray) = saveKeyFile(key.keyId.id, suffix, data) + private fun saveKeyData(keyId: KeyId, suffix: String, data: ByteArray) = saveKeyFile(keyId.id, suffix, data) //TODO consider deprecated methods below diff --git a/src/main/kotlin/id/walt/services/keystore/HKVKeyStoreService.kt b/src/main/kotlin/id/walt/services/keystore/HKVKeyStoreService.kt index 59930b580..0b92cee93 100644 --- a/src/main/kotlin/id/walt/services/keystore/HKVKeyStoreService.kt +++ b/src/main/kotlin/id/walt/services/keystore/HKVKeyStoreService.kt @@ -4,6 +4,8 @@ import id.walt.crypto.* import id.walt.services.context.ContextManager import id.walt.services.hkvstore.HKVKey import mu.KotlinLogging +import java.security.PrivateKey +import java.security.PublicKey open class HKVKeyStoreService : KeyStoreService() { @@ -51,8 +53,7 @@ open class HKVKeyStoreService : KeyStoreService() { log.debug { "Storing key \"${key.keyId}\"." } addAlias(key.keyId, key.keyId.id) storeKeyMetaData(key) - storePublicKey(key) - storePrivateKeyWhenExisting(key) + storeAvailableKeys(key) } override fun getKeyId(alias: String) = @@ -67,32 +68,33 @@ open class HKVKeyStoreService : KeyStoreService() { hkvStore.delete(HKVKey.combine(KEYS_ROOT, keyId), recursive = true) } - private fun storePublicKey(key: Key) = + private fun storeAvailableKeys(key: Key) = run { + key.keyPair?.run { + this.private?.run { saveKey(key.keyId, this) } +// this.public?.run { saveKey(key.keyId, this) } + } + runCatching { key.getPublicKey() }.onSuccess { saveKey(key.keyId, it) } + } + + private fun saveKey(keyId: KeyId, key: java.security.Key) = when (key) { + is PrivateKey -> "enc-privkey" + is PublicKey -> "enc-pubkey" + else -> throw IllegalArgumentException() + }.run { saveKeyData( - key, "enc-pubkey", - when (KEY_FORMAT) { - KeyFormat.PEM -> key.getPublicKey().toPEM() - else -> key.getPublicKey().toBase64() + keyId, this, when (KEY_FORMAT) { + KeyFormat.PEM -> key.toPEM() + else -> key.toBase64() }.toByteArray() ) - - private fun storePrivateKeyWhenExisting(key: Key) { - if (key.keyPair != null && key.keyPair!!.private != null) { - saveKeyData( - key, "enc-privkey", when (KEY_FORMAT) { - KeyFormat.PEM -> key.keyPair!!.private.toPEM() - else -> key.keyPair!!.private.toBase64() - }.toByteArray() - ) - } } private fun storeKeyMetaData(key: Key) { - saveKeyData(key, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).toByteArray()) + saveKeyData(key.keyId, "meta", (key.algorithm.name + ";" + key.cryptoProvider.name).toByteArray()) } - private fun saveKeyData(key: Key, suffix: String, data: ByteArray): Unit = - hkvStore.put(HKVKey.combine(KEYS_ROOT, key.keyId.id, suffix), data) + private fun saveKeyData(keyId: KeyId, suffix: String, data: ByteArray): Unit = + hkvStore.put(HKVKey.combine(KEYS_ROOT, keyId.id, suffix), data) private fun loadKey(keyId: String, suffix: String): ByteArray = HKVKey.combine(KEYS_ROOT, keyId, suffix) diff --git a/src/main/kotlin/id/walt/services/keystore/SqlKeyStoreService.kt b/src/main/kotlin/id/walt/services/keystore/SqlKeyStoreService.kt index d614fab95..bd37ef3bd 100644 --- a/src/main/kotlin/id/walt/services/keystore/SqlKeyStoreService.kt +++ b/src/main/kotlin/id/walt/services/keystore/SqlKeyStoreService.kt @@ -30,7 +30,7 @@ open class SqlKeyStoreService : KeyStoreService() { listOf( keyId.id, keyPair!!.private?.toBase64(), - keyPair!!.public.toBase64(), + keyPair!!.public?.toBase64(), algorithm.name, cryptoProvider.name ).forEachIndexed { index, str -> str?.let { statement.setString(index + 1, str) } }