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()) {
|
||||
storage.approveRequest(id) {
|
||||
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")
|
||||
serverStatus.lastApprovalTime = Instant.now()
|
||||
@ -193,7 +198,7 @@ private fun DoormanParameters.startDoorman() {
|
||||
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA).last()
|
||||
val caCertAndKey = keystore.getCertificateAndKeyPair(caPrivateKeyPassword, CORDA_INTERMEDIATE_CA)
|
||||
// Create DB connection.
|
||||
val (datasource, database) = configureDatabase(dataSourceProperties)
|
||||
val database = configureDatabase(dataSourceProperties).second
|
||||
|
||||
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.assertj.core.api.Assertions.assertThat
|
||||
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.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.junit.After
|
||||
@ -29,7 +32,7 @@ class DoormanServiceTest {
|
||||
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 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 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
|
||||
fun `request not authorised`() {
|
||||
val id = SecureHash.randomSHA256().toString()
|
||||
|
@ -11,6 +11,9 @@ import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
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.junit.After
|
||||
import org.junit.Before
|
||||
@ -139,12 +142,8 @@ class DBCertificateRequestStorageTest {
|
||||
private fun approveRequest(requestId: String) {
|
||||
storage.approveRequest(requestId) {
|
||||
JcaPKCS10CertificationRequest(request).run {
|
||||
X509Utilities.createCertificate(
|
||||
CertificateType.TLS,
|
||||
intermediateCACert,
|
||||
intermediateCAKey,
|
||||
subject,
|
||||
publicKey)
|
||||
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, subject))), arrayOf())
|
||||
X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user