refactor enclave interface to provide invocationID for all calls (#7122)

Co-authored-by: stefano <stefano@DESKTOP-VCFJH4G>
This commit is contained in:
Stefano Franz 2022-03-21 11:42:18 +00:00 committed by GitHub
parent fbc06d7f57
commit 4efc439e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 82 deletions

View File

@ -14,9 +14,9 @@
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" withSubpackages="false" static="false" />
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
<package name="tornadofx" withSubpackages="false" static="false" />
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="tornadofx" alias="false" withSubpackages="false" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />

View File

@ -2,7 +2,6 @@ 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
@ -22,6 +21,7 @@ import net.corda.serialization.internal.AMQP_P2P_CONTEXT
import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.SerializationFactoryCacheKey
import net.corda.serialization.internal.amqp.SerializerFactory
import java.util.*
class EncryptedTxEnclaveClient() : EnclaveClient {
@ -57,18 +57,18 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
return byteArrayOf()
}
override fun registerRemoteEnclaveInstanceInfo(flowIdAndRemoteAttestation: FlowIdAndPayload<ByteArray>) {
override fun registerRemoteEnclaveInstanceInfo(invokeId: UUID, payload: ByteArray) {
// for testing
if (rejectAttestation) {
throw EnclaveClient.RemoteAttestationException("Invalid attestation")
}
}
override fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies) {
verifyTx(txAndDependencies, false)
}
override fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
override fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
verifyTx(txAndDependencies, true)
@ -77,7 +77,7 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
return encrypt(ledgerTx).addSignature(transactionSignature)
}
override fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
override fun enclaveVerifyWithSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
val decrypted = decrypt(encryptedTxAndDependencies.encryptedTransaction)
val verifiableTxAndDependencies = VerifiableTxAndDependencies(
@ -92,22 +92,18 @@ class EncryptedTxEnclaveClient() : EnclaveClient {
return encrypt(decrypted).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
override fun encryptTransactionForLocal(invokeId: UUID, encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
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 encryptConclaveLedgerTxForRemote(invokeId: UUID, conclaveLedgerTx: ConclaveLedgerTxModel) : EncryptedTransaction {
return encrypt(conclaveLedgerTx)
}
override fun encryptEncryptedTransactionForRemote(flowIdWithLocallyEncryptedTx: FlowIdAndPayload<EncryptedTransaction>): EncryptedTransaction {
override fun encryptEncryptedTransactionForRemote(invokeId: UUID, locallyEncryptedTx: 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
return locallyEncryptedTx
}
private fun getSignature(transactionId : SecureHash) : TransactionSignature {

View File

@ -4,8 +4,6 @@ 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.flows.FlowException
import net.corda.core.node.services.CordaService
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.EncryptedTransaction
import java.util.*
@ -14,8 +12,6 @@ import java.util.*
* A structure to wrap any payload with an associated flowID. This will be serialised and used to send data to an enclave as it expects all
* data to arrive in a single ByteArray
*/
@CordaSerializable
data class FlowIdAndPayload<T : Any>(val flowId: UUID, val payload: T)
interface EnclaveClient {
@ -38,12 +34,12 @@ interface EnclaveClient {
* Register a remote enclave's [EnclaveInstanceInfo] with our own enclave. From this point on, our enclave will cache this information,
* and use it whenever it needs it when dealing with requests from the same flowID
*
* @param flowIdAndRemoteAttestation flowId and the remote attestation as a [ByteArray] wrapped in a [FlowIdAndPayload] object
* @param invokeId flowId and the remote attestation as a [ByteArray] wrapped in a [FlowIdAndPayload] object
*
* @throws [RemoteAttestationException] if our enclave does not accept the attestation
*/
@Throws(RemoteAttestationException::class)
fun registerRemoteEnclaveInstanceInfo(flowIdAndRemoteAttestation: FlowIdAndPayload<ByteArray>)
fun registerRemoteEnclaveInstanceInfo(invokeId: UUID, payload: ByteArray)
/**
* Verify an unencrypted transaction (supplied with its dependencies), without checking the signatures. This would be used during
@ -58,7 +54,7 @@ interface EnclaveClient {
* @throws [VerificationException] if verification failed
*/
@Throws(VerificationException::class)
fun enclaveVerifyWithoutSignatures(txAndDependencies : VerifiableTxAndDependencies)
fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies)
/**
* Verify an unencrypted transaction (supplied with its dependencies), and also check the signatures. This would be used during
@ -76,7 +72,7 @@ interface EnclaveClient {
* @throws [VerificationException] if verification failed
*/
@Throws(VerificationException::class)
fun enclaveVerifyWithSignatures(txAndDependencies : VerifiableTxAndDependencies): EncryptedTransaction
fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction
/**
* Verify an encrypted transaction (supplied with its dependencies) and also check the signatures. This would be used during
@ -95,7 +91,7 @@ interface EnclaveClient {
* @throws [VerificationException] if verification failed
*/
@Throws(VerificationException::class)
fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction
fun enclaveVerifyWithSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction
/**
* When we receive an encrypted transaction from another node, before we store it we will want to encrypt it with our long term
@ -106,33 +102,33 @@ interface EnclaveClient {
*
* @return an [EncryptedTransaction] the transaction encrypted with our enclave's long term storage key
*/
fun encryptTransactionForLocal(remoteEncryptedTransaction: EncryptedTransaction): EncryptedTransaction
fun encryptTransactionForLocal(invokeId: UUID, remoteEncryptedTransaction: EncryptedTransaction): EncryptedTransaction
/**
* During backchain resolution, when we send an transaction to another node, we need to encrypt it with a post office related to their
* enclave's remote attestation. This function takes an unencrypted transaction (as a [ConclaveLedgerTxModel]) and returns
* an [EncryptedTransaction] which contains that transaction, but encrypted for the remote enclave.
*
* @param flowIdWithConclaveLedgerTx our local unencrypted transaction wrapped in a [FlowIdAndPayload] class so that the remote
* @param conclaveLedgerTx our local unencrypted transaction wrapped in a [FlowIdAndPayload] class so that the remote
* enclave can identify which cached remote attestation to use.
*
* @return an [EncryptedTransaction] the transaction encrypted according to the remote enclave's remote attestation. Note that we do
* not need our enclave to sign this encrypted transaction, as our signature is only relevant to our own enclave.
*/
fun encryptConclaveLedgerTxForRemote(flowIdWithConclaveLedgerTx: FlowIdAndPayload<ConclaveLedgerTxModel>): EncryptedTransaction
fun encryptConclaveLedgerTxForRemote(invokeId: UUID, conclaveLedgerTx: ConclaveLedgerTxModel): EncryptedTransaction
/**
* During backchain resolution, when we send an transaction to another node, we need to encrypt it with a post office related to their
* enclave's remote attestation. This function takes an encrypted transaction (as a [EncryptedTransaction]) and returns
* an [EncryptedTransaction] which contains that transaction, but encrypted for the remote enclave.
*
* @param flowIdWithLocallyEncryptedTx our local encrypted transaction wrapped in a [FlowIdAndPayload] class so that the remote
* @param locallyEncryptedTx our local encrypted transaction wrapped in a [FlowIdAndPayload] class so that the remote
* enclave can identify which cached remote attestation to use.
*
* @return an [EncryptedTransaction] the transaction re-encrypted according to the remote enclave's remote attestation. Note that we do
* not need our enclave to sign this encrypted transaction, as our signature is only relevant to our own enclave.
*/
fun encryptEncryptedTransactionForRemote(flowIdWithLocallyEncryptedTx: FlowIdAndPayload<EncryptedTransaction>): EncryptedTransaction
fun encryptEncryptedTransactionForRemote(invokeId: UUID, locallyEncryptedTx: EncryptedTransaction): EncryptedTransaction
}
class DummyEnclaveClient: EnclaveClient, SingletonSerializeAsToken() {
@ -141,31 +137,31 @@ class DummyEnclaveClient: EnclaveClient, SingletonSerializeAsToken() {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun registerRemoteEnclaveInstanceInfo(flowIdAndRemoteAttestation: FlowIdAndPayload<ByteArray>) {
override fun registerRemoteEnclaveInstanceInfo(invokeId: UUID, payload: ByteArray) {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
override fun enclaveVerifyWithoutSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies) {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
override fun enclaveVerifyWithSignatures(invokeId: UUID, txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
override fun enclaveVerifyWithSignatures(invokeId: UUID, encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun encryptTransactionForLocal(remoteEncryptedTransaction: EncryptedTransaction): EncryptedTransaction {
override fun encryptTransactionForLocal(invokeId: UUID, remoteEncryptedTransaction: EncryptedTransaction): EncryptedTransaction {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun encryptConclaveLedgerTxForRemote(flowIdWithConclaveLedgerTx: FlowIdAndPayload<ConclaveLedgerTxModel>): EncryptedTransaction {
override fun encryptConclaveLedgerTxForRemote(invokeId: UUID, conclaveLedgerTx: ConclaveLedgerTxModel): EncryptedTransaction {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
override fun encryptEncryptedTransactionForRemote(flowIdWithLocallyEncryptedTx: FlowIdAndPayload<EncryptedTransaction>): EncryptedTransaction {
override fun encryptEncryptedTransactionForRemote(invokeId: UUID, locallyEncryptedTx: EncryptedTransaction): EncryptedTransaction {
throw UnsupportedOperationException("Add your custom enclave client implementation")
}
}

View File

@ -1,29 +1,20 @@
package net.corda.core.conclave.common
/**
* Generic type for an enclave command.
* This type contains no properties or methods and simply instructs the enclave to perform a specific action.
*/
interface EnclaveCommand {
import net.corda.core.serialization.CordaSerializable
/**
* Convert this type to a [String].
* @return serialized [String] of this type.
*/
@CordaSerializable
enum class EnclaveCommand {
InitPostOfficeToRemoteEnclave,
VerifyAndEncryptTransaction,
VerifyTransaction,
EncryptLedgerTransactionForRemote,
EncryptVerifiedTransactionForRemote,
DeserializeTransactionReturnHash;
fun serialize(): String {
return this.javaClass.name
return this.name
}
}
/**
* Deserialize an [EnclaveCommand].
* Convert a serialized string into an [EnclaveCommand] instance.
*/
fun String.toEnclaveCommand(): EnclaveCommand {
return Class.forName(this).newInstance() as EnclaveCommand
return EnclaveCommand.valueOf(this)
}
/**
* An [EnclaveCommand] that instructs the enclave to register a host identity.
*/
class RegisterHostIdentity : EnclaveCommand

View File

@ -0,0 +1,25 @@
package net.corda.core.conclave.common
import net.corda.core.serialization.CordaSerializable
import java.util.*
@CordaSerializable
data class EnclaveMessage(val invocationId: UUID, val command: EnclaveCommand, val message: ByteArray) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as EnclaveMessage
if (invocationId != other.invocationId) return false
if (command != other.command) return false
if (!message.contentEquals(other.message)) return false
return true
}
override fun hashCode(): Int {
var result = command.hashCode()
result = 31 * result + invocationId.hashCode()
result = 31 * result + message.contentHashCode()
return result
}
}

View File

@ -1,9 +0,0 @@
package net.corda.core.conclave.common
/**
* An [EnclaveCommand] that instructs the enclave to initialise a post office to a remote enclave using the serialized
* attestation contained in the mail body (requires an enclave host to be registered).
*/
class InitPostOfficeToRemoteEnclave : EnclaveCommand
class VerifyUnencryptedTx : EnclaveCommand

View File

@ -1,46 +1,53 @@
package net.corda.core.node.services
import co.paralleluniverse.fibers.Fiber
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.internal.FlowStateMachine
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.EncryptedTransaction
import java.util.*
class EncryptedTransactionService(val enclaveClient: EnclaveClient = DummyEnclaveClient()) : SingletonSerializeAsToken() {
fun getEnclaveInstance() : ByteArray {
private fun getCurrentFlowIdOrGenerateNewInvokeId(): UUID {
val currentFiber = Fiber.currentFiber() as? FlowStateMachine<*>
return currentFiber?.id?.uuid ?: UUID.randomUUID()
}
fun getEnclaveInstance(): ByteArray {
return enclaveClient.getEnclaveInstanceInfo()
}
fun registerRemoteEnclaveInstanceInfo(flowId : UUID, remoteAttestation: ByteArray) {
enclaveClient.registerRemoteEnclaveInstanceInfo(FlowIdAndPayload(flowId, remoteAttestation))
fun registerRemoteEnclaveInstanceInfo(flowId: UUID, remoteAttestation: ByteArray) {
enclaveClient.registerRemoteEnclaveInstanceInfo(flowId, remoteAttestation)
}
fun enclaveVerifyWithoutSignatures(txAndDependencies : VerifiableTxAndDependencies) {
return enclaveClient.enclaveVerifyWithoutSignatures(txAndDependencies)
fun enclaveVerifyWithoutSignatures(txAndDependencies: VerifiableTxAndDependencies) {
return enclaveClient.enclaveVerifyWithoutSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), txAndDependencies)
}
fun enclaveVerifyWithSignatures(txAndDependencies : VerifiableTxAndDependencies) : EncryptedTransaction {
return enclaveClient.enclaveVerifyWithSignatures(txAndDependencies)
fun enclaveVerifyWithSignatures(txAndDependencies: VerifiableTxAndDependencies): EncryptedTransaction {
return enclaveClient.enclaveVerifyWithSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), txAndDependencies)
}
fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies) : EncryptedTransaction {
return enclaveClient.enclaveVerifyWithSignatures(encryptedTxAndDependencies)
fun enclaveVerifyWithSignatures(encryptedTxAndDependencies: EncryptedVerifiableTxAndDependencies): EncryptedTransaction {
return enclaveClient.enclaveVerifyWithSignatures(getCurrentFlowIdOrGenerateNewInvokeId(), encryptedTxAndDependencies)
}
fun encryptTransactionForLocal(encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
return enclaveClient.encryptTransactionForLocal(encryptedTransaction)
return enclaveClient.encryptTransactionForLocal(getCurrentFlowIdOrGenerateNewInvokeId(), encryptedTransaction)
}
fun encryptTransactionForRemote(flowId: UUID, conclaveLedgerTxModel: ConclaveLedgerTxModel): EncryptedTransaction {
return enclaveClient.encryptConclaveLedgerTxForRemote(FlowIdAndPayload(flowId,conclaveLedgerTxModel))
return enclaveClient.encryptConclaveLedgerTxForRemote(flowId, conclaveLedgerTxModel)
}
fun encryptTransactionForRemote(flowId: UUID, encryptedTransaction: EncryptedTransaction): EncryptedTransaction {
return enclaveClient.encryptEncryptedTransactionForRemote(FlowIdAndPayload(flowId, encryptedTransaction))
return enclaveClient.encryptEncryptedTransactionForRemote(flowId, encryptedTransaction)
}
}

View File

@ -69,7 +69,7 @@ dependencies {
slowIntegrationTestCompile project(path: ":samples:irs-demo:web", configuration: "demoArtifacts")
testCompile "com.palantir.docker.compose:docker-compose-rule-junit4:$docker_compose_rule_version"
testCompile "org.seleniumhq.selenium:selenium-java:$selenium_version"
testCompile "com.github.detro:ghostdriver:$ghostdriver_version"
// testCompile "com.github.detro:ghostdriver:$ghostdriver_version"
}
bootRepackage {