Merge fixes and updated network-management to work with the move away from X509CertificateHolder

This commit is contained in:
Shams Asari 2018-01-04 15:06:21 +00:00
parent 13619df0b1
commit 133fd27222
16 changed files with 248 additions and 196 deletions

View File

@ -3,14 +3,11 @@ package com.r3.corda.networkmanage.doorman
import com.nhaarman.mockito_kotlin.doReturn import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever import com.nhaarman.mockito_kotlin.whenever
import com.r3.corda.networkmanage.common.persistence.configureDatabase 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 com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.cert
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.node.NodeInfo 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.SerializationEnvironmentRule
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import org.bouncycastle.cert.X509CertificateHolder
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.net.URL import java.net.URL
import java.security.cert.X509Certificate
import java.util.* import java.util.*
import javax.security.auth.x500.X500Principal
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
@ -60,7 +58,7 @@ class DoormanIntegrationTest {
} }
config.trustStoreFile.parent.createDirectories() config.trustStoreFile.parent.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also { 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) it.save(config.trustStoreFile, config.trustStorePassword)
} }
@ -77,18 +75,18 @@ class DoormanIntegrationTest {
loadKeyStore(config.nodeKeystore, config.keyStorePassword).apply { loadKeyStore(config.nodeKeystore, config.keyStorePassword).apply {
assert(containsAlias(X509Utilities.CORDA_CLIENT_CA)) assert(containsAlias(X509Utilities.CORDA_CLIENT_CA))
assertEquals(ALICE_NAME.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subjectX500Principal) 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 { loadKeyStore(config.sslKeystore, config.keyStorePassword).apply {
assert(containsAlias(X509Utilities.CORDA_CLIENT_TLS)) assert(containsAlias(X509Utilities.CORDA_CLIENT_TLS))
assertEquals(ALICE_NAME.x500Principal, getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subjectX500Principal) 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 { loadKeyStore(config.trustStoreFile, config.trustStorePassword).apply {
assert(containsAlias(X509Utilities.CORDA_ROOT_CA)) 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() doorman.close()
@ -110,21 +108,26 @@ class DoormanIntegrationTest {
} }
config.trustStoreFile.parent.createDirectories() config.trustStoreFile.parent.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also { 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) it.save(config.trustStoreFile, config.trustStorePassword)
} }
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore() NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
// Publish NodeInfo // 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 keyStore = loadKeyStore(config.nodeKeystore, config.keyStorePassword)
val clientCertPath = keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA) val clientCertPath = keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, config.keyStorePassword) val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, config.keyStorePassword)
val identityKeyPair = Crypto.generateKeyPair() val identityKeyPair = Crypto.generateKeyPair()
val identityCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, clientCA.certificate, clientCA.keyPair, ALICE_NAME, identityKeyPair.public) val identityCert = X509Utilities.createCertificate(
val certPath = X509CertificateFactory().generateCertPath(identityCert.cert, *clientCertPath) 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 nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoBytes = nodeInfo.serialize() val nodeInfoBytes = nodeInfo.serialize()
@ -156,23 +159,23 @@ class DoormanIntegrationTest {
} }
fun createDoormanIntermediateCertificateAndKeyPair(rootCertificateAndKeyPair: CertificateAndKeyPair): CertificateAndKeyPair { fun createDoormanIntermediateCertificateAndKeyPair(rootCa: CertificateAndKeyPair): CertificateAndKeyPair {
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCertificateAndKeyPair.certificate, rootCertificateAndKeyPair.keyPair, val intermediateCACert = X509Utilities.createCertificate(
CordaX500Name(commonName = "Integration Test Corda Node Intermediate CA", CertificateType.INTERMEDIATE_CA,
locality = "London", rootCa.certificate,
country = "GB", rootCa.keyPair,
organisation = "R3 Ltd"), intermediateCAKey.public) X500Principal("CN=Integration Test Corda Node Intermediate CA,O=R3 Ltd,L=London,C=GB"),
return CertificateAndKeyPair(intermediateCACert, intermediateCAKey) keyPair.public)
return CertificateAndKeyPair(intermediateCACert, keyPair)
} }
fun createDoormanRootCertificateAndKeyPair(): CertificateAndKeyPair { fun createDoormanRootCertificateAndKeyPair(): CertificateAndKeyPair {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate( val rootCaCert = X509Utilities.createSelfSignedCACertificate(
CordaX500Name(commonName = "Integration Test Corda Node Root CA", X500Principal("CN=Integration Test Corda Node Root CA,O=R3 Ltd,L=London,C=GB"),
organisation = "R3 Ltd", locality = "London", keyPair)
country = "GB"), rootCAKey) return CertificateAndKeyPair(rootCaCert, keyPair)
return CertificateAndKeyPair(rootCACert, rootCAKey)
} }
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties { fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
@ -184,9 +187,8 @@ fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().to
return props return props
} }
fun startDoorman(intermediateCACertAndKey: CertificateAndKeyPair, rootCACert: X509CertificateHolder): NetworkManagementServer { fun startDoorman(intermediateCACertAndKey: CertificateAndKeyPair, rootCACert: X509Certificate): NetworkManagementServer {
val signer = LocalSigner(intermediateCACertAndKey.keyPair, val signer = LocalSigner(intermediateCACertAndKey.keyPair, arrayOf(intermediateCACertAndKey.certificate, rootCACert))
arrayOf(intermediateCACertAndKey.certificate.toX509Certificate(), rootCACert.toX509Certificate()))
//Start doorman server //Start doorman server
return startDoorman(signer) return startDoorman(signer)
} }

