Correct behaviour of anonymousToParty()

Correct behaviour of anonymousToParty() in identity API; it previously presumed any Party was a well known
identity, now it tries to look up the well known identity irrespective of whether it's been given a full
party or not.
This commit is contained in:
Ross Nicoll
2017-08-15 14:52:39 +01:00
parent ce0f931716
commit 1a44f98379
3 changed files with 29 additions and 18 deletions

View File

@ -16,6 +16,7 @@ import java.security.cert.*
interface IdentityService {
val trustRoot: X509Certificate
val trustRootHolder: X509CertificateHolder
val trustAnchor: TrustAnchor
val caCertStore: CertStore
/**
@ -31,11 +32,12 @@ interface IdentityService {
/**
* 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.
* @param identity a party and the certificate path linking them to the network trust root.
* @return the issuing entity, if known.
* @throws IllegalArgumentException if the certificate path is invalid.
*/
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
fun verifyAndRegisterIdentity(identity: PartyAndCertificate)
fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate?
/**
* Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with
@ -62,9 +64,11 @@ interface IdentityService {
/**
* Get the certificate and path for a well known identity.
*
* @return the party and certificate, or null if unknown.
* @return the party and certificate.
* @throws IllegalArgumentException if the certificate and path are unknown. This should never happen for a well
* known identity.
*/
fun certificateFromParty(party: Party): PartyAndCertificate?
fun certificateFromParty(party: Party): PartyAndCertificate
// There is no method for removing identities, as once we are made aware of a Party we want to keep track of them
// indefinitely. It may be that in the long term we need to drop or archive very old Party information for space,

View File

@ -44,9 +44,8 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
*/
override val caCertStore: CertStore
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
private val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
private val keyToIssuingParty = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
init {
@ -56,16 +55,17 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
principalToParties.putAll(identities.associateBy { it.name })
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)
override fun registerIdentity(party: PartyAndCertificate) {
verifyAndRegisterIdentity(party)
}
// TODO: Check the certificate validation logic
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate) {
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): 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
identity.verify(trustAnchor)
@ -74,25 +74,32 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
require(Arrays.equals(identity.certificate.subjectPublicKeyInfo.encoded, identity.owningKey.encoded)) { "Party certificate must end with party's public key" }
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 }
return keyToParties[identity.certPath.certificates[1].publicKey]
}
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] ?: throw IllegalArgumentException("Unknown identity ${party.name}")
// We give the caller a copy of the data set to avoid any locking problems
override fun getAllIdentities(): Iterable<PartyAndCertificate> = java.util.ArrayList(keyToParties.values)
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 ?: keyToIssuingParty[party.owningKey]?.party
override fun partyFromAnonymous(party: AbstractParty): Party? {
// Expand the anonymous party to a full party (i.e. has a name) if possible
val candidate = party as? Party ?: keyToParties[party.owningKey]?.party
// TODO: This should be done via the network map cache, which is the authoritative source of well known identities
// Look up the well known identity for that name
return if (candidate != null) {
// If we have a well known identity by that name, use it in preference to the candidate. Otherwise default
// back to the candidate.
principalToParties[candidate.name]?.party ?: candidate
} else {
null
}
}
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()}")

View File

@ -356,7 +356,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
nodes += createPartyNode(mapAddress)
}
nodes.forEach { itNode ->
nodes.map { it.info.legalIdentityAndCert }.forEach(itNode.services.identityService::verifyAndRegisterIdentity)
nodes.map { it.info.legalIdentityAndCert }.map(itNode.services.identityService::verifyAndRegisterIdentity)
}
return BasketOfNodes(nodes, notaryNode, mapNode)
}