mirror of
https://github.com/corda/corda.git
synced 2024-12-20 21:43:14 +00:00
Correct identity service tests
* Correct path composition in identity service tests * Correct identity service certificate path verification to handle the owning certificate being anywhere in the path, rather than expecting it to be trust root
This commit is contained in:
parent
56ad64c524
commit
b874b3e62a
@ -295,5 +295,6 @@ enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurpo
|
||||
INTERMEDIATE_CA(KeyUsage(KeyUsage.digitalSignature or KeyUsage.keyCertSign or KeyUsage.cRLSign), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = true),
|
||||
CLIENT_CA(KeyUsage(KeyUsage.digitalSignature or KeyUsage.keyCertSign or KeyUsage.cRLSign), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = true),
|
||||
TLS(KeyUsage(KeyUsage.digitalSignature or KeyUsage.keyEncipherment or KeyUsage.keyAgreement), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = false),
|
||||
IDENTITY(KeyUsage(KeyUsage.digitalSignature), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = false)
|
||||
// TODO: Identity certs should have only limited depth (i.e. 1) CA signing capability, with tight name constraints
|
||||
IDENTITY(KeyUsage(KeyUsage.digitalSignature or KeyUsage.keyCertSign), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = true)
|
||||
}
|
@ -69,8 +69,8 @@ val DUMMY_CA: CertificateAndKeyPair by lazy {
|
||||
/**
|
||||
* Build a test party with a nonsense certificate authority for testing purposes.
|
||||
*/
|
||||
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey): PartyAndCertificate {
|
||||
val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, DUMMY_CA.certificate, DUMMY_CA.keyPair, name, publicKey)
|
||||
val certPath = X509Utilities.createCertificatePath(DUMMY_CA.certificate, cert, revocationEnabled = false)
|
||||
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey, ca: CertificateAndKeyPair = DUMMY_CA): PartyAndCertificate {
|
||||
val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, ca.certificate, ca.keyPair, name, publicKey)
|
||||
val certPath = X509Utilities.createCertificatePath(ca.certificate, cert, revocationEnabled = false)
|
||||
return PartyAndCertificate(name, publicKey, cert, certPath)
|
||||
}
|
||||
|
@ -117,14 +117,12 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate>,
|
||||
@Throws(IdentityService.UnknownAnonymousPartyException::class)
|
||||
override fun assertOwnership(party: Party, anonymousParty: AnonymousParty) {
|
||||
val path = partyToPath[anonymousParty] ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}")
|
||||
val target = path.certificates.last() as X509Certificate
|
||||
requireThat {
|
||||
"Certificate path ends with \"${target.issuerX500Principal}\" expected \"${party.name}\"" using (X500Name(target.subjectX500Principal.name) == party.name)
|
||||
"Certificate path ends with correct public key" using (target.publicKey == anonymousParty.owningKey)
|
||||
}
|
||||
val root: X509Certificate = path.certificates
|
||||
.filterIsInstance<X509Certificate>()
|
||||
.lastOrNull { it.publicKey == party.owningKey } ?: throw IllegalArgumentException("Certificate path must include a certificate for the party public key.")
|
||||
// Verify there's a previous certificate in the path, which matches
|
||||
val root = path.certificates.first() as X509Certificate
|
||||
require(X500Name(root.issuerX500Principal.name) == party.name) { "Certificate path starts with \"${root.issuerX500Principal}\" expected \"${party.name}\"" }
|
||||
val target = path.certificates.first() as X509Certificate
|
||||
require(target.publicKey == anonymousParty.owningKey) { "Certificate path starts with a certificate for the anonymous party" }
|
||||
}
|
||||
|
||||
override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty]
|
||||
|
@ -6,14 +6,13 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.flows.TxKeyFlow
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.testing.ALICE_PUBKEY
|
||||
import net.corda.testing.BOB_PUBKEY
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.security.cert.CertificateFactory
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNull
|
||||
@ -57,10 +56,11 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by substring match`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
val trustRoot = DUMMY_CA
|
||||
val service = InMemoryIdentityService(trustRoot = trustRoot.certificate)
|
||||
service.registerIdentity(ALICE_IDENTITY)
|
||||
service.registerIdentity(BOB_IDENTITY)
|
||||
val (_, _, alicente) = createParty(X500Name("O=Alicente Worldwide,L=London,C=UK"))
|
||||
val alicente = getTestPartyAndCertificate(X500Name("O=Alicente Worldwide,L=London,C=UK"), generateKeyPair().public)
|
||||
service.registerIdentity(alicente)
|
||||
assertEquals(setOf(ALICE, alicente.party), service.partiesFromName("Alice", false))
|
||||
assertEquals(setOf(ALICE), service.partiesFromName("Alice Corp", true))
|
||||
@ -101,41 +101,44 @@ class InMemoryIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `assert ownership`() {
|
||||
val (aliceTxKey, aliceCertPath, alice) = createParty(ALICE.name)
|
||||
val trustRoot = DUMMY_CA
|
||||
val (alice, aliceTxIdentity) = createParty(ALICE.name, trustRoot)
|
||||
|
||||
val certFactory = CertificateFactory.getInstance("X509")
|
||||
val bobRootKey = Crypto.generateKeyPair()
|
||||
val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey)
|
||||
val bobRoot = getTestPartyAndCertificate(BOB.name, bobRootKey.public)
|
||||
val bobRootCert = bobRoot.certificate
|
||||
val bobTxKey = Crypto.generateKeyPair()
|
||||
val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
|
||||
val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false)
|
||||
val bobCertPath = certFactory.generateCertPath(listOf(bobTxCert.cert, bobRootCert.cert))
|
||||
val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath)
|
||||
|
||||
// Now we have identities, construct the service and let it know about both
|
||||
val service = InMemoryIdentityService(setOf(alice, bob), emptyMap(), null as X509Certificate?)
|
||||
val anonymousAlice = AnonymousParty(aliceTxKey.public)
|
||||
service.registerAnonymousIdentity(anonymousAlice, alice.party, aliceCertPath)
|
||||
val service = InMemoryIdentityService(setOf(alice, bob), emptyMap(), trustRoot.certificate.cert)
|
||||
service.registerAnonymousIdentity(aliceTxIdentity.identity, alice.party, aliceTxIdentity.certPath)
|
||||
|
||||
val anonymousBob = AnonymousParty(bobTxKey.public)
|
||||
service.registerAnonymousIdentity(anonymousBob, bob.party, bobCertPath)
|
||||
|
||||
// Verify that paths are verified
|
||||
service.assertOwnership(alice.party, anonymousAlice)
|
||||
service.assertOwnership(alice.party, aliceTxIdentity.identity)
|
||||
service.assertOwnership(bob.party, anonymousBob)
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
service.assertOwnership(alice.party, anonymousBob)
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
service.assertOwnership(bob.party, anonymousAlice)
|
||||
service.assertOwnership(bob.party, aliceTxIdentity.identity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createParty(x500Name: X500Name): Triple<KeyPair, CertPath, PartyAndCertificate> {
|
||||
val rootKey = Crypto.generateKeyPair()
|
||||
val rootCert = X509Utilities.createSelfSignedCACertificate(x500Name, rootKey)
|
||||
private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, TxKeyFlow.AnonymousIdentity> {
|
||||
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, rootCert, rootKey, x500Name, txKey.public)
|
||||
val certPath = X509Utilities.createCertificatePath(rootCert, txCert, revocationEnabled = false)
|
||||
return Triple(txKey, certPath, PartyAndCertificate(x500Name, rootKey.public, rootCert, certPath))
|
||||
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, TxKeyFlow.AnonymousIdentity(txCertPath, txCert, AnonymousParty(txKey.public)))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,7 +147,7 @@ class InMemoryIdentityServiceTests {
|
||||
@Test
|
||||
fun `deanonymising a well known identity`() {
|
||||
val expected = ALICE
|
||||
val actual = InMemoryIdentityService(trustRoot = null).partyFromAnonymous(expected)
|
||||
val actual = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate).partyFromAnonymous(expected)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user