mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
Merged in pat-doorman-name-constraints (pull request #34)
Doorman now issue CA to client with name constraint. * Doorman now issue CA to client with name constraint. * address PR issues Approved-by: Matthew Nesbit <matthew.nesbit@r3cev.com>
This commit is contained in:
parent
cdb222cff2
commit
ae691ab4e0
@ -83,7 +83,12 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CertificateAnd
|
|||||||
for (id in storage.getApprovedRequestIds()) {
|
for (id in storage.getApprovedRequestIds()) {
|
||||||
storage.approveRequest(id) {
|
storage.approveRequest(id) {
|
||||||
val request = JcaPKCS10CertificationRequest(request)
|
val request = JcaPKCS10CertificationRequest(request)
|
||||||
createCertificate(CertificateType.CLIENT_CA, caCertAndKey.certificate, caCertAndKey.keyPair, request.subject, request.publicKey, nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, request.subject))), arrayOf()))
|
// The sub certs issued by the client must satisfy this directory name (or legal name in Corda) constraints, sub certs' directory name must be within client CA's name's subtree,
|
||||||
|
// please see [sun.security.x509.X500Name.isWithinSubtree()] for more information.
|
||||||
|
// We assume all attributes in the subject name has been checked prior approval.
|
||||||
|
// TODO: add validation to subject name.
|
||||||
|
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, request.subject))), arrayOf())
|
||||||
|
createCertificate(CertificateType.CLIENT_CA, caCertAndKey.certificate, caCertAndKey.keyPair, request.subject, request.publicKey, nameConstraints = nameConstraints)
|
||||||
}
|
}
|
||||||
logger.info("Approved request $id")
|
logger.info("Approved request $id")
|
||||||
serverStatus.lastApprovalTime = Instant.now()
|
serverStatus.lastApprovalTime = Instant.now()
|
||||||
@ -193,7 +198,7 @@ private fun DoormanParameters.startDoorman() {
|
|||||||
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA).last()
|
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA).last()
|
||||||
val caCertAndKey = keystore.getCertificateAndKeyPair(caPrivateKeyPassword, CORDA_INTERMEDIATE_CA)
|
val caCertAndKey = keystore.getCertificateAndKeyPair(caPrivateKeyPassword, CORDA_INTERMEDIATE_CA)
|
||||||
// Create DB connection.
|
// Create DB connection.
|
||||||
val (datasource, database) = configureDatabase(dataSourceProperties)
|
val database = configureDatabase(dataSourceProperties).second
|
||||||
|
|
||||||
val requestStorage = DBCertificateRequestStorage(database)
|
val requestStorage = DBCertificateRequestStorage(database)
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ import net.corda.core.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
|||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralName
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralSubtree
|
||||||
|
import org.bouncycastle.asn1.x509.NameConstraints
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
@ -29,7 +32,7 @@ class DoormanServiceTest {
|
|||||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(X500Name("CN=Corda Node Root CA,L=London"), rootCAKey)
|
private val rootCACert = X509Utilities.createSelfSignedCACertificate(X500Name("CN=Corda Node Root CA,L=London"), rootCAKey)
|
||||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
private val intermediateCACert = X509Utilities.createSelfSignedCACertificate(X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey)
|
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||||
private lateinit var doormanServer: DoormanServer
|
private lateinit var doormanServer: DoormanServer
|
||||||
|
|
||||||
private fun startSigningServer(storage: CertificationRequestStorage) {
|
private fun startSigningServer(storage: CertificationRequestStorage) {
|
||||||
@ -108,6 +111,48 @@ class DoormanServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `retrieve certificate and create valid TLS certificate`() {
|
||||||
|
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
|
val id = SecureHash.randomSHA256().toString()
|
||||||
|
|
||||||
|
// Mock Storage behaviour.
|
||||||
|
val certificateStore = mutableMapOf<String, Certificate>()
|
||||||
|
val storage = mock<CertificationRequestStorage> {
|
||||||
|
on { getResponse(eq(id)) }.then {
|
||||||
|
certificateStore[id]?.let { CertificateResponse.Ready(it) } ?: CertificateResponse.NotReady
|
||||||
|
}
|
||||||
|
on { approveRequest(eq(id), any()) }.then {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val certGen = it.arguments[1] as ((CertificationRequestData) -> Certificate)
|
||||||
|
val request = CertificationRequestData("", "", X509Utilities.createCertificateSigningRequest(X500Name("CN=LegalName,L=London"), keyPair))
|
||||||
|
certificateStore[id] = certGen(request)
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
on { getPendingRequestIds() }.then { listOf(id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
startSigningServer(storage)
|
||||||
|
|
||||||
|
assertThat(pollForResponse(id)).isEqualTo(PollResponse.NotReady)
|
||||||
|
|
||||||
|
storage.approveRequest(id) {
|
||||||
|
JcaPKCS10CertificationRequest(request).run {
|
||||||
|
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))), arrayOf())
|
||||||
|
X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
|
||||||
|
verify(storage, times(2)).getResponse(any())
|
||||||
|
assertEquals(3, certificates.size)
|
||||||
|
|
||||||
|
val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
|
val sslCert = X509Utilities.createCertificate(CertificateType.TLS, certificates.first(), keyPair, X500Name("CN=LegalName,L=London"), sslKey.public)
|
||||||
|
|
||||||
|
X509Utilities.validateCertificateChain(certificates.last(), sslCert, *certificates.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `request not authorised`() {
|
fun `request not authorised`() {
|
||||||
val id = SecureHash.randomSHA256().toString()
|
val id = SecureHash.randomSHA256().toString()
|
||||||
|
@ -11,6 +11,9 @@ import net.corda.node.utilities.configureDatabase
|
|||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralName
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralSubtree
|
||||||
|
import org.bouncycastle.asn1.x509.NameConstraints
|
||||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -139,12 +142,8 @@ class DBCertificateRequestStorageTest {
|
|||||||
private fun approveRequest(requestId: String) {
|
private fun approveRequest(requestId: String) {
|
||||||
storage.approveRequest(requestId) {
|
storage.approveRequest(requestId) {
|
||||||
JcaPKCS10CertificationRequest(request).run {
|
JcaPKCS10CertificationRequest(request).run {
|
||||||
X509Utilities.createCertificate(
|
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, subject))), arrayOf())
|
||||||
CertificateType.TLS,
|
X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints)
|
||||||
intermediateCACert,
|
|
||||||
intermediateCAKey,
|
|
||||||
subject,
|
|
||||||
publicKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user