mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
Added various X509 utilities to remove some of the existing boilerplate. (#2416)
This commit is contained in:
@ -12,25 +12,27 @@ import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||
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.CORDA_CLIENT_CA
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.DEV_ROOT_CA
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.PortAllocation
|
||||
import net.corda.testing.node.NotarySpec
|
||||
import net.corda.testing.node.internal.CompatibilityZoneParams
|
||||
import net.corda.testing.node.internal.internalDriver
|
||||
import net.corda.testing.node.internal.network.NetworkMapServer
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.junit.*
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
@ -151,7 +153,7 @@ class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair)
|
||||
val (certPath, name) = createSignedClientCertificate(
|
||||
certificationRequest,
|
||||
rootCertAndKeyPair.keyPair,
|
||||
arrayOf(rootCertAndKeyPair.certificate))
|
||||
listOf(rootCertAndKeyPair.certificate))
|
||||
require(!name.organisation.contains("\\s".toRegex())) { "Whitespace in the organisation name not supported" }
|
||||
certPaths[name.organisation] = certPath
|
||||
return Response.ok(name.organisation).build()
|
||||
@ -180,17 +182,17 @@ class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair)
|
||||
|
||||
private fun createSignedClientCertificate(certificationRequest: PKCS10CertificationRequest,
|
||||
caKeyPair: KeyPair,
|
||||
caCertPath: Array<Certificate>): Pair<CertPath, CordaX500Name> {
|
||||
caCertPath: List<X509Certificate>): Pair<CertPath, CordaX500Name> {
|
||||
val request = JcaPKCS10CertificationRequest(certificationRequest)
|
||||
val name = CordaX500Name.parse(request.subject.toString())
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
caCertPath[0] as X509Certificate ,
|
||||
caCertPath[0],
|
||||
caKeyPair,
|
||||
name.x500Principal,
|
||||
request.publicKey,
|
||||
nameConstraints = null)
|
||||
val certPath = X509CertificateFactory().generateCertPath(nodeCaCert, *caCertPath)
|
||||
val certPath = X509Utilities.buildCertPath(nodeCaCert, caCertPath)
|
||||
return Pair(certPath, name)
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,6 @@ import net.corda.node.shell.InteractiveShell
|
||||
import net.corda.node.utilities.AffinityExecutor
|
||||
import net.corda.nodeapi.internal.DevIdentityGenerator
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
@ -755,7 +754,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
throw ConfigurationException("The name '$singleName' for $id doesn't match what's in the key store: $subject")
|
||||
}
|
||||
|
||||
val certPath = X509CertificateFactory().generateCertPath(certificates)
|
||||
val certPath = X509Utilities.buildCertPath(certificates)
|
||||
return Pair(PartyAndCertificate(certPath), keyPair)
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import net.corda.node.internal.protonwrapper.engine.EventProcessor
|
||||
import net.corda.node.internal.protonwrapper.messages.ReceivedMessage
|
||||
import net.corda.node.internal.protonwrapper.messages.impl.ReceivedMessageImpl
|
||||
import net.corda.node.internal.protonwrapper.messages.impl.SendableMessageImpl
|
||||
import net.corda.nodeapi.internal.crypto.x509
|
||||
import org.apache.qpid.proton.engine.ProtonJTransport
|
||||
import org.apache.qpid.proton.engine.Transport
|
||||
import org.apache.qpid.proton.engine.impl.ProtocolTracer
|
||||
@ -80,8 +81,8 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
|
||||
if (evt is SslHandshakeCompletionEvent) {
|
||||
if (evt.isSuccess) {
|
||||
val sslHandler = ctx.pipeline().get(SslHandler::class.java)
|
||||
localCert = sslHandler.engine().session.localCertificates[0] as X509Certificate
|
||||
remoteCert = sslHandler.engine().session.peerCertificates[0] as X509Certificate
|
||||
localCert = sslHandler.engine().session.localCertificates[0].x509
|
||||
remoteCert = sslHandler.engine().session.peerCertificates[0].x509
|
||||
try {
|
||||
val remoteX500Name = CordaX500Name.build(remoteCert.subjectX500Principal)
|
||||
require(allowedRemoteLegalNames == null || remoteX500Name in allowedRemoteLegalNames)
|
||||
|
@ -9,7 +9,8 @@ import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.*
|
||||
@ -45,24 +46,24 @@ class InMemoryIdentityService(identities: Array<out PartyAndCertificate>,
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? {
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
val identityCertChain = identity.certPath.x509Certificates
|
||||
try {
|
||||
identity.verify(trustAnchor)
|
||||
} catch (e: CertPathValidatorException) {
|
||||
log.warn("Certificate validation failed for ${identity.name} against trusted root ${trustAnchor.trustedCert.subjectX500Principal}.")
|
||||
log.warn("Certificate path :")
|
||||
identity.certPath.certificates.reversed().forEachIndexed { index, certificate ->
|
||||
identityCertChain.reversed().forEachIndexed { index, certificate ->
|
||||
val space = (0 until index).joinToString("") { " " }
|
||||
log.warn("$space${(certificate as X509Certificate).subjectX500Principal}")
|
||||
log.warn("$space${certificate.subjectX500Principal}")
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
// Ensure we record the first identity of the same name, first
|
||||
val wellKnownCert: Certificate = identity.certPath.certificates.single { CertRole.extract(it)?.isWellKnown ?: false }
|
||||
val wellKnownCert = identityCertChain.single { CertRole.extract(it)?.isWellKnown ?: false }
|
||||
if (wellKnownCert != identity.certificate) {
|
||||
val certificates = identity.certPath.certificates
|
||||
val idx = certificates.lastIndexOf(wellKnownCert)
|
||||
val firstPath = X509CertificateFactory().generateCertPath(certificates.slice(idx until certificates.size))
|
||||
val idx = identityCertChain.lastIndexOf(wellKnownCert)
|
||||
val firstPath = X509Utilities.buildCertPath(identityCertChain.slice(idx until identityCertChain.size))
|
||||
verifyAndRegisterIdentity(PartyAndCertificate(firstPath))
|
||||
}
|
||||
|
||||
@ -70,7 +71,7 @@ class InMemoryIdentityService(identities: Array<out PartyAndCertificate>,
|
||||
keyToParties[identity.owningKey] = identity
|
||||
// Always keep the first party we registered, as that's the well known identity
|
||||
principalToParties.computeIfAbsent(identity.name) { identity }
|
||||
return keyToParties[identity.certPath.certificates[1].publicKey]
|
||||
return keyToParties[identityCertChain[1].publicKey]
|
||||
}
|
||||
|
||||
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[owningKey]
|
||||
@ -103,7 +104,7 @@ class InMemoryIdentityService(identities: Array<out PartyAndCertificate>,
|
||||
val results = LinkedHashSet<Party>()
|
||||
for ((x500name, partyAndCertificate) in principalToParties) {
|
||||
val party = partyAndCertificate.party
|
||||
val components = listOf(x500name.commonName, x500name.organisationUnit, x500name.organisation, x500name.locality, x500name.state, x500name.country).filterNotNull()
|
||||
val components = listOfNotNull(x500name.commonName, x500name.organisationUnit, x500name.organisation, x500name.locality, x500name.state, x500name.country)
|
||||
components.forEach { component ->
|
||||
if (exactMatch && component == query) {
|
||||
results += party
|
||||
|
@ -13,6 +13,8 @@ import net.corda.core.utilities.debug
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.PublicKey
|
||||
@ -111,23 +113,23 @@ class PersistentIdentityService(override val trustRoot: X509Certificate,
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? {
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
val identityCertChain = identity.certPath.x509Certificates
|
||||
try {
|
||||
identity.verify(trustAnchor)
|
||||
} catch (e: CertPathValidatorException) {
|
||||
log.warn(e.localizedMessage)
|
||||
log.warn("Path = ")
|
||||
identity.certPath.certificates.reversed().forEach {
|
||||
log.warn((it as X509Certificate).subjectX500Principal.toString())
|
||||
identityCertChain.reversed().forEach {
|
||||
log.warn(it.subjectX500Principal.toString())
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
// Ensure we record the first identity of the same name, first
|
||||
val wellKnownCert: Certificate = identity.certPath.certificates.single { CertRole.extract(it)?.isWellKnown ?: false }
|
||||
val wellKnownCert = identityCertChain.single { CertRole.extract(it)?.isWellKnown ?: false }
|
||||
if (wellKnownCert != identity.certificate) {
|
||||
val certificates = identity.certPath.certificates
|
||||
val idx = certificates.lastIndexOf(wellKnownCert)
|
||||
val firstPath = X509CertificateFactory().generateCertPath(certificates.slice(idx until certificates.size))
|
||||
val idx = identityCertChain.lastIndexOf(wellKnownCert)
|
||||
val firstPath = X509Utilities.buildCertPath(identityCertChain.slice(idx until identityCertChain.size))
|
||||
verifyAndRegisterIdentity(PartyAndCertificate(firstPath))
|
||||
}
|
||||
|
||||
@ -136,7 +138,7 @@ class PersistentIdentityService(override val trustRoot: X509Certificate,
|
||||
keyToParties.addWithDuplicatesAllowed(key, identity)
|
||||
// Always keep the first party we registered, as that's the well known identity
|
||||
principalToParties.addWithDuplicatesAllowed(identity.name, key, false)
|
||||
val parentId = mapToKey(identity.certPath.certificates[1].publicKey)
|
||||
val parentId = mapToKey(identityCertChain[1].publicKey)
|
||||
return keyToParties[parentId]
|
||||
}
|
||||
|
||||
@ -175,7 +177,7 @@ class PersistentIdentityService(override val trustRoot: X509Certificate,
|
||||
val results = LinkedHashSet<Party>()
|
||||
for ((x500name, partyId) in principalToParties.allPersisted()) {
|
||||
val party = keyToParties[partyId]!!.party
|
||||
val components = listOf(x500name.commonName, x500name.organisationUnit, x500name.organisation, x500name.locality, x500name.state, x500name.country).filterNotNull()
|
||||
val components = listOfNotNull(x500name.commonName, x500name.organisationUnit, x500name.organisation, x500name.locality, x500name.state, x500name.country)
|
||||
components.forEach { component ->
|
||||
if (exactMatch && component == query) {
|
||||
results += party
|
||||
|
@ -7,8 +7,8 @@ import net.corda.core.utilities.days
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
@ -43,7 +43,7 @@ fun freshCertificate(identityService: IdentityServiceInternal,
|
||||
issuer.name.x500Principal,
|
||||
subjectPublicKey,
|
||||
window)
|
||||
val ourCertPath = X509CertificateFactory().generateCertPath(listOf(ourCertificate) + issuer.certPath.certificates)
|
||||
val ourCertPath = X509Utilities.buildCertPath(ourCertificate, issuer.certPath.x509Certificates)
|
||||
val anonymisedIdentity = PartyAndCertificate(ourCertPath)
|
||||
identityService.justVerifyAndRegisterIdentity(anonymisedIdentity)
|
||||
return anonymisedIdentity
|
||||
|
@ -13,6 +13,7 @@ import net.corda.nodeapi.internal.ArtemisMessagingComponent
|
||||
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER
|
||||
import net.corda.nodeapi.internal.ArtemisMessagingComponent.RemoteInboxAddress.Companion.translateLocalQueueToInboxAddress
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.x509
|
||||
import org.apache.activemq.artemis.api.core.Message
|
||||
import org.apache.activemq.artemis.core.config.BridgeConfiguration
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection
|
||||
@ -23,7 +24,6 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer
|
||||
import org.apache.activemq.artemis.core.server.cluster.Transformer
|
||||
import org.apache.activemq.artemis.spi.core.remoting.*
|
||||
import org.apache.activemq.artemis.utils.ConfigurationHelper
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
@ -162,7 +162,9 @@ class VerifyingNettyConnectorFactory : NettyConnectorFactory() {
|
||||
"Peer has wrong subject name in the certificate - expected $expectedLegalNames but got $peerCertificateName. This is either a fatal " +
|
||||
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!"
|
||||
}
|
||||
X509Utilities.validateCertificateChain(session.localCertificates.last() as X509Certificate, *session.peerCertificates)
|
||||
X509Utilities.validateCertificateChain(
|
||||
session.localCertificates.last().x509,
|
||||
session.peerCertificates.x509)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
connection.close()
|
||||
log.error(e.message)
|
||||
|
@ -10,6 +10,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_TLS
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.nodeapi.internal.crypto.x509
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
|
||||
import org.bouncycastle.util.io.pem.PemObject
|
||||
import java.io.StringWriter
|
||||
@ -43,7 +44,7 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
|
||||
"This file must contain the root CA cert of your compatibility zone. " +
|
||||
"Please contact your CZ operator."
|
||||
}
|
||||
this.rootCert = rootCert as X509Certificate
|
||||
this.rootCert = rootCert.x509
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +110,7 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
|
||||
}
|
||||
|
||||
println("Checking root of the certificate path is what we expect.")
|
||||
X509Utilities.validateCertificateChain(rootCert, *certificates.toTypedArray())
|
||||
X509Utilities.validateCertificateChain(rootCert, certificates)
|
||||
|
||||
println("Certificate signing request approved, storing private key with the certificate chain.")
|
||||
// Save private key and certificate chain to the key store.
|
||||
|
@ -8,8 +8,8 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
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.x509Certificates
|
||||
import net.corda.testing.core.*
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@ -173,7 +173,7 @@ class InMemoryIdentityServiceTests {
|
||||
issuerKeyPair,
|
||||
x500Name.x500Principal,
|
||||
txKeyPair.public)
|
||||
val txCertPath = X509CertificateFactory().generateCertPath(listOf(txCert) + issuer.certPath.certificates)
|
||||
val txCertPath = X509Utilities.buildCertPath(txCert, issuer.certPath.x509Certificates)
|
||||
return Pair(issuer, PartyAndCertificate(txCertPath))
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
import net.corda.node.internal.configureDatabase
|
||||
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.x509Certificates
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.core.*
|
||||
@ -264,8 +264,13 @@ class PersistentIdentityServiceTests {
|
||||
val issuerKeyPair = generateKeyPair()
|
||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public)
|
||||
val txKey = Crypto.generateKeyPair()
|
||||
val txCert = X509Utilities.createCertificate(CertificateType.CONFIDENTIAL_LEGAL_IDENTITY, issuer.certificate, issuerKeyPair, x500Name.x500Principal, txKey.public)
|
||||
val txCertPath = X509CertificateFactory().generateCertPath(listOf(txCert) + issuer.certPath.certificates)
|
||||
val txCert = X509Utilities.createCertificate(
|
||||
CertificateType.CONFIDENTIAL_LEGAL_IDENTITY,
|
||||
issuer.certificate,
|
||||
issuerKeyPair,
|
||||
x500Name.x500Principal,
|
||||
txKey.public)
|
||||
val txCertPath = X509Utilities.buildCertPath(txCert, issuer.certPath.x509Certificates)
|
||||
return Pair(issuer, PartyAndCertificate(txCertPath))
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user