diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 5f93a410..1cb22784 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -32,7 +32,7 @@ object Versions { const val ProvenanceHdWallet = "0.1.15" const val ProvenanceClient = "1.1.1" const val Unirest = "3.13.6" - const val KeyAccessLib = "0.2.18" + const val KmsConnector = "0.3.0" const val LoanPackage = "0.6.1" const val Grpc = "1.45.0" const val ProvenanceProto = "1.11.1" @@ -164,7 +164,7 @@ object Dependencies { } object Provenance { - val KeyAccessLib = DependencySpec("io.provenance.originator-key-access-lib:lib", Versions.KeyAccessLib) + val KeyAccessLib = DependencySpec("io.provenance.kms-connector:lib", Versions.KmsConnector) val ProtoKotlin = DependencySpec("io.provenance:proto-kotlin", Versions.ProvenanceProto) val AssetModel = DependencySpec("io.provenance.model:metadata-asset-model", Versions.AssetModel) val LoanPackage = DependencySpec("io.provenance.loan-package:contract", Versions.LoanPackage) diff --git a/models/build.gradle.kts b/models/build.gradle.kts index d74882af..b4beee69 100644 --- a/models/build.gradle.kts +++ b/models/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { Dependencies.Jackson.Databind, Dependencies.AssetClassification.Client, Dependencies.AssetClassification.Verifier, + Dependencies.Provenance.KeyAccessLib, ).forEach { dep -> dep.implementation(this) } diff --git a/models/src/main/kotlin/io/provenance/api/models/account/KeyManagementConfig.kt b/models/src/main/kotlin/io/provenance/api/models/account/KeyManagementConfig.kt index aad1175f..50a87a9c 100644 --- a/models/src/main/kotlin/io/provenance/api/models/account/KeyManagementConfig.kt +++ b/models/src/main/kotlin/io/provenance/api/models/account/KeyManagementConfig.kt @@ -1,7 +1,8 @@ package io.provenance.api.models.account +import io.provenance.core.PluginConfig + data class KeyManagementConfig( - val address: String, - val tokenPath: String, val plugin: String = "io.provenance.plugins.vault.VaultPlugin", + val pluginConfig: PluginConfig ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/cee/ContractService.kt b/service/src/main/kotlin/io/provenance/api/domain/cee/ContractService.kt index f4aa65f4..dcfe3e1d 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/cee/ContractService.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/cee/ContractService.kt @@ -1,7 +1,7 @@ package io.provenance.api.domain.cee import com.google.protobuf.Message -import io.provenance.core.Originator +import io.provenance.entity.KeyEntity import io.provenance.metadata.v1.ScopeResponse import io.provenance.scope.contract.proto.Envelopes import io.provenance.scope.contract.proto.Specifications @@ -14,7 +14,17 @@ import java.util.UUID interface ContractService { fun getContract(contractName: String): Class - fun setupContract(client: Client, contractClass: Class, records: Map, scopeUuid: UUID, sessionUuid: UUID? = null, participants: Map? = null, scope: ScopeResponse? = null, scopeSpecification: String, audiences: Set): Session + fun setupContract( + client: Client, + contractClass: Class, + records: Map, + scopeUuid: UUID, + sessionUuid: UUID? = null, + participants: Map? = null, + scope: ScopeResponse? = null, + scopeSpecification: String, + audiences: Set, + ): Session fun executeContract(client: Client, session: Session): ExecutionResult fun executeContract(client: Client, envelope: Envelopes.Envelope): ExecutionResult } diff --git a/service/src/main/kotlin/io/provenance/api/domain/objectStore/ObjectStore.kt b/service/src/main/kotlin/io/provenance/api/domain/objectStore/ObjectStore.kt index a20435f6..fa759796 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/objectStore/ObjectStore.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/objectStore/ObjectStore.kt @@ -1,10 +1,10 @@ package io.provenance.api.domain.objectStore import io.provenance.api.models.eos.store.StoreProtoResponse -import java.security.PrivateKey +import io.provenance.scope.encryption.model.KeyRef import java.security.PublicKey interface ObjectStore { - fun retrieveAndDecrypt(client: T, hash: String, publicKey: PublicKey, privateKey: PrivateKey): ByteArray - fun store(client: T, message: ByteArray, publicKey: PublicKey, privateKey: PrivateKey, additionalAudiences: Set, type: String?): StoreProtoResponse + fun retrieveAndDecrypt(client: T, hash: String, keyRef: KeyRef): ByteArray + fun store(client: T, message: ByteArray, keyRef: KeyRef, additionalAudiences: Set, type: String?): StoreProtoResponse } diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/cee/common/client/CreateClient.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/cee/common/client/CreateClient.kt index 35d05f19..c6b4414b 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/cee/common/client/CreateClient.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/cee/common/client/CreateClient.kt @@ -5,16 +5,13 @@ import io.provenance.api.domain.usecase.cee.common.client.model.CreateClientRequ import io.provenance.api.domain.usecase.common.originator.EntityManager import io.provenance.api.domain.usecase.common.originator.models.KeyManagementConfigWrapper import io.provenance.api.frameworks.config.ProvenanceProperties -import io.provenance.scope.encryption.model.DirectKeyRef +import io.provenance.entity.KeyType import io.provenance.scope.encryption.util.toJavaPublicKey import io.provenance.scope.sdk.Affiliate import io.provenance.scope.sdk.Client import io.provenance.scope.sdk.ClientConfig import io.provenance.scope.sdk.SharedClient import java.net.URI -import java.security.KeyPair -import java.security.PrivateKey -import java.security.PublicKey import java.util.concurrent.TimeUnit import org.springframework.stereotype.Component @@ -26,8 +23,8 @@ class CreateClient( override suspend fun execute(args: CreateClientRequest): Client { val originator = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.account.keyManagementConfig)) val affiliate = Affiliate( - signingKeyRef = DirectKeyRef(KeyPair(originator.signingPublicKey() as PublicKey, originator.signingPrivateKey() as PrivateKey)), - encryptionKeyRef = DirectKeyRef(KeyPair(originator.encryptionPublicKey() as PublicKey, originator.encryptionPrivateKey() as PrivateKey)), + signingKeyRef = originator.getKeyRef(KeyType.SIGNING), + encryptionKeyRef = originator.getKeyRef(KeyType.ENCRYPTION), args.account.partyType, ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/common/originator/EntityManager.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/common/originator/EntityManager.kt index a8316399..3da7c4b0 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/common/originator/EntityManager.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/common/originator/EntityManager.kt @@ -7,13 +7,12 @@ import io.provenance.api.models.account.KeyManagementConfig import io.provenance.api.models.account.Participant import io.provenance.api.models.p8e.AudienceKeyPair import io.provenance.api.models.p8e.PermissionInfo -import io.provenance.core.KeyType -import io.provenance.core.Originator -import io.provenance.core.OriginatorManager +import io.provenance.core.KeyEntityManager import io.provenance.core.Plugin -import io.provenance.plugins.vault.VaultSpec -import java.io.File -import java.util.UUID +import io.provenance.entity.KeyEntity +import io.provenance.entity.KeyType +import io.provenance.plugins.vault.VaultConfig +import io.provenance.scope.objectstore.util.toHex import kotlin.reflect.full.createInstance import org.springframework.stereotype.Component @@ -22,45 +21,47 @@ class EntityManager( private val vaultProperties: VaultProperties, private val provenanceProperties: ProvenanceProperties ) { - private var manager: OriginatorManager = OriginatorManager() - private var tokenMap = mutableMapOf() - - fun getEntity(args: KeyManagementConfigWrapper): Originator { + private var manager = KeyEntityManager() + fun getEntity(args: KeyManagementConfigWrapper): KeyEntity { val config = args.config ?: KeyManagementConfig( - vaultProperties.address, - vaultProperties.tokenPath, + pluginConfig = VaultConfig( + "${vaultProperties.address}/${args.entity}", + vaultProperties.tokenPath, + ) ) - val token = fetchToken(config) - return manager.get(args.entity, VaultSpec(args.entity, "${config.address}/${args.entity}", token)) + val plugin = Class.forName(config.plugin).asSubclass(Plugin::class.java).kotlin.createInstance() + manager.register(plugin) + return manager.get(args.entity, config.pluginConfig) } fun hydrateKeys(permissions: PermissionInfo?, participants: List = emptyList(), keyManagementConfig: KeyManagementConfig? = null): Set { - val additionalAudiences: MutableSet = mutableSetOf() - val config = keyManagementConfig ?: KeyManagementConfig( - vaultProperties.address, - vaultProperties.tokenPath, - ) - fun getEntityKeys(uuid: UUID) { - val originator = getEntity(KeyManagementConfigWrapper(uuid.toString(), config)) + // Populate participants into the audience list + participants.forEach { participant -> + val keyEntity = getEntity(KeyManagementConfigWrapper(participant.uuid.toString(), keyManagementConfig)) + additionalAudiences.add( AudienceKeyPair( - originator.keys[KeyType.ENCRYPTION_PUBLIC_KEY].toString(), - originator.keys[KeyType.SIGNING_PUBLIC_KEY].toString(), + keyEntity.publicKey(KeyType.ENCRYPTION).toHex(), + keyEntity.publicKey(KeyType.SIGNING).toHex(), ) ) } - participants.forEach { participant -> - getEntityKeys(participant.uuid) - } - + // Populate the audiences into the audience list permissions?.audiences?.forEach { it.uuid?.let { entity -> - getEntityKeys(entity) + val keyEntity = getEntity(KeyManagementConfigWrapper(entity.toString(), keyManagementConfig)) + + additionalAudiences.add( + AudienceKeyPair( + keyEntity.publicKey(KeyType.ENCRYPTION).toHex(), + keyEntity.publicKey(KeyType.SIGNING).toHex(), + ) + ) } ?: apply { it.keys?.let { keys -> additionalAudiences.add(keys) @@ -68,8 +69,9 @@ class EntityManager( } } - if (permissions?.permissionPortfolioManager == true) additionalAudiences.add(getMemberKeyPair(DefaultAudience.PORTFOLIO_MANAGER, config)) - if (permissions?.permissionDart == true) additionalAudiences.add(getMemberKeyPair(DefaultAudience.DART, config)) + // DART and Portfolio specific permissioning + if (permissions?.permissionPortfolioManager == true) additionalAudiences.add(getMemberKeyPair(DefaultAudience.PORTFOLIO_MANAGER, keyManagementConfig)) + if (permissions?.permissionDart == true) additionalAudiences.add(getMemberKeyPair(DefaultAudience.DART, keyManagementConfig)) return additionalAudiences } @@ -78,39 +80,18 @@ class EntityManager( addresses.map { getEntity(KeyManagementConfigWrapper(it, keyManagementConfig)).let { entity -> AudienceKeyPair( - entity.keys[KeyType.ENCRYPTION_PUBLIC_KEY].toString(), - entity.keys[KeyType.ENCRYPTION_PUBLIC_KEY].toString(), + entity.publicKey(KeyType.ENCRYPTION).toHex(), + entity.publicKey(KeyType.SIGNING).toHex() ) } }.toSet() - @Suppress("UnsafeCallOnNullableType") - private fun fetchToken(config: KeyManagementConfig): String { - - if (tokenMap.containsKey(config)) { - return tokenMap[config]!! - } - - val plugin = Class.forName(config.plugin).asSubclass(Plugin::class.java).kotlin.createInstance() - manager.register(plugin) - - val tokenPath = if (File(config.tokenPath).exists()) { - File(config.tokenPath) - } else { - File(System.getProperty("user.home")).resolve(config.tokenPath) - } - - tokenMap[config] = tokenPath.readText(Charsets.UTF_8) - - return tokenMap[config]!! - } - - private fun getMemberKeyPair(audience: DefaultAudience, keyManagementConfig: KeyManagementConfig): AudienceKeyPair = + private fun getMemberKeyPair(audience: DefaultAudience, keyManagementConfig: KeyManagementConfig? = null): AudienceKeyPair = provenanceProperties.members.firstOrNull { it.name == audience }?.let { val entity = getEntity(KeyManagementConfigWrapper(it.id, keyManagementConfig)) AudienceKeyPair( - entity.keys[KeyType.ENCRYPTION_PUBLIC_KEY].toString(), - entity.keys[KeyType.SIGNING_PUBLIC_KEY].toString(), + entity.publicKey(KeyType.ENCRYPTION).toHex(), + entity.publicKey(KeyType.SIGNING).toHex(), ) - } ?: throw IllegalStateException("Failed to find requested aud") + } ?: throw IllegalStateException("Failed to find requested audience") } diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/get/GetObject.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/get/GetObject.kt index a6858890..2e863fca 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/get/GetObject.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/get/GetObject.kt @@ -7,10 +7,9 @@ import io.provenance.api.domain.usecase.common.originator.models.KeyManagementCo import io.provenance.api.domain.usecase.objectStore.get.models.RetrieveAndDecryptRequest import io.provenance.api.frameworks.config.ObjectStoreProperties import io.provenance.api.frameworks.config.ProvenanceProperties +import io.provenance.entity.KeyType import io.provenance.scope.objectstore.client.OsClient import java.net.URI -import java.security.PrivateKey -import java.security.PublicKey import org.springframework.stereotype.Component import tech.figure.objectstore.gateway.client.ClientConfig import tech.figure.objectstore.gateway.client.GatewayClient @@ -23,19 +22,14 @@ class GetObject( private val provenanceProperties: ProvenanceProperties, ) : AbstractUseCase() { override suspend fun execute(args: RetrieveAndDecryptRequest): ByteArray { - val originator = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.keyManagementConfig)) - val publicKey = (originator.encryptionPublicKey() as? PublicKey) - ?: throw IllegalStateException("Public key was not present for originator: ${args.uuid}") - - val privateKey = (originator.encryptionPrivateKey() as? PrivateKey) - ?: throw IllegalStateException("Private key was not present for originator: ${args.uuid}") + val entity = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.keyManagementConfig)) if (args.useObjectStoreGateway) { GatewayClient(ClientConfig(URI.create(args.objectStoreAddress), provenanceProperties.mainnet)) } else { OsClient(URI.create(args.objectStoreAddress), objectStoreProperties.timeoutMs) }.use { client -> - return objectStore.retrieveAndDecrypt(client, args.hash, publicKey, privateKey) + return objectStore.retrieveAndDecrypt(client, args.hash, entity.getKeyRef(KeyType.ENCRYPTION)) } } } diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/CreateGatewayJwt.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/CreateGatewayJwt.kt index 813e3952..977b9a64 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/CreateGatewayJwt.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/CreateGatewayJwt.kt @@ -4,25 +4,17 @@ import io.provenance.api.domain.usecase.AbstractUseCase import io.provenance.api.domain.usecase.common.originator.EntityManager import io.provenance.api.domain.usecase.common.originator.models.KeyManagementConfigWrapper import io.provenance.api.domain.usecase.objectStore.store.models.CreateGatewayJwtRequest -import java.security.KeyPair -import java.security.PrivateKey -import java.security.PublicKey +import io.provenance.entity.KeyType import org.springframework.stereotype.Component import tech.figure.objectstore.gateway.client.GatewayJwt @Component class CreateGatewayJwt( private val entityManager: EntityManager -) : AbstractUseCase() { - override suspend fun execute(args: CreateGatewayJwtRequest): GatewayJwt.KeyPairJwt { +) : AbstractUseCase() { + override suspend fun execute(args: CreateGatewayJwtRequest): GatewayJwt.KeyRefJwt { val entity = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.keyManagementConfig)) - val publicKey = (entity.encryptionPublicKey() as? PublicKey) - ?: throw IllegalStateException("Public key was not present for originator: ${args.uuid}") - - val privateKey = (entity.encryptionPrivateKey() as? PrivateKey) - ?: throw IllegalStateException("Private key was not present for originator: ${args.uuid}") - - return GatewayJwt.KeyPairJwt(KeyPair(publicKey, privateKey)) + return GatewayJwt.KeyRefJwt(entity.getKeyRef(KeyType.ENCRYPTION)) } } diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreFile.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreFile.kt index 749bed97..1200594b 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreFile.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreFile.kt @@ -10,8 +10,7 @@ import io.provenance.api.models.account.AccountInfo import io.provenance.api.models.eos.store.StoreProtoResponse import io.provenance.api.models.p8e.PermissionInfo import io.provenance.api.util.awaitAllBytes -import java.security.PrivateKey -import java.security.PublicKey +import io.provenance.entity.KeyType import kotlinx.coroutines.reactor.awaitSingle import org.springframework.http.codec.multipart.FilePart import org.springframework.http.codec.multipart.FormFieldPart @@ -28,12 +27,7 @@ class StoreFile( ) : AbstractUseCase() { override suspend fun execute(args: StoreFileRequestWrapper): StoreProtoResponse { val (account, permissions, objectStoreAddress, storeRawBytes, id, file, type) = getParams(args.request) - val originator = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), account?.keyManagementConfig)) - val publicKey = (originator.encryptionPublicKey() as? PublicKey) - ?: throw IllegalStateException("Public key was not present for originator: ${args.uuid}") - - val privateKey = (originator.encryptionPrivateKey() as? PrivateKey) - ?: throw IllegalStateException("Private key was not present for originator: ${args.uuid}") + val entity = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), account?.keyManagementConfig)) return file.awaitAllBytes().map { bytes -> storeObject.executeBlocking( @@ -51,8 +45,7 @@ class StoreFile( type, objectStoreAddress, args.useObjectStoreGateway, - publicKey, - privateKey, + entity.getKeyRef(KeyType.ENCRYPTION), permissions, account ?: AccountInfo() ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreObject.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreObject.kt index 600a7726..f8c79f09 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreObject.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreObject.kt @@ -33,8 +33,7 @@ class StoreObject( return objectStore.store( client, args.bytes, - args.publicKey, - args.privateKey, + args.keyRef, additionalAudiences.map { it.encryptionKey.toJavaPublicKey() }.toSet(), args.type ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreProto.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreProto.kt index 1d927f73..25232150 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreProto.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/StoreProto.kt @@ -7,8 +7,7 @@ import io.provenance.api.domain.usecase.objectStore.store.models.StoreObjectRequ import io.provenance.api.domain.usecase.objectStore.store.models.StoreProtoRequestWrapper import io.provenance.api.frameworks.cee.parsers.MessageParser import io.provenance.api.models.eos.store.StoreProtoResponse -import java.security.PrivateKey -import java.security.PublicKey +import io.provenance.entity.KeyType import org.springframework.stereotype.Component @Component @@ -19,12 +18,7 @@ class StoreProto( ) : AbstractUseCase() { override suspend fun execute(args: StoreProtoRequestWrapper): StoreProtoResponse { val asset = parser.parse(args.request.message, Class.forName(args.request.type)) - val originator = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.request.account.keyManagementConfig)) - val publicKey = (originator.encryptionPublicKey() as? PublicKey) - ?: throw IllegalStateException("Public key was not present for originator: ${args.uuid}") - - val privateKey = (originator.encryptionPrivateKey() as? PrivateKey) - ?: throw IllegalStateException("Private key was not present for originator: ${args.uuid}") + val entity = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.request.account.keyManagementConfig)) return storeObject.execute( StoreObjectRequest( @@ -32,8 +26,7 @@ class StoreProto( args.request.type, args.request.objectStoreAddress, args.useObjectStoreGateway, - publicKey, - privateKey, + entity.getKeyRef(KeyType.ENCRYPTION), args.request.permissions, args.request.account, ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/models/StoreObjectRequest.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/models/StoreObjectRequest.kt index c2a2569a..4f31dafe 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/models/StoreObjectRequest.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/objectStore/store/models/StoreObjectRequest.kt @@ -2,16 +2,14 @@ package io.provenance.api.domain.usecase.objectStore.store.models import io.provenance.api.models.account.AccountInfo import io.provenance.api.models.p8e.PermissionInfo -import java.security.PrivateKey -import java.security.PublicKey +import io.provenance.scope.encryption.model.KeyRef data class StoreObjectRequest( val bytes: ByteArray, val type: String?, val objectStoreUrl: String, val useObjectStoreGateway: Boolean, - val publicKey: PublicKey, - val privateKey: PrivateKey, + val keyRef: KeyRef, val permissions: PermissionInfo? = null, val account: AccountInfo = AccountInfo(), ) diff --git a/service/src/main/kotlin/io/provenance/api/domain/usecase/provenance/account/GetSigner.kt b/service/src/main/kotlin/io/provenance/api/domain/usecase/provenance/account/GetSigner.kt index 50a04fad..3c84699d 100644 --- a/service/src/main/kotlin/io/provenance/api/domain/usecase/provenance/account/GetSigner.kt +++ b/service/src/main/kotlin/io/provenance/api/domain/usecase/provenance/account/GetSigner.kt @@ -7,13 +7,8 @@ import io.provenance.api.domain.usecase.common.originator.models.KeyManagementCo import io.provenance.api.domain.usecase.provenance.account.models.GetSignerRequest import io.provenance.api.frameworks.config.ProvenanceProperties import io.provenance.client.grpc.Signer -import io.provenance.hdwallet.common.hashing.sha256 -import io.provenance.hdwallet.ec.extensions.toECPrivateKey -import io.provenance.hdwallet.signer.BCECSigner -import io.provenance.scope.encryption.util.getAddress +import io.provenance.entity.KeyType import io.provenance.scope.util.toByteString -import java.security.PrivateKey -import java.security.PublicKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey import org.springframework.stereotype.Component @@ -22,25 +17,17 @@ class GetSigner( private val entityManager: EntityManager, private val provenanceProperties: ProvenanceProperties, ) : AbstractUseCase() { - override suspend fun execute(args: GetSignerRequest): Signer { - val originator = entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.account.keyManagementConfig)) + override suspend fun execute(args: GetSignerRequest): Signer = + entityManager.getEntity(KeyManagementConfigWrapper(args.uuid.toString(), args.account.keyManagementConfig)).let { entity -> + object : Signer { + override fun address(): String = entity.address(KeyType.SIGNING, provenanceProperties.mainnet) - return (originator.signingPublicKey() as PublicKey).let { public -> - (originator.signingPrivateKey() as PrivateKey).let { private -> - object : Signer { - override fun address(): String = public.getAddress(provenanceProperties.mainnet) + override fun pubKey(): Keys.PubKey = + Keys.PubKey.newBuilder() + .setKey((entity.publicKey(KeyType.SIGNING) as BCECPublicKey).q.getEncoded(true).toByteString()) + .build() - override fun pubKey(): Keys.PubKey = - Keys.PubKey.newBuilder() - .setKey((public as BCECPublicKey).q.getEncoded(true).toByteString()) - .build() - - override fun sign(data: ByteArray): ByteArray = - BCECSigner().sign(private.toECPrivateKey(), data.sha256()) - .encodeAsBTC() - .toByteArray() - } + override fun sign(data: ByteArray): ByteArray = entity.sign(KeyType.SIGNING, data) } } - } } diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/cee/P8eContractService.kt b/service/src/main/kotlin/io/provenance/api/frameworks/cee/P8eContractService.kt index 9e1125e7..8e006918 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/cee/P8eContractService.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/cee/P8eContractService.kt @@ -3,14 +3,13 @@ package io.provenance.api.frameworks.cee import com.google.protobuf.Message import io.provenance.api.domain.cee.ContractService import io.provenance.api.frameworks.provenance.exceptions.ContractExecutionException -import io.provenance.core.KeyType -import io.provenance.core.Originator +import io.provenance.entity.KeyEntity +import io.provenance.entity.KeyType import io.provenance.metadata.v1.ScopeResponse import io.provenance.scope.contract.proto.Envelopes.Envelope import io.provenance.scope.contract.proto.Specifications import io.provenance.scope.contract.spec.P8eContract import io.provenance.scope.contract.spec.P8eScopeSpecification -import io.provenance.scope.encryption.util.toJavaPublicKey import io.provenance.scope.sdk.Client import io.provenance.scope.sdk.ExecutionResult import io.provenance.scope.sdk.Session @@ -34,7 +33,7 @@ class P8eContractService : ContractService { records: Map, scopeUuid: UUID, sessionUuid: UUID?, - participants: Map?, + participants: Map?, scope: ScopeResponse?, scopeSpecification: String, audiences: Set @@ -84,15 +83,15 @@ class P8eContractService : ContractService { } ) - private fun Session.Builder.configureSession(records: Map, sessionUuid: UUID? = null, participants: Map?, audiences: Set): Session = + private fun Session.Builder.configureSession(records: Map, sessionUuid: UUID? = null, participants: Map?, audiences: Set): Session = this.setSessionUuid(sessionUuid ?: UUID.randomUUID()) .also { records.forEach { record -> it.addProposedRecord(record.key, record.value) } } .also { participants?.forEach { participant -> it.addParticipant( participant.key, - participant.value.keys[KeyType.SIGNING_PUBLIC_KEY].toString().toJavaPublicKey(), - participant.value.keys[KeyType.ENCRYPTION_PUBLIC_KEY].toString().toJavaPublicKey() + participant.value.publicKey(KeyType.SIGNING), + participant.value.publicKey(KeyType.ENCRYPTION), ) } } diff --git a/service/src/main/kotlin/io/provenance/api/frameworks/objectStore/ObjectStoreService.kt b/service/src/main/kotlin/io/provenance/api/frameworks/objectStore/ObjectStoreService.kt index 99d5a3c7..e4f521ec 100644 --- a/service/src/main/kotlin/io/provenance/api/frameworks/objectStore/ObjectStoreService.kt +++ b/service/src/main/kotlin/io/provenance/api/frameworks/objectStore/ObjectStoreService.kt @@ -5,14 +5,10 @@ import io.provenance.api.frameworks.config.ObjectStoreProperties import io.provenance.api.models.eos.store.StoreProtoResponse import io.provenance.api.models.eos.store.toModel import io.provenance.api.util.toModel -import io.provenance.scope.encryption.crypto.Pen import io.provenance.scope.encryption.domain.inputstream.DIMEInputStream -import io.provenance.scope.encryption.ecies.ProvenanceKeyGenerator -import io.provenance.scope.encryption.model.DirectKeyRef +import io.provenance.scope.encryption.model.KeyRef import io.provenance.scope.objectstore.client.OsClient import java.io.ByteArrayInputStream -import java.security.KeyPair -import java.security.PrivateKey import java.security.PublicKey import java.time.Duration import java.util.concurrent.TimeUnit @@ -29,32 +25,31 @@ class ObjectStoreService( override fun retrieveAndDecrypt( client: T, hash: String, - publicKey: PublicKey, - privateKey: PrivateKey, + keyRef: KeyRef ): ByteArray = when (client) { is OsClient -> { - val future = client.get(decodeBase64(hash), publicKey) + val future = client.get(decodeBase64(hash), keyRef.publicKey) val res: DIMEInputStream = future.get(objectStoreProperties.timeoutMs, TimeUnit.MILLISECONDS) - res.getDecryptedPayload(DirectKeyRef(publicKey, privateKey)).readAllBytes() + res.getDecryptedPayload(keyRef).readAllBytes() } is GatewayClient -> { client.getObject( Base64.encodeBase64String(decodeBase64(hash)), - GatewayJwt.KeyPairJwt(KeyPair(publicKey, privateKey)), + GatewayJwt.KeyRefJwt(keyRef), Duration.ofMillis(objectStoreProperties.timeoutMs) ).`object`.objectBytes.toByteArray() } else -> throw IllegalArgumentException("Unsupported client type while retrieving object!") } - override fun store(client: T, message: ByteArray, publicKey: PublicKey, privateKey: PrivateKey, additionalAudiences: Set, type: String?): StoreProtoResponse = + override fun store(client: T, message: ByteArray, keyRef: KeyRef, additionalAudiences: Set, type: String?): StoreProtoResponse = when (client) { is OsClient -> { client.put( ByteArrayInputStream(message), - publicKey, - Pen(ProvenanceKeyGenerator.generateKeyPair(publicKey)), + keyRef.publicKey, + keyRef.signer(), message.size.toLong(), additionalAudiences, type?.let { mapOf("type" to type) } ?: mapOf() @@ -65,7 +60,7 @@ class ObjectStoreService( client.putObject( message, type, - GatewayJwt.KeyPairJwt(KeyPair(publicKey, privateKey)), + GatewayJwt.KeyRefJwt(keyRef), Duration.ofMillis(objectStoreProperties.timeoutMs), additionalAudiences.toList() ).toModel() diff --git a/service/src/test/kotlin/io/provenance/api/domain/usecase/objectstore/StoreAssetTest.kt b/service/src/test/kotlin/io/provenance/api/domain/usecase/objectstore/StoreAssetTest.kt index 5b70e7be..48044b7a 100644 --- a/service/src/test/kotlin/io/provenance/api/domain/usecase/objectstore/StoreAssetTest.kt +++ b/service/src/test/kotlin/io/provenance/api/domain/usecase/objectstore/StoreAssetTest.kt @@ -1,6 +1,5 @@ package io.provenance.api.domain.usecase.objectstore -import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.mockk.clearAllMocks import io.mockk.coEvery @@ -21,7 +20,8 @@ import io.provenance.api.models.eos.store.StoreProtoResponse import io.provenance.api.models.p8e.Audience import io.provenance.api.models.p8e.AudienceKeyPair import io.provenance.api.models.p8e.PermissionInfo -import io.provenance.core.Originator +import io.provenance.entity.KeyEntity +import io.provenance.scope.encryption.model.DirectKeyRef import io.provenance.scope.encryption.util.toJavaPublicKey import io.provenance.scope.objectstore.client.OsClient import io.provenance.scope.util.toUuid @@ -43,7 +43,7 @@ class StoreAssetTest : FunSpec({ val mockObjectStore = mockk() val mockStoreObject = mockk(relaxed = true) val mockEntityManager = mockk() - val mockOriginator = mockk() + val mockOriginator = mockk() val mockOriginatorPublicKey = mockk() val mockOriginatorPrivateKey = mockk() val mockAddAssetAudiencePublicKey = mockk() @@ -74,11 +74,11 @@ class StoreAssetTest : FunSpec({ test("happy path") { val storeAssetResponse = StoreProtoResponse("HASH", "URI", "BUCKET", "NAME") - every { mockObjectStore.store(any(), any(), any(), any(), any(), any()) } returns storeAssetResponse + every { mockObjectStore.store(any(), any(), any(), any(), any()) } returns storeAssetResponse coEvery { mockStoreObject.execute(any()) } returns storeAssetResponse every { mockEntityManager.hydrateKeys(any()) } returns emptySet() - every { mockOriginator.encryptionPublicKey() } returns mockOriginatorPublicKey - every { mockOriginator.encryptionPrivateKey() } returns mockOriginatorPrivateKey + every { mockOriginator.publicKey(any()) } returns mockOriginatorPublicKey + every { mockOriginator.getKeyRef(any()) } returns DirectKeyRef(mockOriginatorPublicKey, mockOriginatorPrivateKey) every { mockParser.parse(any(), any()) } returns Asset.getDefaultInstance() // Execute enable replication code @@ -107,31 +107,9 @@ class StoreAssetTest : FunSpec({ ) } } - - test("exception when public key is not set") { - every { mockOriginator.encryptionPublicKey() } returns FakeKey() - every { mockEntityManager.hydrateKeys(any()) } returns emptySet() - every { mockParser.parse(any(), any()) } returns Asset.getDefaultInstance() - - // Execute enable replication code - shouldThrow { - storeAsset.execute( - StoreProtoRequestWrapper( - REQUEST_UUID, - StoreProtoRequest( - ADD_ASSET_OBJECT_STORE_ADDRESS, - PermissionInfo(emptySet()), - AccountInfo(), - ASSET, - String::class.java.canonicalName - ) - ) - ) - } - } }) -class FakeKey : java.security.Key { +class FakeKey : PublicKey { override fun getAlgorithm(): String { TODO("Not yet implemented") } diff --git a/service/src/test/kotlin/io/provenance/api/integration/objectstore/ObjectStoreSpec.kt b/service/src/test/kotlin/io/provenance/api/integration/objectstore/ObjectStoreSpec.kt index c8ff5668..0ac184ca 100644 --- a/service/src/test/kotlin/io/provenance/api/integration/objectstore/ObjectStoreSpec.kt +++ b/service/src/test/kotlin/io/provenance/api/integration/objectstore/ObjectStoreSpec.kt @@ -11,6 +11,7 @@ import io.provenance.api.models.account.KeyManagementConfig import io.provenance.api.models.eos.get.GetProtoRequest import io.provenance.api.models.eos.store.StoreProtoRequest import io.provenance.api.util.toPrettyJson +import io.provenance.plugins.vault.VaultConfig import io.provenance.scope.util.toUuid import java.util.UUID import tech.figure.asset.v1beta1.Asset @@ -43,8 +44,10 @@ class ObjectStoreSpec( type = "tech.figure.asset.v1beta1.Asset", account = AccountInfo( keyManagementConfig = KeyManagementConfig( - vaultAddress, - "src/test/resources/vault/token.output" + pluginConfig = VaultConfig( + "$vaultAddress/${entities.first()}", + "src/test/resources/vault/token.output" + ) ) ) ) @@ -60,8 +63,10 @@ class ObjectStoreSpec( type = "tech.figure.asset.v1beta1.Asset", account = AccountInfo( keyManagementConfig = KeyManagementConfig( - vaultAddress, - "src/test/resources/vault/token.output" + pluginConfig = VaultConfig( + "$vaultAddress/${entities.first()}", + "src/test/resources/vault/token.output" + ) ) ) )