mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +00:00
Merge fixes and updated network-management to work with the move away from X509CertificateHolder
This commit is contained in:
parent
13619df0b1
commit
133fd27222
@ -3,14 +3,11 @@ package com.r3.corda.networkmanage.doorman
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.node.NodeInfo
|
||||
@ -28,12 +25,13 @@ import net.corda.testing.ALICE_NAME
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.net.URL
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
@ -60,7 +58,7 @@ class DoormanIntegrationTest {
|
||||
}
|
||||
config.trustStoreFile.parent.createDirectories()
|
||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate)
|
||||
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||
}
|
||||
|
||||
@ -77,18 +75,18 @@ class DoormanIntegrationTest {
|
||||
loadKeyStore(config.nodeKeystore, config.keyStorePassword).apply {
|
||||
assert(containsAlias(X509Utilities.CORDA_CLIENT_CA))
|
||||
assertEquals(ALICE_NAME.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subjectX500Principal)
|
||||
assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_CA).drop(1).toList())
|
||||
assertEquals(listOf(intermediateCACert, rootCACert), getCertificateChain(X509Utilities.CORDA_CLIENT_CA).drop(1).toList())
|
||||
}
|
||||
|
||||
loadKeyStore(config.sslKeystore, config.keyStorePassword).apply {
|
||||
assert(containsAlias(X509Utilities.CORDA_CLIENT_TLS))
|
||||
assertEquals(ALICE_NAME.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subjectX500Principal)
|
||||
assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).drop(2).toList())
|
||||
assertEquals(listOf(intermediateCACert, rootCACert), getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).drop(2).toList())
|
||||
}
|
||||
|
||||
loadKeyStore(config.trustStoreFile, config.trustStorePassword).apply {
|
||||
assert(containsAlias(X509Utilities.CORDA_ROOT_CA))
|
||||
assertEquals(rootCACert.cert.subjectX500Principal, getX509Certificate(X509Utilities.CORDA_ROOT_CA).subjectX500Principal)
|
||||
assertEquals(rootCACert.subjectX500Principal, getX509Certificate(X509Utilities.CORDA_ROOT_CA).subjectX500Principal)
|
||||
}
|
||||
|
||||
doorman.close()
|
||||
@ -110,21 +108,26 @@ class DoormanIntegrationTest {
|
||||
}
|
||||
config.trustStoreFile.parent.createDirectories()
|
||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate)
|
||||
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||
}
|
||||
|
||||
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
||||
|
||||
// Publish NodeInfo
|
||||
val networkMapClient = NetworkMapClient(config.compatibilityZoneURL!!, rootCertAndKey.certificate.cert)
|
||||
val networkMapClient = NetworkMapClient(config.compatibilityZoneURL!!, rootCertAndKey.certificate)
|
||||
|
||||
val keyStore = loadKeyStore(config.nodeKeystore, config.keyStorePassword)
|
||||
val clientCertPath = keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
|
||||
val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, config.keyStorePassword)
|
||||
val identityKeyPair = Crypto.generateKeyPair()
|
||||
val identityCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, clientCA.certificate, clientCA.keyPair, ALICE_NAME, identityKeyPair.public)
|
||||
val certPath = X509CertificateFactory().generateCertPath(identityCert.cert, *clientCertPath)
|
||||
val identityCert = X509Utilities.createCertificate(
|
||||
CertificateType.LEGAL_IDENTITY,
|
||||
clientCA.certificate,
|
||||
clientCA.keyPair,
|
||||
ALICE_NAME.x500Principal,
|
||||
identityKeyPair.public)
|
||||
val certPath = X509CertificateFactory().generateCertPath(identityCert, *clientCertPath)
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoBytes = nodeInfo.serialize()
|
||||
|
||||
@ -156,23 +159,23 @@ class DoormanIntegrationTest {
|
||||
}
|
||||
|
||||
|
||||
fun createDoormanIntermediateCertificateAndKeyPair(rootCertificateAndKeyPair: CertificateAndKeyPair): CertificateAndKeyPair {
|
||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCertificateAndKeyPair.certificate, rootCertificateAndKeyPair.keyPair,
|
||||
CordaX500Name(commonName = "Integration Test Corda Node Intermediate CA",
|
||||
locality = "London",
|
||||
country = "GB",
|
||||
organisation = "R3 Ltd"), intermediateCAKey.public)
|
||||
return CertificateAndKeyPair(intermediateCACert, intermediateCAKey)
|
||||
fun createDoormanIntermediateCertificateAndKeyPair(rootCa: CertificateAndKeyPair): CertificateAndKeyPair {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCACert = X509Utilities.createCertificate(
|
||||
CertificateType.INTERMEDIATE_CA,
|
||||
rootCa.certificate,
|
||||
rootCa.keyPair,
|
||||
X500Principal("CN=Integration Test Corda Node Intermediate CA,O=R3 Ltd,L=London,C=GB"),
|
||||
keyPair.public)
|
||||
return CertificateAndKeyPair(intermediateCACert, keyPair)
|
||||
}
|
||||
|
||||
fun createDoormanRootCertificateAndKeyPair(): CertificateAndKeyPair {
|
||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(
|
||||
CordaX500Name(commonName = "Integration Test Corda Node Root CA",
|
||||
organisation = "R3 Ltd", locality = "London",
|
||||
country = "GB"), rootCAKey)
|
||||
return CertificateAndKeyPair(rootCACert, rootCAKey)
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCaCert = X509Utilities.createSelfSignedCACertificate(
|
||||
X500Principal("CN=Integration Test Corda Node Root CA,O=R3 Ltd,L=London,C=GB"),
|
||||
keyPair)
|
||||
return CertificateAndKeyPair(rootCaCert, keyPair)
|
||||
}
|
||||
|
||||
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||
@ -184,9 +187,8 @@ fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().to
|
||||
return props
|
||||
}
|
||||
|
||||
fun startDoorman(intermediateCACertAndKey: CertificateAndKeyPair, rootCACert: X509CertificateHolder): NetworkManagementServer {
|
||||
val signer = LocalSigner(intermediateCACertAndKey.keyPair,
|
||||
arrayOf(intermediateCACertAndKey.certificate.toX509Certificate(), rootCACert.toX509Certificate()))
|
||||
fun startDoorman(intermediateCACertAndKey: CertificateAndKeyPair, rootCACert: X509Certificate): NetworkManagementServer {
|
||||
val signer = LocalSigner(intermediateCACertAndKey.keyPair, arrayOf(intermediateCACertAndKey.certificate, rootCACert))
|
||||
//Start doorman server
|
||||
return startDoorman(signer)
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStor
|
||||
import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorage
|
||||
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
@ -28,12 +27,12 @@ import net.corda.testing.CHARLIE_NAME
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.h2.tools.Server
|
||||
import org.junit.*
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.net.URL
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import javax.persistence.PersistenceException
|
||||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
@ -55,7 +54,7 @@ class SigningServiceIntegrationTest {
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private lateinit var timer: Timer
|
||||
private lateinit var rootCaCert: X509CertificateHolder
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
@ -79,7 +78,7 @@ class SigningServiceIntegrationTest {
|
||||
for (approvedRequest in approvedRequests) {
|
||||
JcaPKCS10CertificationRequest(approvedRequest.request).run {
|
||||
val nodeCa = createDevNodeCa(intermediateCa, CordaX500Name.parse(subject.toString()))
|
||||
approvedRequest.certPath = buildCertPath(nodeCa.certificate.cert, intermediateCa.certificate.cert, rootCaCert.cert)
|
||||
approvedRequest.certPath = buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCaCert)
|
||||
}
|
||||
}
|
||||
storage.store(approvedRequests, listOf("TEST"))
|
||||
@ -124,7 +123,7 @@ class SigningServiceIntegrationTest {
|
||||
}
|
||||
config.certificatesDirectory.createDirectories()
|
||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCaCert.cert)
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCaCert)
|
||||
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||
}
|
||||
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
||||
@ -168,7 +167,7 @@ class SigningServiceIntegrationTest {
|
||||
}
|
||||
config.certificatesDirectory.createDirectories()
|
||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCaCert.cert)
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCaCert)
|
||||
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||
}
|
||||
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
||||
|
@ -5,15 +5,14 @@ import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRe
|
||||
import com.r3.corda.networkmanage.common.utils.hashString
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.x500Name
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.hibernate.Session
|
||||
import java.security.cert.CertPath
|
||||
import java.time.Instant
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
/**
|
||||
* Database implementation of the [CertificationRequestStorage] interface.
|
||||
@ -48,7 +47,7 @@ class PersistentCertificateRequestStorage(private val database: CordaPersistence
|
||||
val (legalName, rejectReason) = parseAndValidateLegalName(request, session)
|
||||
session.save(CertificateSigningRequestEntity(
|
||||
requestId = requestId,
|
||||
legalName = legalName.toString(),
|
||||
legalName = legalName,
|
||||
requestBytes = request.encoded,
|
||||
remark = rejectReason,
|
||||
modifiedBy = emptyList(),
|
||||
@ -126,25 +125,27 @@ class PersistentCertificateRequestStorage(private val database: CordaPersistence
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseAndValidateLegalName(request: PKCS10CertificationRequest, session: Session): Pair<X500Name, String?> {
|
||||
private fun parseAndValidateLegalName(request: PKCS10CertificationRequest, session: Session): Pair<String, String?> {
|
||||
// It's important that we always use the toString() output of CordaX500Name as it standardises the string format
|
||||
// to make querying possible.
|
||||
val legalName = try {
|
||||
CordaX500Name.parse(request.subject.toString())
|
||||
CordaX500Name.build(X500Principal(request.subject.encoded)).toString()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return Pair(request.subject, "Name validation failed with exception : ${e.message}")
|
||||
return Pair(request.subject.toString(), "Name validation failed: ${e.message}")
|
||||
}
|
||||
|
||||
val query = session.criteriaBuilder.run {
|
||||
val criteriaQuery = createQuery(CertificateSigningRequestEntity::class.java)
|
||||
criteriaQuery.from(CertificateSigningRequestEntity::class.java).run {
|
||||
criteriaQuery.where(equal(get<String>(CertificateSigningRequestEntity::legalName.name), legalName.toString()))
|
||||
criteriaQuery.where(equal(get<String>(CertificateSigningRequestEntity::legalName.name), legalName))
|
||||
}
|
||||
}
|
||||
|
||||
val duplicates = session.createQuery(query).resultList.filter {
|
||||
it.status in setOf(RequestStatus.NEW, RequestStatus.TICKET_CREATED, RequestStatus.APPROVED) || it.certificateData?.certificateStatus == CertificateStatus.VALID
|
||||
}
|
||||
return if (duplicates.isEmpty()) {
|
||||
Pair(legalName.x500Name, null)
|
||||
} else {
|
||||
Pair(legalName.x500Name, "Duplicate legal name")
|
||||
it.status in setOf(RequestStatus.NEW, RequestStatus.TICKET_CREATED, RequestStatus.APPROVED) ||
|
||||
it.certificateData?.certificateStatus == CertificateStatus.VALID
|
||||
}
|
||||
|
||||
return Pair(legalName, if (duplicates.isEmpty()) null else "Duplicate legal name")
|
||||
}
|
||||
}
|
@ -6,9 +6,7 @@ import com.atlassian.jira.rest.client.api.domain.Issue
|
||||
import com.atlassian.jira.rest.client.api.domain.IssueType
|
||||
import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder
|
||||
import com.atlassian.jira.rest.client.api.domain.input.TransitionInput
|
||||
import net.corda.core.internal.country
|
||||
import net.corda.core.internal.locality
|
||||
import net.corda.core.internal.organisation
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||
@ -17,6 +15,7 @@ import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.bouncycastle.util.io.pem.PemObject
|
||||
import java.io.StringWriter
|
||||
import java.security.cert.CertPath
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
class JiraClient(private val restClient: JiraRestClient, private val projectCode: String, private val doneTransitionCode: Int) {
|
||||
companion object {
|
||||
@ -39,16 +38,17 @@ class JiraClient(private val restClient: JiraRestClient, private val projectCode
|
||||
JcaPEMWriter(request).use {
|
||||
it.writeObject(PemObject("CERTIFICATE REQUEST", signingRequest.encoded))
|
||||
}
|
||||
val organisation = signingRequest.subject.organisation
|
||||
val nearestCity = signingRequest.subject.locality
|
||||
val country = signingRequest.subject.country
|
||||
|
||||
// TODO The subject of the signing request has already been validated and parsed into a CordaX500Name. We shouldn't
|
||||
// have to do it again here.
|
||||
val subject = CordaX500Name.build(X500Principal(signingRequest.subject.encoded))
|
||||
|
||||
val email = signingRequest.getAttributes(BCStyle.E).firstOrNull()?.attrValues?.firstOrNull()?.toString()
|
||||
|
||||
val issue = IssueInputBuilder().setIssueTypeId(taskIssueType.id)
|
||||
.setProjectKey(projectCode)
|
||||
.setDescription("Organisation: $organisation\nNearest City: $nearestCity\nCountry: $country\nEmail: $email\n\n{code}$request{code}")
|
||||
.setSummary(organisation)
|
||||
.setDescription("Organisation: ${subject.organisation}\nNearest City: ${subject.locality}\nCountry: ${subject.country}\nEmail: $email\n\n{code}$request{code}")
|
||||
.setSummary(subject.organisation)
|
||||
.setFieldValue(requestIdField.id, requestId)
|
||||
// This will block until the issue is created.
|
||||
restClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim()
|
||||
|
@ -13,7 +13,6 @@ import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||
@ -188,8 +187,8 @@ fun generateRootKeyPair(rootStoreFile: Path, rootKeystorePass: String?, rootPriv
|
||||
val selfSignKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
// TODO Make the cert subject configurable
|
||||
val selfSignCert = X509Utilities.createSelfSignedCACertificate(
|
||||
CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null),
|
||||
selfSignKey).cert
|
||||
CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null).x500Principal,
|
||||
selfSignKey)
|
||||
rootStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, selfSignKey.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert))
|
||||
rootStore.save(rootStoreFile, rootKeystorePassword)
|
||||
|
||||
@ -226,11 +225,20 @@ fun generateCAKeyPair(keystoreFile: Path, rootStoreFile: Path, rootKeystorePass:
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
val intermediateKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootKeyAndCert.certificate, rootKeyAndCert.keyPair,
|
||||
CordaX500Name(commonName = "Corda Intermediate CA", organisation = "R3 Ltd", organisationUnit = "Corda", locality = "London", country = "GB", state = null), intermediateKey.public)
|
||||
keyStore.addOrReplaceKey(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateKey.private,
|
||||
caPrivateKeyPassword.toCharArray(), arrayOf(intermediateCert, rootKeyAndCert.certificate))
|
||||
val intermediateKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCert = X509Utilities.createCertificate(
|
||||
CertificateType.INTERMEDIATE_CA,
|
||||
rootKeyAndCert.certificate,
|
||||
rootKeyAndCert.keyPair,
|
||||
CordaX500Name(commonName = "Corda Intermediate CA", organisation = "R3 Ltd", organisationUnit = "Corda", locality = "London", country = "GB", state = null).x500Principal,
|
||||
intermediateKeyPair.public
|
||||
)
|
||||
keyStore.addOrReplaceKey(
|
||||
X509Utilities.CORDA_INTERMEDIATE_CA,
|
||||
intermediateKeyPair.private,
|
||||
caPrivateKeyPassword.toCharArray(),
|
||||
arrayOf(intermediateCert, rootKeyAndCert.certificate)
|
||||
)
|
||||
keyStore.save(keystoreFile, keystorePassword)
|
||||
println("Intermediate CA keypair and certificate stored in $keystoreFile.")
|
||||
println(loadKeyStore(keystoreFile, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey)
|
||||
|
@ -4,9 +4,6 @@ import com.r3.corda.networkmanage.common.signer.Signer
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
@ -18,6 +15,7 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import java.security.KeyPair
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
/**
|
||||
* The [LocalSigner] class signs [PKCS10CertificationRequest] using provided CA key pair and certificate path.
|
||||
@ -35,12 +33,12 @@ class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array<
|
||||
arrayOf())
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
caCertPath.first().toX509CertHolder(),
|
||||
caCertPath[0],
|
||||
caKeyPair,
|
||||
CordaX500Name.parse(request.subject.toString()),
|
||||
X500Principal(request.subject.encoded),
|
||||
request.publicKey,
|
||||
nameConstraints = nameConstraints)
|
||||
return buildCertPath(nodeCaCert.cert, *caCertPath)
|
||||
return buildCertPath(nodeCaCert, *caCertPath)
|
||||
}
|
||||
|
||||
override fun sign(data: ByteArray): DigitalSignatureWithCert {
|
||||
|
@ -9,13 +9,12 @@ import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.getAndInitializeKeyStore
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.signData
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.verify
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.core.utilities.minutes
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
@ -68,7 +67,7 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
val caKey = keyStore.getKey(caCertificateKeyName, caPrivateKeyPass.toCharArray()) as PrivateKey
|
||||
val signature = signData(data, KeyPair(caCertificateChain.first().publicKey, caKey), provider)
|
||||
verify(data, signature, caCertificateChain.first().publicKey)
|
||||
signature.withCert(caCertificateChain.first().toX509CertHolder().cert)
|
||||
signature.withCert(caCertificateChain[0] as X509Certificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package com.r3.corda.networkmanage.hsm.utils
|
||||
import CryptoServerJCE.CryptoServerProvider
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.internal.x500Name
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
@ -81,7 +80,7 @@ object X509Utilities {
|
||||
cert.checkValidity(Date())
|
||||
cert.verify(pubKey)
|
||||
|
||||
return CertificateAndKeyPair(cert.toX509CertHolder(), KeyPair(pubKey, keyPair.private))
|
||||
return CertificateAndKeyPair(cert, KeyPair(pubKey, keyPair.private))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +108,7 @@ object X509Utilities {
|
||||
fun retrieveCertificateAndKeys(certificateKeyName: String, privateKeyPassword: String, keyStore: KeyStore): CertificateAndKeyPair {
|
||||
val privateKey = keyStore.getKey(certificateKeyName, privateKeyPassword.toCharArray()) as PrivateKey
|
||||
val publicKey = keyStore.getCertificate(certificateKeyName).publicKey
|
||||
val certificate = keyStore.getX509Certificate(certificateKeyName).toX509CertHolder()
|
||||
val certificate = keyStore.getX509Certificate(certificateKeyName)
|
||||
return CertificateAndKeyPair(certificate, getCleanEcdsaKeyPair(publicKey, privateKey))
|
||||
}
|
||||
|
||||
@ -160,7 +159,7 @@ object X509Utilities {
|
||||
cert.checkValidity(Date())
|
||||
cert.verify(certificateAuthority.keyPair.public)
|
||||
|
||||
return CertificateAndKeyPair(cert.toX509CertHolder(), KeyPair(pubKey, keyPair.private))
|
||||
return CertificateAndKeyPair(cert, KeyPair(pubKey, keyPair.private))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,7 +185,7 @@ object X509Utilities {
|
||||
val subject = CordaX500Name.parse(jcaRequest.subject.toString()).x500Name
|
||||
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(jcaRequest.publicKey.encoded))
|
||||
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } })
|
||||
val builder = JcaX509v3CertificateBuilder(issuerCertificate.subject, serial, validityWindow.first, validityWindow.second, subject, jcaRequest.publicKey)
|
||||
val builder = JcaX509v3CertificateBuilder(issuerCertificate, serial, validityWindow.first, validityWindow.second, subject, jcaRequest.publicKey)
|
||||
.addExtension(Extension.subjectKeyIdentifier, false, BcX509ExtensionUtils().createSubjectKeyIdentifier(subjectPublicKeyInfo))
|
||||
.addExtension(Extension.basicConstraints, certificateType.isCA, BasicConstraints(certificateType.isCA))
|
||||
.addExtension(Extension.keyUsage, false, certificateType.keyUsage)
|
||||
|
@ -4,15 +4,13 @@ import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
|
||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.internal.createDevNodeCaCertPath
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.hibernate.envers.AuditReaderFactory
|
||||
@ -21,9 +19,10 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.*
|
||||
|
||||
class DBCertificateRequestStorageTest : TestBase() {
|
||||
class PersistentCertificateRequestStorageTest : TestBase() {
|
||||
private lateinit var storage: PersistentCertificateRequestStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
|
||||
@ -84,14 +83,15 @@ class DBCertificateRequestStorageTest : TestBase() {
|
||||
// New request should be empty.
|
||||
assertTrue(storage.getRequests(RequestStatus.NEW).isEmpty())
|
||||
// Sign certificate
|
||||
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
|
||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
|
||||
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
}, listOf(DOORMAN_SIGNATURE))
|
||||
storage.putCertificatePath(
|
||||
requestId,
|
||||
JcaPKCS10CertificationRequest(csr).run {
|
||||
// TODO We need a utility in InternalUtils for converting X500Name -> CordaX500Name
|
||||
val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
|
||||
buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
|
||||
},
|
||||
listOf(DOORMAN_SIGNATURE)
|
||||
)
|
||||
// Check request is ready
|
||||
assertNotNull(storage.getRequest(requestId)!!.certData)
|
||||
}
|
||||
@ -104,25 +104,24 @@ class DBCertificateRequestStorageTest : TestBase() {
|
||||
// Store certificate to DB.
|
||||
storage.markRequestTicketCreated(requestId)
|
||||
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
|
||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
|
||||
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
}, listOf(DOORMAN_SIGNATURE))
|
||||
storage.putCertificatePath(
|
||||
requestId,
|
||||
JcaPKCS10CertificationRequest(csr).run {
|
||||
val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
|
||||
buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
|
||||
},
|
||||
listOf(DOORMAN_SIGNATURE)
|
||||
)
|
||||
// Sign certificate
|
||||
// When subsequent signature requested
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
|
||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
|
||||
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
}, listOf(DOORMAN_SIGNATURE))
|
||||
storage.putCertificatePath(
|
||||
requestId,
|
||||
JcaPKCS10CertificationRequest(csr).run {
|
||||
val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
|
||||
buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
|
||||
},
|
||||
listOf(DOORMAN_SIGNATURE))
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,6 +206,6 @@ class DBCertificateRequestStorageTest : TestBase() {
|
||||
|
||||
internal fun createRequest(organisation: String): Pair<PKCS10CertificationRequest, KeyPair> {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(organisation = organisation, locality = "London", country = "GB"), "my@mail.com", keyPair)
|
||||
val request = X509Utilities.createCertificateSigningRequest(X500Principal("O=$organisation,L=London,C=GB"), "my@mail.com", keyPair)
|
||||
return Pair(request, keyPair)
|
||||
}
|
@ -3,25 +3,24 @@ package com.r3.corda.networkmanage.common.persistence
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.TestNodeInfoBuilder
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.cert.X509Certificate
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class PersistentNetworkMapStorageTest : TestBase() {
|
||||
@ -30,15 +29,16 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
|
||||
private lateinit var requestStorage: PersistentCertificateRequestStorage
|
||||
|
||||
private val rootCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair)
|
||||
private val intermediateCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCaCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCaCert, rootCaKeyPair, CordaX500Name("Corda Node Intermediate CA", "R3 LTD", "London", "GB"), intermediateCaKeyPair.public)
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
persistence = configureDatabase(makeTestDataSourceProperties())
|
||||
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(intermediateCaKeyPair, arrayOf(intermediateCaCert.cert, rootCaCert.cert)))
|
||||
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(intermediateCa.keyPair, arrayOf(intermediateCa.certificate, rootCaCert)))
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||
}
|
||||
@ -60,7 +60,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
|
||||
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
|
||||
// when
|
||||
@ -70,7 +70,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||
|
||||
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
||||
assertEquals(signedNetworkMap.verified(rootCaCert.cert), persistedSignedNetworkMap?.verified(rootCaCert.cert))
|
||||
assertEquals(signedNetworkMap.verified(rootCaCert), persistedSignedNetworkMap?.verified(rootCaCert))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -96,7 +96,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
// Sign network map making it current network map
|
||||
val networkMap = NetworkMap(emptyList(), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
||||
@ -117,7 +117,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
val netParamsHash = networkMapStorage.saveNetworkParameters(netParams)
|
||||
val signedNetParams = networkMapStorage.getSignedNetworkParameters(netParamsHash)
|
||||
assertThat(signedNetParams?.verified()).isEqualTo(netParams)
|
||||
assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCaKeyPair.public)
|
||||
assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCa.keyPair.public)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -135,7 +135,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
|
||||
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
|
||||
// Sign network map
|
||||
|
@ -6,15 +6,16 @@ import com.r3.corda.networkmanage.common.utils.hashString
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.internal.TestNodeInfoBuilder
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.signWith
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -22,6 +23,7 @@ import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
@ -31,13 +33,14 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
||||
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
persistence = configureDatabase(MockServices.makeTestDataSourceProperties())
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||
@ -53,9 +56,14 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
||||
// Create node info.
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val name = CordaX500Name(organisation = "Test", locality = "London", country = "GB")
|
||||
val nodeCaCert = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, name, keyPair.public)
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
intermediateCa.certificate,
|
||||
intermediateCa.keyPair,
|
||||
name.x500Principal,
|
||||
keyPair.public)
|
||||
|
||||
val request = X509Utilities.createCertificateSigningRequest(name, "my@mail.com", keyPair)
|
||||
val request = X509Utilities.createCertificateSigningRequest(name.x500Principal, "my@mail.com", keyPair)
|
||||
|
||||
val requestId = requestStorage.saveRequest(request)
|
||||
requestStorage.markRequestTicketCreated(requestId)
|
||||
@ -63,12 +71,15 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
||||
|
||||
assertNull(nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString())))
|
||||
|
||||
requestStorage.putCertificatePath(requestId, buildCertPath(nodeCaCert.cert, intermediateCACert.cert, rootCACert.cert), listOf(CertificationRequestStorage.DOORMAN_SIGNATURE))
|
||||
requestStorage.putCertificatePath(
|
||||
requestId,
|
||||
buildCertPath(nodeCaCert, intermediateCa.certificate, rootCaCert),
|
||||
listOf(CertificationRequestStorage.DOORMAN_SIGNATURE))
|
||||
|
||||
val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
|
||||
assertNotNull(storedCertPath)
|
||||
|
||||
assertEquals(nodeCaCert.cert, storedCertPath!!.certificates.first())
|
||||
assertEquals(nodeCaCert, storedCertPath!!.certificates.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -4,20 +4,18 @@ import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.cert.X509Certificate
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@ -25,12 +23,15 @@ class NetworkMapSignerTest : TestBase() {
|
||||
private lateinit var signer: Signer
|
||||
private lateinit var networkMapStorage: NetworkMapStorage
|
||||
private lateinit var networkMapSigner: NetworkMapSigner
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
|
||||
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
signer = mock()
|
||||
networkMapStorage = mock()
|
||||
networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
||||
@ -43,11 +44,11 @@ class NetworkMapSignerTest : TestBase() {
|
||||
val networkParameters = testNetworkParameters(emptyList())
|
||||
val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize()
|
||||
whenever(networkMapStorage.getCurrentNetworkMap())
|
||||
.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)))
|
||||
.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)))
|
||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||
whenever(signer.sign(any())).then {
|
||||
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
||||
intermediateCa.keyPair.sign(it.arguments[0] as ByteArray).withCert(intermediateCa.certificate)
|
||||
}
|
||||
|
||||
// when
|
||||
@ -59,7 +60,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
verify(networkMapStorage).getLatestNetworkParameters()
|
||||
argumentCaptor<SignedNetworkMap>().apply {
|
||||
verify(networkMapStorage).saveNetworkMap(capture())
|
||||
val networkMap = firstValue.verified(rootCACert.cert)
|
||||
val networkMap = firstValue.verified(rootCaCert)
|
||||
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
||||
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
||||
@ -73,7 +74,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
val networkMapParametersHash = networkParameters.serialize().bytes.sha256()
|
||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert))
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate))
|
||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||
@ -94,7 +95,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||
whenever(signer.sign(any())).then {
|
||||
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
||||
intermediateCa.keyPair.sign(it.arguments[0] as ByteArray).withCert(intermediateCa.certificate)
|
||||
}
|
||||
// when
|
||||
networkMapSigner.signNetworkMap()
|
||||
@ -105,7 +106,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
verify(networkMapStorage).getLatestNetworkParameters()
|
||||
argumentCaptor<SignedNetworkMap>().apply {
|
||||
verify(networkMapStorage).saveNetworkMap(capture())
|
||||
val networkMap = firstValue.verified(rootCACert.cert)
|
||||
val networkMap = firstValue.verified(rootCaCert)
|
||||
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,23 @@ import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage
|
||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import com.r3.corda.networkmanage.doorman.signer.DefaultCsrHandler
|
||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import org.junit.Test
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DefaultRequestProcessorTest : TestBase() {
|
||||
@Test
|
||||
fun `get response`() {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val cert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "Test", country = "GB"), keyPair)
|
||||
val cert = X509Utilities.createSelfSignedCACertificate(X500Principal("O=Test,L=London,C=GB"), keyPair)
|
||||
|
||||
val requestStorage: CertificationRequestStorage = mock {
|
||||
on { getRequest("New") }.thenReturn(certificateSigningRequest())
|
||||
on { getRequest("Signed") }.thenReturn(certificateSigningRequest(status = RequestStatus.SIGNED, certData = certificateData("", CertificateStatus.VALID, buildCertPath(cert.toX509Certificate()))))
|
||||
on { getRequest("Signed") }.thenReturn(certificateSigningRequest(status = RequestStatus.SIGNED, certData = certificateData("", CertificateStatus.VALID, buildCertPath(cert))))
|
||||
on { getRequest("Rejected") }.thenReturn(certificateSigningRequest(status = RequestStatus.REJECTED, remark = "Random reason"))
|
||||
}
|
||||
val signer: LocalSigner = mock()
|
||||
@ -35,15 +34,15 @@ class DefaultRequestProcessorTest : TestBase() {
|
||||
|
||||
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("random"))
|
||||
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("New"))
|
||||
assertEquals(CertificateResponse.Ready(buildCertPath(cert.toX509Certificate())), requestProcessor.getResponse("Signed"))
|
||||
assertEquals(CertificateResponse.Ready(buildCertPath(cert)), requestProcessor.getResponse("Signed"))
|
||||
assertEquals(CertificateResponse.Unauthorised("Random reason"), requestProcessor.getResponse("Rejected"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `process request`() {
|
||||
val request1 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test1", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
|
||||
val request2 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test2", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
|
||||
val request3 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test3", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
|
||||
val (request1, request2, request3) = (1..3).map {
|
||||
X509Utilities.createCertificateSigningRequest(X500Principal("O=Test1,L=London,C=GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
|
||||
}
|
||||
|
||||
val requestStorage: CertificationRequestStorage = mock {
|
||||
on { getRequests(RequestStatus.APPROVED) }.thenReturn(listOf(
|
||||
|
@ -7,33 +7,32 @@ import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.openHttpConnection
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.createNodeInfoAndSigned
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.FileNotFoundException
|
||||
import java.net.URL
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.ws.rs.core.MediaType
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -42,12 +41,18 @@ class NodeInfoWebServiceTest {
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private val rootCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair)
|
||||
private val intermediateCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCaCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCaCert, rootCaKeyPair, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCaKeyPair.public)
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
|
||||
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
||||
|
||||
@Before
|
||||
fun init() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `submit nodeInfo`() {
|
||||
// Create node info.
|
||||
@ -65,7 +70,7 @@ class NodeInfoWebServiceTest {
|
||||
fun `get network map`() {
|
||||
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert))
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate))
|
||||
|
||||
val networkMapStorage: NetworkMapStorage = mock {
|
||||
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
|
||||
@ -75,7 +80,7 @@ class NodeInfoWebServiceTest {
|
||||
it.start()
|
||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
||||
assertEquals(signedNetworkMapResponse.verified(rootCaCert.cert), networkMap)
|
||||
assertEquals(signedNetworkMapResponse.verified(rootCaCert), networkMap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +109,7 @@ class NodeInfoWebServiceTest {
|
||||
fun `get network parameters`() {
|
||||
val netParams = testNetworkParameters(emptyList())
|
||||
val serializedNetParams = netParams.serialize()
|
||||
val signedNetParams = SignedData(serializedNetParams, intermediateCaKeyPair.sign(serializedNetParams))
|
||||
val signedNetParams = SignedData(serializedNetParams, intermediateCa.keyPair.sign(serializedNetParams))
|
||||
val netParamsHash = serializedNetParams.hash
|
||||
|
||||
val networkMapStorage: NetworkMapStorage = mock {
|
||||
@ -116,7 +121,7 @@ class NodeInfoWebServiceTest {
|
||||
val netParamsResponse = it.doGet<SignedData<NetworkParameters>>("network-parameter/$netParamsHash")
|
||||
verify(networkMapStorage, times(1)).getSignedNetworkParameters(netParamsHash)
|
||||
assertThat(netParamsResponse.verified()).isEqualTo(netParams)
|
||||
assertThat(netParamsResponse.sig.by).isEqualTo(intermediateCaKeyPair.public)
|
||||
assertThat(netParamsResponse.sig.by).isEqualTo(intermediateCa.keyPair.public)
|
||||
|
||||
assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
|
||||
it.doGet<SignedData<NetworkParameters>>("network-parameter/${randomSHA256()}")
|
||||
|
@ -4,46 +4,54 @@ import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateResponse
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import com.r3.corda.networkmanage.doorman.signer.CsrHandler
|
||||
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
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.cert.X509CertificateHolder
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.HttpURLConnection.*
|
||||
import java.net.URL
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import java.util.zip.ZipInputStream
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import javax.ws.rs.core.MediaType
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class RegistrationWebServiceTest : TestBase() {
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 Ltd", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var webServer: NetworkManagementWebServer
|
||||
|
||||
@Before
|
||||
fun init() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
}
|
||||
|
||||
private fun startSigningServer(csrHandler: CsrHandler) {
|
||||
webServer = NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), RegistrationWebService(csrHandler))
|
||||
webServer.start()
|
||||
@ -65,7 +73,10 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
startSigningServer(requestProcessor)
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB"), "my@mail.com", keyPair)
|
||||
val request = X509Utilities.createCertificateSigningRequest(
|
||||
CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB").x500Principal,
|
||||
"my@mail.com",
|
||||
keyPair)
|
||||
// Post request to signing server via http.
|
||||
|
||||
assertEquals(id, submitRequest(request))
|
||||
@ -79,6 +90,8 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val id = SecureHash.randomSHA256().toString()
|
||||
|
||||
val subject = CordaX500Name(locality = "London", organisation = "LegalName", country = "GB").x500Principal
|
||||
|
||||
// Mock Storage behaviour.
|
||||
val certificateStore = mutableMapOf<String, CertPath>()
|
||||
val requestProcessor = mock<CsrHandler> {
|
||||
@ -88,10 +101,15 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
} ?: CertificateResponse.NotReady
|
||||
}
|
||||
on { processApprovedRequests() }.then {
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "LegalName", country = "GB"), "my@mail.com", keyPair)
|
||||
val request = X509Utilities.createCertificateSigningRequest(subject, "my@mail.com", keyPair)
|
||||
certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
|
||||
val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
|
||||
buildCertPath(tlsCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val tlsCert = X509Utilities.createCertificate(
|
||||
CertificateType.TLS,
|
||||
intermediateCa.certificate,
|
||||
intermediateCa.keyPair,
|
||||
X500Principal(subject.encoded),
|
||||
publicKey)
|
||||
buildCertPath(tlsCert, intermediateCa.certificate, rootCaCert)
|
||||
}
|
||||
null
|
||||
}
|
||||
@ -104,22 +122,15 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
|
||||
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
|
||||
verify(requestProcessor, times(2)).getResponse(any())
|
||||
assertEquals(3, certificates.size)
|
||||
|
||||
certificates.first().run {
|
||||
assertThat(subjectDN.name).contains("O=LegalName")
|
||||
assertThat(subjectDN.name).contains("L=London")
|
||||
}
|
||||
|
||||
certificates.last().run {
|
||||
assertThat(subjectDN.name).contains("CN=Corda Node Root CA")
|
||||
assertThat(subjectDN.name).contains("L=London")
|
||||
}
|
||||
assertThat(certificates).hasSize(3)
|
||||
assertThat(certificates[0].subjectX500Principal).isEqualTo(subject)
|
||||
assertThat(certificates).endsWith(intermediateCa.certificate, rootCaCert)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `retrieve certificate and create valid TLS certificate`() {
|
||||
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val nodeCaKeyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val id = SecureHash.randomSHA256().toString()
|
||||
|
||||
// Mock Storage behaviour.
|
||||
@ -131,11 +142,22 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
} ?: CertificateResponse.NotReady
|
||||
}
|
||||
on { processApprovedRequests() }.then {
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB"), "my@mail.com", keyPair)
|
||||
val request = X509Utilities.createCertificateSigningRequest(
|
||||
CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB").x500Principal,
|
||||
"my@mail.com",
|
||||
nodeCaKeyPair)
|
||||
certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
|
||||
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))), arrayOf())
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints).toX509Certificate()
|
||||
buildCertPath(clientCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nameConstraints = NameConstraints(
|
||||
arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))),
|
||||
arrayOf())
|
||||
val clientCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
intermediateCa.certificate,
|
||||
intermediateCa.keyPair,
|
||||
X500Principal(subject.encoded),
|
||||
publicKey,
|
||||
nameConstraints = nameConstraints)
|
||||
buildCertPath(clientCert, intermediateCa.certificate, rootCaCert)
|
||||
}
|
||||
true
|
||||
}
|
||||
@ -149,11 +171,17 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
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, X509CertificateHolder(certificates.first().encoded), keyPair, X500Name("CN=LegalName,L=London"), sslKey.public).toX509Certificate()
|
||||
val sslKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val sslCert = X509Utilities.createCertificate(
|
||||
CertificateType.TLS,
|
||||
certificates[0],
|
||||
nodeCaKeyPair,
|
||||
// TODO Investigate why X500Principal("CN=LegalName, L=London") results in a name constraints violation
|
||||
X500Principal(X500Name("CN=LegalName, L=London").encoded),
|
||||
sslKeyPair.public)
|
||||
|
||||
// TODO: This is temporary solution, remove all certificate re-shaping after identity refactoring is done.
|
||||
X509Utilities.validateCertificateChain(certificates.last(), sslCert, *certificates.toTypedArray())
|
||||
X509Utilities.validateCertificateChain(rootCaCert, sslCert, *certificates.toTypedArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -192,7 +220,7 @@ class RegistrationWebServiceTest : TestBase() {
|
||||
PollResponse.Ready(certificates)
|
||||
}
|
||||
HTTP_NO_CONTENT -> PollResponse.NotReady
|
||||
HTTP_UNAUTHORIZED -> PollResponse.Unauthorised(IOUtils.toString(conn.errorStream))
|
||||
HTTP_UNAUTHORIZED -> PollResponse.Unauthorised(IOUtils.toString(conn.errorStream, UTF_8))
|
||||
else -> throw IOException("Cannot connect to Certificate Signing Server, HTTP response code : ${conn.responseCode}")
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,10 @@ class JiraCsrHandlerTest {
|
||||
private lateinit var certificateResponse: CertificateResponse.Ready
|
||||
|
||||
private val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val pkcS10CertificationRequest = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "LegalName", country = "GB"), "my@mail.com", keyPair)
|
||||
private val pkcS10CertificationRequest = X509Utilities.createCertificateSigningRequest(
|
||||
CordaX500Name(locality = "London", organisation = "LegalName", country = "GB").x500Principal,
|
||||
"my@mail.com",
|
||||
keyPair)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
|
Loading…
Reference in New Issue
Block a user