Store certificate and path with well known identity (#726)

* Construct standard flows using PartyAndCertificate, and add support for launching
flows that are constructed with PartyAndCertificate or just Party.
* Store PartyAndCertificate in network map service
* Expand identity service to store certificates along with all identities.
This commit is contained in:
Ross Nicoll 2017-05-31 14:45:58 +01:00 committed by GitHub
parent 08c91bd611
commit 34eb5a3b70
66 changed files with 379 additions and 249 deletions

View File

@ -3,45 +3,34 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate
/** /**
* Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction. * Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction.
* This is intended for use as a subflow of another flow. * This is intended for use as a subflow of another flow.
*/ */
object TxKeyFlow { object TxKeyFlow {
abstract class AbstractIdentityFlow<out T>(val otherSide: Party): FlowLogic<T>() { abstract class AbstractIdentityFlow<out T>(val otherSide: PartyAndCertificate, val revocationEnabled: Boolean): FlowLogic<T>() {
fun validateIdentity(untrustedIdentity: Pair<X509CertificateHolder, CertPath>): AnonymousIdentity { fun validateIdentity(untrustedIdentity: AnonymousIdentity): AnonymousIdentity {
val (wellKnownCert, certPath) = untrustedIdentity val (certPath, theirCert, txIdentity) = untrustedIdentity
val theirCert = certPath.certificates.last() if (theirCert.subject == otherSide.name) {
// TODO: Don't trust self-signed certificates serviceHub.identityService.registerAnonymousIdentity(txIdentity, otherSide, certPath)
return if (theirCert is X509Certificate) { return AnonymousIdentity(certPath, theirCert, txIdentity)
val certName = X500Name(theirCert.subjectDN.name) } else
if (certName == otherSide.name) { throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${theirCert.subject}")
val anonymousParty = AnonymousParty(theirCert.publicKey)
serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath)
AnonymousIdentity(certPath, X509CertificateHolder(theirCert.encoded), anonymousParty)
} else {
throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found $certName")
}
} else {
throw IllegalStateException("Expected an X.509 certificate but received ${theirCert.javaClass.name}")
}
} }
} }
@StartableByRPC @StartableByRPC
@InitiatingFlow @InitiatingFlow
class Requester(otherSide: Party, class Requester(otherSide: PartyAndCertificate,
val revocationEnabled: Boolean, override val progressTracker: ProgressTracker) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide, false) {
override val progressTracker: ProgressTracker) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide) { constructor(otherSide: PartyAndCertificate) : this(otherSide, tracker())
constructor(otherSide: Party, revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker())
companion object { companion object {
object AWAITING_KEY : ProgressTracker.Step("Awaiting key") object AWAITING_KEY : ProgressTracker.Step("Awaiting key")
@ -52,9 +41,10 @@ object TxKeyFlow {
override fun call(): Map<Party, AnonymousIdentity> { override fun call(): Map<Party, AnonymousIdentity> {
progressTracker.currentStep = AWAITING_KEY progressTracker.currentStep = AWAITING_KEY
val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled)
val theirIdentity = receive<Pair<X509CertificateHolder, CertPath>>(otherSide).unwrap { validateIdentity(it) } val myIdentity = AnonymousIdentity(myIdentityFragment)
send(otherSide, myIdentityFragment) val theirIdentity = receive<AnonymousIdentity>(otherSide).unwrap { validateIdentity(it) }
return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), send(otherSide, myIdentity)
return mapOf(Pair(otherSide, myIdentity),
Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) Pair(serviceHub.myInfo.legalIdentity, theirIdentity))
} }
} }
@ -64,7 +54,7 @@ object TxKeyFlow {
* counterparty and as the result from the flow. * counterparty and as the result from the flow.
*/ */
@InitiatedBy(Requester::class) @InitiatedBy(Requester::class)
class Provider(otherSide: Party) : AbstractIdentityFlow<Unit>(otherSide) { class Provider(otherSide: PartyAndCertificate) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide, false) {
companion object { companion object {
object SENDING_KEY : ProgressTracker.Step("Sending key") object SENDING_KEY : ProgressTracker.Step("Sending key")
} }
@ -72,15 +62,19 @@ object TxKeyFlow {
override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY) override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY)
@Suspendable @Suspendable
override fun call() { override fun call(): Map<Party, AnonymousIdentity> {
val revocationEnabled = false val revocationEnabled = false
progressTracker.currentStep = SENDING_KEY progressTracker.currentStep = SENDING_KEY
val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled)
send(otherSide, myIdentityFragment) val myIdentity = AnonymousIdentity(myIdentityFragment)
receive<Pair<X509CertificateHolder, CertPath>>(otherSide).unwrap { validateIdentity(it) } send(otherSide, myIdentity)
val theirIdentity = receive<AnonymousIdentity>(otherSide).unwrap { validateIdentity(it) }
return mapOf(Pair(otherSide, myIdentity),
Pair(serviceHub.myInfo.legalIdentity, theirIdentity))
} }
} }
@CordaSerializable
data class AnonymousIdentity( data class AnonymousIdentity(
val certPath: CertPath, val certPath: CertPath,
val certificate: X509CertificateHolder, val certificate: X509CertificateHolder,

View File

@ -1,12 +1,9 @@
package net.corda.core.identity package net.corda.core.identity
import net.corda.core.contracts.PartyAndReference
import net.corda.core.serialization.OpaqueBytes
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate
/** /**
* A full party plus the X.509 certificate and path linking the party back to a trust root. * A full party plus the X.509 certificate and path linking the party back to a trust root.

View File

@ -11,6 +11,7 @@ import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StateMachineRunId import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkMapCache
import net.corda.core.node.services.StateMachineTransactionMapping import net.corda.core.node.services.StateMachineTransactionMapping
@ -231,18 +232,18 @@ interface CordaRPCOps : RPCOps {
/** /**
* Returns the [Party] corresponding to the given key, if found. * Returns the [Party] corresponding to the given key, if found.
*/ */
fun partyFromKey(key: PublicKey): Party? fun partyFromKey(key: PublicKey): PartyAndCertificate?
/** /**
* Returns the [Party] with the given name as it's [Party.name] * Returns the [Party] with the given name as it's [Party.name]
*/ */
@Deprecated("Use partyFromX500Name instead") @Deprecated("Use partyFromX500Name instead")
fun partyFromName(name: String): Party? fun partyFromName(name: String): PartyAndCertificate?
/** /**
* Returns the [Party] with the X.500 principal as it's [Party.name] * Returns the [Party] with the X.500 principal as it's [Party.name]
*/ */
fun partyFromX500Name(x500Name: X500Name): Party? fun partyFromX500Name(x500Name: X500Name): PartyAndCertificate?
/** Enumerates the class names of the flows that this node knows about. */ /** Enumerates the class names of the flows that this node knows about. */
fun registeredFlows(): List<String> fun registeredFlows(): List<String>

View File

@ -1,24 +1,28 @@
package net.corda.core.node package net.corda.core.node
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.ServiceType import net.corda.core.node.services.ServiceType
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import java.security.cert.TrustAnchor
import java.security.cert.X509Certificate
/** /**
* Information for an advertised service including the service specific identity information. * Information for an advertised service including the service specific identity information.
* The identity can be used in flows and is distinct from the Node's legalIdentity * The identity can be used in flows and is distinct from the Node's legalIdentity
*/ */
@CordaSerializable @CordaSerializable
data class ServiceEntry(val info: ServiceInfo, val identity: Party) data class ServiceEntry(val info: ServiceInfo, val identity: PartyAndCertificate)
/** /**
* Info about a network node that acts on behalf of some form of contract party. * Info about a network node that acts on behalf of some form of contract party.
*/ */
@CordaSerializable @CordaSerializable
data class NodeInfo(val address: SingleMessageRecipient, data class NodeInfo(val address: SingleMessageRecipient,
val legalIdentity: Party, val legalIdentity: PartyAndCertificate,
val platformVersion: Int, val platformVersion: Int,
var advertisedServices: List<ServiceEntry> = emptyList(), var advertisedServices: List<ServiceEntry> = emptyList(),
val physicalLocation: PhysicalLocation? = null) { val physicalLocation: PhysicalLocation? = null) {
@ -26,6 +30,6 @@ data class NodeInfo(val address: SingleMessageRecipient,
require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" } require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" }
} }
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity val notaryIdentity: PartyAndCertificate get() = advertisedServices.single { it.info.type.isNotary() }.identity
fun serviceIdentities(type: ServiceType): List<Party> = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity } fun serviceIdentities(type: ServiceType): List<Party> = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity }
} }

View File

