mirror of
https://github.com/corda/corda.git
synced 2025-02-02 01:08:09 +00:00
Updated EnclaveClient interface
This commit is contained in:
parent
fac5db73f4
commit
95adf626f9
@ -2,6 +2,7 @@ package com.r3.conclave.encryptedtx.enclave
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import net.corda.core.conclave.common.EnclaveClient
|
||||
import net.corda.core.conclave.common.FlowIdAndPayload
|
||||
import net.corda.core.conclave.common.LedgerTxHelper
|
||||
import net.corda.core.conclave.common.dto.ConclaveLedgerTxModel
|
||||
import net.corda.core.conclave.common.dto.EncryptedVerifiableTxAndDependencies
|
||||
@ -13,12 +14,6 @@ import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.internal.dependencies
|
||||
import net.corda.core.node.AppServiceHub
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.CordaService
|
||||
import net.corda.core.serialization.ConstructorForDeserialization
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.EncryptedTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.ByteSequence
|
||||
@ -44,6 +39,8 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
|
||||
|
||||
private val serializationFactoryImpl: SerializationFactoryImpl
|
||||
|
||||
var rejectAttestation = false
|
||||
|
||||
init {
|
||||
val serverScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts)
|
||||
val clientScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts)
|
||||
@ -60,22 +57,27 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
|
||||
return byteArrayOf()
|
||||
}
|
||||
|
||||
override fun enclaveVerifyAndEncrypt(txAndDependencies: VerifiableTxAndDependencies, checkSufficientSignatures: Boolean): EncryptedTransaction {
|
||||
override fun registerRemoteEnclaveInstanceInfo(flowIdAndRemoteAttestation: FlowIdAndPayload<ByteArray>) {
|
||||
// for testing
|
||||
if (rejectAttestation) {
|
||||
throw EnclaveClient.RemoteAttestationException("Invalid attestation")
|
||||
}
|
||||
}
|
||||
|
||||
verifyTx(txAndDependencies, checkSufficientSignatures)
|
||||
override fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
|
||||
verifyTx(txAndDependencies, false)
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
|
||||
|
||||
verifyTx(txAndDependencies, true)
|
||||
|
||||
val ledgerTx = txAndDependencies.conclaveLedgerTxModel
|
||||
val transactionSignature = getSignature(ledgerTx.signedTransaction.id)
|
||||
return encrypt(ledgerTx).addSignature(transactionSignature)
|
||||
}
|
||||
|
||||
override fun encryptTransactionForLocal(encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
// no re-encryption in this mock enclave, in a real one we'd need to decrypt from the remote then re-encrypt with whatever key
|
||||
// we want to use for long term storage
|
||||
return encryptedTransaction
|
||||
}
|
||||
|
||||
override fun enclaveVerify(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
|
||||
override fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
|
||||
val decrypted = decrypt(encryptedTxAndDependencies.encryptedTransaction)
|
||||
|
||||
val verifiableTxAndDependencies = VerifiableTxAndDependencies(
|
||||
@ -90,18 +92,24 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
|
||||
return encrypt(decrypted).addSignature(transactionSignature)
|
||||
}
|
||||
|
||||
override fun encryptTransactionForRemote(conclaveLedgerTxModel: ConclaveLedgerTxModel, remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
// just serialise in this mock enclave, in a real one we'd need to encrypt for the remote party
|
||||
return encrypt(conclaveLedgerTxModel)
|
||||
}
|
||||
|
||||
override fun encryptTransactionForRemote(encryptedTransaction: EncryptedTransaction, remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
|
||||
override fun encryptTransactionForLocal(encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
// no re-encryption in this mock enclave, in a real one we'd need to decrypt from the remote then re-encrypt with whatever key
|
||||
// we want to use for long term storage
|
||||
return encryptedTransaction
|
||||
}
|
||||
|
||||
override fun encryptConclaveLedgerTxForRemote(flowIdWithConclaveLedgerTx: FlowIdAndPayload<ConclaveLedgerTxModel>) : EncryptedTransaction {
|
||||
// just serialise in this mock enclave, in a real one we'd need to encrypt for the remote party
|
||||
val conclaveLedgerTxModel = flowIdWithConclaveLedgerTx.payload
|
||||
return encrypt(conclaveLedgerTxModel)
|
||||
}
|
||||
|
||||
override fun encryptEncryptedTransactionForRemote(flowIdWithLocallyEncryptedTx: FlowIdAndPayload<EncryptedTransaction>): EncryptedTransaction {
|
||||
// no re-encryption in this mock enclave, in a real one we'd need to decrypt from the remote then re-encrypt with whatever key
|
||||
// we want to use for long term storage
|
||||
return flowIdWithLocallyEncryptedTx.payload
|
||||
}
|
||||
|
||||
private fun getSignature(transactionId : SecureHash) : TransactionSignature {
|
||||
val signableData = SignableData(transactionId, signatureMetadata)
|
||||
return enclaveKeyPair.sign(signableData)
|
||||
|
@ -141,25 +141,31 @@ class DummyEnclaveClient: EnclaveClient, SingletonSerializeAsToken() {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun enclaveVerifyAndEncrypt(txAndDependencies: VerifiableTxAndDependencies, checkSufficientSignatures: Boolean): EncryptedTransaction {
|
||||
override fun registerRemoteEnclaveInstanceInfo(flowIdAndRemoteAttestation: FlowIdAndPayload<ByteArray>) {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun enclaveVerify(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) : EncryptedTransaction {
|
||||
override fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun encryptTransactionForLocal(encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
override fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun encryptTransactionForRemote(conclaveLedgerTxModel: ConclaveLedgerTxModel,
|
||||
remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
override fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun encryptTransactionForRemote(encryptedTransaction: EncryptedTransaction,
|
||||
remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
override fun encryptTransactionForLocal(remoteEncryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun encryptConclaveLedgerTxForRemote(flowIdWithConclaveLedgerTx: FlowIdAndPayload<ConclaveLedgerTxModel>): EncryptedTransaction {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun encryptEncryptedTransactionForRemote(flowIdWithLocallyEncryptedTx: FlowIdAndPayload<EncryptedTransaction>): EncryptedTransaction {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
}
|
@ -312,11 +312,13 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio
|
||||
validatedTxSvc.getTransaction(it)
|
||||
}.toSet()
|
||||
|
||||
encryptionService.enclaveVerifyAndEncrypt(VerifiableTxAndDependencies(
|
||||
encryptionService.enclaveVerifyWithoutSignatures(
|
||||
VerifiableTxAndDependencies(
|
||||
conclaveLedgerTxModel!!,
|
||||
signedTxs,
|
||||
encryptedTxs
|
||||
), false)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
||||
stx.tx.toLedgerTransaction(serviceHub).verify()
|
||||
|
@ -8,9 +8,14 @@ class ExchangeAttestationFlow(private val session : FlowSession) : FlowLogic<Byt
|
||||
@Suspendable
|
||||
override fun call() : ByteArray {
|
||||
|
||||
val ourAttestationBytes = serviceHub.encryptedTransactionService.getEnclaveInstance()
|
||||
val encSvc = serviceHub.encryptedTransactionService
|
||||
val ourAttestationBytes = encSvc.getEnclaveInstance()
|
||||
|
||||
return session.sendAndReceive<ByteArray>(ourAttestationBytes).unwrap { it }
|
||||
val theirAttestationBytes = session.sendAndReceive<ByteArray>(ourAttestationBytes).unwrap { it }
|
||||
// this can throw if the enclave does not believe the attestation to be valid
|
||||
encSvc.registerRemoteEnclaveInstanceInfo(runId.uuid, theirAttestationBytes)
|
||||
|
||||
return theirAttestationBytes
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,9 +24,12 @@ class ExchangeAttestationFlowHandler(private val otherSideSession: FlowSession)
|
||||
@Suspendable
|
||||
override fun call(): ByteArray {
|
||||
|
||||
val ourAttestationBytes = serviceHub.encryptedTransactionService.getEnclaveInstance()
|
||||
val encSvc = serviceHub.encryptedTransactionService
|
||||
val ourAttestationBytes = encSvc.getEnclaveInstance()
|
||||
|
||||
val theirAttestationBytes = otherSideSession.receive<ByteArray>().unwrap { it }
|
||||
// this can throw if the enclave does not believe the attestation to be valid
|
||||
encSvc.registerRemoteEnclaveInstanceInfo(runId.uuid, theirAttestationBytes)
|
||||
|
||||
otherSideSession.send(ourAttestationBytes)
|
||||
|
||||
|
@ -120,10 +120,12 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
signedTxs,
|
||||
encryptedTxs
|
||||
)
|
||||
val encryptedAndVerifiedTx = serviceHub.encryptedTransactionService.enclaveVerifyAndEncrypt(verifiableTx, checkSufficientSignatures)
|
||||
|
||||
if (checkSufficientSignatures) {
|
||||
val encryptedAndVerifiedTx = serviceHub.encryptedTransactionService.enclaveVerifyWithSignatures(verifiableTx)
|
||||
serviceHub.recordEncryptedTransactions(listOf(encryptedAndVerifiedTx))
|
||||
} else {
|
||||
serviceHub.encryptedTransactionService.enclaveVerifyWithoutSignatures(verifiableTx)
|
||||
}
|
||||
|
||||
it
|
||||
|
@ -93,7 +93,6 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any,
|
||||
override fun call(): Void? {
|
||||
|
||||
val encryptSvc = serviceHub.encryptedTransactionService
|
||||
var remoteAttestation : ByteArray? = null
|
||||
|
||||
val networkMaxMessageSize = serviceHub.networkParameters.maxMessageSize
|
||||
val maxPayloadSize = networkMaxMessageSize / 2
|
||||
@ -122,8 +121,9 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any,
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
// The first step in an encrypted exchange, is to request an exchange of attestations
|
||||
remoteAttestation = subFlow(ExchangeAttestationFlow(otherSideSession))
|
||||
// The first step in an encrypted exchange, is to request an exchange of attestations. This will also cache the attestation
|
||||
// in the enclave for future use
|
||||
subFlow(ExchangeAttestationFlow(otherSideSession))
|
||||
|
||||
// also send the ledger transaction
|
||||
if (payload is SignedTransaction) {
|
||||
@ -168,18 +168,15 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any,
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
|
||||
val remoteAtt = remoteAttestation ?:
|
||||
throw IllegalStateException("Cannot share encrypted backchain without a remote attestation")
|
||||
|
||||
val flowId = runId.uuid
|
||||
val encryptedTx = serviceHub.validatedTransactions.getEncryptedTransaction(txId)
|
||||
|
||||
val encryptedTransactionToSend = if (encryptedTx != null) {
|
||||
encryptSvc.encryptTransactionForRemote(encryptedTx, remoteAtt)
|
||||
encryptSvc.encryptTransactionForRemote(flowId, encryptedTx)
|
||||
} else {
|
||||
val tx = serviceHub.validatedTransactions.getTransaction(txId)
|
||||
?: throw FetchDataFlow.HashNotFound(txId)
|
||||
encryptSvc.encryptTransactionForRemote(tx.toLedgerTxModel(serviceHub), remoteAtt)
|
||||
encryptSvc.encryptTransactionForRemote(flowId, tx.toLedgerTxModel(serviceHub))
|
||||
}
|
||||
|
||||
authorisedTransactions.removeAuthorised(txId)
|
||||
|
@ -48,8 +48,7 @@ import java.util.*
|
||||
sealed class FetchDataFlow<T : NamedByHash, in W : Any>(
|
||||
protected val requests: Set<SecureHash>,
|
||||
protected val otherSideSession: FlowSession,
|
||||
protected val dataType: DataType,
|
||||
protected val remoteAttestation: ByteArray? = null) : FlowLogic<FetchDataFlow.Result<T>>() {
|
||||
protected val dataType: DataType) : FlowLogic<FetchDataFlow.Result<T>>() {
|
||||
|
||||
@CordaSerializable
|
||||
class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException()
|
||||
@ -275,17 +274,12 @@ class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: FlowSession) :
|
||||
override fun load(txid: SecureHash): SignedTransaction? = serviceHub.validatedTransactions.getTransaction(txid)
|
||||
}
|
||||
|
||||
class FetchEncryptedTransactionsFlow(requests: Set<SecureHash>, otherSide: FlowSession, remoteAttestation: ByteArray) :
|
||||
FetchDataFlow<EncryptedTransaction, EncryptedTransaction>(requests, otherSide, DataType.TRANSACTION, remoteAttestation) {
|
||||
class FetchEncryptedTransactionsFlow(requests: Set<SecureHash>, otherSide: FlowSession) :
|
||||
FetchDataFlow<EncryptedTransaction, EncryptedTransaction>(requests, otherSide, DataType.TRANSACTION) {
|
||||
|
||||
override fun load(txid: SecureHash): EncryptedTransaction? {
|
||||
|
||||
require(remoteAttestation != null) {
|
||||
"FetchEncryptedTransactionsFlow requires a remoteAttestation"
|
||||
}
|
||||
|
||||
return serviceHub.validatedTransactions.getEncryptedTransaction(txid)?.let {
|
||||
serviceHub.encryptedTransactionService.encryptTransactionForRemote(it, remoteAttestation!!)
|
||||
serviceHub.encryptedTransactionService.encryptTransactionForRemote(runId.uuid,it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ package net.corda.core.node.services
|
||||
|
||||
import net.corda.core.conclave.common.DummyEnclaveClient
|
||||
import net.corda.core.conclave.common.EnclaveClient
|
||||
import net.corda.core.conclave.common.FlowIdAndPayload
|
||||
import net.corda.core.conclave.common.dto.ConclaveLedgerTxModel
|
||||
import net.corda.core.conclave.common.dto.EncryptedVerifiableTxAndDependencies
|
||||
import net.corda.core.conclave.common.dto.VerifiableTxAndDependencies
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.EncryptedTransaction
|
||||
import java.util.*
|
||||
|
||||
class EncryptedTransactionService(val enclaveClient: EnclaveClient = DummyEnclaveClient()) : SingletonSerializeAsToken() {
|
||||
|
||||
@ -14,25 +16,31 @@ class EncryptedTransactionService(val enclaveClient: EnclaveClient = DummyEnclav
|
||||
return enclaveClient.getEnclaveInstanceInfo()
|
||||
}
|
||||
|
||||
fun enclaveVerifyAndEncrypt(txAndDependencies : VerifiableTxAndDependencies, checkSufficientSignatures: Boolean = true): EncryptedTransaction {
|
||||
return enclaveClient.enclaveVerifyAndEncrypt(txAndDependencies, checkSufficientSignatures)
|
||||
fun registerRemoteEnclaveInstanceInfo(flowId : UUID, remoteAttestation: ByteArray) {
|
||||
enclaveClient.registerRemoteEnclaveInstanceInfo(FlowIdAndPayload(flowId, remoteAttestation))
|
||||
}
|
||||
|
||||
fun enclaveVerifyAndEncrypt(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) : EncryptedTransaction {
|
||||
return enclaveClient.enclaveVerify(encryptedTxAndDependencies)
|
||||
fun enclaveVerifyWithoutSignatures(txAndDependencies : VerifiableTxAndDependencies) {
|
||||
return enclaveClient.enclaveVerifyWithoutSignatures(txAndDependencies)
|
||||
}
|
||||
|
||||
fun enclaveVerifyWithSignatures(txAndDependencies : VerifiableTxAndDependencies) : EncryptedTransaction {
|
||||
return enclaveClient.enclaveVerifyWithSignatures(txAndDependencies)
|
||||
}
|
||||
|
||||
fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) : EncryptedTransaction {
|
||||
return enclaveClient.enclaveVerifyWithSignatures(encryptedTxAndDependencies)
|
||||
}
|
||||
|
||||
fun encryptTransactionForLocal(encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
return enclaveClient.encryptTransactionForLocal(encryptedTransaction)
|
||||
}
|
||||
|
||||
fun encryptTransactionForRemote(conclaveLedgerTxModel: ConclaveLedgerTxModel,
|
||||
remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
return enclaveClient.encryptTransactionForRemote(conclaveLedgerTxModel, remoteAttestation)
|
||||
fun encryptTransactionForRemote(flowId: UUID, conclaveLedgerTxModel: ConclaveLedgerTxModel): EncryptedTransaction {
|
||||
return enclaveClient.encryptConclaveLedgerTxForRemote(FlowIdAndPayload(flowId,conclaveLedgerTxModel))
|
||||
}
|
||||
|
||||
fun encryptTransactionForRemote(encryptedTransaction: EncryptedTransaction,
|
||||
remoteAttestation: ByteArray): EncryptedTransaction {
|
||||
return enclaveClient.encryptTransactionForRemote(encryptedTransaction, remoteAttestation)
|
||||
fun encryptTransactionForRemote(flowId: UUID, encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
|
||||
return enclaveClient.encryptEncryptedTransactionForRemote(FlowIdAndPayload(flowId, encryptedTransaction))
|
||||
}
|
||||
}
|
@ -195,7 +195,7 @@ class DbTransactionsResolver(private val flow: ResolveTransactionsFlow) : Transa
|
||||
val signedTransactions = tx.dependencies.mapNotNull { transactionStorage.getTransaction(it) }.toSet()
|
||||
val encryptedTransactions = tx.dependencies.mapNotNull { transactionStorage.getEncryptedTransaction(it) }.toSet()
|
||||
|
||||
val verifiedTransaction = encryptSvc.enclaveVerifyAndEncrypt(
|
||||
val verifiedTransaction = encryptSvc.enclaveVerifyWithSignatures(
|
||||
EncryptedVerifiableTxAndDependencies(
|
||||
tx,
|
||||
signedTransactions,
|
||||
@ -229,7 +229,7 @@ class DbTransactionsResolver(private val flow: ResolveTransactionsFlow) : Transa
|
||||
val remoteAttestation = flow.remoteAttestation ?:
|
||||
throw IllegalStateException("fetchEncryptedRequiredTransactions requires a remoteAttestation")
|
||||
|
||||
val requestedTxs = flow.subFlow(FetchEncryptedTransactionsFlow(requests, flow.otherSide, remoteAttestation))
|
||||
val requestedTxs = flow.subFlow(FetchEncryptedTransactionsFlow(requests, flow.otherSide))
|
||||
return Pair(requestedTxs.fromDisk.map { it.id }, requestedTxs.downloaded)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user