mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Send current transaction encrypted
This commit is contained in:
parent
711eb11a2e
commit
b36a06b588
@ -64,18 +64,18 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
|
||||
}
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies) {
|
||||
verifyTx(txAndDependencies, false)
|
||||
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) {
|
||||
val decrypted = decrypt(encryptedTxAndDependencies.encryptedTransaction)
|
||||
|
||||
val verifiableTxAndDependencies = VerifiableTxAndDependencies(
|
||||
decrypted,
|
||||
encryptedTxAndDependencies.dependencies,
|
||||
encryptedTxAndDependencies.encryptedDependencies
|
||||
)
|
||||
|
||||
verifyTx(verifiableTxAndDependencies, false)
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
|
||||
|
||||
verifyTx(txAndDependencies, true)
|
||||
|
||||
val ledgerTx = txAndDependencies.conclaveLedgerTxModel
|
||||
val transactionSignature = getSignature(ledgerTx.signedTransaction.id)
|
||||
return encrypt(ledgerTx).addSignature(transactionSignature)
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
|
||||
val decrypted = decrypt(encryptedTxAndDependencies.encryptedTransaction)
|
||||
|
@ -42,37 +42,19 @@ interface EnclaveClient {
|
||||
fun registerRemoteEnclaveInstanceInfo(invokeId: UUID, payload: ByteArray)
|
||||
|
||||
/**
|
||||
* Verify an unencrypted transaction (supplied with its dependencies), without checking the signatures. This would be used during
|
||||
* Verify an encrypted transaction (supplied with its dependencies), without checking the signatures. This would be used during
|
||||
* [CollectSignaturesFlow], where we need to verify a transaction, but it is not fully signed (e.g. we haven't signed it yet, the
|
||||
* notary hasn't signed it yet, and possibly other parties).
|
||||
*
|
||||
* We do not return a signed and encrypted transaction from this call, as we will not be storing these transactions long term. They
|
||||
* are not fully signed at this stage therefore cannot be committed to the ledger.
|
||||
*
|
||||
* @param txAndDependencies the transaction to verify
|
||||
* @param encryptedTxAndDependencies the encrypted transaction to verify
|
||||
*
|
||||
* @throws [VerificationException] if verification failed
|
||||
*/
|
||||
@Throws(VerificationException::class)
|
||||
fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies)
|
||||
|
||||
/**
|
||||
* Verify an unencrypted transaction (supplied with its dependencies), and also check the signatures. This would be used during
|
||||
* [FinalityFlow], where we need to verify a transaction fully.
|
||||
*
|
||||
* We return a signed and encrypted transaction from this call, as we can store that and supply it to the enclave whenever we need it
|
||||
* as proof that we have verified a transaction previously. I.e. our own signature over the id means that we (as an enclave) have
|
||||
* previously verified this transaction
|
||||
*
|
||||
* @param txAndDependencies the transaction to verify
|
||||
*
|
||||
* @return an [EncryptedTransaction] which will be an encrypted version of the transaction, along with our enclave's signature
|
||||
* over the transaction id.
|
||||
*
|
||||
* @throws [VerificationException] if verification failed
|
||||
*/
|
||||
@Throws(VerificationException::class)
|
||||
fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction
|
||||
fun enclaveVerifyWithoutSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies)
|
||||
|
||||
/**
|
||||
* Verify an encrypted transaction (supplied with its dependencies) and also check the signatures. This would be used during
|
||||
@ -141,11 +123,7 @@ class DummyEnclaveClient: EnclaveClient, SingletonSerializeAsToken() {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies) {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
override fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
|
||||
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) {
|
||||
throw UnsupportedOperationException("Add your custom enclave client implementation")
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.corda.core.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.sun.org.apache.xpath.internal.operations.Bool
|
||||
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.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
@ -13,6 +13,7 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.groupPublicKeysByWellKnownParty
|
||||
import net.corda.core.internal.dependencies
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.transactions.EncryptedTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
@ -279,11 +280,12 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio
|
||||
progressTracker.currentStep = RECEIVING
|
||||
// Receive transaction and resolve dependencies, check sufficient signatures is disabled as we don't have all signatures.
|
||||
|
||||
var conclaveLedgerTxModel : ConclaveLedgerTxModel? = null
|
||||
var receivedEncryptedTx : EncryptedTransaction? = null
|
||||
|
||||
val stx = if (encrypted) {
|
||||
conclaveLedgerTxModel = subFlow(ReceiveTransactionAsConclaveModelFlow(otherSideSession, checkSufficientSignatures = false, encrypted = true))
|
||||
conclaveLedgerTxModel.signedTransaction
|
||||
val stxAndEncrypted = subFlow(ReceiveTransactionWithEncryptedFlow(otherSideSession, checkSufficientSignatures = false))
|
||||
receivedEncryptedTx = stxAndEncrypted.encryptedTransaction
|
||||
stxAndEncrypted.signedTransaction
|
||||
} else {
|
||||
subFlow(ReceiveTransactionFlow(otherSideSession, checkSufficientSignatures = false, encrypted = true))
|
||||
}
|
||||
@ -304,6 +306,10 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio
|
||||
val encryptionService = serviceHub.encryptedTransactionService
|
||||
val validatedTxSvc = serviceHub.validatedTransactions
|
||||
|
||||
val usableReceivedTx = receivedEncryptedTx ?: throw IllegalStateException("An encrypted transaction is required")
|
||||
|
||||
val locallyEncryptedTransaction = encryptionService.encryptTransactionForLocal(usableReceivedTx)
|
||||
|
||||
val encryptedTxs = stx.dependencies.mapNotNull {
|
||||
validatedTxSvc.getEncryptedTransaction(it)
|
||||
}.toSet()
|
||||
@ -313,8 +319,8 @@ abstract class SignTransactionFlow @JvmOverloads constructor(val otherSideSessio
|
||||
}.toSet()
|
||||
|
||||
encryptionService.enclaveVerifyWithoutSignatures(
|
||||
VerifiableTxAndDependencies(
|
||||
conclaveLedgerTxModel!!,
|
||||
EncryptedVerifiableTxAndDependencies(
|
||||
locallyEncryptedTransaction,
|
||||
signedTxs,
|
||||
encryptedTxs
|
||||
)
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
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.contracts.*
|
||||
import net.corda.core.internal.ResolveTransactionsFlow
|
||||
@ -9,6 +10,8 @@ import net.corda.core.internal.checkParameterHash
|
||||
import net.corda.core.internal.dependencies
|
||||
import net.corda.core.internal.pushToLoggingContext
|
||||
import net.corda.core.node.StatesToRecord
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.EncryptedTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -38,19 +41,28 @@ open class ReceiveTransactionFlow @JvmOverloads constructor(private val otherSid
|
||||
private val encrypted : Boolean = false) :
|
||||
ReceiveTransactionFlowBase<SignedTransaction>(otherSideSession, checkSufficientSignatures, statesToRecord, encrypted) {
|
||||
|
||||
override fun getReturnVal(stx: SignedTransaction, conclaveLedgerTxModel: ConclaveLedgerTxModel?): SignedTransaction {
|
||||
override fun getReturnVal(stx: SignedTransaction, encryptedTransaction: EncryptedTransaction?): SignedTransaction {
|
||||
return stx
|
||||
}
|
||||
}
|
||||
|
||||
open class ReceiveTransactionAsConclaveModelFlow @JvmOverloads constructor(private val otherSideSession: FlowSession,
|
||||
private val checkSufficientSignatures: Boolean = true,
|
||||
private val statesToRecord: StatesToRecord = StatesToRecord.NONE,
|
||||
private val encrypted : Boolean = false) :
|
||||
ReceiveTransactionFlowBase<ConclaveLedgerTxModel>(otherSideSession, checkSufficientSignatures, statesToRecord, encrypted) {
|
||||
|
||||
override fun getReturnVal(stx: SignedTransaction, conclaveLedgerTxModel: ConclaveLedgerTxModel?): ConclaveLedgerTxModel {
|
||||
return conclaveLedgerTxModel ?: throw IllegalStateException("Cannot return a null ConclaveLedgerTxModel")
|
||||
@CordaSerializable
|
||||
data class SignedTransactionWithEncrypted(val signedTransaction: SignedTransaction, val encryptedTransaction: EncryptedTransaction)
|
||||
|
||||
open class ReceiveTransactionWithEncryptedFlow @JvmOverloads constructor(private val otherSideSession: FlowSession,
|
||||
private val checkSufficientSignatures: Boolean = true,
|
||||
private val statesToRecord: StatesToRecord = StatesToRecord.NONE) :
|
||||
ReceiveTransactionFlowBase<SignedTransactionWithEncrypted>(otherSideSession, checkSufficientSignatures, statesToRecord, true) {
|
||||
|
||||
|
||||
override fun getReturnVal(stx: SignedTransaction, encryptedTransaction: EncryptedTransaction?): SignedTransactionWithEncrypted {
|
||||
|
||||
require(encryptedTransaction != null) {
|
||||
"Cannot return a null ConclaveLedgerTxModel"
|
||||
}
|
||||
|
||||
return SignedTransactionWithEncrypted(stx, encryptedTransaction!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +72,7 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
private val encrypted : Boolean = false) : FlowLogic<T>() {
|
||||
|
||||
@Suspendable
|
||||
abstract fun getReturnVal(stx: SignedTransaction, conclaveLedgerTxModel: ConclaveLedgerTxModel?) : T
|
||||
abstract fun getReturnVal(stx: SignedTransaction, encryptedTransaction: EncryptedTransaction?) : T
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
@Suspendable
|
||||
@ -75,12 +87,11 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
logger.trace { "Receiving a transaction (but without checking the signatures) from ${otherSideSession.counterparty}" }
|
||||
}
|
||||
|
||||
var conclaveLedgerTxModel : ConclaveLedgerTxModel? = null
|
||||
var remoteAttestation : ByteArray? = null
|
||||
var encryptedTx : EncryptedTransaction? = null
|
||||
if (encrypted) {
|
||||
// The first step in an encrypted exchange, is to request an exchange of attestations
|
||||
remoteAttestation = subFlow(ExchangeAttestationFlowHandler(otherSideSession))
|
||||
conclaveLedgerTxModel = otherSideSession.receive<ConclaveLedgerTxModel>().unwrap { it }
|
||||
subFlow(ExchangeAttestationFlowHandler(otherSideSession))
|
||||
encryptedTx = otherSideSession.receive<EncryptedTransaction>().unwrap { it }
|
||||
}
|
||||
|
||||
val stx = otherSideSession.receive<SignedTransaction>().unwrap {
|
||||
@ -88,17 +99,13 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
logger.info("Received transaction acknowledgement request from party ${otherSideSession.counterparty}.")
|
||||
checkParameterHash(it.networkParametersHash)
|
||||
|
||||
if (conclaveLedgerTxModel != null) {
|
||||
require(conclaveLedgerTxModel.signedTransaction == it) {
|
||||
"The supplied signed transaction and conclaveLedgerTxModel are different"
|
||||
if (encryptedTx != null) {
|
||||
require(encryptedTx.id == it.id) {
|
||||
"The supplied signed transaction and encrypted transactions are different"
|
||||
}
|
||||
}
|
||||
|
||||
require(remoteAttestation != null) {
|
||||
"A remote attestation is required for encrypted mode"
|
||||
}
|
||||
|
||||
subFlow(ResolveTransactionsFlow(it, otherSideSession, statesToRecord, encrypted = encrypted, remoteAttestation = remoteAttestation!!))
|
||||
subFlow(ResolveTransactionsFlow(it, otherSideSession, statesToRecord, encrypted = encrypted))
|
||||
|
||||
logger.info("Transaction dependencies resolution completed.")
|
||||
try {
|
||||
@ -115,8 +122,8 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
validatedTxSvc.getEncryptedTransaction(validatedTxId)
|
||||
}.toSet()
|
||||
|
||||
val verifiableTx = VerifiableTxAndDependencies(
|
||||
conclaveLedgerTxModel!!,
|
||||
val verifiableTx = EncryptedVerifiableTxAndDependencies(
|
||||
encryptedTx!!,
|
||||
signedTxs,
|
||||
encryptedTxs
|
||||
)
|
||||
@ -146,7 +153,7 @@ abstract class ReceiveTransactionFlowBase<T> @JvmOverloads constructor(private v
|
||||
serviceHub.recordTransactions(statesToRecord, setOf(stx))
|
||||
logger.info("Successfully recorded received transaction locally.")
|
||||
}
|
||||
return getReturnVal(stx, conclaveLedgerTxModel)
|
||||
return getReturnVal(stx, encryptedTx)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,7 +128,8 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any,
|
||||
// also send the ledger transaction
|
||||
if (payload is SignedTransaction) {
|
||||
val conclaveLedgerTxModel = payload.toLedgerTxModel(serviceHub, false)
|
||||
otherSideSession.send(conclaveLedgerTxModel)
|
||||
val encryptedTransaction = encryptSvc.encryptTransactionForRemote(runId.uuid, conclaveLedgerTxModel)
|
||||
otherSideSession.send(encryptedTransaction)
|
||||
}
|
||||
}
|
||||
// This loop will receive [FetchDataFlow.Request] continuously until the `otherSideSession` has all the data they need
|
||||
|
@ -23,8 +23,7 @@ class ResolveTransactionsFlow private constructor(
|
||||
val txHashes: Set<SecureHash>,
|
||||
val otherSide: FlowSession,
|
||||
val statesToRecord: StatesToRecord,
|
||||
val encrypted: Boolean = false,
|
||||
val remoteAttestation : ByteArray? = null
|
||||
val encrypted: Boolean = false
|
||||
) : FlowLogic<Unit>() {
|
||||
|
||||
constructor(txHashes: Set<SecureHash>, otherSide: FlowSession, statesToRecord: StatesToRecord = StatesToRecord.NONE)
|
||||
@ -40,8 +39,8 @@ class ResolveTransactionsFlow private constructor(
|
||||
: this(transaction, transaction.dependencies, otherSide, statesToRecord)
|
||||
|
||||
// TODO: PoC constructor
|
||||
constructor(transaction: SignedTransaction, otherSide: FlowSession, statesToRecord: StatesToRecord = StatesToRecord.NONE, encrypted: Boolean, remoteAttestation: ByteArray)
|
||||
: this(transaction, transaction.dependencies, otherSide, statesToRecord, encrypted, remoteAttestation)
|
||||
constructor(transaction: SignedTransaction, otherSide: FlowSession, statesToRecord: StatesToRecord = StatesToRecord.NONE, encrypted: Boolean)
|
||||
: this(transaction, transaction.dependencies, otherSide, statesToRecord, encrypted)
|
||||
|
||||
private var fetchNetParamsFromCounterpart = false
|
||||
|
||||
|
@ -26,13 +26,8 @@ class EncryptedTransactionService(val enclaveClient: EnclaveClient = DummyEnclav
|
||||
enclaveClient.registerRemoteEnclaveInstanceInfo(flowId, remoteAttestation)
|
||||
}
|
||||
|
||||
fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
|
||||
|
||||
return enclaveClient.enclaveVerifyWithoutSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), txAndDependencies)
|
||||
}
|
||||
|
||||
fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
|
||||
return enclaveClient.enclaveVerifyWithSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), txAndDependencies)
|
||||
fun enclaveVerifyWithoutSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) {
|
||||
return enclaveClient.enclaveVerifyWithoutSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), encryptedTxAndDependencies)
|
||||
}
|
||||
|
||||
fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
|
||||
|
@ -225,10 +225,6 @@ class DbTransactionsResolver(private val flow: ResolveTransactionsFlow) : Transa
|
||||
|
||||
@Suspendable
|
||||
private fun fetchEncryptedRequiredTransactions(requests: Set<SecureHash>): Pair<List<SecureHash>, List<EncryptedTransaction>> {
|
||||
|
||||
val remoteAttestation = flow.remoteAttestation ?:
|
||||
throw IllegalStateException("fetchEncryptedRequiredTransactions requires a remoteAttestation")
|
||||
|
||||
val requestedTxs = flow.subFlow(FetchEncryptedTransactionsFlow(requests, flow.otherSide))
|
||||
return Pair(requestedTxs.fromDisk.map { it.id }, requestedTxs.downloaded)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user