CORDA-3979: Support for multiple trust roots (#6772)

This commit is contained in:
Denis Rekalov
2020-10-20 12:18:00 +03:00
committed by GitHub
parent 401d8b8856
commit 4193adf6fd
37 changed files with 486 additions and 131 deletions

View File

@ -105,6 +105,17 @@ fun createDevNodeCa(intermediateCa: CertificateAndKeyPair,
return CertificateAndKeyPair(cert, nodeKeyPair)
}
fun createDevNodeIdentity(nodeCa: CertificateAndKeyPair, legalName: CordaX500Name): CertificateAndKeyPair {
val keyPair = generateKeyPair()
val cert = X509Utilities.createCertificate(
CertificateType.LEGAL_IDENTITY,
nodeCa.certificate,
nodeCa.keyPair,
legalName.x500Principal,
keyPair.public)
return CertificateAndKeyPair(cert, keyPair)
}
val DEV_INTERMEDIATE_CA: CertificateAndKeyPair get() = DevCaHelper.loadDevCa(X509Utilities.CORDA_INTERMEDIATE_CA)
val DEV_ROOT_CA: CertificateAndKeyPair get() = DevCaHelper.loadDevCa(X509Utilities.CORDA_ROOT_CA)
const val DEV_CA_PRIVATE_KEY_PASS: String = "cordacadevkeypass"

View File

@ -124,17 +124,17 @@ object X509Utilities {
return createCertificate(CertificateType.ROOT_CA, subject, keyPair, subject, keyPair.public, window)
}
fun validateCertificateChain(trustedRoot: X509Certificate, vararg certificates: X509Certificate) {
validateCertificateChain(trustedRoot, certificates.asList())
fun validateCertificateChain(trustedRoots: Set<X509Certificate>, vararg certificates: X509Certificate) {
validateCertificateChain(trustedRoots, certificates.asList())
}
fun validateCertificateChain(trustedRoot: X509Certificate, certificates: List<X509Certificate>) {
fun validateCertificateChain(trustedRoots: Set<X509Certificate>, certificates: List<X509Certificate>) {
require(certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
validateCertPath(trustedRoot, buildCertPath(certificates))
validateCertPath(trustedRoots, buildCertPath(certificates))
}
fun validateCertPath(trustedRoot: X509Certificate, certPath: CertPath) {
certPath.validate(TrustAnchor(trustedRoot, null))
fun validateCertPath(trustedRoots: Set<X509Certificate>, certPath: CertPath) {
certPath.validate(trustedRoots.map { TrustAnchor(it, null) }.toSet())
}
/**

View File

@ -399,7 +399,7 @@ constructor(private val initSerEnv: Boolean,
when (netParamsFilesGrouped.size) {
0 -> return null
1 -> return netParamsFilesGrouped.keys.first().deserialize().verifiedNetworkParametersCert(DEV_ROOT_CA.certificate)
1 -> return netParamsFilesGrouped.keys.first().deserialize().verifiedNetworkParametersCert(setOf(DEV_ROOT_CA.certificate))
}
val msg = StringBuilder("Differing sets of network parameters were found. Make sure all the nodes have the same " +
@ -409,7 +409,7 @@ constructor(private val initSerEnv: Boolean,
netParamsFiles.map { it.parent.fileName }.joinTo(msg, ", ")
msg.append(":\n")
val netParamsString = try {
bytes.deserialize().verifiedNetworkParametersCert(DEV_ROOT_CA.certificate).toString()
bytes.deserialize().verifiedNetworkParametersCert(setOf(DEV_ROOT_CA.certificate)).toString()
} catch (e: Exception) {
"Invalid network parameters file: $e"
}

View File

@ -55,25 +55,26 @@ data class ParametersUpdate(
)
/** Verify that a certificate path and its [CertRole] is correct. */
fun <T : Any> SignedDataWithCert<T>.verifiedCertWithRole(rootCert: X509Certificate, vararg certRoles: CertRole): T {
fun <T : Any> SignedDataWithCert<T>.verifiedCertWithRole(rootCerts: Set<X509Certificate>, vararg certRoles: CertRole): T {
require(CertRole.extract(sig.by) in certRoles) { "Incorrect cert role: ${CertRole.extract(sig.by)}" }
val path = if (sig.parentCertsChain.isEmpty()) {
listOf(sig.by, rootCert)
val rootCandidate = rootCerts.firstOrNull { it.subjectX500Principal == sig.by.issuerX500Principal }
listOf(sig.by, rootCandidate ?: rootCerts.first())
} else {
sig.fullCertChain
}
X509Utilities.validateCertificateChain(rootCert, path)
X509Utilities.validateCertificateChain(rootCerts, path)
return verified()
}
/** Verify that a Network Map certificate path and its [CertRole] is correct. */
fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certificate): T {
return verifiedCertWithRole(rootCert, CertRole.NETWORK_MAP)
fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCerts: Set<X509Certificate>): T {
return verifiedCertWithRole(rootCerts, CertRole.NETWORK_MAP)
}
/** Verify that a Network Parameters certificate path and its [CertRole] is correct. */
fun <T : Any> SignedDataWithCert<T>.verifiedNetworkParametersCert(rootCert: X509Certificate): T {
fun <T : Any> SignedDataWithCert<T>.verifiedNetworkParametersCert(rootCerts: Set<X509Certificate>): T {
// for backwards compatibility we allow network parameters to be signed with
// the networkmap cert, but going forwards we also accept the specific netparams cert as well
return verifiedCertWithRole(rootCert, CertRole.NETWORK_PARAMETERS, CertRole.NETWORK_MAP)
return verifiedCertWithRole(rootCerts, CertRole.NETWORK_PARAMETERS, CertRole.NETWORK_MAP)
}

View File

@ -33,7 +33,7 @@ class DevCertificatesTest {
val certPath = X509Utilities.buildCertPath(*oldX509Certificates)
// when
certPath.validate(newTrustAnchor)
certPath.validate(setOf(newTrustAnchor))
// then no exception is thrown
}

View File

@ -127,7 +127,7 @@ class TlsDiffAlgorithmsTest(private val serverAlgo: String, private val clientAl
val peerChain = peerChainTry.getOrThrow()
val peerX500Principal = peerChain[0].subjectX500Principal
assertEquals(serverCa.certificate.subjectX500Principal, peerX500Principal)
X509Utilities.validateCertificateChain(rootCa, peerChain)
X509Utilities.validateCertificateChain(setOf(rootCa), peerChain)
with(DataOutputStream(clientSocket.outputStream)) {
writeUTF(testPhrase)
}

View File

@ -175,7 +175,7 @@ class TlsDiffProtocolsTest(private val serverAlgo: String, private val clientAlg
val peerChain = peerChainTry.getOrThrow()
val peerX500Principal = peerChain[0].subjectX500Principal
assertEquals(serverCa.certificate.subjectX500Principal, peerX500Principal)
X509Utilities.validateCertificateChain(rootCa, peerChain)
X509Utilities.validateCertificateChain(setOf(rootCa), peerChain)
with(DataOutputStream(clientSocket.outputStream)) {
writeUTF(testPhrase)
}