mirror of
https://github.com/corda/corda.git
synced 2024-12-21 13:57:54 +00:00
Doorman can sign TLS certs directly. (#4078)
This commit is contained in:
parent
87a6585573
commit
68d736dd81
@ -26,20 +26,25 @@ import java.security.cert.X509Certificate
|
||||
enum class CertRole(val validParents: NonEmptySet<CertRole?>, val isIdentity: Boolean, val isWellKnown: Boolean) : ASN1Encodable {
|
||||
/** Signing certificate for the Doorman CA. */
|
||||
DOORMAN_CA(NonEmptySet.of(null), false, false),
|
||||
|
||||
/** Signing certificate for the network map. */
|
||||
NETWORK_MAP(NonEmptySet.of(null), false, false),
|
||||
|
||||
/** Well known (publicly visible) identity of a service (such as notary). */
|
||||
SERVICE_IDENTITY(NonEmptySet.of(DOORMAN_CA), true, true),
|
||||
|
||||
/** Node level CA from which the TLS and well known identity certificates are issued. */
|
||||
NODE_CA(NonEmptySet.of(DOORMAN_CA), false, false),
|
||||
|
||||
// [DOORMAN_CA] is also added as a valid parent of [TLS] and [LEGAL_IDENTITY] for backwards compatibility purposes
|
||||
// (eg. if we decide [TLS] has its own [ROOT_CA] and [DOORMAN_CA] directly issues [TLS] and [LEGAL_IDENTITY]; thus,
|
||||
// there won't be a requirement for [NODE_CA]).
|
||||
/** Transport layer security certificate for a node. */
|
||||
TLS(NonEmptySet.of(NODE_CA), false, false),
|
||||
TLS(NonEmptySet.of(DOORMAN_CA, NODE_CA), false, false),
|
||||
|
||||
/** Well known (publicly visible) identity of a legal entity. */
|
||||
// TODO: at the moment, Legal Identity certs are issued by Node CA only. However, [DOORMAN_CA] is also added
|
||||
// as a valid parent of [LEGAL_IDENTITY] for backwards compatibility purposes (eg. if we decide TLS has its
|
||||
// own Root CA and Doorman CA directly issues Legal Identities; thus, there won't be a requirement for
|
||||
// Node CA). Consider removing [DOORMAN_CA] from [validParents] when the model is finalised.
|
||||
LEGAL_IDENTITY(NonEmptySet.of(DOORMAN_CA, NODE_CA), true, true),
|
||||
|
||||
/** Confidential (limited visibility) identity of a legal entity. */
|
||||
CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false);
|
||||
|
||||
@ -88,4 +93,4 @@ enum class CertRole(val validParents: NonEmptySet<CertRole?>, val isIdentity: Bo
|
||||
fun isValidParent(parent: CertRole?): Boolean = parent in validParents
|
||||
|
||||
override fun toASN1Primitive(): ASN1Primitive = ASN1Integer(this.ordinal + 1L)
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import org.bouncycastle.asn1.ASN1Integer
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.*
|
||||
|
||||
class CertRoleTests {
|
||||
@Test
|
||||
@ -22,4 +25,74 @@ class CertRoleTests {
|
||||
// Outside of the range of integers
|
||||
assertFailsWith<IllegalArgumentException> { CertRole.getInstance(ASN1Integer(Integer.MAX_VALUE + 1L)) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check cert roles verify for various cert hierarchies`(){
|
||||
|
||||
// Testing for various certificate hierarchies (with or without NodeCA).
|
||||
// ROOT -> Intermediate Root -> Doorman -> NodeCA -> Legal Identity cert -> Confidential key cert
|
||||
// -> NodeCA -> TLS
|
||||
// -> Legal Identity cert -> Confidential key cert
|
||||
// -> TLS
|
||||
val rootSubject = X500Principal("CN=Root,O=R3 Ltd,L=London,C=GB")
|
||||
val intermediateRootSubject = X500Principal("CN=Intermediate Root,O=R3 Ltd,L=London,C=GB")
|
||||
val doormanSubject = X500Principal("CN=Doorman,O=R3 Ltd,L=London,C=GB")
|
||||
val nodeSubject = X500Principal("CN=Node,O=R3 Ltd,L=London,C=GB")
|
||||
|
||||
val rootKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCert = X509Utilities.createSelfSignedCACertificate(rootSubject, rootKeyPair)
|
||||
val rootCertRole = CertRole.extract(rootCert)
|
||||
|
||||
val intermediateRootKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
// Note that [CertificateType.ROOT_CA] is used for both root and intermediate root.
|
||||
val intermediateRootCert = X509Utilities.createCertificate(CertificateType.ROOT_CA, rootCert, rootKeyPair, intermediateRootSubject, intermediateRootKeyPair.public)
|
||||
val intermediateRootCertRole = CertRole.extract(intermediateRootCert)
|
||||
|
||||
val doormanKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
// Note that [CertificateType.INTERMEDIATE_CA] has actually role = CertRole.DOORMAN_CA, see [CertificateType] in [X509Utilities].
|
||||
val doormanCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, intermediateRootCert, intermediateRootKeyPair, doormanSubject, doormanKeyPair.public)
|
||||
val doormanCertRole = CertRole.extract(doormanCert)!!
|
||||
|
||||
val nodeCAKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val nodeCACert = X509Utilities.createCertificate(CertificateType.NODE_CA, doormanCert, doormanKeyPair, nodeSubject, nodeCAKeyPair.public)
|
||||
val nodeCACertRole = CertRole.extract(nodeCACert)!!
|
||||
|
||||
val tlsKeyPairFromNodeCA = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val tlsCertFromNodeCA = X509Utilities.createCertificate(CertificateType.TLS, nodeCACert, nodeCAKeyPair, nodeSubject, tlsKeyPairFromNodeCA.public)
|
||||
val tlsCertFromNodeCARole = CertRole.extract(tlsCertFromNodeCA)!!
|
||||
|
||||
val tlsKeyPairFromDoorman = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val tlsCertFromDoorman = X509Utilities.createCertificate(CertificateType.TLS, doormanCert, doormanKeyPair, nodeSubject, tlsKeyPairFromDoorman.public)
|
||||
val tlsCertFromDoormanRole = CertRole.extract(tlsCertFromDoorman)!!
|
||||
|
||||
val legalIDKeyPairFromNodeCA = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val legalIDCertFromNodeCA = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, nodeCACert, nodeCAKeyPair, nodeSubject, legalIDKeyPairFromNodeCA.public)
|
||||
val legalIDCertFromNodeCARole = CertRole.extract(legalIDCertFromNodeCA)!!
|
||||
|
||||
val legalIDKeyPairFromDoorman = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val legalIDCertFromDoorman = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, doormanCert, doormanKeyPair, nodeSubject, legalIDKeyPairFromDoorman.public)
|
||||
val legalIDCertFromDoormanRole = CertRole.extract(legalIDCertFromDoorman)!!
|
||||
|
||||
val confidentialKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val confidentialCert = X509Utilities.createCertificate(CertificateType.CONFIDENTIAL_LEGAL_IDENTITY, legalIDCertFromNodeCA, legalIDKeyPairFromNodeCA, nodeSubject, confidentialKeyPair.public)
|
||||
val confidentialCertRole = CertRole.extract(confidentialCert)!!
|
||||
|
||||
assertNull(rootCertRole)
|
||||
assertNull(intermediateRootCertRole)
|
||||
assertEquals(tlsCertFromNodeCARole, tlsCertFromDoormanRole)
|
||||
assertEquals(legalIDCertFromNodeCARole, legalIDCertFromDoormanRole)
|
||||
|
||||
assertTrue { doormanCertRole.isValidParent(intermediateRootCertRole) } // Doorman is signed by Intermediate Root.
|
||||
assertTrue { nodeCACertRole.isValidParent(doormanCertRole) } // NodeCA is signed by Doorman.
|
||||
assertTrue { tlsCertFromNodeCARole.isValidParent(nodeCACertRole) } // TLS is signed by NodeCA.
|
||||
assertTrue { tlsCertFromDoormanRole.isValidParent(doormanCertRole) } // TLS can also be signed by Doorman.
|
||||
assertTrue { legalIDCertFromNodeCARole.isValidParent(nodeCACertRole) } // Legal Identity is signed by NodeCA.
|
||||
assertTrue { legalIDCertFromDoormanRole.isValidParent(doormanCertRole) } // Legal Identity can also be signed by Doorman.
|
||||
assertTrue { confidentialCertRole.isValidParent(legalIDCertFromNodeCARole) } // Confidential key cert is signed by Legal Identity.
|
||||
|
||||
assertFalse { legalIDCertFromDoormanRole.isValidParent(tlsCertFromDoormanRole) } // Legal Identity cannot be signed by TLS.
|
||||
assertFalse { tlsCertFromNodeCARole.isValidParent(legalIDCertFromNodeCARole) } // TLS cannot be signed by Legal Identity.
|
||||
assertFalse { confidentialCertRole.isValidParent(nodeCACertRole) } // Confidential key cert cannot be signed by NodeCA.
|
||||
assertFalse { confidentialCertRole.isValidParent(doormanCertRole) } // Confidential key cert cannot be signed by Doorman.
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user