Simplify identity registration API

* Merge identity registration of well known and confidential identities
* Move verification logic into PartyAndCertificate from IdentityService
* Add note about why PartyAndCertificate exists
This commit is contained in:
Ross Nicoll
2017-08-15 00:17:21 +01:00
committed by GitHub
parent 532deffca0
commit 62576b12b3
22 changed files with 158 additions and 261 deletions

View File

@ -6,7 +6,7 @@ import net.corda.core.contracts.UpgradeCommand
import net.corda.core.contracts.UpgradedContract
import net.corda.core.contracts.requireThat
import net.corda.core.flows.*
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.identity.Party
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker
@ -87,9 +87,8 @@ class TransactionKeyHandler(val otherSide: Party, val revocationEnabled: Boolean
val revocationEnabled = false
progressTracker.currentStep = SENDING_KEY
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled)
val otherSideAnonymous = sendAndReceive<AnonymousPartyAndPath>(otherSide, legalIdentityAnonymous).unwrap { TransactionKeyFlow.validateIdentity(otherSide, it) }
// Validate then store their identity so that we can prove the key in the transaction is owned by the
// counterparty.
serviceHub.identityService.registerAnonymousIdentity(otherSideAnonymous, otherSide)
sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->
TransactionKeyFlow.validateAndRegisterIdentity(serviceHub.identityService, otherSide, confidentialIdentity)
}
}
}

View File