@ -2,6 +2,7 @@ package net.corda.core.node
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
/** /**
* A service hub to be used by the [CordaPluginRegistry] * A service hub to be used by the [CordaPluginRegistry]
@ -9,5 +10,5 @@ import net.corda.core.identity.Party
interface PluginServiceHub : ServiceHub { interface PluginServiceHub : ServiceHub {
@Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " + @Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " +
"them point to the initiating flow class.", level = DeprecationLevel.ERROR) "them point to the initiating flow class.", level = DeprecationLevel.ERROR)
fun registerFlowInitiator(initiatingFlowClass: Class<out FlowLogic<*>>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit fun registerFlowInitiator(initiatingFlowClass: Class<out FlowLogic<*>>, serviceFlowFactory: (PartyAndCertificate) -> FlowLogic<*>) = Unit
} }

View File

@ -1,15 +1,16 @@
package net.corda.core.node.services package net.corda.core.node.services
import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.PartyAndReference
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509CertificateHolder import java.security.InvalidAlgorithmParameterException
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateNotYetValidException
/** /**
* An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports * An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports
@ -17,21 +18,26 @@ import java.security.cert.X509Certificate
* service would provide. * service would provide.
*/ */
interface IdentityService { interface IdentityService {
fun registerIdentity(party: Party) /**
* Verify and then store a well known identity.
*
* @param party a party representing a legal entity.
* @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing
* certificate chain for the anonymous party.
*/
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
fun registerIdentity(party: PartyAndCertificate)
/** /**
* Verify and then store the certificates proving that an anonymous party's key is owned by the given full * Verify and then store an identity.
* party.
* *
* @param trustedRoot trusted root certificate, typically the R3 master signing certificate. * @param anonymousParty a party representing a legal entity in a transaction.
* @param anonymousParty an anonymised party belonging to the legal entity. * @param path certificate path from the trusted root to the party.
* @param path certificate path from the trusted root to the anonymised party. * @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing
* @throws IllegalArgumentException if the chain does not link the two parties, or if there is already an existing * certificate chain for the anonymous party.
* certificate chain for the anonymous party. Anonymous parties must always resolve to a single owning party.
*/ */
// TODO: Move this into internal identity service once available @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
@Throws(IllegalArgumentException::class) fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath)
fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath)
/** /**
* Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with * Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with
@ -52,10 +58,10 @@ interface IdentityService {
// indefinitely. It may be that in the long term we need to drop or archive very old Party information for space, // indefinitely. It may be that in the long term we need to drop or archive very old Party information for space,
// but for now this is not supported. // but for now this is not supported.
fun partyFromKey(key: PublicKey): Party? fun partyFromKey(key: PublicKey): PartyAndCertificate?
@Deprecated("Use partyFromX500Name") @Deprecated("Use partyFromX500Name")
fun partyFromName(name: String): Party? fun partyFromName(name: String): PartyAndCertificate?
fun partyFromX500Name(principal: X500Name): Party? fun partyFromX500Name(principal: X500Name): PartyAndCertificate?
/** /**
* Resolve the well known identity of a party. If the party passed in is already a well known identity * Resolve the well known identity of a party. If the party passed in is already a well known identity
@ -63,7 +69,7 @@ interface IdentityService {
* *
* @return the well known identity, or null if unknown. * @return the well known identity, or null if unknown.
*/ */
fun partyFromAnonymous(party: AbstractParty): Party? fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate?
/** /**
* Resolve the well known identity of a party. If the party passed in is already a well known identity * Resolve the well known identity of a party. If the party passed in is already a well known identity

View File

@ -10,6 +10,7 @@ import net.corda.core.crypto.keys
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.vault.PageSpecification
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.node.services.vault.Sort import net.corda.core.node.services.vault.Sort
@ -20,6 +21,7 @@ import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.operator.ContentSigner
import rx.Observable import rx.Observable
import java.io.InputStream import java.io.InputStream
import java.security.PublicKey import java.security.PublicKey
@ -399,7 +401,7 @@ interface KeyManagementService {
* @return X.509 certificate and path to the trust root. * @return X.509 certificate and path to the trust root.
*/ */
@Suspendable @Suspendable
fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath>
/** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data. /** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data.
* @param bytes The data to sign over using the chosen key. * @param bytes The data to sign over using the chosen key.

View File

@ -10,6 +10,7 @@ import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
@ -119,7 +120,7 @@ abstract class AbstractStateReplacementFlow {
// Type parameter should ideally be Unit but that prevents Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). // Type parameter should ideally be Unit but that prevents Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964).
// We use Void? instead of Unit? as that's what you'd use in Java. // We use Void? instead of Unit? as that's what you'd use in Java.
abstract class Acceptor<in T>(val otherSide: Party, abstract class Acceptor<in T>(val otherSide: PartyAndCertificate,
override val progressTracker: ProgressTracker = tracker()) : FlowLogic<Void?>() { override val progressTracker: ProgressTracker = tracker()) : FlowLogic<Void?>() {
companion object { companion object {
object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal") object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal")

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.toBase58String
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
@ -173,7 +174,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction,
* *
* @param otherParty The counter-party which is providing you a transaction to sign. * @param otherParty The counter-party which is providing you a transaction to sign.
*/ */
abstract class SignTransactionFlow(val otherParty: Party, abstract class SignTransactionFlow(val otherParty: PartyAndCertificate,
override val progressTracker: ProgressTracker = tracker()) : FlowLogic<SignedTransaction>() { override val progressTracker: ProgressTracker = tracker()) : FlowLogic<SignedTransaction>() {
companion object { companion object {

View File

@ -5,7 +5,7 @@ import net.corda.core.contracts.Attachment
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256 import net.corda.core.crypto.sha256
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.SerializationToken import net.corda.core.serialization.SerializationToken
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SerializeAsTokenContext import net.corda.core.serialization.SerializeAsTokenContext
@ -16,7 +16,7 @@ import net.corda.core.serialization.SerializeAsTokenContext
*/ */
@InitiatingFlow @InitiatingFlow
class FetchAttachmentsFlow(requests: Set<SecureHash>, class FetchAttachmentsFlow(requests: Set<SecureHash>,
otherSide: Party) : FetchDataFlow<Attachment, ByteArray>(requests, otherSide) { otherSide: PartyAndCertificate) : FetchDataFlow<Attachment, ByteArray>(requests, otherSide) {
override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid) override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid)

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
@ -31,7 +32,7 @@ import java.util.*
*/ */
abstract class FetchDataFlow<T : NamedByHash, in W : Any>( abstract class FetchDataFlow<T : NamedByHash, in W : Any>(
protected val requests: Set<SecureHash>, protected val requests: Set<SecureHash>,
protected val otherSide: Party) : FlowLogic<FetchDataFlow.Result<T>>() { protected val otherSide: PartyAndCertificate) : FlowLogic<FetchDataFlow.Result<T>>() {
@CordaSerializable @CordaSerializable
class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException() class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException()

View File

@ -2,7 +2,7 @@ package net.corda.flows
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
/** /**
@ -14,7 +14,7 @@ import net.corda.core.transactions.SignedTransaction
* the database, because it's up to the caller to actually verify the transactions are valid. * the database, because it's up to the caller to actually verify the transactions are valid.
*/ */
@InitiatingFlow @InitiatingFlow
class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: Party) : class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: PartyAndCertificate) :
FetchDataFlow<SignedTransaction, SignedTransaction>(requests, otherSide) { FetchDataFlow<SignedTransaction, SignedTransaction>(requests, otherSide) {
override fun load(txid: SecureHash): SignedTransaction? { override fun load(txid: SecureHash): SignedTransaction? {

View File

@ -4,6 +4,7 @@ import net.corda.core.contracts.*
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
@ -21,7 +22,7 @@ import java.security.PublicKey
@InitiatingFlow @InitiatingFlow
class NotaryChangeFlow<out T : ContractState>( class NotaryChangeFlow<out T : ContractState>(
originalState: StateAndRef<T>, originalState: StateAndRef<T>,
newNotary: Party, newNotary: PartyAndCertificate,
progressTracker: ProgressTracker = tracker()) progressTracker: ProgressTracker = tracker())
: AbstractStateReplacementFlow.Instigator<T, T, Party>(originalState, newNotary, progressTracker) { : AbstractStateReplacementFlow.Instigator<T, T, Party>(originalState, newNotary, progressTracker) {

View File

@ -11,6 +11,7 @@ import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessException
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
@ -96,7 +97,7 @@ object NotaryFlow {
* Additional transaction validation logic can be added when implementing [receiveAndVerifyTx]. * Additional transaction validation logic can be added when implementing [receiveAndVerifyTx].
*/ */
// See AbstractStateReplacementFlow.Acceptor for why it's Void? // See AbstractStateReplacementFlow.Acceptor for why it's Void?
abstract class Service(val otherSide: Party, abstract class Service(val otherSide: PartyAndCertificate,
val timeWindowChecker: TimeWindowChecker, val timeWindowChecker: TimeWindowChecker,
val uniquenessProvider: UniquenessProvider) : FlowLogic<Void?>() { val uniquenessProvider: UniquenessProvider) : FlowLogic<Void?>() {
@Suspendable @Suspendable

View File

@ -5,7 +5,7 @@ import net.corda.core.checkedAdd
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.getOrThrow import net.corda.core.getOrThrow
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
@ -30,7 +30,7 @@ import java.util.*
* The flow returns a list of verified [LedgerTransaction] objects, in a depth-first order. * The flow returns a list of verified [LedgerTransaction] objects, in a depth-first order.
*/ */
class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>, class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>,
private val otherSide: Party) : FlowLogic<List<LedgerTransaction>>() { private val otherSide: PartyAndCertificate) : FlowLogic<List<LedgerTransaction>>() {
companion object { companion object {
private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet() private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet()
@ -82,14 +82,14 @@ class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>,
/** /**
* Resolve the full history of a transaction and verify it with its dependencies. * Resolve the full history of a transaction and verify it with its dependencies.
*/ */
constructor(stx: SignedTransaction, otherSide: Party) : this(stx.tx, otherSide) { constructor(stx: SignedTransaction, otherSide: PartyAndCertificate) : this(stx.tx, otherSide) {
this.stx = stx this.stx = stx
} }
/** /**
* Resolve the full history of a transaction and verify it with its dependencies. * Resolve the full history of a transaction and verify it with its dependencies.
*/ */
constructor(wtx: WireTransaction, otherSide: Party) : this(dependencyIDs(wtx), otherSide) { constructor(wtx: WireTransaction, otherSide: PartyAndCertificate) : this(dependencyIDs(wtx), otherSide) {
this.wtx = wtx this.wtx = wtx
} }

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.ServiceType import net.corda.core.node.services.ServiceType
import net.corda.core.seconds import net.corda.core.seconds
@ -45,7 +46,7 @@ object TwoPartyDealFlow {
abstract val payload: Any abstract val payload: Any
abstract val notaryNode: NodeInfo abstract val notaryNode: NodeInfo
abstract val otherParty: Party abstract val otherParty: PartyAndCertificate
abstract val myKey: PublicKey abstract val myKey: PublicKey
@Suspendable override fun call(): SignedTransaction { @Suspendable override fun call(): SignedTransaction {
@ -149,7 +150,7 @@ object TwoPartyDealFlow {
/** /**
* One side of the flow for inserting a pre-agreed deal. * One side of the flow for inserting a pre-agreed deal.
*/ */
open class Instigator(override val otherParty: Party, open class Instigator(override val otherParty: PartyAndCertificate,
override val payload: AutoOffer, override val payload: AutoOffer,
override val myKey: PublicKey, override val myKey: PublicKey,
override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() { override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() {

View File

@ -7,6 +7,7 @@ import net.corda.core.contracts.TransactionType
import net.corda.core.contracts.requireThat import net.corda.core.contracts.requireThat
import net.corda.core.getOrThrow import net.corda.core.getOrThrow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.flows.CollectSignaturesFlow import net.corda.flows.CollectSignaturesFlow
@ -54,7 +55,7 @@ class CollectSignaturesFlowTests {
// "collectSignaturesFlow" and "SignTransactionFlow" can be used in practise. // "collectSignaturesFlow" and "SignTransactionFlow" can be used in practise.
object TestFlow { object TestFlow {
@InitiatingFlow @InitiatingFlow
class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: Party) : FlowLogic<SignedTransaction>() { class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
@Suspendable @Suspendable
override fun call(): SignedTransaction { override fun call(): SignedTransaction {
send(otherParty, state) send(otherParty, state)
@ -114,7 +115,7 @@ class CollectSignaturesFlowTests {
} }
@InitiatedBy(TestFlowTwo.Initiator::class) @InitiatedBy(TestFlowTwo.Initiator::class)
class Responder(val otherParty: Party) : FlowLogic<SignedTransaction>() { class Responder(val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
@Suspendable override fun call(): SignedTransaction { @Suspendable override fun call(): SignedTransaction {
val flow = object : SignTransactionFlow(otherParty) { val flow = object : SignTransactionFlow(otherParty) {
@Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat { @Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat {

View File

@ -3,6 +3,7 @@ package net.corda.core.flows
import net.corda.core.getOrThrow import net.corda.core.getOrThrow
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.utilities.ALICE import net.corda.core.utilities.ALICE
import net.corda.core.utilities.BOB import net.corda.core.utilities.BOB
import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY
@ -26,12 +27,11 @@ class TxKeyFlowTests {
net = MockNetwork(false, true) net = MockNetwork(false, true)
// Set up values we'll need // Set up values we'll need
val revocationEnabled = false
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
val alice: Party = aliceNode.services.myInfo.legalIdentity val alice: PartyAndCertificate = aliceNode.services.myInfo.legalIdentity
val bob: Party = bobNode.services.myInfo.legalIdentity val bob: PartyAndCertificate = bobNode.services.myInfo.legalIdentity
aliceNode.services.identityService.registerIdentity(bob) aliceNode.services.identityService.registerIdentity(bob)
aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity)
bobNode.services.identityService.registerIdentity(alice) bobNode.services.identityService.registerIdentity(alice)
@ -39,7 +39,7 @@ class TxKeyFlowTests {
// Run the flows // Run the flows
bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java) bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java)
val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob, revocationEnabled)) val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob))
// Get the results // Get the results
val actual: Map<Party, TxKeyFlow.AnonymousIdentity> = requesterFlow.resultFuture.getOrThrow() val actual: Map<Party, TxKeyFlow.AnonymousIdentity> = requesterFlow.resultFuture.getOrThrow()

View File

@ -7,6 +7,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.getOrThrow import net.corda.core.getOrThrow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
@ -139,7 +140,7 @@ class AttachmentSerializationTest {
private fun launchFlow(clientLogic: ClientLogic, rounds: Int) { private fun launchFlow(clientLogic: ClientLogic, rounds: Int) {
server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory<ServerLogic> { server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory<ServerLogic> {
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): ServerLogic { override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): ServerLogic {
return ServerLogic(otherParty) return ServerLogic(otherParty)
} }
}, ServerLogic::class.java, track = false) }, ServerLogic::class.java, track = false)

View File

@ -43,9 +43,18 @@ UNRELEASED
* There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces * There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces
use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on
use-case. use-case.
* A new ``PartyAndCertificate`` class has been added which contains an X.509 certificate and certificate path back
to a network trust root. This is widely used in place of ``Party`` inside Corda, with the exception of a few cases
where proof of identity is not required.
* Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the
name. As a result all node legal names must now be structured as X.500 distinguished names. name. As a result all node legal names must now be structured as X.500 distinguished names.
* Flows can now accept ``PartyAndCertificate`` instead of ``Party`` in their constructor, which should be the default for
new flows. The sample flows have been updated to use ``PartyAndCertificate`` to illustrate this.
* The identity management service takes an optional network trust root which it will validate certificate paths to, if
provided. A later release will make this a required parameter.
* There are major changes to transaction signing in flows: * There are major changes to transaction signing in flows:
* You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most * You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most

View File

@ -12,6 +12,8 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.PluginServiceHub
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.node.services.unconsumedStates import net.corda.core.node.services.unconsumedStates
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
@ -24,8 +26,8 @@ import java.util.*
@CordaSerializable @CordaSerializable
private data class FxRequest(val tradeId: String, private data class FxRequest(val tradeId: String,
val amount: Amount<Issued<Currency>>, val amount: Amount<Issued<Currency>>,
val owner: Party, val owner: PartyAndCertificate,
val counterparty: Party, val counterparty: PartyAndCertificate,
val notary: Party? = null) val notary: Party? = null)
@CordaSerializable @CordaSerializable
@ -101,8 +103,8 @@ private fun prepareOurInputsAndOutputs(serviceHub: ServiceHub, request: FxReques
class ForeignExchangeFlow(val tradeId: String, class ForeignExchangeFlow(val tradeId: String,
val baseCurrencyAmount: Amount<Issued<Currency>>, val baseCurrencyAmount: Amount<Issued<Currency>>,
val quoteCurrencyAmount: Amount<Issued<Currency>>, val quoteCurrencyAmount: Amount<Issued<Currency>>,
val baseCurrencyBuyer: Party, val baseCurrencyBuyer: PartyAndCertificate,
val baseCurrencySeller: Party) : FlowLogic<SecureHash>() { val baseCurrencySeller: PartyAndCertificate) : FlowLogic<SecureHash>() {
@Suspendable @Suspendable
override fun call(): SecureHash { override fun call(): SecureHash {
// Select correct sides of the Fx exchange to query for. // Select correct sides of the Fx exchange to query for.
@ -206,7 +208,7 @@ class ForeignExchangeFlow(val tradeId: String,
} }
@InitiatedBy(ForeignExchangeFlow::class) @InitiatedBy(ForeignExchangeFlow::class)
class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() { class ForeignExchangeRemoteFlow(val source: PartyAndCertificate) : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
// Initial receive from remote party // Initial receive from remote party

View File

@ -7,7 +7,7 @@ import net.corda.core.crypto.DigitalSignature
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.seconds import net.corda.core.seconds
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
@ -61,7 +61,7 @@ object TwoPartyTradeFlow {
data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey,
val notarySig: DigitalSignature.WithKey) val notarySig: DigitalSignature.WithKey)
open class Seller(val otherParty: Party, open class Seller(val otherParty: PartyAndCertificate,
val notaryNode: NodeInfo, val notaryNode: NodeInfo,
val assetToSell: StateAndRef<OwnableState>, val assetToSell: StateAndRef<OwnableState>,
val price: Amount<Currency>, val price: Amount<Currency>,
@ -141,8 +141,8 @@ object TwoPartyTradeFlow {
} }
} }
open class Buyer(val otherParty: Party, open class Buyer(val otherParty: PartyAndCertificate,
val notary: Party, val notary: PartyAndCertificate,
val acceptablePrice: Amount<Currency>, val acceptablePrice: Amount<Currency>,
val typeToBuy: Class<out OwnableState>) : FlowLogic<SignedTransaction>() { val typeToBuy: Class<out OwnableState>) : FlowLogic<SignedTransaction>() {
// DOCSTART 2 // DOCSTART 2

View File

@ -1,6 +1,7 @@
package net.corda.flows; package net.corda.flows;
import net.corda.core.identity.Party; import net.corda.core.identity.Party;
import net.corda.core.identity.PartyAndCertificate;
import net.corda.core.utilities.*; import net.corda.core.utilities.*;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
@ -9,7 +10,7 @@ public class AbstractStateReplacementFlowTest {
// Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). // Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964).
private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor { private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor {
public TestAcceptorCanBeInheritedInJava(@NotNull Party otherSide, @NotNull ProgressTracker progressTracker) { public TestAcceptorCanBeInheritedInJava(@NotNull PartyAndCertificate otherSide, @NotNull ProgressTracker progressTracker) {
super(otherSide, progressTracker); super(otherSide, progressTracker);
} }

View File

@ -24,6 +24,7 @@ import net.corda.testing.node.SimpleNode
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509CertificateHolder
import org.junit.Test import org.junit.Test
import java.time.Instant import java.time.Instant
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
@ -56,17 +57,19 @@ class P2PSecurityTest : NodeBasedTest() {
} }
} }
private fun startSimpleNode(legalName: X500Name): SimpleNode { private fun startSimpleNode(legalName: X500Name,
trustRoot: X509CertificateHolder? = null): SimpleNode {
val config = TestNodeConfiguration( val config = TestNodeConfiguration(
baseDirectory = baseDirectory(legalName), baseDirectory = baseDirectory(legalName),
myLegalName = legalName, myLegalName = legalName,
networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name)) networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name))
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
return SimpleNode(config).apply { start() } return SimpleNode(config, trustRoot = trustRoot).apply { start() }
} }
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> { private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> {
val nodeInfo = NodeInfo(net.myAddress, getTestPartyAndCertificate(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion) val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public)
val nodeInfo = NodeInfo(net.myAddress, legalIdentity, MOCK_VERSION_INFO.platformVersion)
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX) val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress) val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress)
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress) return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)

View File

@ -14,6 +14,9 @@ import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.appendToCommonName import net.corda.core.crypto.appendToCommonName
import net.corda.core.crypto.commonName import net.corda.core.crypto.commonName
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.ShutdownHook
import net.corda.core.internal.addShutdownHook
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
@ -28,8 +31,6 @@ import net.corda.nodeapi.ArtemisMessagingComponent
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.nodeapi.config.SSLConfiguration import net.corda.nodeapi.config.SSLConfiguration
import net.corda.nodeapi.config.parseAs import net.corda.nodeapi.config.parseAs
import net.corda.core.internal.ShutdownHook
import net.corda.core.internal.addShutdownHook
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
@ -96,7 +97,7 @@ interface DriverDSLExposedInterface : CordformContext {
clusterSize: Int = 3, clusterSize: Int = 3,
type: ServiceType = RaftValidatingNotaryService.type, type: ServiceType = RaftValidatingNotaryService.type,
verifierType: VerifierType = VerifierType.InMemory, verifierType: VerifierType = VerifierType.InMemory,
rpcUsers: List<User> = emptyList()): Future<Pair<Party, List<NodeHandle>>> rpcUsers: List<User> = emptyList()): Future<Pair<PartyAndCertificate, List<NodeHandle>>>
/** /**
* Starts a web server for a node * Starts a web server for a node
@ -553,7 +554,7 @@ class DriverDSL(
type: ServiceType, type: ServiceType,
verifierType: VerifierType, verifierType: VerifierType,
rpcUsers: List<User> rpcUsers: List<User>
): ListenableFuture<Pair<Party, List<NodeHandle>>> { ): ListenableFuture<Pair<PartyAndCertificate, List<NodeHandle>>> {
val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") } val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") }
val paths = nodeNames.map { baseDirectory(it) } val paths = nodeNames.map { baseDirectory(it) }
ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName) ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName)

View File

@ -71,6 +71,7 @@ import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.security.KeyPair import java.security.KeyPair
import java.security.KeyStoreException import java.security.KeyStoreException
import java.security.cert.X509Certificate
import java.time.Clock import java.time.Clock
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -346,7 +347,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
} }
private fun <F : FlowLogic<*>> registerInitiatedFlowInternal(initiatedFlow: Class<F>, track: Boolean): Observable<F> { private fun <F : FlowLogic<*>> registerInitiatedFlowInternal(initiatedFlow: Class<F>, track: Boolean): Observable<F> {
val ctor = initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } val ctor = try {
initiatedFlow.getDeclaredConstructor(PartyAndCertificate::class.java).apply { isAccessible = true }
} catch(ex: NoSuchMethodException) {
// Fall back to a constructor that takes in a Party
// TODO: Consider removing for 1.0 release, as flows should generally take the more detailed class
initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true }
}
val initiatingFlow = initiatedFlow.requireAnnotation<InitiatedBy>().value.java val initiatingFlow = initiatedFlow.requireAnnotation<InitiatedBy>().value.java
val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass
require(classWithAnnotation == initiatingFlow) { require(classWithAnnotation == initiatingFlow) {
@ -394,7 +401,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
* @suppress * @suppress
*/ */
@VisibleForTesting @VisibleForTesting
fun installCoreFlow(clientFlowClass: KClass<out FlowLogic<*>>, flowFactory: (Party, Int) -> FlowLogic<*>) { fun installCoreFlow(clientFlowClass: KClass<out FlowLogic<*>>, flowFactory: (PartyAndCertificate, Int) -> FlowLogic<*>) {
require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) { require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) {
"${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version" "${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version"
} }
@ -656,7 +663,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
protected abstract fun makeUniquenessProvider(type: ServiceType): UniquenessProvider protected abstract fun makeUniquenessProvider(type: ServiceType): UniquenessProvider
protected open fun makeIdentityService(): IdentityService { protected open fun makeIdentityService(): IdentityService {
val service = InMemoryIdentityService() val keyStore = KeyStoreUtilities.loadKeyStore(configuration.trustStoreFile, configuration.trustStorePassword)
val trustRoot = keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA) as? X509Certificate
val service = InMemoryIdentityService(trustRoot = trustRoot)
service.registerIdentity(info.legalIdentity) service.registerIdentity(info.legalIdentity)
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) } services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) }
netMapCache.changed.subscribe { mapChange -> netMapCache.changed.subscribe { mapChange ->

View File

@ -2,19 +2,20 @@ package net.corda.node.internal
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.node.services.statemachine.SessionInit import net.corda.node.services.statemachine.SessionInit
interface InitiatedFlowFactory<out F : FlowLogic<*>> { interface InitiatedFlowFactory<out F : FlowLogic<*>> {
fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F
data class Core<out F : FlowLogic<*>>(val factory: (Party, Int) -> F) : InitiatedFlowFactory<F> { data class Core<out F : FlowLogic<*>>(val factory: (PartyAndCertificate, Int) -> F) : InitiatedFlowFactory<F> {
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F {
return factory(otherParty, platformVersion) return factory(otherParty, platformVersion)
} }
} }
data class CorDapp<out F : FlowLogic<*>>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory<F> { data class CorDapp<out F : FlowLogic<*>>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory<F> {
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F {
// TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders // TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders
if (sessionInit.flowVerison == version) return factory(otherParty) if (sessionInit.flowVerison == version) return factory(otherParty)
throw SessionRejectException( throw SessionRejectException(

View File

@ -5,10 +5,11 @@ import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionType import net.corda.core.contracts.TransactionType
import net.corda.core.contracts.UpgradedContract import net.corda.core.contracts.UpgradedContract
import net.corda.core.contracts.requireThat import net.corda.core.contracts.requireThat
import net.corda.core.identity.Party
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.flows.* import net.corda.flows.*
@ -25,20 +26,20 @@ import net.corda.flows.*
* *
* Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null. * Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null.
*/ */
class FetchTransactionsHandler(otherParty: Party) : FetchDataHandler<SignedTransaction>(otherParty) { class FetchTransactionsHandler(otherParty: PartyAndCertificate) : FetchDataHandler<SignedTransaction>(otherParty) {
override fun getData(id: SecureHash): SignedTransaction? { override fun getData(id: SecureHash): SignedTransaction? {
return serviceHub.storageService.validatedTransactions.getTransaction(id) return serviceHub.storageService.validatedTransactions.getTransaction(id)
} }
} }
// TODO: Use Artemis message streaming support here, called "large messages". This avoids the need to buffer. // TODO: Use Artemis message streaming support here, called "large messages". This avoids the need to buffer.
class FetchAttachmentsHandler(otherParty: Party) : FetchDataHandler<ByteArray>(otherParty) { class FetchAttachmentsHandler(otherParty: PartyAndCertificate) : FetchDataHandler<ByteArray>(otherParty) {
override fun getData(id: SecureHash): ByteArray? { override fun getData(id: SecureHash): ByteArray? {
return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes() return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes()
} }
} }
abstract class FetchDataHandler<out T>(val otherParty: Party) : FlowLogic<Unit>() { abstract class FetchDataHandler<out T>(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
@Suspendable @Suspendable
@Throws(FetchDataFlow.HashNotFound::class) @Throws(FetchDataFlow.HashNotFound::class)
override fun call() { override fun call() {
@ -59,7 +60,7 @@ abstract class FetchDataHandler<out T>(val otherParty: Party) : FlowLogic<Unit>(
// includes us in any outside that list. Potentially just if it includes any outside that list at all. // includes us in any outside that list. Potentially just if it includes any outside that list at all.
// TODO: Do we want to be able to reject specific transactions on more complex rules, for example reject incoming // TODO: Do we want to be able to reject specific transactions on more complex rules, for example reject incoming
// cash without from unknown parties? // cash without from unknown parties?
class NotifyTransactionHandler(val otherParty: Party) : FlowLogic<Unit>() { class NotifyTransactionHandler(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
val request = receive<BroadcastTransactionFlow.NotifyTxRequest>(otherParty).unwrap { it } val request = receive<BroadcastTransactionFlow.NotifyTxRequest>(otherParty).unwrap { it }
@ -68,7 +69,7 @@ class NotifyTransactionHandler(val otherParty: Party) : FlowLogic<Unit>() {
} }
} }
class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor<Party>(otherSide) { class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<PartyAndCertificate>(otherSide) {
/** /**
* Check the notary change proposal. * Check the notary change proposal.
* *
@ -76,7 +77,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep
* and is also in a geographically convenient location we can just automatically approve the change. * and is also in a geographically convenient location we can just automatically approve the change.
* TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal * TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal
*/ */
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<Party>): Unit { override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<PartyAndCertificate>): Unit {
val state = proposal.stateRef val state = proposal.stateRef
val proposedTx = proposal.stx.tx val proposedTx = proposal.stx.tx
@ -101,7 +102,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep
} }
} }
class ContractUpgradeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor<Class<out UpgradedContract<ContractState, *>>>(otherSide) { class ContractUpgradeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<Class<out UpgradedContract<ContractState, *>>>(otherSide) {
@Suspendable @Suspendable
@Throws(StateReplacementException::class) @Throws(StateReplacementException::class)
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<Class<out UpgradedContract<ContractState, *>>>) { override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<Class<out UpgradedContract<ContractState, *>>>) {

View File

@ -2,10 +2,12 @@ package net.corda.node.services.identity
import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.PartyAndReference
import net.corda.core.contracts.requireThat import net.corda.core.contracts.requireThat
import net.corda.core.crypto.subject
import net.corda.core.crypto.toStringShort import net.corda.core.crypto.toStringShort
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
@ -27,15 +29,20 @@ import javax.annotation.concurrent.ThreadSafe
* @param certPaths initial set of certificate paths for the service, typically only used for unit tests. * @param certPaths initial set of certificate paths for the service, typically only used for unit tests.
*/ */
@ThreadSafe @ThreadSafe
class InMemoryIdentityService(identities: Iterable<Party> = emptySet(), class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
certPaths: Map<AnonymousParty, CertPath> = emptyMap()) : SingletonSerializeAsToken(), IdentityService { certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
val trustRoot: X509Certificate?) : SingletonSerializeAsToken(), IdentityService {
constructor(identities: Iterable<PartyAndCertificate> = emptySet(),
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
trustRoot: X509CertificateHolder?) : this(identities, certPaths, trustRoot?.let { JcaX509CertificateConverter().getCertificate(it) })
companion object { companion object {
private val log = loggerFor<InMemoryIdentityService>() private val log = loggerFor<InMemoryIdentityService>()
} }
private val keyToParties = ConcurrentHashMap<PublicKey, Party>() private val trustAnchor: TrustAnchor? = trustRoot?.let { cert -> TrustAnchor(cert, null) }
private val principalToParties = ConcurrentHashMap<X500Name, Party>() private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
private val partyToPath = ConcurrentHashMap<AnonymousParty, CertPath>() private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
private val partyToPath = ConcurrentHashMap<AbstractParty, CertPath>()
init { init {
keyToParties.putAll(identities.associateBy { it.owningKey } ) keyToParties.putAll(identities.associateBy { it.owningKey } )
@ -43,8 +50,29 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
partyToPath.putAll(certPaths) partyToPath.putAll(certPaths)
} }
override fun registerIdentity(party: Party) { // TODO: Check the validation logic
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
override fun registerIdentity(party: PartyAndCertificate) {
require(party.certPath.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
// Validate the chain first, before we do anything clever with it
val validatorParameters = if (trustAnchor != null) {
PKIXParameters(setOf(trustAnchor))
} else {
// TODO: We should always require a full chain back to a trust anchor, but until we have a network
// trust anchor everywhere, this will have to do.
val converter = JcaX509CertificateConverter()
PKIXParameters(setOf(TrustAnchor(converter.getCertificate(party.certificate), null)))
}
val validator = CertPathValidator.getInstance("PKIX")
validatorParameters.isRevocationEnabled = false
// TODO: val result = validator.validate(party.certPath, validatorParameters) as PKIXCertPathValidatorResult
// require(trustAnchor == null || result.trustAnchor == trustAnchor)
// require(result.publicKey == party.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" }
log.trace { "Registering identity $party" } log.trace { "Registering identity $party" }
require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" }
partyToPath[party] = party.certPath
keyToParties[party.owningKey] = party keyToParties[party.owningKey] = party
principalToParties[party.name] = party principalToParties[party.name] = party
} }
@ -52,12 +80,12 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
// We give the caller a copy of the data set to avoid any locking problems // We give the caller a copy of the data set to avoid any locking problems
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values) override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key] override fun partyFromKey(key: PublicKey): PartyAndCertificate? = keyToParties[key]
@Deprecated("Use partyFromX500Name") @Deprecated("Use partyFromX500Name")
override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)] override fun partyFromName(name: String): PartyAndCertificate? = principalToParties[X500Name(name)]
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal] override fun partyFromX500Name(principal: X500Name): PartyAndCertificate? = principalToParties[principal]
override fun partyFromAnonymous(party: AbstractParty): Party? { override fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? {
return if (party is Party) { return if (party is PartyAndCertificate) {
party party
} else { } else {
partyFromKey(party.owningKey) partyFromKey(party.owningKey)
@ -84,20 +112,29 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty] override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty]
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
override fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) { override fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) {
val converter = JcaX509CertificateConverter()
val expectedTrustAnchor = TrustAnchor(converter.getCertificate(trustedRoot), null)
require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
val target = path.certificates.last() as X509Certificate // Validate the chain first, before we do anything clever with it
require(target.publicKey == anonymousParty.owningKey) { "Certificate path must end with anonymous party's public key" }
val validator = CertPathValidator.getInstance("PKIX") val validator = CertPathValidator.getInstance("PKIX")
val validatorParameters = PKIXParameters(setOf(expectedTrustAnchor)).apply { val validatorParameters = if (trustAnchor != null) {
isRevocationEnabled = false PKIXParameters(setOf(trustAnchor))
} else {
// TODO: We should always require a full chain back to a trust anchor, but until we have a network
// trust anchor everywhere, this will have to do.
val converter = JcaX509CertificateConverter()
PKIXParameters(setOf(TrustAnchor(converter.getCertificate(fullParty.certificate), null)))
} }
validatorParameters.isRevocationEnabled = false
val result = validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult val result = validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult
require(result.trustAnchor == expectedTrustAnchor) val subjectCertificate = path.certificates.first()
require(result.publicKey == anonymousParty.owningKey) require(trustAnchor == null || result.trustAnchor == trustAnchor)
require(result.publicKey == anonymousParty.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" }
require(subjectCertificate is X509Certificate && subjectCertificate.subject == fullParty.name) { "Subject of the transaction certificate must match the well known identity" }
log.trace { "Registering identity $fullParty" }
partyToPath[anonymousParty] = path partyToPath[anonymousParty] = path
keyToParties[anonymousParty.owningKey] = fullParty
principalToParties[fullParty.name] = fullParty
} }
} }

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.keys import net.corda.core.crypto.keys
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
@ -57,7 +58,11 @@ class E2ETestKeyManagementService(val identityService: IdentityService,
return keyPair.public return keyPair.public
} }
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> = freshKeyAndCert(this, identityService, identity, revocationEnabled) override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
}
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
return mutex.locked { return mutex.locked {

View File

@ -5,38 +5,49 @@ import net.corda.core.crypto.ContentSignerBuilder
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.X509Utilities
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.operator.ContentSigner import org.bouncycastle.operator.ContentSigner
import java.security.KeyPair import java.security.KeyPair
import java.security.PublicKey
import java.security.Security import java.security.Security
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.time.Duration
import java.util.*
/** /**
* Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding * Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding
* [X509Certificate] and adds it to the identity service. * [X509Certificate] and adds it to the identity service.
* *
* @param keyManagementService key service to use when generating the new key. * @param subjectPublicKey public key of new identity.
* @param identityService identity service to use when registering the certificate. * @param issuerSigner a content signer for the issuer.
* @param identity identity to generate a key and certificate for. Must be an identity this node has CA privileges for. * @param identityService issuer service to use when registering the certificate.
* @param issuer issuer to generate a key and certificate for. Must be an identity this node has the private key for.
* @param revocationEnabled whether to check revocation status of certificates in the certificate path. * @param revocationEnabled whether to check revocation status of certificates in the certificate path.
* @return X.509 certificate and path to the trust root. * @return X.509 certificate and path to the trust root.
*/ */
fun freshKeyAndCert(keyManagementService: KeyManagementService, fun freshCertificate(identityService: IdentityService,
identityService: IdentityService, subjectPublicKey: PublicKey,
identity: Party, issuer: PartyAndCertificate,
issuerSigner: ContentSigner,
revocationEnabled: Boolean = false): Pair<X509CertificateHolder, CertPath> { revocationEnabled: Boolean = false): Pair<X509CertificateHolder, CertPath> {
val ourPublicKey = keyManagementService.freshKey() val issuerCertificate = issuer.certificate
// FIXME: Use the actual certificate for the identity the flow is presenting themselves as val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, Duration.ofDays(10 * 365), issuerCertificate)
val issuerKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME) val ourCertificate = Crypto.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window)
val issuerCertificate = X509Utilities.createSelfSignedCACertificate(identity.name, issuerKey) val actualPublicKey = Crypto.toSupportedPublicKey(ourCertificate.subjectPublicKeyInfo)
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate, issuerKey, identity.name, ourPublicKey) require(subjectPublicKey == actualPublicKey)
val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled) val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled)
identityService.registerPath(issuerCertificate, require(Arrays.equals(ourCertificate.subjectPublicKeyInfo.encoded, subjectPublicKey.encoded))
AnonymousParty(ourPublicKey), identityService.registerAnonymousIdentity(AnonymousParty(subjectPublicKey),
issuer,
ourCertPath) ourCertPath)
return Pair(issuerCertificate, ourCertPath) return Pair(issuerCertificate, ourCertPath)
} }
fun getSigner(issuerKeyPair: KeyPair): ContentSigner {
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
val provider = Security.getProvider(signatureScheme.providerName)
return ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
}

View File

@ -5,7 +5,7 @@ import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.keys import net.corda.core.crypto.keys
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
@ -67,7 +67,12 @@ class PersistentKeyManagementService(val identityService: IdentityService,
} }
return keyPair.public return keyPair.public
} }
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> = freshKeyAndCert(this, identityService, identity, revocationEnabled)
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
}
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
return mutex.locked { return mutex.locked {

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.SignedData import net.corda.core.crypto.SignedData
import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.MessageRecipients
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
@ -116,7 +117,7 @@ interface NetworkMapService {
class InMemoryNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int) class InMemoryNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int)
: AbstractNetworkMapService(services, minimumPlatformVersion) { : AbstractNetworkMapService(services, minimumPlatformVersion) {
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = ConcurrentHashMap() override val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo> = ConcurrentHashMap()
override val subscribers = ThreadBox(mutableMapOf<SingleMessageRecipient, LastAcknowledgeInfo>()) override val subscribers = ThreadBox(mutableMapOf<SingleMessageRecipient, LastAcknowledgeInfo>())
init { init {
@ -142,7 +143,7 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal,
private val logger = loggerFor<AbstractNetworkMapService>() private val logger = loggerFor<AbstractNetworkMapService>()
} }
protected abstract val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> protected abstract val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo>
// Map from subscriber address, to most recently acknowledged update map version. // Map from subscriber address, to most recently acknowledged update map version.
protected abstract val subscribers: ThreadBox<MutableMap<SingleMessageRecipient, LastAcknowledgeInfo>> protected abstract val subscribers: ThreadBox<MutableMap<SingleMessageRecipient, LastAcknowledgeInfo>>

View File

@ -1,7 +1,7 @@
package net.corda.node.services.network package net.corda.node.services.network
import net.corda.core.ThreadBox import net.corda.core.ThreadBox
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.* import net.corda.node.utilities.*
@ -22,22 +22,25 @@ class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformV
: AbstractNetworkMapService(services, minimumPlatformVersion) { : AbstractNetworkMapService(services, minimumPlatformVersion) {
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") { private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") {
val nodeParty = party("node_party_name", "node_party_key") val nodeParty = partyAndCertificate("node_party_name", "node_party_key", "node_party_certificate", "node_party_path")
val registrationInfo = blob("node_registration_info") val registrationInfo = blob("node_registration_info")
} }
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<Party, NodeRegistrationInfo, Table>(Table, loadOnInit = true) { override val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<PartyAndCertificate, NodeRegistrationInfo, Table>(Table, loadOnInit = true) {
// TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves // TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves
override fun keyFromRow(row: ResultRow): Party = Party(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey]) override fun keyFromRow(row: ResultRow): PartyAndCertificate = PartyAndCertificate(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey],
row[table.nodeParty.certificate], row[table.nodeParty.certPath])
override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo]) override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo])
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) { override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<PartyAndCertificate, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
insert[table.nodeParty.name] = entry.key.name.toString() insert[table.nodeParty.name] = entry.key.name.toString()
insert[table.nodeParty.owningKey] = entry.key.owningKey insert[table.nodeParty.owningKey] = entry.key.owningKey
insert[table.nodeParty.certPath] = entry.key.certPath
insert[table.nodeParty.certificate] = entry.key.certificate
} }
override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) { override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry<PartyAndCertificate, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
insert[table.registrationInfo] = serializeToBlob(entry.value, finalizables) insert[table.registrationInfo] = serializeToBlob(entry.value, finalizables)
} }
}) })

View File

@ -18,6 +18,7 @@ import net.corda.core.*
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.debug import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
@ -339,7 +340,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
waitingForResponse is WaitForLedgerCommit && message is ErrorSessionEnd waitingForResponse is WaitForLedgerCommit && message is ErrorSessionEnd
} }
private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: Party) { private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: PartyAndCertificate) {
logger.trace { "Received $sessionInit from $sender" } logger.trace { "Received $sessionInit from $sender" }
val otherPartySessionId = sessionInit.initiatorSessionId val otherPartySessionId = sessionInit.initiatorSessionId

View File

@ -3,7 +3,7 @@ package net.corda.node.services.transactions
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.DigitalSignature
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
@ -42,11 +42,11 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig,
private val log = loggerFor<BFTNonValidatingNotaryService>() private val log = loggerFor<BFTNonValidatingNotaryService>()
} }
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ -> override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
ServiceFlow(otherParty, client) ServiceFlow(otherParty, client)
} }
private class ServiceFlow(val otherSide: Party, val client: BFTSMaRt.Client) : FlowLogic<Void?>() { private class ServiceFlow(val otherSide: PartyAndCertificate, val client: BFTSMaRt.Client) : FlowLogic<Void?>() {
@Suspendable @Suspendable
override fun call(): Void? { override fun call(): Void? {
val stx = receive<FilteredTransaction>(otherSide).unwrap { it } val stx = receive<FilteredTransaction>(otherSide).unwrap { it }
@ -81,7 +81,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig,
return response.serialize().bytes return response.serialize().bytes
} }
fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse { fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: PartyAndCertificate): BFTSMaRt.ReplicaResponse {
return try { return try {
val id = ftx.rootHash val id = ftx.rootHash
val inputs = ftx.filteredLeaves.inputs val inputs = ftx.filteredLeaves.inputs

View File

@ -13,7 +13,7 @@ import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
@ -51,7 +51,7 @@ import java.util.*
object BFTSMaRt { object BFTSMaRt {
/** Sent from [Client] to [Server]. */ /** Sent from [Client] to [Server]. */
@CordaSerializable @CordaSerializable
data class CommitRequest(val tx: Any, val callerIdentity: Party) data class CommitRequest(val tx: Any, val callerIdentity: PartyAndCertificate)
/** Sent from [Server] to [Client]. */ /** Sent from [Server] to [Client]. */
@CordaSerializable @CordaSerializable
@ -83,7 +83,7 @@ object BFTSMaRt {
* Sends a transaction commit request to the BFT cluster. The [proxy] will deliver the request to every * Sends a transaction commit request to the BFT cluster. The [proxy] will deliver the request to every
* replica, and block until a sufficient number of replies are received. * replica, and block until a sufficient number of replies are received.
*/ */
fun commitTransaction(transaction: Any, otherSide: Party): ClusterResponse { fun commitTransaction(transaction: Any, otherSide: PartyAndCertificate): ClusterResponse {
require(transaction is FilteredTransaction || transaction is SignedTransaction) { "Unsupported transaction type: ${transaction.javaClass.name}" } require(transaction is FilteredTransaction || transaction is SignedTransaction) { "Unsupported transaction type: ${transaction.javaClass.name}" }
val request = CommitRequest(transaction, otherSide) val request = CommitRequest(transaction, otherSide)
val responseBytes = proxy.invokeOrdered(request.serialize().bytes) val responseBytes = proxy.invokeOrdered(request.serialize().bytes)
@ -178,7 +178,7 @@ object BFTSMaRt {
*/ */
abstract fun executeCommand(command: ByteArray): ByteArray? abstract fun executeCommand(command: ByteArray): ByteArray?
protected fun commitInputStates(states: List<StateRef>, txId: SecureHash, callerIdentity: Party) { protected fun commitInputStates(states: List<StateRef>, txId: SecureHash, callerIdentity: PartyAndCertificate) {
log.debug { "Attempting to commit inputs for transaction: $txId" } log.debug { "Attempting to commit inputs for transaction: $txId" }
val conflicts = mutableMapOf<StateRef, UniquenessProvider.ConsumingTx>() val conflicts = mutableMapOf<StateRef, UniquenessProvider.ConsumingTx>()
db.transaction { db.transaction {

View File

@ -1,7 +1,7 @@
package net.corda.node.services.transactions package net.corda.node.services.transactions
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
import net.corda.core.transactions.FilteredTransaction import net.corda.core.transactions.FilteredTransaction
@ -9,7 +9,7 @@ import net.corda.core.utilities.unwrap
import net.corda.flows.NotaryFlow import net.corda.flows.NotaryFlow
import net.corda.flows.TransactionParts import net.corda.flows.TransactionParts
class NonValidatingNotaryFlow(otherSide: Party, class NonValidatingNotaryFlow(otherSide: PartyAndCertificate,
timeWindowChecker: TimeWindowChecker, timeWindowChecker: TimeWindowChecker,
uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) {
/** /**

View File

@ -2,13 +2,15 @@ package net.corda.node.services.transactions
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
interface NotaryService { interface NotaryService {
/** /**
* Factory for producing notary service flows which have the corresponding sends and receives as NotaryFlow.Client. * Factory for producing notary service flows which have the corresponding sends and receives as NotaryFlow.Client.
* The first parameter is the client [Party] making the request and the second is the platform version of the client's * The first parameter is the client [PartyAndCertificate] making the request and the second is the platform version
* node. Use this version parameter to provide backwards compatibility if the notary flow protocol changes. * of the client's node. Use this version parameter to provide backwards compatibility if the notary flow protocol
* changes.
*/ */
val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?>
} }

View File

@ -1,7 +1,7 @@
package net.corda.node.services.transactions package net.corda.node.services.transactions
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ /** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
@ -11,7 +11,7 @@ class RaftNonValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
val type = SimpleNotaryService.type.getSubType("raft") val type = SimpleNotaryService.type.getSubType("raft")
} }
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ -> override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
} }
} }

View File

@ -1,7 +1,7 @@
package net.corda.node.services.transactions package net.corda.node.services.transactions
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ /** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
@ -11,7 +11,7 @@ class RaftValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
val type = ValidatingNotaryService.type.getSubType("raft") val type = ValidatingNotaryService.type.getSubType("raft")
} }
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ -> override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
} }
} }

View File

@ -1,7 +1,7 @@
package net.corda.node.services.transactions package net.corda.node.services.transactions
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.ServiceType import net.corda.core.node.services.ServiceType
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
@ -13,7 +13,7 @@ class SimpleNotaryService(val timeWindowChecker: TimeWindowChecker,
val type = ServiceType.notary.getSubType("simple") val type = ServiceType.notary.getSubType("simple")
} }
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ -> override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
} }
} }

View File

@ -2,7 +2,7 @@ package net.corda.node.services.transactions
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.TransactionVerificationException import net.corda.core.contracts.TransactionVerificationException
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
@ -17,7 +17,7 @@ import java.security.SignatureException
* has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was * has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was
* indeed valid. * indeed valid.
*/ */
class ValidatingNotaryFlow(otherSide: Party, class ValidatingNotaryFlow(otherSide: PartyAndCertificate,
timeWindowChecker: TimeWindowChecker, timeWindowChecker: TimeWindowChecker,
uniquenessProvider: UniquenessProvider) : uniquenessProvider: UniquenessProvider) :
NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) {

View File

@ -1,7 +1,7 @@
package net.corda.node.services.transactions package net.corda.node.services.transactions
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.ServiceType import net.corda.core.node.services.ServiceType
import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.UniquenessProvider import net.corda.core.node.services.UniquenessProvider
@ -13,7 +13,7 @@ class ValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
val type = ServiceType.notary.getSubType("validating") val type = ServiceType.notary.getSubType("validating")
} }
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ -> override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
} }
} }

View File

@ -11,7 +11,7 @@ import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.DUMMY_PUBKEY_1 import net.corda.core.utilities.DUMMY_CA
import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.UntrustworthyData
import net.corda.jackson.JacksonSupport import net.corda.jackson.JacksonSupport
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
@ -33,8 +33,7 @@ class InteractiveShellTest {
override fun call() = a override fun call() = a
} }
private val someCorpLegalName = MEGA_CORP.name private val ids = InMemoryIdentityService(listOf(MEGA_CORP), trustRoot = DUMMY_CA.certificate)
private val ids = InMemoryIdentityService().apply { registerIdentity(Party(someCorpLegalName, DUMMY_PUBKEY_1)) }
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory()) private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
private fun check(input: String, expected: String) { private fun check(input: String, expected: String) {
@ -67,7 +66,7 @@ class InteractiveShellTest {
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "") fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
@Test @Test
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName.toString()) fun party() = check("party: \"${MEGA_CORP.name}\"", MEGA_CORP.name.toString())
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> { class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData<T> { override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData<T> {

View File

@ -13,6 +13,8 @@ import net.corda.core.flows.*
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.map
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.* import net.corda.core.node.services.*
@ -493,7 +495,7 @@ class TwoPartyTradeFlowTests {
} }
@InitiatingFlow @InitiatingFlow
class SellerInitiator(val buyer: Party, class SellerInitiator(val buyer: PartyAndCertificate,
val notary: NodeInfo, val notary: NodeInfo,
val assetToSell: StateAndRef<OwnableState>, val assetToSell: StateAndRef<OwnableState>,
val price: Amount<Currency>) : FlowLogic<SignedTransaction>() { val price: Amount<Currency>) : FlowLogic<SignedTransaction>() {
@ -510,10 +512,10 @@ class TwoPartyTradeFlowTests {
} }
@InitiatedBy(SellerInitiator::class) @InitiatedBy(SellerInitiator::class)
class BuyerAcceptor(val seller: Party) : FlowLogic<SignedTransaction>() { class BuyerAcceptor(val seller: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
@Suspendable @Suspendable
override fun call(): SignedTransaction { override fun call(): SignedTransaction {
val (notary, price) = receive<Pair<Party, Amount<Currency>>>(seller).unwrap { val (notary, price) = receive<Pair<PartyAndCertificate, Amount<Currency>>>(seller).unwrap {
require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" }
it it
} }

View File

@ -3,6 +3,7 @@ package net.corda.node.services
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken

View File

@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
import net.corda.core.seconds import net.corda.core.seconds
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.core.utilities.getTestPartyAndCertificate
import net.corda.flows.NotaryChangeFlow import net.corda.flows.NotaryChangeFlow
import net.corda.flows.StateReplacementException import net.corda.flows.StateReplacementException
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
@ -75,7 +76,7 @@ class NotaryChangeTests {
@Test @Test
fun `should throw when a participant refuses to change Notary`() { fun `should throw when a participant refuses to change Notary`() {
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode) val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
val newEvilNotary = Party(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public) val newEvilNotary = getTestPartyAndCertificate(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public)
val flow = NotaryChangeFlow(state, newEvilNotary) val flow = NotaryChangeFlow(state, newEvilNotary)
val future = clientNodeA.services.startFlow(flow) val future = clientNodeA.services.startFlow(flow)

View File

@ -10,6 +10,7 @@ import net.corda.core.node.ServiceHub
import net.corda.core.node.services.VaultService import net.corda.core.node.services.VaultService
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.ALICE_KEY import net.corda.core.utilities.ALICE_KEY
import net.corda.core.utilities.DUMMY_CA
import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.node.services.MockServiceHubInternal import net.corda.node.services.MockServiceHubInternal
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
@ -76,7 +77,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
val dataSourceAndDatabase = configureDatabase(dataSourceProps) val dataSourceAndDatabase = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second database = dataSourceAndDatabase.second
val identityService = InMemoryIdentityService() val identityService = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
val kms = MockKeyManagementService(identityService, ALICE_KEY) val kms = MockKeyManagementService(identityService, ALICE_KEY)
database.transaction { database.transaction {

View File

@ -3,14 +3,15 @@ package net.corda.node.services.network
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.utilities.ALICE import net.corda.core.utilities.*
import net.corda.core.utilities.BOB
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.testing.ALICE_PUBKEY import net.corda.testing.ALICE_PUBKEY
import net.corda.testing.BOB_PUBKEY import net.corda.testing.BOB_PUBKEY
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test import org.junit.Test
import java.security.cert.X509Certificate
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
import kotlin.test.assertNull import kotlin.test.assertNull
@ -21,7 +22,7 @@ import kotlin.test.assertNull
class InMemoryIdentityServiceTests { class InMemoryIdentityServiceTests {
@Test @Test
fun `get all identities`() { fun `get all identities`() {
val service = InMemoryIdentityService() val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
assertNull(service.getAllIdentities().firstOrNull()) assertNull(service.getAllIdentities().firstOrNull())
service.registerIdentity(ALICE) service.registerIdentity(ALICE)
var expected = setOf<Party>(ALICE) var expected = setOf<Party>(ALICE)
@ -37,7 +38,7 @@ class InMemoryIdentityServiceTests {
@Test @Test
fun `get identity by key`() { fun `get identity by key`() {
val service = InMemoryIdentityService() val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
assertNull(service.partyFromKey(ALICE_PUBKEY)) assertNull(service.partyFromKey(ALICE_PUBKEY))
service.registerIdentity(ALICE) service.registerIdentity(ALICE)
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY)) assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
@ -46,15 +47,15 @@ class InMemoryIdentityServiceTests {
@Test @Test
fun `get identity by name with no registered identities`() { fun `get identity by name with no registered identities`() {
val service = InMemoryIdentityService() val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
assertNull(service.partyFromX500Name(ALICE.name)) assertNull(service.partyFromX500Name(ALICE.name))
} }
@Test @Test
fun `get identity by name`() { fun `get identity by name`() {
val service = InMemoryIdentityService() val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
val identities = listOf("Node A", "Node B", "Node C") val identities = listOf("Node A", "Node B", "Node C")
.map { Party(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) } .map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) }
assertNull(service.partyFromX500Name(identities.first().name)) assertNull(service.partyFromX500Name(identities.first().name))
identities.forEach { service.registerIdentity(it) } identities.forEach { service.registerIdentity(it) }
identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) } identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) }
@ -68,7 +69,7 @@ class InMemoryIdentityServiceTests {
val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey) val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey)
val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val service = InMemoryIdentityService() val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
// TODO: Generate certificate with an EdDSA key rather than ECDSA // TODO: Generate certificate with an EdDSA key rather than ECDSA
val identity = Party(CertificateAndKeyPair(rootCert, rootKey)) val identity = Party(CertificateAndKeyPair(rootCert, rootKey))
val txIdentity = AnonymousParty(txKey.public) val txIdentity = AnonymousParty(txKey.public)
@ -84,26 +85,26 @@ class InMemoryIdentityServiceTests {
*/ */
@Test @Test
fun `assert ownership`() { fun `assert ownership`() {
val service = InMemoryIdentityService(trustRoot = null as X509Certificate?)
val aliceRootKey = Crypto.generateKeyPair() val aliceRootKey = Crypto.generateKeyPair()
val aliceRootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, aliceRootKey) val aliceRootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, aliceRootKey)
val aliceTxKey = Crypto.generateKeyPair() val aliceTxKey = Crypto.generateKeyPair()
val aliceTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public) val aliceTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public)
val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCert, aliceTxCert, revocationEnabled = false) val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCert, aliceTxCert, revocationEnabled = false)
val alice = PartyAndCertificate(ALICE.name, aliceRootKey.public, aliceRootCert, aliceCertPath)
val anonymousAlice = AnonymousParty(aliceTxKey.public)
service.registerAnonymousIdentity(anonymousAlice, alice, aliceCertPath)
val bobRootKey = Crypto.generateKeyPair() val bobRootKey = Crypto.generateKeyPair()
val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey) val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey)
val bobTxKey = Crypto.generateKeyPair() val bobTxKey = Crypto.generateKeyPair()
val bobTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, bobRootCert, bobRootKey, BOB.name, bobTxKey.public) val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false) val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false)
val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath)
val service = InMemoryIdentityService()
val alice = Party(CertificateAndKeyPair(aliceRootCert, aliceRootKey))
val anonymousAlice = AnonymousParty(aliceTxKey.public)
val bob = Party(CertificateAndKeyPair(bobRootCert, bobRootKey))
val anonymousBob = AnonymousParty(bobTxKey.public) val anonymousBob = AnonymousParty(bobTxKey.public)
service.registerAnonymousIdentity(anonymousBob, bob, bobCertPath)
service.registerPath(aliceRootCert, anonymousAlice, aliceCertPath)
service.registerPath(bobRootCert, anonymousBob, bobCertPath)
// Verify that paths are verified // Verify that paths are verified
service.assertOwnership(alice, anonymousAlice) service.assertOwnership(alice, anonymousAlice)
@ -122,7 +123,7 @@ class InMemoryIdentityServiceTests {
@Test @Test
fun `deanonymising a well known identity`() { fun `deanonymising a well known identity`() {
val expected = ALICE val expected = ALICE
val actual = InMemoryIdentityService().partyFromAnonymous(expected) val actual = InMemoryIdentityService(trustRoot = null as X509Certificate?).partyFromAnonymous(expected)
assertEquals(expected, actual) assertEquals(expected, actual)
} }
} }

View File

@ -9,7 +9,7 @@ import net.corda.core.contracts.USD
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.unconsumedStates import net.corda.core.node.services.unconsumedStates
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY
@ -93,13 +93,13 @@ class DataVendingServiceTests {
} }
@InitiatingFlow @InitiatingFlow
private class NotifyTxFlow(val otherParty: Party, val stx: SignedTransaction) : FlowLogic<Unit>() { private class NotifyTxFlow(val otherParty: PartyAndCertificate, val stx: SignedTransaction) : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() = send(otherParty, NotifyTxRequest(stx)) override fun call() = send(otherParty, NotifyTxRequest(stx))
} }
@InitiatedBy(NotifyTxFlow::class) @InitiatedBy(NotifyTxFlow::class)
private class InitiateNotifyTxFlow(val otherParty: Party) : FlowLogic<Unit>() { private class InitiateNotifyTxFlow(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() = subFlow(NotifyTransactionHandler(otherParty)) override fun call() = subFlow(NotifyTransactionHandler(otherParty))
} }

View File

@ -14,6 +14,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSessionException import net.corda.core.flows.FlowSessionException
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.MessageRecipients
import net.corda.core.node.services.PartyInfo import net.corda.core.node.services.PartyInfo
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
@ -673,10 +674,10 @@ class FlowFrameworkTests {
private inline fun <reified P : FlowLogic<*>> MockNode.registerFlowFactory( private inline fun <reified P : FlowLogic<*>> MockNode.registerFlowFactory(
initiatingFlowClass: KClass<out FlowLogic<*>>, initiatingFlowClass: KClass<out FlowLogic<*>>,
noinline flowFactory: (Party) -> P): ListenableFuture<P> noinline flowFactory: (PartyAndCertificate) -> P): ListenableFuture<P>
{ {
val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory<P> { val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory<P> {
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P { override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): P {
return flowFactory(otherParty) return flowFactory(otherParty)
} }
}, P::class.java, track = true) }, P::class.java, track = true)

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.*
import net.corda.core.exists import net.corda.core.exists
import net.corda.core.mapToArray import net.corda.core.mapToArray
import net.corda.core.utilities.ALICE import net.corda.core.utilities.ALICE
import net.corda.core.utilities.getTestPartyAndCertificate
import net.corda.testing.TestNodeConfiguration import net.corda.testing.TestNodeConfiguration
import net.corda.testing.getTestX509Name import net.corda.testing.getTestX509Name
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
@ -14,6 +15,7 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.security.cert.Certificate
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue

View File

@ -9,6 +9,7 @@ import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.SchedulableFlow import net.corda.core.flows.SchedulableFlow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.ServiceType import net.corda.core.node.services.ServiceType
import net.corda.core.seconds import net.corda.core.seconds
@ -30,8 +31,7 @@ object FixingFlow {
* who does what in the flow. * who does what in the flow.
*/ */
@InitiatedBy(FixingRoleDecider::class) @InitiatedBy(FixingRoleDecider::class)
class Fixer(override val otherParty: Party) : TwoPartyDealFlow.Secondary<FixingSession>() { class Fixer(override val otherParty: PartyAndCertificate) : TwoPartyDealFlow.Secondary<FixingSession>() {
override val progressTracker: ProgressTracker = TwoPartyDealFlow.Secondary.tracker()
private lateinit var txState: TransactionState<*> private lateinit var txState: TransactionState<*>
private lateinit var deal: FixableDealState private lateinit var deal: FixableDealState
@ -97,7 +97,7 @@ object FixingFlow {
* is just the "side" of the flow run by the party with the floating leg as a way of deciding who * is just the "side" of the flow run by the party with the floating leg as a way of deciding who
* does what in the flow. * does what in the flow.
*/ */
class Floater(override val otherParty: Party, class Floater(override val otherParty: PartyAndCertificate,
override val payload: FixingSession, override val payload: FixingSession,
override val progressTracker: ProgressTracker = TwoPartyDealFlow.Primary.tracker()) : TwoPartyDealFlow.Primary() { override val progressTracker: ProgressTracker = TwoPartyDealFlow.Primary.tracker()) : TwoPartyDealFlow.Primary() {

View File

@ -15,8 +15,10 @@ import net.corda.core.flows.FlowStateMachine
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.linearHeadsOfType import net.corda.core.node.services.linearHeadsOfType
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.DUMMY_CA
import net.corda.flows.TwoPartyDealFlow.Acceptor import net.corda.flows.TwoPartyDealFlow.Acceptor
import net.corda.flows.TwoPartyDealFlow.AutoOffer import net.corda.flows.TwoPartyDealFlow.AutoOffer
import net.corda.flows.TwoPartyDealFlow.Instigator import net.corda.flows.TwoPartyDealFlow.Instigator
@ -46,7 +48,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
override fun startMainSimulation(): ListenableFuture<Unit> { override fun startMainSimulation(): ListenableFuture<Unit> {
val future = SettableFuture.create<Unit>() val future = SettableFuture.create<Unit>()
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity })) om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity }, trustRoot = DUMMY_CA.certificate))
startIRSDealBetween(0, 1).success { startIRSDealBetween(0, 1).success {
// Next iteration is a pause. // Next iteration is a pause.
@ -129,7 +131,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
node2.registerInitiatedFlow(FixingFlow.Fixer::class.java) node2.registerInitiatedFlow(FixingFlow.Fixer::class.java)
@InitiatingFlow @InitiatingFlow
class StartDealFlow(val otherParty: Party, class StartDealFlow(val otherParty: PartyAndCertificate,
val payload: AutoOffer, val payload: AutoOffer,
val myKey: PublicKey) : FlowLogic<SignedTransaction>() { val myKey: PublicKey) : FlowLogic<SignedTransaction>() {
@Suspendable @Suspendable

View File

@ -9,6 +9,7 @@ import net.corda.core.crypto.*
import net.corda.core.getOrThrow import net.corda.core.getOrThrow
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.utilities.DUMMY_MAP import net.corda.core.utilities.DUMMY_MAP
@ -35,7 +36,7 @@ import javax.ws.rs.core.Response
@Path("simmvaluationdemo") @Path("simmvaluationdemo")
class PortfolioApi(val rpc: CordaRPCOps) { class PortfolioApi(val rpc: CordaRPCOps) {
private val ownParty: Party get() = rpc.nodeIdentity().legalIdentity private val ownParty: PartyAndCertificate get() = rpc.nodeIdentity().legalIdentity
private val portfolioUtils = PortfolioApiUtils(ownParty) private val portfolioUtils = PortfolioApiUtils(ownParty)
private inline fun <reified T : DealState> dealsWith(party: AbstractParty): List<StateAndRef<T>> { private inline fun <reified T : DealState> dealsWith(party: AbstractParty): List<StateAndRef<T>> {
@ -48,7 +49,7 @@ class PortfolioApi(val rpc: CordaRPCOps) {
* DSL to get a party and then executing the passed function with the party as a parameter. * DSL to get a party and then executing the passed function with the party as a parameter.
* Used as such: withParty(name) { doSomethingWith(it) } * Used as such: withParty(name) { doSomethingWith(it) }
*/ */
private fun withParty(partyName: String, func: (Party) -> Response): Response { private fun withParty(partyName: String, func: (PartyAndCertificate) -> Response): Response {
val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName)) val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName))
return if (otherParty != null) { return if (otherParty != null) {
func(otherParty) func(otherParty)

View File

@ -6,6 +6,7 @@ import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
@ -20,7 +21,7 @@ object IRSTradeFlow {
@InitiatingFlow @InitiatingFlow
@StartableByRPC @StartableByRPC
class Requester(val swap: SwapData, val otherParty: Party) : FlowLogic<SignedTransaction>() { class Requester(val swap: SwapData, val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
@Suspendable @Suspendable
override fun call(): SignedTransaction { override fun call(): SignedTransaction {
require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" } require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" }

View File

@ -15,6 +15,7 @@ import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.PluginServiceHub import net.corda.core.node.PluginServiceHub
import net.corda.core.node.services.dealsWith import net.corda.core.node.services.dealsWith
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
@ -185,7 +186,7 @@ object SimmFlow {
* Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM. * Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM.
*/ */
@InitiatedBy(Requester::class) @InitiatedBy(Requester::class)
class Receiver(val replyToParty: Party) : FlowLogic<Unit>() { class Receiver(val replyToParty: PartyAndCertificate) : FlowLogic<Unit>() {
lateinit var ownParty: Party lateinit var ownParty: Party
lateinit var offer: OfferMessage lateinit var offer: OfferMessage

View File

@ -3,6 +3,7 @@ package net.corda.vega.flows
import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateAndRef
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.seconds import net.corda.core.seconds
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.flows.AbstractStateReplacementFlow import net.corda.flows.AbstractStateReplacementFlow
@ -26,7 +27,7 @@ object StateRevisionFlow {
} }
} }
open class Receiver<in T>(otherParty: Party) : AbstractStateReplacementFlow.Acceptor<T>(otherParty) { open class Receiver<in T>(otherParty: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<T>(otherParty) {
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<T>) { override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<T>) {
val proposedTx = proposal.stx.tx val proposedTx = proposal.stx.tx
val state = proposal.stateRef val state = proposal.stateRef

View File

@ -7,7 +7,7 @@ import net.corda.core.contracts.TransactionGraphSearch
import net.corda.core.div import net.corda.core.div
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.Emoji import net.corda.core.utilities.Emoji
@ -17,7 +17,7 @@ import net.corda.flows.TwoPartyTradeFlow
import java.util.* import java.util.*
@InitiatedBy(SellerFlow::class) @InitiatedBy(SellerFlow::class)
class BuyerFlow(val otherParty: Party) : FlowLogic<Unit>() { class BuyerFlow(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset")

View File

@ -12,6 +12,7 @@ import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.seconds import net.corda.core.seconds
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
@ -24,10 +25,10 @@ import java.util.*
@InitiatingFlow @InitiatingFlow
@StartableByRPC @StartableByRPC
class SellerFlow(val otherParty: Party, class SellerFlow(val otherParty: PartyAndCertificate,
val amount: Amount<Currency>, val amount: Amount<Currency>,
override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() { override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() {
constructor(otherParty: Party, amount: Amount<Currency>) : this(otherParty, amount, tracker()) constructor(otherParty: PartyAndCertificate, amount: Amount<Currency>) : this(otherParty, amount, tracker())
companion object { companion object {
val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9") val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")

View File

@ -9,7 +9,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.commonName import net.corda.core.crypto.commonName
import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.node.VersionInfo import net.corda.core.node.VersionInfo
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
@ -66,22 +66,22 @@ val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public
val BOB_PUBKEY: PublicKey get() = BOB_KEY.public val BOB_PUBKEY: PublicKey get() = BOB_KEY.public
val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public
val MEGA_CORP: Party get() = Party(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY) val MEGA_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY)
val MINI_CORP: Party get() = Party(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY) val MINI_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY)
val BOC_KEY: KeyPair by lazy { generateKeyPair() } val BOC_KEY: KeyPair by lazy { generateKeyPair() }
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
val BOC: Party get() = Party(getTestX509Name("BankOfCorda"), BOC_PUBKEY) val BOC: PartyAndCertificate get() = getTestPartyAndCertificate(getTestX509Name("BankOfCorda"), BOC_PUBKEY)
val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference
val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() } val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public
val BIG_CORP: Party get() = Party(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY) val BIG_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY)
val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference
val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY)
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), emptyMap(), DUMMY_CA.certificate)
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor") val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")

View File

@ -7,6 +7,7 @@ import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.* import net.corda.core.*
import net.corda.core.crypto.entropyToKeyPair import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.CordaPluginRegistry import net.corda.core.node.CordaPluginRegistry
@ -14,6 +15,7 @@ import net.corda.core.node.PhysicalLocation
import net.corda.core.node.ServiceEntry import net.corda.core.node.ServiceEntry
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.utilities.DUMMY_NOTARY_KEY import net.corda.core.utilities.DUMMY_NOTARY_KEY
import net.corda.core.utilities.getTestPartyAndCertificate
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
@ -38,6 +40,7 @@ import org.slf4j.Logger
import java.math.BigInteger import java.math.BigInteger
import java.nio.file.FileSystem import java.nio.file.FileSystem
import java.security.KeyPair import java.security.KeyPair
import java.security.cert.X509Certificate
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
@ -68,7 +71,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
// A unique identifier for this network to segregate databases with the same nodeID but different networks. // A unique identifier for this network to segregate databases with the same nodeID but different networks.
private val networkId = random63BitValue() private val networkId = random63BitValue()
val identities = ArrayList<Party>() val identities = ArrayList<PartyAndCertificate>()
private val _nodes = ArrayList<MockNode>() private val _nodes = ArrayList<MockNode>()
/** A read only view of the current set of executing nodes. */ /** A read only view of the current set of executing nodes. */
@ -162,7 +165,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
.getOrThrow() .getOrThrow()
} }
override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities) // TODO: Specify a CA to validate registration against
override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities, trustRoot = null as X509Certificate?)
override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties) override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties)
@ -187,7 +191,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
val override = overrideServices[it.info] val override = overrideServices[it.info]
if (override != null) { if (override != null) {
// TODO: Store the key // TODO: Store the key
ServiceEntry(it.info, Party(it.identity.name, override.public)) ServiceEntry(it.info, getTestPartyAndCertificate(it.identity.name, override.public))
} else { } else {
it it
} }

View File

@ -3,7 +3,7 @@ package net.corda.testing.node
import net.corda.core.contracts.Attachment import net.corda.core.contracts.Attachment
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.flows.StateMachineRunId import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
@ -11,10 +11,12 @@ import net.corda.core.node.services.*
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.DUMMY_CA
import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.core.utilities.getTestPartyAndCertificate
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.services.keys.freshKeyAndCert import net.corda.node.services.keys.freshCertificate
import net.corda.node.services.keys.getSigner
import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage
import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
@ -24,6 +26,7 @@ import net.corda.testing.MEGA_CORP
import net.corda.testing.MINI_CORP import net.corda.testing.MINI_CORP
import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.MOCK_VERSION_INFO
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.operator.ContentSigner
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -63,7 +66,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub {
} }
override val storageService: TxWritableStorageService = MockStorageService() override val storageService: TxWritableStorageService = MockStorageService()
override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY),
trustRoot = DUMMY_CA.certificate)
override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys) override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys)
override val vaultService: VaultService get() = throw UnsupportedOperationException() override val vaultService: VaultService get() = throw UnsupportedOperationException()
@ -96,10 +100,12 @@ class MockKeyManagementService(val identityService: IdentityService,
return k.public return k.public
} }
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> { override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
return freshKeyAndCert(this, identityService, identity, revocationEnabled) return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
} }
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
val pk = publicKey.keys.first { keyStore.containsKey(it) } val pk = publicKey.keys.first { keyStore.containsKey(it) }
return KeyPair(pk, keyStore[pk]!!) return KeyPair(pk, keyStore[pk]!!)

View File

@ -3,7 +3,6 @@ package net.corda.testing.node
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.SettableFuture import com.google.common.util.concurrent.SettableFuture
import net.corda.core.crypto.CertificateAndKeyPair
import net.corda.core.crypto.commonName import net.corda.core.crypto.commonName
import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.generateKeyPair
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
@ -22,6 +21,7 @@ import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction import net.corda.node.utilities.transaction
import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.MOCK_VERSION_INFO
import net.corda.testing.freeLocalHostAndPort import net.corda.testing.freeLocalHostAndPort
import org.bouncycastle.cert.X509CertificateHolder
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import java.io.Closeable import java.io.Closeable
import java.security.KeyPair import java.security.KeyPair
@ -33,14 +33,14 @@ import kotlin.concurrent.thread
*/ */
class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(),
rpcAddress: HostAndPort = freeLocalHostAndPort(), rpcAddress: HostAndPort = freeLocalHostAndPort(),
networkRoot: CertificateAndKeyPair? = null) : AutoCloseable { trustRoot: X509CertificateHolder? = null) : AutoCloseable {
private val databaseWithCloseable: Pair<Closeable, Database> = configureDatabase(config.dataSourceProperties) private val databaseWithCloseable: Pair<Closeable, Database> = configureDatabase(config.dataSourceProperties)
val database: Database get() = databaseWithCloseable.second val database: Database get() = databaseWithCloseable.second
val userService = RPCUserServiceImpl(config.rpcUsers) val userService = RPCUserServiceImpl(config.rpcUsers)
val monitoringService = MonitoringService(MetricRegistry()) val monitoringService = MonitoringService(MetricRegistry())
val identity: KeyPair = generateKeyPair() val identity: KeyPair = generateKeyPair()
val identityService: IdentityService = InMemoryIdentityService() val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot)
val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity))
val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1) val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1)
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService) val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)

View File

@ -183,7 +183,7 @@ class NewTransaction : Fragment() {
// Issuer // Issuer
issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull) issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull)
issuerChoiceBox.apply { issuerChoiceBox.apply {
items = issuers.map { it.legalIdentity }.unique().sorted() items = issuers.map { it.legalIdentity as Party }.unique().sorted()
converter = stringConverter { PartyNameFormatter.short.format(it.name) } converter = stringConverter { PartyNameFormatter.short.format(it.name) }
visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay }) visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay })
} }