mirror of
https://github.com/corda/corda.git
synced 2024-12-30 01:39:04 +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),
|
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),
|
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),
|
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.
|
* Build a test party with a nonsense certificate authority for testing purposes.
|
||||||
*/
|
*/
|
||||||
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey): PartyAndCertificate {
|
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey, ca: CertificateAndKeyPair = DUMMY_CA): PartyAndCertificate {
|
||||||
val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, DUMMY_CA.certificate, DUMMY_CA.keyPair, name, publicKey)
|
val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, ca.certificate, ca.keyPair, name, publicKey)
|
||||||
val certPath = X509Utilities.createCertificatePath(DUMMY_CA.certificate, cert, revocationEnabled = false)
|
val certPath = X509Utilities.createCertificatePath(ca.certificate, cert, revocationEnabled = false)
|
||||||
return PartyAndCertificate(name, publicKey, cert, certPath)
|
return PartyAndCertificate(name, publicKey, cert, certPath)
|
||||||
}
|
}
|
||||||
|
@ -117,14 +117,12 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate>,
|
|||||||
@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] ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}")
|
val path = partyToPath[anonymousParty] ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}")
|
||||||
val target = path.certificates.last() as X509Certificate
|
val root: X509Certificate = path.certificates
|
||||||
requireThat {
|
.filterIsInstance<X509Certificate>()
|
||||||
"Certificate path ends with \"${target.issuerX500Principal}\" expected \"${party.name}\"" using (X500Name(target.subjectX500Principal.name) == party.name)
|
.lastOrNull { it.publicKey == party.owningKey } ?: throw IllegalArgumentException("Certificate path must include a certificate for the party public key.")
|
||||||
"Certificate path ends with correct public key" using (target.publicKey == anonymousParty.owningKey)
|
|
||||||
}
|
|
||||||
// Verify there's a previous certificate in the path, which matches
|
// Verify there's a previous certificate in the path, which matches
|
||||||
val root = path.certificates.first() as X509Certificate
|
val target = path.certificates.first() as X509Certificate
|
||||||
require(X500Name(root.issuerX500Principal.name) == party.name) { "Certificate path starts with \"${root.issuerX500Principal}\" expected \"${party.name}\"" }
|
require(target.publicKey == anonymousParty.owningKey) { "Certificate path starts with a certificate for the anonymous party" }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty]
|
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.identity.PartyAndCertificate
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
|
import net.corda.flows.TxKeyFlow
|
||||||
import net.corda.node.services.identity.InMemoryIdentityService
|
import net.corda.node.services.identity.InMemoryIdentityService
|
||||||
import net.corda.testing.ALICE_PUBKEY
|
import net.corda.testing.ALICE_PUBKEY
|
||||||
import net.corda.testing.BOB_PUBKEY
|
import net.corda.testing.BOB_PUBKEY
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.KeyPair
|
import java.security.cert.CertificateFactory
|
||||||
import java.security.cert.CertPath
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
@ -57,10 +56,11 @@ class InMemoryIdentityServiceTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get identity by substring match`() {
|
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(ALICE_IDENTITY)
|
||||||
service.registerIdentity(BOB_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)
|
service.registerIdentity(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))
|
||||||
@ -101,41 +101,44 @@ class InMemoryIdentityServiceTests {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `assert ownership`() {
|
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 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 bobTxKey = Crypto.generateKeyPair()
|
||||||
val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
|
val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
|
||||||
val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false)
|
val bobCertPath = certFactory.generateCertPath(listOf(bobTxCert.cert, bobRootCert.cert))
|
||||||
val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath)
|
val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath)
|
||||||
|
|
||||||
// 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(), null as X509Certificate?)
|
val service = InMemoryIdentityService(setOf(alice, bob), emptyMap(), trustRoot.certificate.cert)
|
||||||
val anonymousAlice = AnonymousParty(aliceTxKey.public)
|
service.registerAnonymousIdentity(aliceTxIdentity.identity, alice.party, aliceTxIdentity.certPath)
|
||||||
service.registerAnonymousIdentity(anonymousAlice, alice.party, aliceCertPath)
|
|
||||||
|
|
||||||
val anonymousBob = AnonymousParty(bobTxKey.public)
|
val anonymousBob = AnonymousParty(bobTxKey.public)
|
||||||
service.registerAnonymousIdentity(anonymousBob, bob.party, bobCertPath)
|
service.registerAnonymousIdentity(anonymousBob, bob.party, bobCertPath)
|
||||||
|
|
||||||
// Verify that paths are verified
|
// Verify that paths are verified
|
||||||
service.assertOwnership(alice.party, anonymousAlice)
|
service.assertOwnership(alice.party, aliceTxIdentity.identity)
|
||||||
service.assertOwnership(bob.party, anonymousBob)
|
service.assertOwnership(bob.party, anonymousBob)
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
service.assertOwnership(alice.party, anonymousBob)
|
service.assertOwnership(alice.party, anonymousBob)
|
||||||
}
|
}
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
service.assertOwnership(bob.party, anonymousAlice)
|
service.assertOwnership(bob.party, aliceTxIdentity.identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createParty(x500Name: X500Name): Triple<KeyPair, CertPath, PartyAndCertificate> {
|
private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, TxKeyFlow.AnonymousIdentity> {
|
||||||
val rootKey = Crypto.generateKeyPair()
|
val certFactory = CertificateFactory.getInstance("X509")
|
||||||
val rootCert = X509Utilities.createSelfSignedCACertificate(x500Name, rootKey)
|
val issuerKeyPair = generateKeyPair()
|
||||||
|
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
|
||||||
val txKey = Crypto.generateKeyPair()
|
val txKey = Crypto.generateKeyPair()
|
||||||
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, rootCert, rootKey, x500Name, txKey.public)
|
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public)
|
||||||
val certPath = X509Utilities.createCertificatePath(rootCert, txCert, revocationEnabled = false)
|
val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates)
|
||||||
return Triple(txKey, certPath, PartyAndCertificate(x500Name, rootKey.public, rootCert, certPath))
|
return Pair(issuer, TxKeyFlow.AnonymousIdentity(txCertPath, txCert, AnonymousParty(txKey.public)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +147,7 @@ class InMemoryIdentityServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `deanonymising a well known identity`() {
|
fun `deanonymising a well known identity`() {
|
||||||
val expected = ALICE
|
val expected = ALICE
|
||||||
val actual = InMemoryIdentityService(trustRoot = null).partyFromAnonymous(expected)
|
val actual = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate).partyFromAnonymous(expected)
|
||||||
assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user