@ -1,11 +1,12 @@
package net.corda.node.services.identity
import net.corda.core.contracts.PartyAndReference
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.cert
import net.corda.core.crypto.subject
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.*
import net.corda.core.identity.AbstractParty
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.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.loggerFor
@ -28,12 +29,12 @@ import kotlin.collections.LinkedHashSet
*/
@ThreadSafe
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
override val trustRoot: X509Certificate,
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
constructor(identities: Iterable<PartyAndCertificate> = emptySet(),
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
trustRoot: X509CertificateHolder) : this(identities, certPaths, trustRoot.cert)
constructor(wellKnownIdentities: Iterable<PartyAndCertificate> = emptySet(),
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
trustRoot: X509CertificateHolder) : this(wellKnownIdentities, confidentialIdentities, trustRoot.cert)
companion object {
private val log = loggerFor<InMemoryIdentityService>()
}
@ -45,41 +46,44 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
private val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
private val keyToIssuingParty = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
private val partyToPath = ConcurrentHashMap<AbstractParty, Pair<CertPath, X509CertificateHolder>>()
init {
val caCertificatesWithRoot: Set<X509Certificate> = caCertificates.toSet() + trustRoot
caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(caCertificatesWithRoot))
keyToParties.putAll(identities.associateBy { it.owningKey } )
principalToParties.putAll(identities.associateBy { it.name })
certPaths.forEach { (party, path) ->
partyToPath.put(party, Pair(path, X509CertificateHolder(path.certificates.first().encoded)))
confidentialIdentities.forEach { identity ->
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
keyToIssuingParty[identity.owningKey] = keyToParties[identity.certPath.certificates[1].publicKey]!!
principalToParties.computeIfAbsent(identity.name) { identity }
}
}
override fun registerIdentity(party: PartyAndCertificate) = verifyAndRegisterIdentity(party)
// TODO: Check the certificate 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" }
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate) {
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
// Validate the chain first, before we do anything clever with it
validateCertificatePath(party.party, party.certPath)
identity.verify(trustAnchor)
log.trace { "Registering identity $party" }
require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" }
log.trace { "Registering identity $identity" }
require(Arrays.equals(identity.certificate.subjectPublicKeyInfo.encoded, identity.owningKey.encoded)) { "Party certificate must end with party's public key" }
partyToPath[party.party] = Pair(party.certPath, party.certificate)
keyToParties[party.owningKey] = party
principalToParties[party.name] = party
}
override fun anonymousFromKey(owningKey: PublicKey): AnonymousPartyAndPath? {
val anonymousParty = AnonymousParty(owningKey)
val path = partyToPath[anonymousParty]
return path?.let { it ->
AnonymousPartyAndPath(anonymousParty, it.first)
keyToParties[identity.owningKey] = identity
// TODO: This map should only be deanonymised parties, not all issuers, but we have no good way of checking for
// confidential vs anonymous identities
val issuer = keyToParties[identity.certPath.certificates[1].publicKey]
if (issuer != null) {
keyToIssuingParty[identity.owningKey] = issuer
}
// Always keep the first party we registered, as that's the well known identity
principalToParties.computeIfAbsent(identity.name) { identity }
}
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[owningKey]
override fun certificateFromParty(party: Party): PartyAndCertificate? = principalToParties[party.name]
@ -88,7 +92,7 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party
override fun partyFromAnonymous(party: AbstractParty) = party as? Party ?: partyFromKey(party.owningKey)
override fun partyFromAnonymous(party: AbstractParty) = party as? Party ?: keyToIssuingParty[party.owningKey]?.party
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
override fun requirePartyFromAnonymous(party: AbstractParty): Party {
return partyFromAnonymous(party) ?: throw IllegalStateException("Could not deanonymise party ${party.owningKey.toStringShort()}")
@ -119,56 +123,11 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
@Throws(IdentityService.UnknownAnonymousPartyException::class)
override fun assertOwnership(party: Party, anonymousParty: AnonymousParty) {
val path = partyToPath[anonymousParty]?.first ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}")
val path = keyToParties[anonymousParty.owningKey]?.certPath ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}")
require(path.certificates.size > 1) { "Certificate path must contain at least two certificates" }
val actual = path.certificates[1]
require(actual is X509Certificate && actual.publicKey == party.owningKey) { "Next certificate in the path must match the party key ${party.owningKey.toStringShort()}." }
val target = path.certificates.first()
require(target is X509Certificate && target.publicKey == anonymousParty.owningKey) { "Certificate path starts with a certificate for the anonymous party" }
}
override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty]?.first
override fun registerAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, party: Party): PartyAndCertificate = verifyAndRegisterAnonymousIdentity(anonymousIdentity, party)
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
override fun verifyAndRegisterAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, wellKnownIdentity: Party): PartyAndCertificate {
val fullParty = verifyAnonymousIdentity(anonymousIdentity, wellKnownIdentity)
val certificate = X509CertificateHolder(anonymousIdentity.certPath.certificates.first().encoded)
log.trace { "Registering identity $fullParty" }
partyToPath[anonymousIdentity.party] = Pair(anonymousIdentity.certPath, certificate)
keyToParties[anonymousIdentity.party.owningKey] = fullParty
return fullParty
}
override fun verifyAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, party: Party): PartyAndCertificate {
val (anonymousParty, path) = anonymousIdentity
val fullParty = certificateFromParty(party) ?: throw IllegalArgumentException("Unknown identity ${party.name}")
require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
// Validate the chain first, before we do anything clever with it
validateCertificatePath(anonymousParty, path)
val subjectCertificate = path.certificates.first()
require(subjectCertificate is X509Certificate && subjectCertificate.subject == fullParty.name) { "Subject of the transaction certificate must match the well known identity" }
return fullParty
}
/**
* Verify that the given certificate path is valid and leads to the owning key of the party.
*/
private fun validateCertificatePath(party: AbstractParty, path: CertPath): PKIXCertPathValidatorResult {
// Check that the path ends with a certificate for the correct party.
val endCertificate = path.certificates.first()
// Ensure the key is in the correct format for comparison.
// TODO: Replace with a Bouncy Castle cert path so we can avoid Sun internal classes appearing unexpectedly.
// For now we have to deal with this potentially being an [X509Key] which is Sun's equivalent to
// [SubjectPublicKeyInfo] but doesn't compare properly with [PublicKey].
val endKey = Crypto.decodePublicKey(endCertificate.publicKey.encoded)
require(endKey == party.owningKey) { "Certificate path validation must end at owning key ${party.owningKey.toStringShort()}, found ${endKey.toStringShort()}" }
val validatorParameters = PKIXParameters(setOf(trustAnchor))
val validator = CertPathValidator.getInstance("PKIX")
validatorParameters.isRevocationEnabled = false
return validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult
}
}

View File

@ -1,7 +1,6 @@
package net.corda.node.services.keys
import net.corda.core.crypto.*
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.ThreadBox
import net.corda.core.node.services.IdentityService
@ -53,7 +52,7 @@ class E2ETestKeyManagementService(val identityService: IdentityService,
return keyPair.public
}
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): AnonymousPartyAndPath {
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate {
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
}

View File

@ -3,7 +3,7 @@ package net.corda.node.services.keys
import net.corda.core.crypto.ContentSignerBuilder
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.cert
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService
import net.corda.core.utilities.days
@ -32,15 +32,14 @@ fun freshCertificate(identityService: IdentityService,
subjectPublicKey: PublicKey,
issuer: PartyAndCertificate,
issuerSigner: ContentSigner,
revocationEnabled: Boolean = false): AnonymousPartyAndPath {
revocationEnabled: Boolean = false): PartyAndCertificate {
val issuerCertificate = issuer.certificate
val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCertificate)
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window)
val certFactory = CertificateFactory.getInstance("X509")
val ourCertPath = certFactory.generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates)
val anonymisedIdentity = AnonymousPartyAndPath(subjectPublicKey, ourCertPath)
identityService.verifyAndRegisterAnonymousIdentity(anonymisedIdentity,
issuer.party)
val anonymisedIdentity = PartyAndCertificate(Party(issuer.name, subjectPublicKey), ourCertificate, ourCertPath)
identityService.verifyAndRegisterIdentity(anonymisedIdentity)
return anonymisedIdentity
}