View File

@ -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.persistence.SignedCertificateRequestStorage
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.uncheckedCast 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.SerializationEnvironmentRule
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.h2.tools.Server import org.h2.tools.Server
import org.junit.* import org.junit.*
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.net.URL import java.net.URL
import java.security.cert.X509Certificate
import java.util.* import java.util.*
import javax.persistence.PersistenceException import javax.persistence.PersistenceException
import kotlin.concurrent.scheduleAtFixedRate import kotlin.concurrent.scheduleAtFixedRate
@ -55,7 +54,7 @@ class SigningServiceIntegrationTest {
val testSerialization = SerializationEnvironmentRule(true) val testSerialization = SerializationEnvironmentRule(true)
private lateinit var timer: Timer private lateinit var timer: Timer
private lateinit var rootCaCert: X509CertificateHolder private lateinit var rootCaCert: X509Certificate
private lateinit var intermediateCa: CertificateAndKeyPair private lateinit var intermediateCa: CertificateAndKeyPair
@Before @Before
@ -79,7 +78,7 @@ class SigningServiceIntegrationTest {
for (approvedRequest in approvedRequests) { for (approvedRequest in approvedRequests) {
JcaPKCS10CertificationRequest(approvedRequest.request).run { JcaPKCS10CertificationRequest(approvedRequest.request).run {
val nodeCa = createDevNodeCa(intermediateCa, CordaX500Name.parse(subject.toString())) 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")) storage.store(approvedRequests, listOf("TEST"))
@ -124,7 +123,7 @@ class SigningServiceIntegrationTest {
} }
config.certificatesDirectory.createDirectories() config.certificatesDirectory.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also { 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) it.save(config.trustStoreFile, config.trustStorePassword)
} }
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore() NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
@ -168,7 +167,7 @@ class SigningServiceIntegrationTest {
} }
config.certificatesDirectory.createDirectories() config.certificatesDirectory.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also { 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) it.save(config.trustStoreFile, config.trustStorePassword)
} }
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore() NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()

View File

