mirror of
https://github.com/corda/corda.git
synced 2025-06-16 14:18:20 +00:00
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:
@ -1,8 +1,10 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousParty
|
||||||
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.node.services.IdentityService
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
|
|
||||||
@ -14,33 +16,37 @@ import net.corda.core.utilities.unwrap
|
|||||||
@InitiatingFlow
|
@InitiatingFlow
|
||||||
class TransactionKeyFlow(val otherSide: Party,
|
class TransactionKeyFlow(val otherSide: Party,
|
||||||
val revocationEnabled: Boolean,
|
val revocationEnabled: Boolean,
|
||||||
override val progressTracker: ProgressTracker) : FlowLogic<LinkedHashMap<Party, AnonymousPartyAndPath>>() {
|
override val progressTracker: ProgressTracker) : FlowLogic<LinkedHashMap<Party, AnonymousParty>>() {
|
||||||
constructor(otherSide: Party) : this(otherSide, false, tracker())
|
constructor(otherSide: Party) : this(otherSide, false, tracker())
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
object AWAITING_KEY : ProgressTracker.Step("Awaiting key")
|
object AWAITING_KEY : ProgressTracker.Step("Awaiting key")
|
||||||
|
|
||||||
fun tracker() = ProgressTracker(AWAITING_KEY)
|
fun tracker() = ProgressTracker(AWAITING_KEY)
|
||||||
fun validateIdentity(otherSide: Party, anonymousOtherSide: AnonymousPartyAndPath): AnonymousPartyAndPath {
|
fun validateAndRegisterIdentity(identityService: IdentityService, otherSide: Party, anonymousOtherSide: PartyAndCertificate): PartyAndCertificate {
|
||||||
require(anonymousOtherSide.name == otherSide.name)
|
require(anonymousOtherSide.name == otherSide.name)
|
||||||
|
// Validate then store their identity so that we can prove the key in the transaction is owned by the
|
||||||
|
// counterparty.
|
||||||
|
identityService.verifyAndRegisterIdentity(anonymousOtherSide)
|
||||||
return anonymousOtherSide
|
return anonymousOtherSide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): LinkedHashMap<Party, AnonymousPartyAndPath> {
|
override fun call(): LinkedHashMap<Party, AnonymousParty> {
|
||||||
progressTracker.currentStep = AWAITING_KEY
|
progressTracker.currentStep = AWAITING_KEY
|
||||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled)
|
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled)
|
||||||
|
|
||||||
// Special case that if we're both parties, a single identity is generated
|
// Special case that if we're both parties, a single identity is generated
|
||||||
val identities = LinkedHashMap<Party, AnonymousPartyAndPath>()
|
val identities = LinkedHashMap<Party, AnonymousParty>()
|
||||||
if (otherSide == serviceHub.myInfo.legalIdentity) {
|
if (otherSide == serviceHub.myInfo.legalIdentity) {
|
||||||
identities.put(otherSide, legalIdentityAnonymous)
|
identities.put(otherSide, legalIdentityAnonymous.party.anonymise())
|
||||||
} else {
|
} else {
|
||||||
val otherSideAnonymous = sendAndReceive<AnonymousPartyAndPath>(otherSide, legalIdentityAnonymous).unwrap { validateIdentity(otherSide, it) }
|
val anonymousOtherSide = sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->
|
||||||
serviceHub.identityService.verifyAndRegisterAnonymousIdentity(otherSideAnonymous, otherSide)
|
validateAndRegisterIdentity(serviceHub.identityService, otherSide, confidentialIdentity)
|
||||||
identities.put(serviceHub.myInfo.legalIdentity, legalIdentityAnonymous)
|
}
|
||||||
identities.put(otherSide, otherSideAnonymous)
|
identities.put(serviceHub.myInfo.legalIdentity, legalIdentityAnonymous.party.anonymise())
|
||||||
|
identities.put(otherSide, anonymousOtherSide.party.anonymise())
|
||||||
}
|
}
|
||||||
return identities
|
return identities
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package net.corda.core.identity
|
|
||||||
|
|
||||||
import net.corda.core.crypto.subject
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
|
||||||
import java.security.PublicKey
|
|
||||||
import java.security.cert.CertPath
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A pair of an anonymous party and the certificate path to prove it is owned by a well known identity. This class
|
|
||||||
* does not validate the certificate path matches the party, and should not be trusted without being verified, for example
|
|
||||||
* using [IdentityService.verifyAnonymousIdentity].
|
|
||||||
*
|
|
||||||
* Although similar to [PartyAndCertificate], the two distinct types exist in order to minimise risk of mixing up
|
|
||||||
* confidential and well known identities. In contrast to [PartyAndCertificate] equality tests are based on the anonymous
|
|
||||||
* party's key rather than name, which is the appropriate test for confidential parties but not for well known identities.
|
|
||||||
*/
|
|
||||||
@CordaSerializable
|
|
||||||
data class AnonymousPartyAndPath(
|
|
||||||
val party: AnonymousParty,
|
|
||||||
val certPath: CertPath) {
|
|
||||||
constructor(party: PublicKey, certPath: CertPath)
|
|
||||||
: this(AnonymousParty(party), certPath)
|
|
||||||
init {
|
|
||||||
require(certPath.certificates.isNotEmpty()) { "Certificate path cannot be empty" }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the X.500 name of the certificate for the anonymous party.
|
|
||||||
*
|
|
||||||
* @return the X.500 name if the anonymous party's certificate is an X.509 certificate, or null otherwise.
|
|
||||||
*/
|
|
||||||
val name: X500Name?
|
|
||||||
get() = (certPath.certificates.first() as? X509Certificate)?.subject
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
return if (other is AnonymousPartyAndPath)
|
|
||||||
party == other.party
|
|
||||||
else
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = party.hashCode()
|
|
||||||
}
|
|
@ -30,5 +30,6 @@ class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey)
|
|||||||
override fun toString() = name.toString()
|
override fun toString() = name.toString()
|
||||||
override fun nameOrNull(): X500Name? = name
|
override fun nameOrNull(): X500Name? = name
|
||||||
|
|
||||||
|
fun anonymise(): AnonymousParty = AnonymousParty(owningKey)
|
||||||
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
|
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ import net.corda.core.serialization.CordaSerializable
|
|||||||
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.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of
|
* A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of
|
||||||
* [PartyAndCertificate] instances is based on the party only, as certificate and path are data associated with the party,
|
* [PartyAndCertificate] instances is based on the party only, as certificate and path are data associated with the party,
|
||||||
* not part of the identifier themselves.
|
* not part of the identifier themselves. While party and certificate can both be derived from the certificate path,
|
||||||
|
* this class exists in order to ensure the implementation classes of certificates and party public keys are kept stable.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class PartyAndCertificate(val party: Party,
|
data class PartyAndCertificate(val party: Party,
|
||||||
@ -29,12 +31,19 @@ data class PartyAndCertificate(val party: Party,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int = party.hashCode()
|
override fun hashCode(): Int = party.hashCode()
|
||||||
/**
|
|
||||||
* Convert this party and certificate into an anomymised identity. This exists primarily for example cases which
|
|
||||||
* want to use well known identities as if they're anonymous identities.
|
|
||||||
*/
|
|
||||||
fun toAnonymisedIdentity(): AnonymousPartyAndPath {
|
|
||||||
return AnonymousPartyAndPath(party.owningKey, certPath)
|
|
||||||
}
|
|
||||||
override fun toString(): String = party.toString()
|
override fun toString(): String = party.toString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the given certificate path is valid and leads to the owning key of the party.
|
||||||
|
*/
|
||||||
|
fun verify(trustAnchor: TrustAnchor): PKIXCertPathValidatorResult {
|
||||||
|
require(certPath.certificates.first() is X509Certificate) { "Subject certificate must be an X.509 certificate" }
|
||||||
|
require(Arrays.equals(party.owningKey.encoded, certificate.subjectPublicKeyInfo.encoded)) { "Certificate public key must match party owning key" }
|
||||||
|
require(Arrays.equals(certPath.certificates.first().encoded, certificate.encoded)) { "Certificate path must link to certificate" }
|
||||||
|
|
||||||
|
val validatorParameters = PKIXParameters(setOf(trustAnchor))
|
||||||
|
val validator = CertPathValidator.getInstance("PKIX")
|
||||||
|
validatorParameters.isRevocationEnabled = false
|
||||||
|
return validator.validate(certPath, validatorParameters) as PKIXCertPathValidatorResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,49 +19,23 @@ interface IdentityService {
|
|||||||
val caCertStore: CertStore
|
val caCertStore: CertStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify and then store a well known identity.
|
* Verify and then store an identity.
|
||||||
*
|
*
|
||||||
* @param party a party representing a legal entity.
|
* @param party a party representing a legal entity and the certificate path linking them to the network trust root.
|
||||||
* @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 an anonymous identity.
|
|
||||||
*
|
|
||||||
* @param anonymousIdentity an anonymised identity representing a legal entity in a transaction.
|
|
||||||
* @param party well known party the anonymised party must represent.
|
|
||||||
* @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)
|
|
||||||
@Deprecated("Use verifyAndRegisterAnonymousIdentity() instead, which is the same function with a better name")
|
|
||||||
fun registerAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, party: Party): PartyAndCertificate
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify and then store an anonymous identity.
|
|
||||||
*
|
|
||||||
* @param anonymousIdentity an anonymised identity representing a legal entity in a transaction.
|
|
||||||
* @param wellKnownIdentity well known party the anonymised party must represent.
|
|
||||||
* @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 verifyAndRegisterAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, wellKnownIdentity: Party): PartyAndCertificate
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify an anonymous identity.
|
|
||||||
*
|
|
||||||
* @param anonymousParty a party representing a legal entity in a transaction.
|
|
||||||
* @param party well known party the anonymised party must represent.
|
|
||||||
* @param path certificate path from the trusted root to the party.
|
|
||||||
* @return the full well known identity.
|
|
||||||
* @throws IllegalArgumentException if the certificate path is invalid.
|
* @throws IllegalArgumentException if the certificate path is invalid.
|
||||||
*/
|
*/
|
||||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||||
fun verifyAnonymousIdentity(anonymousIdentity: AnonymousPartyAndPath, party: Party): PartyAndCertificate
|
@Deprecated("Use verifyAndRegisterIdentity() instead, which is the same function with a better name")
|
||||||
|
fun registerIdentity(party: PartyAndCertificate)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify and then store an identity.
|
||||||
|
*
|
||||||
|
* @param identity a party representing a legal entity and the certificate path linking them to the network trust root.
|
||||||
|
* @throws IllegalArgumentException if the certificate path is invalid.
|
||||||
|
*/
|
||||||
|
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||||
|
fun verifyAndRegisterIdentity(identity: PartyAndCertificate)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -78,12 +52,6 @@ interface IdentityService {
|
|||||||
*/
|
*/
|
||||||
fun getAllIdentities(): Iterable<PartyAndCertificate>
|
fun getAllIdentities(): Iterable<PartyAndCertificate>
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the certificate and path for a previously registered anonymous identity. These are used to prove an anonmyous
|
|
||||||
* identity is owned by a well known identity.
|
|
||||||
*/
|
|
||||||
fun anonymousFromKey(owningKey: PublicKey): AnonymousPartyAndPath?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the certificate and path for a well known identity's owning key.
|
* Get the certificate and path for a well known identity's owning key.
|
||||||
*
|
*
|
||||||
@ -133,12 +101,6 @@ interface IdentityService {
|
|||||||
*/
|
*/
|
||||||
fun requirePartyFromAnonymous(party: AbstractParty): Party
|
fun requirePartyFromAnonymous(party: AbstractParty): Party
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the certificate chain showing an anonymous party is owned by the given party.
|
|
||||||
*/
|
|
||||||
@Deprecated("Use anonymousFromKey instead, which provides more detail and takes in a more relevant input", replaceWith = ReplaceWith("anonymousFromKey(anonymousParty.owningKey)"))
|
|
||||||
fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of candidate matches for a given string, with optional fuzzy(ish) matching. Fuzzy matching may
|
* Returns a list of candidate matches for a given string, with optional fuzzy(ish) matching. Fuzzy matching may
|
||||||
* get smarter with time e.g. to correct spelling errors, so you should not hard-code indexes into the results
|
* get smarter with time e.g. to correct spelling errors, so you should not hard-code indexes into the results
|
||||||
|
@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.crypto.SignableData
|
import net.corda.core.crypto.SignableData
|
||||||
import net.corda.core.crypto.TransactionSignature
|
import net.corda.core.crypto.TransactionSignature
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
@ -34,7 +33,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: PartyAndCertificate, revocationEnabled: Boolean): AnonymousPartyAndPath
|
fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter some keys down to the set that this node owns (has private keys for).
|
* Filter some keys down to the set that this node owns (has private keys for).
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
@ -26,32 +26,32 @@ class TransactionKeyFlowTests {
|
|||||||
val bobNode = mockNet.createPartyNode(notaryNode.network.myAddress, BOB.name)
|
val bobNode = mockNet.createPartyNode(notaryNode.network.myAddress, BOB.name)
|
||||||
val alice: Party = aliceNode.services.myInfo.legalIdentity
|
val alice: Party = aliceNode.services.myInfo.legalIdentity
|
||||||
val bob: Party = bobNode.services.myInfo.legalIdentity
|
val bob: Party = bobNode.services.myInfo.legalIdentity
|
||||||
aliceNode.services.identityService.registerIdentity(bobNode.info.legalIdentityAndCert)
|
aliceNode.services.identityService.verifyAndRegisterIdentity(bobNode.info.legalIdentityAndCert)
|
||||||
aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentityAndCert)
|
aliceNode.services.identityService.verifyAndRegisterIdentity(notaryNode.info.legalIdentityAndCert)
|
||||||
bobNode.services.identityService.registerIdentity(aliceNode.info.legalIdentityAndCert)
|
bobNode.services.identityService.verifyAndRegisterIdentity(aliceNode.info.legalIdentityAndCert)
|
||||||
bobNode.services.identityService.registerIdentity(notaryNode.info.legalIdentityAndCert)
|
bobNode.services.identityService.verifyAndRegisterIdentity(notaryNode.info.legalIdentityAndCert)
|
||||||
|
|
||||||
// Run the flows
|
// Run the flows
|
||||||
val requesterFlow = aliceNode.services.startFlow(TransactionKeyFlow(bob))
|
val requesterFlow = aliceNode.services.startFlow(TransactionKeyFlow(bob))
|
||||||
|
|
||||||
// Get the results
|
// Get the results
|
||||||
val actual: Map<Party, AnonymousPartyAndPath> = requesterFlow.resultFuture.getOrThrow().toMap()
|
val actual: Map<Party, AnonymousParty> = requesterFlow.resultFuture.getOrThrow().toMap()
|
||||||
assertEquals(2, actual.size)
|
assertEquals(2, actual.size)
|
||||||
// Verify that the generated anonymous identities do not match the well known identities
|
// Verify that the generated anonymous identities do not match the well known identities
|
||||||
val aliceAnonymousIdentity = actual[alice] ?: throw IllegalStateException()
|
val aliceAnonymousIdentity = actual[alice] ?: throw IllegalStateException()
|
||||||
val bobAnonymousIdentity = actual[bob] ?: throw IllegalStateException()
|
val bobAnonymousIdentity = actual[bob] ?: throw IllegalStateException()
|
||||||
assertNotEquals<AbstractParty>(alice, aliceAnonymousIdentity.party)
|
assertNotEquals<AbstractParty>(alice, aliceAnonymousIdentity)
|
||||||
assertNotEquals<AbstractParty>(bob, bobAnonymousIdentity.party)
|
assertNotEquals<AbstractParty>(bob, bobAnonymousIdentity)
|
||||||
|
|
||||||
// Verify that the anonymous identities look sane
|
// Verify that the anonymous identities look sane
|
||||||
assertEquals(alice.name, aliceAnonymousIdentity.name)
|
assertEquals(alice.name, aliceNode.services.identityService.partyFromAnonymous(aliceAnonymousIdentity)!!.name)
|
||||||
assertEquals(bob.name, bobAnonymousIdentity.name)
|
assertEquals(bob.name, bobNode.services.identityService.partyFromAnonymous(bobAnonymousIdentity)!!.name)
|
||||||
|
|
||||||
// Verify that the nodes have the right anonymous identities
|
// Verify that the nodes have the right anonymous identities
|
||||||
assertTrue { aliceAnonymousIdentity.party.owningKey in aliceNode.services.keyManagementService.keys }
|
assertTrue { aliceAnonymousIdentity.owningKey in aliceNode.services.keyManagementService.keys }
|
||||||
assertTrue { bobAnonymousIdentity.party.owningKey in bobNode.services.keyManagementService.keys }
|
assertTrue { bobAnonymousIdentity.owningKey in bobNode.services.keyManagementService.keys }
|
||||||
assertFalse { aliceAnonymousIdentity.party.owningKey in bobNode.services.keyManagementService.keys }
|
assertFalse { aliceAnonymousIdentity.owningKey in bobNode.services.keyManagementService.keys }
|
||||||
assertFalse { bobAnonymousIdentity.party.owningKey in aliceNode.services.keyManagementService.keys }
|
assertFalse { bobAnonymousIdentity.owningKey in aliceNode.services.keyManagementService.keys }
|
||||||
|
|
||||||
mockNet.stopNodes()
|
mockNet.stopNodes()
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ UNRELEASED
|
|||||||
* Trader demo now issues cash and commercial paper directly from the bank node, rather than the seller node self-issuing
|
* Trader demo now issues cash and commercial paper directly from the bank node, rather than the seller node self-issuing
|
||||||
commercial paper but labelling it as if issued by the bank.
|
commercial paper but labelling it as if issued by the bank.
|
||||||
|
|
||||||
|
* Merged handling of well known and confidential identities in the identity service. Registration now takes in an identity
|
||||||
|
(either type) plus supporting certificate path, and de-anonymisation simply returns the issuing identity where known.
|
||||||
|
If you specifically need well known identities, use the network map, which is the authoritative source of current well
|
||||||
|
known identities.
|
||||||
|
|
||||||
Milestone 14
|
Milestone 14
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ Here are release notes for each snapshot release from M9 onwards.
|
|||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* Merged handling of well known and confidential identities in the identity service.
|
||||||
|
|
||||||
Milestone 14
|
Milestone 14
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import net.corda.core.contracts.issuedBy
|
|||||||
import net.corda.core.flows.FinalityFlow
|
import net.corda.core.flows.FinalityFlow
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.flows.TransactionKeyFlow
|
import net.corda.core.flows.TransactionKeyFlow
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
@ -45,9 +45,9 @@ class CashIssueFlow(val amount: Amount<Currency>,
|
|||||||
val txIdentities = if (anonymous) {
|
val txIdentities = if (anonymous) {
|
||||||
subFlow(TransactionKeyFlow(recipient))
|
subFlow(TransactionKeyFlow(recipient))
|
||||||
} else {
|
} else {
|
||||||
emptyMap<Party, AnonymousPartyAndPath>()
|
emptyMap<Party, AnonymousParty>()
|
||||||
}
|
}
|
||||||
val anonymousRecipient = txIdentities[recipient]?.party ?: recipient
|
val anonymousRecipient = txIdentities[recipient] ?: recipient
|
||||||
progressTracker.currentStep = GENERATING_TX
|
progressTracker.currentStep = GENERATING_TX
|
||||||
val builder: TransactionBuilder = TransactionBuilder(notary)
|
val builder: TransactionBuilder = TransactionBuilder(notary)
|
||||||
val issuer = serviceHub.myInfo.legalIdentity.ref(issueRef)
|
val issuer = serviceHub.myInfo.legalIdentity.ref(issueRef)
|
||||||
|
@ -6,7 +6,7 @@ import net.corda.core.contracts.Amount
|
|||||||
import net.corda.core.contracts.InsufficientBalanceException
|
import net.corda.core.contracts.InsufficientBalanceException
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.flows.TransactionKeyFlow
|
import net.corda.core.flows.TransactionKeyFlow
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -39,9 +39,9 @@ open class CashPaymentFlow(
|
|||||||
val txIdentities = if (anonymous) {
|
val txIdentities = if (anonymous) {
|
||||||
subFlow(TransactionKeyFlow(recipient))
|
subFlow(TransactionKeyFlow(recipient))
|
||||||
} else {
|
} else {
|
||||||
emptyMap<Party, AnonymousPartyAndPath>()
|
emptyMap<Party, AnonymousParty>()
|
||||||
}
|
}
|
||||||
val anonymousRecipient = txIdentities.get(recipient)?.party ?: recipient
|
val anonymousRecipient = txIdentities.get(recipient) ?: recipient
|
||||||
progressTracker.currentStep = GENERATING_TX
|
progressTracker.currentStep = GENERATING_TX
|
||||||
val builder: TransactionBuilder = TransactionBuilder(null as Party?)
|
val builder: TransactionBuilder = TransactionBuilder(null as Party?)
|
||||||
// TODO: Have some way of restricting this to states the caller controls
|
// TODO: Have some way of restricting this to states the caller controls
|
||||||
|
@ -6,7 +6,7 @@ import net.corda.core.contracts.UpgradeCommand
|
|||||||
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.flows.*
|
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.identity.Party
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -87,9 +87,8 @@ class TransactionKeyHandler(val otherSide: Party, val revocationEnabled: Boolean
|
|||||||
val revocationEnabled = false
|
val revocationEnabled = false
|
||||||
progressTracker.currentStep = SENDING_KEY
|
progressTracker.currentStep = SENDING_KEY
|
||||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled)
|
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled)
|
||||||
val otherSideAnonymous = sendAndReceive<AnonymousPartyAndPath>(otherSide, legalIdentityAnonymous).unwrap { TransactionKeyFlow.validateIdentity(otherSide, it) }
|
sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->
|
||||||
// Validate then store their identity so that we can prove the key in the transaction is owned by the
|
TransactionKeyFlow.validateAndRegisterIdentity(serviceHub.identityService, otherSide, confidentialIdentity)
|
||||||
// counterparty.
|
}
|
||||||
serviceHub.identityService.registerAnonymousIdentity(otherSideAnonymous, otherSide)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,12 @@
|
|||||||
package net.corda.node.services.identity
|
package net.corda.node.services.identity
|
||||||
|
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.crypto.Crypto
|
|
||||||
import net.corda.core.crypto.cert
|
import net.corda.core.crypto.cert
|
||||||
import net.corda.core.crypto.subject
|
|
||||||
import net.corda.core.crypto.toStringShort
|
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.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
|
||||||
@ -28,12 +29,12 @@ import kotlin.collections.LinkedHashSet
|
|||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
|
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
|
||||||
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
|
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||||
override val trustRoot: X509Certificate,
|
override val trustRoot: X509Certificate,
|
||||||
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
|
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
|
||||||
constructor(identities: Iterable<PartyAndCertificate> = emptySet(),
|
constructor(wellKnownIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||||
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
|
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||||
trustRoot: X509CertificateHolder) : this(identities, certPaths, trustRoot.cert)
|
trustRoot: X509CertificateHolder) : this(wellKnownIdentities, confidentialIdentities, trustRoot.cert)
|
||||||
companion object {
|
companion object {
|
||||||
private val log = loggerFor<InMemoryIdentityService>()
|
private val log = loggerFor<InMemoryIdentityService>()
|
||||||
}
|
}
|
||||||
@ -45,41 +46,44 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
|
|||||||
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
|
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
|
||||||
private val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
|
private val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
|
||||||
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
||||||
|
private val keyToIssuingParty = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
||||||
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
|
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
|
||||||
private val partyToPath = ConcurrentHashMap<AbstractParty, Pair<CertPath, X509CertificateHolder>>()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val caCertificatesWithRoot: Set<X509Certificate> = caCertificates.toSet() + trustRoot
|
val caCertificatesWithRoot: Set<X509Certificate> = caCertificates.toSet() + trustRoot
|
||||||
caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(caCertificatesWithRoot))
|
caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(caCertificatesWithRoot))
|
||||||
keyToParties.putAll(identities.associateBy { it.owningKey } )
|
keyToParties.putAll(identities.associateBy { it.owningKey } )
|
||||||
principalToParties.putAll(identities.associateBy { it.name })
|
principalToParties.putAll(identities.associateBy { it.name })
|
||||||
certPaths.forEach { (party, path) ->
|
confidentialIdentities.forEach { identity ->
|
||||||
partyToPath.put(party, Pair(path, X509CertificateHolder(path.certificates.first().encoded)))
|
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
|
// TODO: Check the certificate validation logic
|
||||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||||
override fun registerIdentity(party: PartyAndCertificate) {
|
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate) {
|
||||||
require(party.certPath.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
|
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
|
// Validate the chain first, before we do anything clever with it
|
||||||
validateCertificatePath(party.party, party.certPath)
|
identity.verify(trustAnchor)
|
||||||
|
|
||||||
log.trace { "Registering identity $party" }
|
log.trace { "Registering identity $identity" }
|
||||||
require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" }
|
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[identity.owningKey] = identity
|
||||||
keyToParties[party.owningKey] = party
|
// TODO: This map should only be deanonymised parties, not all issuers, but we have no good way of checking for
|
||||||
principalToParties[party.name] = party
|
// confidential vs anonymous identities
|
||||||
}
|
val issuer = keyToParties[identity.certPath.certificates[1].publicKey]
|
||||||
|
if (issuer != null) {
|
||||||
override fun anonymousFromKey(owningKey: PublicKey): AnonymousPartyAndPath? {
|
keyToIssuingParty[identity.owningKey] = issuer
|
||||||
val anonymousParty = AnonymousParty(owningKey)
|
|
||||||
val path = partyToPath[anonymousParty]
|
|
||||||
return path?.let { it ->
|
|
||||||
AnonymousPartyAndPath(anonymousParty, it.first)
|
|
||||||
}
|
}
|
||||||
|
// 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 certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[owningKey]
|
||||||
override fun certificateFromParty(party: Party): PartyAndCertificate? = principalToParties[party.name]
|
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 partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party
|
||||||
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.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 partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
||||||
override fun requirePartyFromAnonymous(party: AbstractParty): Party {
|
override fun requirePartyFromAnonymous(party: AbstractParty): Party {
|
||||||
return partyFromAnonymous(party) ?: throw IllegalStateException("Could not deanonymise party ${party.owningKey.toStringShort()}")
|
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)
|
@Throws(IdentityService.UnknownAnonymousPartyException::class)
|
||||||
override fun assertOwnership(party: Party, anonymousParty: AnonymousParty) {
|
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" }
|
require(path.certificates.size > 1) { "Certificate path must contain at least two certificates" }
|
||||||
val actual = path.certificates[1]
|
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()}." }
|
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()
|
val target = path.certificates.first()
|
||||||
require(target is X509Certificate && target.publicKey == anonymousParty.owningKey) { "Certificate path starts with a certificate for the anonymous party" }
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.node.services.keys
|
package net.corda.node.services.keys
|
||||||
|
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
@ -53,7 +52,7 @@ class E2ETestKeyManagementService(val identityService: IdentityService,
|
|||||||
return keyPair.public
|
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)
|
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package net.corda.node.services.keys
|
|||||||
import net.corda.core.crypto.ContentSignerBuilder
|
import net.corda.core.crypto.ContentSignerBuilder
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.cert
|
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.identity.PartyAndCertificate
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
@ -32,15 +32,14 @@ fun freshCertificate(identityService: IdentityService,
|
|||||||
subjectPublicKey: PublicKey,
|
subjectPublicKey: PublicKey,
|
||||||
issuer: PartyAndCertificate,
|
issuer: PartyAndCertificate,
|
||||||
issuerSigner: ContentSigner,
|
issuerSigner: ContentSigner,
|
||||||
revocationEnabled: Boolean = false): AnonymousPartyAndPath {
|
revocationEnabled: Boolean = false): PartyAndCertificate {
|
||||||
val issuerCertificate = issuer.certificate
|
val issuerCertificate = issuer.certificate
|
||||||
val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCertificate)
|
val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCertificate)
|
||||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window)
|
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window)
|
||||||
val certFactory = CertificateFactory.getInstance("X509")
|
val certFactory = CertificateFactory.getInstance("X509")
|
||||||
val ourCertPath = certFactory.generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates)
|
val ourCertPath = certFactory.generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates)
|
||||||
val anonymisedIdentity = AnonymousPartyAndPath(subjectPublicKey, ourCertPath)
|
val anonymisedIdentity = PartyAndCertificate(Party(issuer.name, subjectPublicKey), ourCertificate, ourCertPath)
|
||||||
identityService.verifyAndRegisterAnonymousIdentity(anonymisedIdentity,
|
identityService.verifyAndRegisterIdentity(anonymisedIdentity)
|
||||||
issuer.party)
|
|
||||||
return anonymisedIdentity
|
return anonymisedIdentity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
package net.corda.node.services.keys
|
package net.corda.node.services.keys
|
||||||
|
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
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.IdentityService
|
||||||
import net.corda.core.node.services.KeyManagementService
|
import net.corda.core.node.services.KeyManagementService
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
import net.corda.node.utilities.*
|
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 org.bouncycastle.operator.ContentSigner
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
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.
|
* A persistent re-implementation of [E2ETestKeyManagementService] to support node re-start.
|
||||||
@ -71,7 +76,7 @@ class PersistentKeyManagementService(val identityService: IdentityService,
|
|||||||
return keyPair.public
|
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)
|
freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||||
|
|
||||||
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
|
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
|
||||||
|
@ -2,11 +2,11 @@ package net.corda.node.messaging
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.contracts.CommercialPaper
|
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.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.contracts.asset.`issued by`
|
import net.corda.contracts.asset.`issued by`
|
||||||
import net.corda.contracts.asset.`owned by`
|
import net.corda.contracts.asset.`owned by`
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.flows.FlowLogic
|
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.flows.StateMachineRunId
|
||||||
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.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
import net.corda.core.internal.concurrent.map
|
import net.corda.core.internal.concurrent.map
|
||||||
@ -521,7 +520,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
assetToSell: StateAndRef<OwnableState>): RunResult {
|
assetToSell: StateAndRef<OwnableState>): RunResult {
|
||||||
val anonymousSeller = sellerNode.services.let { serviceHub ->
|
val anonymousSeller = sellerNode.services.let { serviceHub ->
|
||||||
serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, false)
|
serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, false)
|
||||||
}
|
}.party.anonymise()
|
||||||
val buyerFlows: Observable<BuyerAcceptor> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
|
val buyerFlows: Observable<BuyerAcceptor> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
|
||||||
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
|
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
|
||||||
val seller = SellerInitiator(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, anonymousSeller)
|
val seller = SellerInitiator(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, anonymousSeller)
|
||||||
@ -534,7 +533,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
val notary: NodeInfo,
|
val notary: NodeInfo,
|
||||||
val assetToSell: StateAndRef<OwnableState>,
|
val assetToSell: StateAndRef<OwnableState>,
|
||||||
val price: Amount<Currency>,
|
val price: Amount<Currency>,
|
||||||
val me: AnonymousPartyAndPath) : FlowLogic<SignedTransaction>() {
|
val me: AnonymousParty) : FlowLogic<SignedTransaction>() {
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): SignedTransaction {
|
override fun call(): SignedTransaction {
|
||||||
send(buyer, Pair(notary.notaryIdentity, price))
|
send(buyer, Pair(notary.notaryIdentity, price))
|
||||||
@ -543,7 +542,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
notary,
|
notary,
|
||||||
assetToSell,
|
assetToSell,
|
||||||
price,
|
price,
|
||||||
me.party))
|
me))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import net.corda.core.crypto.Crypto
|
|||||||
import net.corda.core.crypto.cert
|
import net.corda.core.crypto.cert
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
@ -30,13 +29,13 @@ class InMemoryIdentityServiceTests {
|
|||||||
// Nothing registered, so empty set
|
// Nothing registered, so empty set
|
||||||
assertNull(service.getAllIdentities().firstOrNull())
|
assertNull(service.getAllIdentities().firstOrNull())
|
||||||
|
|
||||||
service.registerIdentity(ALICE_IDENTITY)
|
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||||
var expected = setOf(ALICE)
|
var expected = setOf(ALICE)
|
||||||
var actual = service.getAllIdentities().map { it.party }.toHashSet()
|
var actual = service.getAllIdentities().map { it.party }.toHashSet()
|
||||||
assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
|
|
||||||
// Add a second party and check we get both back
|
// Add a second party and check we get both back
|
||||||
service.registerIdentity(BOB_IDENTITY)
|
service.verifyAndRegisterIdentity(BOB_IDENTITY)
|
||||||
expected = setOf(ALICE, BOB)
|
expected = setOf(ALICE, BOB)
|
||||||
actual = service.getAllIdentities().map { it.party }.toHashSet()
|
actual = service.getAllIdentities().map { it.party }.toHashSet()
|
||||||
assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
@ -46,7 +45,7 @@ class InMemoryIdentityServiceTests {
|
|||||||
fun `get identity by key`() {
|
fun `get identity by key`() {
|
||||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||||
assertNull(service.partyFromKey(ALICE_PUBKEY))
|
assertNull(service.partyFromKey(ALICE_PUBKEY))
|
||||||
service.registerIdentity(ALICE_IDENTITY)
|
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||||
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
|
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
|
||||||
assertNull(service.partyFromKey(BOB_PUBKEY))
|
assertNull(service.partyFromKey(BOB_PUBKEY))
|
||||||
}
|
}
|
||||||
@ -61,10 +60,10 @@ class InMemoryIdentityServiceTests {
|
|||||||
fun `get identity by substring match`() {
|
fun `get identity by substring match`() {
|
||||||
val trustRoot = DUMMY_CA
|
val trustRoot = DUMMY_CA
|
||||||
val service = InMemoryIdentityService(trustRoot = trustRoot.certificate)
|
val service = InMemoryIdentityService(trustRoot = trustRoot.certificate)
|
||||||
service.registerIdentity(ALICE_IDENTITY)
|
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||||
service.registerIdentity(BOB_IDENTITY)
|
service.verifyAndRegisterIdentity(BOB_IDENTITY)
|
||||||
val alicente = getTestPartyAndCertificate(X500Name("O=Alicente Worldwide,L=London,C=GB"), generateKeyPair().public)
|
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, alicente.party), service.partiesFromName("Alice", false))
|
||||||
assertEquals(setOf(ALICE), service.partiesFromName("Alice Corp", true))
|
assertEquals(setOf(ALICE), service.partiesFromName("Alice Corp", true))
|
||||||
assertEquals(setOf(BOB), service.partiesFromName("Bob Plc", true))
|
assertEquals(setOf(BOB), service.partiesFromName("Bob Plc", true))
|
||||||
@ -76,7 +75,7 @@ class InMemoryIdentityServiceTests {
|
|||||||
val identities = listOf("Node A", "Node B", "Node C")
|
val identities = listOf("Node A", "Node B", "Node C")
|
||||||
.map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=GB"), generateKeyPair().public) }
|
.map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=GB"), generateKeyPair().public) }
|
||||||
assertNull(service.partyFromX500Name(identities.first().name))
|
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)) }
|
identities.forEach { assertEquals(it.party, service.partyFromX500Name(it.name)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,15 +110,15 @@ class InMemoryIdentityServiceTests {
|
|||||||
val (bob, bobTxIdentity) = createParty(ALICE.name, trustRoot)
|
val (bob, bobTxIdentity) = createParty(ALICE.name, trustRoot)
|
||||||
|
|
||||||
// Now we have identities, construct the service and let it know about both
|
// Now we have identities, construct the service and let it know about both
|
||||||
val service = InMemoryIdentityService(setOf(alice), emptyMap(), trustRoot.certificate.cert)
|
val service = InMemoryIdentityService(setOf(alice), emptySet(), trustRoot.certificate.cert)
|
||||||
service.verifyAndRegisterAnonymousIdentity(aliceTxIdentity, alice.party)
|
service.verifyAndRegisterIdentity(aliceTxIdentity)
|
||||||
|
|
||||||
var actual = service.anonymousFromKey(aliceTxIdentity.party.owningKey)
|
var actual = service.certificateFromKey(aliceTxIdentity.party.owningKey)
|
||||||
assertEquals(aliceTxIdentity, actual!!)
|
assertEquals(aliceTxIdentity, actual!!)
|
||||||
|
|
||||||
assertNull(service.anonymousFromKey(bobTxIdentity.party.owningKey))
|
assertNull(service.certificateFromKey(bobTxIdentity.party.owningKey))
|
||||||
service.verifyAndRegisterAnonymousIdentity(bobTxIdentity, bob.party)
|
service.verifyAndRegisterIdentity(bobTxIdentity)
|
||||||
actual = service.anonymousFromKey(bobTxIdentity.party.owningKey)
|
actual = service.certificateFromKey(bobTxIdentity.party.owningKey)
|
||||||
assertEquals(bobTxIdentity, actual!!)
|
assertEquals(bobTxIdentity, actual!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,36 +134,36 @@ class InMemoryIdentityServiceTests {
|
|||||||
val (bob, anonymousBob) = createParty(BOB.name, trustRoot)
|
val (bob, anonymousBob) = createParty(BOB.name, trustRoot)
|
||||||
|
|
||||||
// Now we have identities, construct the service and let it know about both
|
// 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.verifyAndRegisterIdentity(anonymousAlice)
|
||||||
service.verifyAndRegisterAnonymousIdentity(anonymousBob, bob.party)
|
service.verifyAndRegisterIdentity(anonymousBob)
|
||||||
|
|
||||||
// Verify that paths are verified
|
// Verify that paths are verified
|
||||||
service.assertOwnership(alice.party, anonymousAlice.party)
|
service.assertOwnership(alice.party, anonymousAlice.party.anonymise())
|
||||||
service.assertOwnership(bob.party, anonymousBob.party)
|
service.assertOwnership(bob.party, anonymousBob.party.anonymise())
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
service.assertOwnership(alice.party, anonymousBob.party)
|
service.assertOwnership(alice.party, anonymousBob.party.anonymise())
|
||||||
}
|
}
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
service.assertOwnership(bob.party, anonymousAlice.party)
|
service.assertOwnership(bob.party, anonymousAlice.party.anonymise())
|
||||||
}
|
}
|
||||||
|
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
val owningKey = Crypto.decodePublicKey(trustRoot.certificate.subjectPublicKeyInfo.encoded)
|
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 certFactory = CertificateFactory.getInstance("X509")
|
||||||
val issuerKeyPair = generateKeyPair()
|
val issuerKeyPair = generateKeyPair()
|
||||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
|
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
|
||||||
val txKey = Crypto.generateKeyPair()
|
val txKey = Crypto.generateKeyPair()
|
||||||
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public)
|
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public)
|
||||||
val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates)
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +89,7 @@ class FlowFrameworkTests {
|
|||||||
val nodes = listOf(node1, node2, notary1, notary2)
|
val nodes = listOf(node1, node2, notary1, notary2)
|
||||||
nodes.forEach { node ->
|
nodes.forEach { node ->
|
||||||
nodes.map { it.services.myInfo.legalIdentityAndCert }.forEach { identity ->
|
nodes.map { it.services.myInfo.legalIdentityAndCert }.forEach { identity ->
|
||||||
node.services.identityService.registerIdentity(identity)
|
node.services.identityService.verifyAndRegisterIdentity(identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ 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_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_NOTARY_IDENTITY)
|
val MOCK_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_NOTARY_IDENTITY)
|
||||||
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(MOCK_IDENTITIES, emptyMap(), DUMMY_CA.certificate.cert)
|
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(MOCK_IDENTITIES, emptySet(), DUMMY_CA.certificate.cert)
|
||||||
|
|
||||||
val MOCK_HOST_AND_PORT = NetworkHostAndPort("mockHost", 30000)
|
val MOCK_HOST_AND_PORT = NetworkHostAndPort("mockHost", 30000)
|
||||||
|
|
||||||
|
@ -356,7 +356,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
nodes += createPartyNode(mapAddress)
|
nodes += createPartyNode(mapAddress)
|
||||||
}
|
}
|
||||||
nodes.forEach { itNode ->
|
nodes.forEach { itNode ->
|
||||||
nodes.map { it.info.legalIdentityAndCert }.forEach(itNode.services.identityService::registerIdentity)
|
nodes.map { it.info.legalIdentityAndCert }.forEach(itNode.services.identityService::verifyAndRegisterIdentity)
|
||||||
}
|
}
|
||||||
return BasketOfNodes(nodes, notaryNode, mapNode)
|
return BasketOfNodes(nodes, notaryNode, mapNode)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ 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.AnonymousPartyAndPath
|
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
@ -115,7 +114,7 @@ class MockKeyManagementService(val identityService: IdentityService,
|
|||||||
|
|
||||||
override fun filterMyKeys(candidateKeys: Iterable<PublicKey>): Iterable<PublicKey> = candidateKeys.filter { it in this.keys }
|
override fun filterMyKeys(candidateKeys: Iterable<PublicKey>): Iterable<PublicKey> = candidateKeys.filter { it in this.keys }
|
||||||
|
|
||||||
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)
|
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user