View File

@ -1,18 +1,23 @@
package net.corda.node.services.keys
import net.corda.core.crypto.*
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.ThreadBox
import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.*
import net.corda.node.utilities.*
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.node.utilities.NODE_DATABASE_PREFIX
import org.bouncycastle.operator.ContentSigner
import java.security.KeyPair
import java.security.PrivateKey
import java.security.PublicKey
import javax.persistence.*
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Lob
/**
* A persistent re-implementation of [E2ETestKeyManagementService] to support node re-start.
@ -71,7 +76,7 @@ class PersistentKeyManagementService(val identityService: IdentityService,
return keyPair.public
}
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): AnonymousPartyAndPath =
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate =
freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))

View File

@ -2,11 +2,11 @@ package net.corda.node.messaging
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.CommercialPaper
import net.corda.core.concurrent.CordaFuture
import net.corda.contracts.asset.CASH
import net.corda.contracts.asset.Cash
import net.corda.contracts.asset.`issued by`
import net.corda.contracts.asset.`owned by`
import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.flows.FlowLogic
@ -15,7 +15,6 @@ import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.Party
import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.concurrent.map
@ -521,7 +520,7 @@ class TwoPartyTradeFlowTests {
assetToSell: StateAndRef<OwnableState>): RunResult {
val anonymousSeller = sellerNode.services.let { serviceHub ->
serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, false)
}
}.party.anonymise()
val buyerFlows: Observable<BuyerAcceptor> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
val seller = SellerInitiator(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, anonymousSeller)
@ -534,7 +533,7 @@ class TwoPartyTradeFlowTests {
val notary: NodeInfo,
val assetToSell: StateAndRef<OwnableState>,
val price: Amount<Currency>,
val me: AnonymousPartyAndPath) : FlowLogic<SignedTransaction>() {
val me: AnonymousParty) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
send(buyer, Pair(notary.notaryIdentity, price))
@ -543,7 +542,7 @@ class TwoPartyTradeFlowTests {
notary,
assetToSell,
price,
me.party))
me))
}
}

View File

@ -5,7 +5,6 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.cert
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.AnonymousPartyAndPath
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService
@ -30,13 +29,13 @@ class InMemoryIdentityServiceTests {
// Nothing registered, so empty set
assertNull(service.getAllIdentities().firstOrNull())
service.registerIdentity(ALICE_IDENTITY)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
var expected = setOf(ALICE)
var actual = service.getAllIdentities().map { it.party }.toHashSet()
assertEquals(expected, actual)
// Add a second party and check we get both back
service.registerIdentity(BOB_IDENTITY)
service.verifyAndRegisterIdentity(BOB_IDENTITY)
expected = setOf(ALICE, BOB)
actual = service.getAllIdentities().map { it.party }.toHashSet()
assertEquals(expected, actual)
@ -46,7 +45,7 @@ class InMemoryIdentityServiceTests {
fun `get identity by key`() {
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
assertNull(service.partyFromKey(ALICE_PUBKEY))
service.registerIdentity(ALICE_IDENTITY)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
assertNull(service.partyFromKey(BOB_PUBKEY))
}
@ -61,10 +60,10 @@ class InMemoryIdentityServiceTests {
fun `get identity by substring match`() {
val trustRoot = DUMMY_CA
val service = InMemoryIdentityService(trustRoot = trustRoot.certificate)
service.registerIdentity(ALICE_IDENTITY)
service.registerIdentity(BOB_IDENTITY)
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
service.verifyAndRegisterIdentity(BOB_IDENTITY)
val alicente = getTestPartyAndCertificate(X500Name("O=Alicente Worldwide,L=London,C=GB"), generateKeyPair().public)
service.registerIdentity(alicente)
service.verifyAndRegisterIdentity(alicente)
assertEquals(setOf(ALICE, alicente.party), service.partiesFromName("Alice", false))
assertEquals(setOf(ALICE), service.partiesFromName("Alice Corp", true))
assertEquals(setOf(BOB), service.partiesFromName("Bob Plc", true))
@ -76,7 +75,7 @@ class InMemoryIdentityServiceTests {
val identities = listOf("Node A", "Node B", "Node C")
.map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=GB"), generateKeyPair().public) }
assertNull(service.partyFromX500Name(identities.first().name))
identities.forEach { service.registerIdentity(it) }
identities.forEach { service.verifyAndRegisterIdentity(it) }
identities.forEach { assertEquals(it.party, service.partyFromX500Name(it.name)) }
}
@ -111,15 +110,15 @@ class InMemoryIdentityServiceTests {
val (bob, bobTxIdentity) = createParty(ALICE.name, trustRoot)
// Now we have identities, construct the service and let it know about both
val service = InMemoryIdentityService(setOf(alice), emptyMap(), trustRoot.certificate.cert)
service.verifyAndRegisterAnonymousIdentity(aliceTxIdentity, alice.party)
val service = InMemoryIdentityService(setOf(alice), emptySet(), trustRoot.certificate.cert)
service.verifyAndRegisterIdentity(aliceTxIdentity)
var actual = service.anonymousFromKey(aliceTxIdentity.party.owningKey)
var actual = service.certificateFromKey(aliceTxIdentity.party.owningKey)
assertEquals(aliceTxIdentity, actual!!)
assertNull(service.anonymousFromKey(bobTxIdentity.party.owningKey))
service.verifyAndRegisterAnonymousIdentity(bobTxIdentity, bob.party)
actual = service.anonymousFromKey(bobTxIdentity.party.owningKey)
assertNull(service.certificateFromKey(bobTxIdentity.party.owningKey))
service.verifyAndRegisterIdentity(bobTxIdentity)
actual = service.certificateFromKey(bobTxIdentity.party.owningKey)
assertEquals(bobTxIdentity, actual!!)
}
@ -135,36 +134,36 @@ class InMemoryIdentityServiceTests {
val (bob, anonymousBob) = createParty(BOB.name, trustRoot)
// Now we have identities, construct the service and let it know about both
val service = InMemoryIdentityService(setOf(alice, bob), emptyMap(), trustRoot.certificate.cert)
val service = InMemoryIdentityService(setOf(alice, bob), emptySet(), trustRoot.certificate.cert)
service.verifyAndRegisterAnonymousIdentity(anonymousAlice, alice.party)
service.verifyAndRegisterAnonymousIdentity(anonymousBob, bob.party)
service.verifyAndRegisterIdentity(anonymousAlice)
service.verifyAndRegisterIdentity(anonymousBob)
// Verify that paths are verified
service.assertOwnership(alice.party, anonymousAlice.party)
service.assertOwnership(bob.party, anonymousBob.party)
service.assertOwnership(alice.party, anonymousAlice.party.anonymise())
service.assertOwnership(bob.party, anonymousBob.party.anonymise())
assertFailsWith<IllegalArgumentException> {
service.assertOwnership(alice.party, anonymousBob.party)
service.assertOwnership(alice.party, anonymousBob.party.anonymise())
}
assertFailsWith<IllegalArgumentException> {
service.assertOwnership(bob.party, anonymousAlice.party)
service.assertOwnership(bob.party, anonymousAlice.party.anonymise())
}
assertFailsWith<IllegalArgumentException> {
val owningKey = Crypto.decodePublicKey(trustRoot.certificate.subjectPublicKeyInfo.encoded)
service.assertOwnership(Party(trustRoot.certificate.subject, owningKey), anonymousAlice.party)
service.assertOwnership(Party(trustRoot.certificate.subject, owningKey), anonymousAlice.party.anonymise())
}
}
}
private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, AnonymousPartyAndPath> {
private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, PartyAndCertificate> {
val certFactory = CertificateFactory.getInstance("X509")
val issuerKeyPair = generateKeyPair()
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
val txKey = Crypto.generateKeyPair()
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public)
val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates)
return Pair(issuer, AnonymousPartyAndPath(AnonymousParty(txKey.public), txCertPath))
return Pair(issuer, PartyAndCertificate(Party(x500Name, txKey.public), txCert, txCertPath))
}
/**

View File

@ -89,7 +89,7 @@ class FlowFrameworkTests {
val nodes = listOf(node1, node2, notary1, notary2)
nodes.forEach { node ->
nodes.map { it.services.myInfo.legalIdentityAndCert }.forEach { identity ->
node.services.identityService.registerIdentity(identity)
node.services.identityService.verifyAndRegisterIdentity(identity)
}
}
}