@ -5,15 +5,14 @@ import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRe
import com.r3.corda.networkmanage.common.utils.hashString import com.r3.corda.networkmanage.common.utils.hashString
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name 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.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseTransaction import net.corda.nodeapi.internal.persistence.DatabaseTransaction
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.hibernate.Session import org.hibernate.Session
import java.security.cert.CertPath import java.security.cert.CertPath
import java.time.Instant import java.time.Instant
import javax.security.auth.x500.X500Principal
/** /**
* Database implementation of the [CertificationRequestStorage] interface. * Database implementation of the [CertificationRequestStorage] interface.
@ -48,7 +47,7 @@ class PersistentCertificateRequestStorage(private val database: CordaPersistence
val (legalName, rejectReason) = parseAndValidateLegalName(request, session) val (legalName, rejectReason) = parseAndValidateLegalName(request, session)
session.save(CertificateSigningRequestEntity( session.save(CertificateSigningRequestEntity(
requestId = requestId, requestId = requestId,
legalName = legalName.toString(), legalName = legalName,
requestBytes = request.encoded, requestBytes = request.encoded,
remark = rejectReason, remark = rejectReason,
modifiedBy = emptyList(), 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 { val legalName = try {
CordaX500Name.parse(request.subject.toString()) CordaX500Name.build(X500Principal(request.subject.encoded)).toString()
} catch (e: IllegalArgumentException) { } 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 query = session.criteriaBuilder.run {
val criteriaQuery = createQuery(CertificateSigningRequestEntity::class.java) val criteriaQuery = createQuery(CertificateSigningRequestEntity::class.java)
criteriaQuery.from(CertificateSigningRequestEntity::class.java).run { 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 { val duplicates = session.createQuery(query).resultList.filter {
it.status in setOf(RequestStatus.NEW, RequestStatus.TICKET_CREATED, RequestStatus.APPROVED) || it.certificateData?.certificateStatus == CertificateStatus.VALID 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")
} }
return Pair(legalName, if (duplicates.isEmpty()) null else "Duplicate legal name")
} }
} }

View File

@ -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.IssueType
import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder
import com.atlassian.jira.rest.client.api.domain.input.TransitionInput import com.atlassian.jira.rest.client.api.domain.input.TransitionInput
import net.corda.core.internal.country import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.locality
import net.corda.core.internal.organisation
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import org.bouncycastle.asn1.x500.style.BCStyle import org.bouncycastle.asn1.x500.style.BCStyle
@ -17,6 +15,7 @@ import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.util.io.pem.PemObject import org.bouncycastle.util.io.pem.PemObject
import java.io.StringWriter import java.io.StringWriter
import java.security.cert.CertPath 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) { class JiraClient(private val restClient: JiraRestClient, private val projectCode: String, private val doneTransitionCode: Int) {
companion object { companion object {
@ -39,16 +38,17 @@ class JiraClient(private val restClient: JiraRestClient, private val projectCode
JcaPEMWriter(request).use { JcaPEMWriter(request).use {
it.writeObject(PemObject("CERTIFICATE REQUEST", signingRequest.encoded)) it.writeObject(PemObject("CERTIFICATE REQUEST", signingRequest.encoded))
} }
val organisation = signingRequest.subject.organisation
val nearestCity = signingRequest.subject.locality // TODO The subject of the signing request has already been validated and parsed into a CordaX500Name. We shouldn't
val country = signingRequest.subject.country // 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 email = signingRequest.getAttributes(BCStyle.E).firstOrNull()?.attrValues?.firstOrNull()?.toString()
val issue = IssueInputBuilder().setIssueTypeId(taskIssueType.id) val issue = IssueInputBuilder().setIssueTypeId(taskIssueType.id)
.setProjectKey(projectCode) .setProjectKey(projectCode)
.setDescription("Organisation: $organisation\nNearest City: $nearestCity\nCountry: $country\nEmail: $email\n\n{code}$request{code}") .setDescription("Organisation: ${subject.organisation}\nNearest City: ${subject.locality}\nCountry: ${subject.country}\nEmail: $email\n\n{code}$request{code}")
.setSummary(organisation) .setSummary(subject.organisation)
.setFieldValue(requestIdField.id, requestId) .setFieldValue(requestIdField.id, requestId)
// This will block until the issue is created. // This will block until the issue is created.
restClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim() restClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim()

View File

@ -13,7 +13,6 @@ import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.serialization.internal.SerializationEnvironmentImpl 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) val selfSignKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
// TODO Make the cert subject configurable // TODO Make the cert subject configurable
val selfSignCert = X509Utilities.createSelfSignedCACertificate( val selfSignCert = X509Utilities.createSelfSignedCACertificate(
CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null), CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null).x500Principal,
selfSignKey).cert selfSignKey)
rootStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, selfSignKey.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert)) rootStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, selfSignKey.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert))
rootStore.save(rootStoreFile, rootKeystorePassword) rootStore.save(rootStoreFile, rootKeystorePassword)
@ -226,11 +225,20 @@ fun generateCAKeyPair(keystoreFile: Path, rootStoreFile: Path, rootKeystorePass:
exitProcess(1) exitProcess(1)
} }
val intermediateKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val intermediateKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val intermediateCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootKeyAndCert.certificate, rootKeyAndCert.keyPair, val intermediateCert = X509Utilities.createCertificate(
CordaX500Name(commonName = "Corda Intermediate CA", organisation = "R3 Ltd", organisationUnit = "Corda", locality = "London", country = "GB", state = null), intermediateKey.public) CertificateType.INTERMEDIATE_CA,
keyStore.addOrReplaceKey(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateKey.private, rootKeyAndCert.certificate,
caPrivateKeyPassword.toCharArray(), arrayOf(intermediateCert, 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) keyStore.save(keystoreFile, keystorePassword)
println("Intermediate CA keypair and certificate stored in $keystoreFile.") println("Intermediate CA keypair and certificate stored in $keystoreFile.")
println(loadKeyStore(keystoreFile, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey) println(loadKeyStore(keystoreFile, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey)

View File

@ -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.buildCertPath
import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.common.utils.withCert
import net.corda.core.crypto.sign 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.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
@ -18,6 +15,7 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import java.security.KeyPair import java.security.KeyPair
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import javax.security.auth.x500.X500Principal
/** /**
* The [LocalSigner] class signs [PKCS10CertificationRequest] using provided CA key pair and certificate path. * 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()) arrayOf())
val nodeCaCert = X509Utilities.createCertificate( val nodeCaCert = X509Utilities.createCertificate(
CertificateType.NODE_CA, CertificateType.NODE_CA,
caCertPath.first().toX509CertHolder(), caCertPath[0],
caKeyPair, caKeyPair,
CordaX500Name.parse(request.subject.toString()), X500Principal(request.subject.encoded),
request.publicKey, request.publicKey,
nameConstraints = nameConstraints) nameConstraints = nameConstraints)
return buildCertPath(nodeCaCert.cert, *caCertPath) return buildCertPath(nodeCaCert, *caCertPath)
} }
override fun sign(data: ByteArray): DigitalSignatureWithCert { override fun sign(data: ByteArray): DigitalSignatureWithCert {

View File

@ -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.getAndInitializeKeyStore
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.signData import com.r3.corda.networkmanage.hsm.utils.X509Utilities.signData
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.verify 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.loggerFor
import net.corda.core.utilities.minutes import net.corda.core.utilities.minutes
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
import java.security.KeyPair import java.security.KeyPair
import java.security.PrivateKey import java.security.PrivateKey
import java.security.cert.X509Certificate
import java.time.Duration import java.time.Duration
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledExecutorService
@ -68,7 +67,7 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
val caKey = keyStore.getKey(caCertificateKeyName, caPrivateKeyPass.toCharArray()) as PrivateKey val caKey = keyStore.getKey(caCertificateKeyName, caPrivateKeyPass.toCharArray()) as PrivateKey
val signature = signData(data, KeyPair(caCertificateChain.first().publicKey, caKey), provider) val signature = signData(data, KeyPair(caCertificateChain.first().publicKey, caKey), provider)
verify(data, signature, caCertificateChain.first().publicKey) verify(data, signature, caCertificateChain.first().publicKey)
signature.withCert(caCertificateChain.first().toX509CertHolder().cert) signature.withCert(caCertificateChain[0] as X509Certificate)
} }
} }
} }

View File

@ -3,7 +3,6 @@ package com.r3.corda.networkmanage.hsm.utils
import CryptoServerJCE.CryptoServerProvider import CryptoServerJCE.CryptoServerProvider
import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.DigitalSignature
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.toX509CertHolder
import net.corda.core.internal.x500Name import net.corda.core.internal.x500Name
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
@ -81,7 +80,7 @@ object X509Utilities {
cert.checkValidity(Date()) cert.checkValidity(Date())
cert.verify(pubKey) 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 { fun retrieveCertificateAndKeys(certificateKeyName: String, privateKeyPassword: String, keyStore: KeyStore): CertificateAndKeyPair {
val privateKey = keyStore.getKey(certificateKeyName, privateKeyPassword.toCharArray()) as PrivateKey val privateKey = keyStore.getKey(certificateKeyName, privateKeyPassword.toCharArray()) as PrivateKey
val publicKey = keyStore.getCertificate(certificateKeyName).publicKey val publicKey = keyStore.getCertificate(certificateKeyName).publicKey
val certificate = keyStore.getX509Certificate(certificateKeyName).toX509CertHolder() val certificate = keyStore.getX509Certificate(certificateKeyName)
return CertificateAndKeyPair(certificate, getCleanEcdsaKeyPair(publicKey, privateKey)) return CertificateAndKeyPair(certificate, getCleanEcdsaKeyPair(publicKey, privateKey))
} }
@ -160,7 +159,7 @@ object X509Utilities {
cert.checkValidity(Date()) cert.checkValidity(Date())
cert.verify(certificateAuthority.keyPair.public) 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 subject = CordaX500Name.parse(jcaRequest.subject.toString()).x500Name
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(jcaRequest.publicKey.encoded)) val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(jcaRequest.publicKey.encoded))
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } }) 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.subjectKeyIdentifier, false, BcX509ExtensionUtils().createSubjectKeyIdentifier(subjectPublicKeyInfo))
.addExtension(Extension.basicConstraints, certificateType.isCA, BasicConstraints(certificateType.isCA)) .addExtension(Extension.basicConstraints, certificateType.isCA, BasicConstraints(certificateType.isCA))
.addExtension(Extension.keyUsage, false, certificateType.keyUsage) .addExtension(Extension.keyUsage, false, certificateType.keyUsage)

View File

@ -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.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
import com.r3.corda.networkmanage.common.utils.buildCertPath 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.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name 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.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.internal.createDevNodeCaCertPath
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.hibernate.envers.AuditReaderFactory import org.hibernate.envers.AuditReaderFactory
@ -21,9 +19,10 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import java.security.KeyPair import java.security.KeyPair
import java.util.* import java.util.*
import javax.security.auth.x500.X500Principal
import kotlin.test.* import kotlin.test.*
class DBCertificateRequestStorageTest : TestBase() { class PersistentCertificateRequestStorageTest : TestBase() {
private lateinit var storage: PersistentCertificateRequestStorage private lateinit var storage: PersistentCertificateRequestStorage
private lateinit var persistence: CordaPersistence private lateinit var persistence: CordaPersistence
@ -84,14 +83,15 @@ class DBCertificateRequestStorageTest : TestBase() {
// New request should be empty. // New request should be empty.
assertTrue(storage.getRequests(RequestStatus.NEW).isEmpty()) assertTrue(storage.getRequests(RequestStatus.NEW).isEmpty())
// Sign certificate // Sign certificate
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run { storage.putCertificatePath(
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) requestId,
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey) JcaPKCS10CertificationRequest(csr).run {
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) // TODO We need a utility in InternalUtils for converting X500Name -> CordaX500Name
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public) val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate() buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) },
}, listOf(DOORMAN_SIGNATURE)) listOf(DOORMAN_SIGNATURE)
)
// Check request is ready // Check request is ready
assertNotNull(storage.getRequest(requestId)!!.certData) assertNotNull(storage.getRequest(requestId)!!.certData)
} }
@ -104,25 +104,24 @@ class DBCertificateRequestStorageTest : TestBase() {
// Store certificate to DB. // Store certificate to DB.
storage.markRequestTicketCreated(requestId) storage.markRequestTicketCreated(requestId)
storage.approveRequest(requestId, DOORMAN_SIGNATURE) storage.approveRequest(requestId, DOORMAN_SIGNATURE)
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run { storage.putCertificatePath(
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) requestId,
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey) JcaPKCS10CertificationRequest(csr).run {
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public) buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate() },
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) listOf(DOORMAN_SIGNATURE)
}, listOf(DOORMAN_SIGNATURE)) )
// Sign certificate // Sign certificate
// When subsequent signature requested // When subsequent signature requested
assertFailsWith(IllegalArgumentException::class) { assertFailsWith(IllegalArgumentException::class) {
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run { storage.putCertificatePath(
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) requestId,
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey) JcaPKCS10CertificationRequest(csr).run {
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val (rootCa, intermediateCa, nodeCa) = createDevNodeCaCertPath(CordaX500Name.build(X500Principal(subject.encoded)))
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public) buildCertPath(nodeCa.certificate, intermediateCa.certificate, rootCa.certificate)
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate() },
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) listOf(DOORMAN_SIGNATURE))
}, listOf(DOORMAN_SIGNATURE))
} }
} }
@ -207,6 +206,6 @@ class DBCertificateRequestStorageTest : TestBase() {
internal fun createRequest(organisation: String): Pair<PKCS10CertificationRequest, KeyPair> { internal fun createRequest(organisation: String): Pair<PKCS10CertificationRequest, KeyPair> {
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) 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) return Pair(request, keyPair)
} }

View File

@ -3,25 +3,24 @@ package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.TestBase
import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.common.utils.withCert
import com.r3.corda.networkmanage.doorman.signer.LocalSigner import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.SignedNodeInfo 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.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.TestNodeInfoBuilder import net.corda.testing.internal.TestNodeInfoBuilder
import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.security.cert.X509Certificate
import kotlin.test.assertEquals import kotlin.test.assertEquals
class PersistentNetworkMapStorageTest : TestBase() { class PersistentNetworkMapStorageTest : TestBase() {
@ -30,15 +29,16 @@ class PersistentNetworkMapStorageTest : TestBase() {
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
private lateinit var requestStorage: PersistentCertificateRequestStorage private lateinit var requestStorage: PersistentCertificateRequestStorage
private val rootCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) private lateinit var rootCaCert: X509Certificate
private val rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair) private lateinit var intermediateCa: CertificateAndKeyPair
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)
@Before @Before
fun startDb() { fun startDb() {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.intermediateCa = intermediateCa
persistence = configureDatabase(makeTestDataSourceProperties()) 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) nodeInfoStorage = PersistentNodeInfoStorage(persistence)
requestStorage = PersistentCertificateRequestStorage(persistence) requestStorage = PersistentCertificateRequestStorage(persistence)
} }
@ -60,7 +60,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash) val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
val serializedNetworkMap = networkMap.serialize() 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) val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
// when // when
@ -70,7 +70,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap() val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature) assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
assertEquals(signedNetworkMap.verified(rootCaCert.cert), persistedSignedNetworkMap?.verified(rootCaCert.cert)) assertEquals(signedNetworkMap.verified(rootCaCert), persistedSignedNetworkMap?.verified(rootCaCert))
} }
@Test @Test
@ -96,7 +96,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
// Sign network map making it current network map // Sign network map making it current network map
val networkMap = NetworkMap(emptyList(), networkParametersHash) val networkMap = NetworkMap(emptyList(), networkParametersHash)
val serializedNetworkMap = networkMap.serialize() 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) val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
networkMapStorage.saveNetworkMap(signedNetworkMap) networkMapStorage.saveNetworkMap(signedNetworkMap)
@ -117,7 +117,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
val netParamsHash = networkMapStorage.saveNetworkParameters(netParams) val netParamsHash = networkMapStorage.saveNetworkParameters(netParams)
val signedNetParams = networkMapStorage.getSignedNetworkParameters(netParamsHash) val signedNetParams = networkMapStorage.getSignedNetworkParameters(netParamsHash)
assertThat(signedNetParams?.verified()).isEqualTo(netParams) assertThat(signedNetParams?.verified()).isEqualTo(netParams)
assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCaKeyPair.public) assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCa.keyPair.public)
} }
@Test @Test
@ -135,7 +135,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList())) val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash) val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
val serializedNetworkMap = networkMap.serialize() 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) val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
// Sign network map // Sign network map

View File

@ -6,15 +6,16 @@ import com.r3.corda.networkmanage.common.utils.hashString
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.SignedNodeInfo 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.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.internal.TestNodeInfoBuilder import net.corda.testing.internal.TestNodeInfoBuilder
import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.internal.signWith import net.corda.testing.internal.signWith
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -22,6 +23,7 @@ import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.security.PrivateKey import java.security.PrivateKey
import java.security.cert.X509Certificate
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import kotlin.test.assertNull import kotlin.test.assertNull
@ -31,13 +33,14 @@ class PersitenceNodeInfoStorageTest : TestBase() {
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
private lateinit var persistence: CordaPersistence private lateinit var persistence: CordaPersistence
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) private lateinit var rootCaCert: X509Certificate
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey) private lateinit var intermediateCa: CertificateAndKeyPair
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)
@Before @Before
fun startDb() { fun startDb() {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.intermediateCa = intermediateCa
persistence = configureDatabase(MockServices.makeTestDataSourceProperties()) persistence = configureDatabase(MockServices.makeTestDataSourceProperties())
nodeInfoStorage = PersistentNodeInfoStorage(persistence) nodeInfoStorage = PersistentNodeInfoStorage(persistence)
requestStorage = PersistentCertificateRequestStorage(persistence) requestStorage = PersistentCertificateRequestStorage(persistence)
@ -53,9 +56,14 @@ class PersitenceNodeInfoStorageTest : TestBase() {
// Create node info. // Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val name = CordaX500Name(organisation = "Test", locality = "London", country = "GB") 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) val requestId = requestStorage.saveRequest(request)
requestStorage.markRequestTicketCreated(requestId) requestStorage.markRequestTicketCreated(requestId)
@ -63,12 +71,15 @@ class PersitenceNodeInfoStorageTest : TestBase() {
assertNull(nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))) 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())) val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
assertNotNull(storedCertPath) assertNotNull(storedCertPath)
assertEquals(nodeCaCert.cert, storedCertPath!!.certificates.first()) assertEquals(nodeCaCert, storedCertPath!!.certificates.first())
} }
@Test @Test

View File

@ -4,20 +4,18 @@ import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.TestBase
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.utils.withCert 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.SecureHash
import net.corda.core.crypto.sha256 import net.corda.core.crypto.sha256
import net.corda.core.crypto.sign 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.core.serialization.serialize
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.createDevIntermediateCaCertPath
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.security.cert.X509Certificate
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -25,12 +23,15 @@ class NetworkMapSignerTest : TestBase() {
private lateinit var signer: Signer private lateinit var signer: Signer
private lateinit var networkMapStorage: NetworkMapStorage private lateinit var networkMapStorage: NetworkMapStorage
private lateinit var networkMapSigner: NetworkMapSigner 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 lateinit var rootCaCert: X509Certificate
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) private lateinit var intermediateCa: CertificateAndKeyPair
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)
@Before @Before
fun setUp() { fun setUp() {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.intermediateCa = intermediateCa
signer = mock() signer = mock()
networkMapStorage = mock() networkMapStorage = mock()
networkMapSigner = NetworkMapSigner(networkMapStorage, signer) networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
@ -43,11 +44,11 @@ class NetworkMapSignerTest : TestBase() {
val networkParameters = testNetworkParameters(emptyList()) val networkParameters = testNetworkParameters(emptyList())
val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize() val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize()
whenever(networkMapStorage.getCurrentNetworkMap()) 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.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
whenever(signer.sign(any())).then { 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 // when
@ -59,7 +60,7 @@ class NetworkMapSignerTest : TestBase() {
verify(networkMapStorage).getLatestNetworkParameters() verify(networkMapStorage).getLatestNetworkParameters()
argumentCaptor<SignedNetworkMap>().apply { argumentCaptor<SignedNetworkMap>().apply {
verify(networkMapStorage).saveNetworkMap(capture()) verify(networkMapStorage).saveNetworkMap(capture())
val networkMap = firstValue.verified(rootCACert.cert) val networkMap = firstValue.verified(rootCaCert)
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash) assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size) assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes)) assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
@ -73,7 +74,7 @@ class NetworkMapSignerTest : TestBase() {
val networkMapParametersHash = networkParameters.serialize().bytes.sha256() val networkMapParametersHash = networkParameters.serialize().bytes.sha256()
val networkMap = NetworkMap(emptyList(), networkMapParametersHash) val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
val serializedNetworkMap = networkMap.serialize() 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.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
@ -94,7 +95,7 @@ class NetworkMapSignerTest : TestBase() {
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
whenever(signer.sign(any())).then { 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 // when
networkMapSigner.signNetworkMap() networkMapSigner.signNetworkMap()
@ -105,7 +106,7 @@ class NetworkMapSignerTest : TestBase() {
verify(networkMapStorage).getLatestNetworkParameters() verify(networkMapStorage).getLatestNetworkParameters()
argumentCaptor<SignedNetworkMap>().apply { argumentCaptor<SignedNetworkMap>().apply {
verify(networkMapStorage).saveNetworkMap(capture()) verify(networkMapStorage).saveNetworkMap(capture())
val networkMap = firstValue.verified(rootCACert.cert) val networkMap = firstValue.verified(rootCaCert)
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash) assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
} }
} }

View File

@ -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.CertificationRequestStorage
import com.r3.corda.networkmanage.common.persistence.RequestStatus import com.r3.corda.networkmanage.common.persistence.RequestStatus
import com.r3.corda.networkmanage.common.utils.buildCertPath 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.DefaultCsrHandler
import com.r3.corda.networkmanage.doorman.signer.LocalSigner import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import org.junit.Test import org.junit.Test
import javax.security.auth.x500.X500Principal
import kotlin.test.assertEquals import kotlin.test.assertEquals
class DefaultRequestProcessorTest : TestBase() { class DefaultRequestProcessorTest : TestBase() {
@Test @Test
fun `get response`() { fun `get response`() {
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) 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 { val requestStorage: CertificationRequestStorage = mock {
on { getRequest("New") }.thenReturn(certificateSigningRequest()) 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")) on { getRequest("Rejected") }.thenReturn(certificateSigningRequest(status = RequestStatus.REJECTED, remark = "Random reason"))
} }
val signer: LocalSigner = mock() val signer: LocalSigner = mock()
@ -35,15 +34,15 @@ class DefaultRequestProcessorTest : TestBase() {
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("random")) assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("random"))
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("New")) 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")) assertEquals(CertificateResponse.Unauthorised("Random reason"), requestProcessor.getResponse("Rejected"))
} }
@Test @Test
fun `process request`() { 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 (request1, request2, request3) = (1..3).map {
val request2 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test2", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) X509Utilities.createCertificateSigningRequest(X500Principal("O=Test1,L=London,C=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 requestStorage: CertificationRequestStorage = mock { val requestStorage: CertificationRequestStorage = mock {
on { getRequests(RequestStatus.APPROVED) }.thenReturn(listOf( on { getRequests(RequestStatus.APPROVED) }.thenReturn(listOf(

View File

@ -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.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.common.utils.withCert
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService 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.SecureHash.Companion.randomSHA256
import net.corda.core.crypto.SignedData import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.openHttpConnection import net.corda.core.internal.openHttpConnection
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.SignedNodeInfo 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.X509Utilities
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.NetworkParameters import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.internal.createNodeInfoAndSigned import net.corda.testing.internal.createNodeInfoAndSigned
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.bouncycastle.asn1.x500.X500Name import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.net.URL import java.net.URL
import java.security.cert.X509Certificate
import javax.ws.rs.core.MediaType import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -42,12 +41,18 @@ class NodeInfoWebServiceTest {
@JvmField @JvmField
val testSerialization = SerializationEnvironmentRule(true) val testSerialization = SerializationEnvironmentRule(true)
private val rootCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) private lateinit var rootCaCert: X509Certificate
private val rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair) private lateinit var intermediateCa: CertificateAndKeyPair
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 val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis()) private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
@Before
fun init() {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.intermediateCa = intermediateCa
}
@Test @Test
fun `submit nodeInfo`() { fun `submit nodeInfo`() {
// Create node info. // Create node info.
@ -65,7 +70,7 @@ class NodeInfoWebServiceTest {
fun `get network map`() { fun `get network map`() {
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256()) val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
val serializedNetworkMap = networkMap.serialize() 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 { val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap) on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
@ -75,7 +80,7 @@ class NodeInfoWebServiceTest {
it.start() it.start()
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("") val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
verify(networkMapStorage, times(1)).getCurrentNetworkMap() 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`() { fun `get network parameters`() {
val netParams = testNetworkParameters(emptyList()) val netParams = testNetworkParameters(emptyList())
val serializedNetParams = netParams.serialize() val serializedNetParams = netParams.serialize()
val signedNetParams = SignedData(serializedNetParams, intermediateCaKeyPair.sign(serializedNetParams)) val signedNetParams = SignedData(serializedNetParams, intermediateCa.keyPair.sign(serializedNetParams))
val netParamsHash = serializedNetParams.hash val netParamsHash = serializedNetParams.hash
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
@ -116,7 +121,7 @@ class NodeInfoWebServiceTest {
val netParamsResponse = it.doGet<SignedData<NetworkParameters>>("network-parameter/$netParamsHash") val netParamsResponse = it.doGet<SignedData<NetworkParameters>>("network-parameter/$netParamsHash")
verify(networkMapStorage, times(1)).getSignedNetworkParameters(netParamsHash) verify(networkMapStorage, times(1)).getSignedNetworkParameters(netParamsHash)
assertThat(netParamsResponse.verified()).isEqualTo(netParams) 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 { assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
it.doGet<SignedData<NetworkParameters>>("network-parameter/${randomSHA256()}") it.doGet<SignedData<NetworkParameters>>("network-parameter/${randomSHA256()}")

View File

@ -4,46 +4,54 @@ import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.TestBase
import com.r3.corda.networkmanage.common.persistence.CertificateResponse import com.r3.corda.networkmanage.common.persistence.CertificateResponse
import com.r3.corda.networkmanage.common.utils.buildCertPath 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.signer.CsrHandler
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort 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.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME 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.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.GeneralName
import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.GeneralSubtree
import org.bouncycastle.asn1.x509.NameConstraints import org.bouncycastle.asn1.x509.NameConstraints
import org.bouncycastle.cert.X509CertificateHolder
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
import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
import java.net.URL import java.net.URL
import java.nio.charset.StandardCharsets.UTF_8
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.util.* import java.util.*
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
import javax.security.auth.x500.X500Principal
import javax.ws.rs.core.MediaType import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals import kotlin.test.assertEquals
class RegistrationWebServiceTest : TestBase() { class RegistrationWebServiceTest : TestBase() {
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) private lateinit var rootCaCert: X509Certificate
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 Ltd", country = "GB"), rootCAKey) private lateinit var intermediateCa: CertificateAndKeyPair
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 webServer: NetworkManagementWebServer private lateinit var webServer: NetworkManagementWebServer
@Before
fun init() {
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.intermediateCa = intermediateCa
}
private fun startSigningServer(csrHandler: CsrHandler) { private fun startSigningServer(csrHandler: CsrHandler) {
webServer = NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), RegistrationWebService(csrHandler)) webServer = NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), RegistrationWebService(csrHandler))
webServer.start() webServer.start()
@ -65,7 +73,10 @@ class RegistrationWebServiceTest : TestBase() {
startSigningServer(requestProcessor) startSigningServer(requestProcessor)
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) 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. // Post request to signing server via http.
assertEquals(id, submitRequest(request)) assertEquals(id, submitRequest(request))
@ -79,6 +90,8 @@ class RegistrationWebServiceTest : TestBase() {
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
val id = SecureHash.randomSHA256().toString() val id = SecureHash.randomSHA256().toString()
val subject = CordaX500Name(locality = "London", organisation = "LegalName", country = "GB").x500Principal
// Mock Storage behaviour. // Mock Storage behaviour.
val certificateStore = mutableMapOf<String, CertPath>() val certificateStore = mutableMapOf<String, CertPath>()
val requestProcessor = mock<CsrHandler> { val requestProcessor = mock<CsrHandler> {
@ -88,10 +101,15 @@ class RegistrationWebServiceTest : TestBase() {
} ?: CertificateResponse.NotReady } ?: CertificateResponse.NotReady
} }
on { processApprovedRequests() }.then { 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 { certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate() val tlsCert = X509Utilities.createCertificate(
buildCertPath(tlsCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) CertificateType.TLS,
intermediateCa.certificate,
intermediateCa.keyPair,
X500Principal(subject.encoded),
publicKey)
buildCertPath(tlsCert, intermediateCa.certificate, rootCaCert)
} }
null null
} }
@ -104,22 +122,15 @@ class RegistrationWebServiceTest : TestBase() {
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
verify(requestProcessor, times(2)).getResponse(any()) verify(requestProcessor, times(2)).getResponse(any())
assertEquals(3, certificates.size)
certificates.first().run { assertThat(certificates).hasSize(3)
assertThat(subjectDN.name).contains("O=LegalName") assertThat(certificates[0].subjectX500Principal).isEqualTo(subject)
assertThat(subjectDN.name).contains("L=London") assertThat(certificates).endsWith(intermediateCa.certificate, rootCaCert)
}
certificates.last().run {
assertThat(subjectDN.name).contains("CN=Corda Node Root CA")
assertThat(subjectDN.name).contains("L=London")
}
} }
@Test @Test
fun `retrieve certificate and create valid TLS certificate`() { 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() val id = SecureHash.randomSHA256().toString()
// Mock Storage behaviour. // Mock Storage behaviour.
@ -131,11 +142,22 @@ class RegistrationWebServiceTest : TestBase() {
} ?: CertificateResponse.NotReady } ?: CertificateResponse.NotReady
} }
on { processApprovedRequests() }.then { 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 { certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))), arrayOf()) val nameConstraints = NameConstraints(
val clientCert = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints).toX509Certificate() arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))),
buildCertPath(clientCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) arrayOf())
val clientCert = X509Utilities.createCertificate(
CertificateType.NODE_CA,
intermediateCa.certificate,
intermediateCa.keyPair,
X500Principal(subject.encoded),
publicKey,
nameConstraints = nameConstraints)
buildCertPath(clientCert, intermediateCa.certificate, rootCaCert)
} }
true true
} }
@ -149,11 +171,17 @@ class RegistrationWebServiceTest : TestBase() {
verify(storage, times(2)).getResponse(any()) verify(storage, times(2)).getResponse(any())
assertEquals(3, certificates.size) assertEquals(3, certificates.size)
val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val sslKeyPair = 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 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. // 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 @Test
@ -192,7 +220,7 @@ class RegistrationWebServiceTest : TestBase() {
PollResponse.Ready(certificates) PollResponse.Ready(certificates)
} }
HTTP_NO_CONTENT -> PollResponse.NotReady 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}") else -> throw IOException("Cannot connect to Certificate Signing Server, HTTP response code : ${conn.responseCode}")
} }
} }

View File

@ -39,7 +39,10 @@ class JiraCsrHandlerTest {
private lateinit var certificateResponse: CertificateResponse.Ready private lateinit var certificateResponse: CertificateResponse.Ready
private val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) 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 @Before
fun setup() { fun setup() {