From a9b794ace501b6456ab63a1e432187c6bc16870b Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Tue, 13 Jun 2017 10:45:06 +0200 Subject: [PATCH] Cleanup: add an extension function to X509CertificateHolder and use that instead of the verbose JcaX509CertificateConverter construct everywhere. --- .../corda/core/crypto/KeyStoreUtilities.kt | 6 +----- .../net/corda/core/crypto/X509Utilities.kt | 4 ++-- .../core/crypto/X509NameConstraintsTest.kt | 6 ++---- .../corda/core/crypto/X509UtilitiesTest.kt | 19 +++++++------------ .../net/corda/node/internal/AbstractNode.kt | 4 +--- .../identity/InMemoryIdentityService.kt | 10 ++++------ .../registration/NetworkRegistrationHelper.kt | 4 +--- .../NetworkisRegistrationHelperTest.kt | 4 +--- 8 files changed, 19 insertions(+), 38 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt b/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt index 21ec1094ee..0c88ee2f27 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt @@ -4,16 +4,13 @@ import net.corda.core.exists import net.corda.core.read import net.corda.core.write import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.cert.path.CertPath -import org.bouncycastle.crypto.util.PublicKeyFactory import java.io.IOException import java.io.InputStream import java.io.OutputStream import java.nio.file.Path import java.security.* import java.security.cert.Certificate -import java.security.cert.X509Certificate object KeyStoreUtilities { val KEYSTORE_TYPE = "JKS" @@ -80,8 +77,7 @@ object KeyStoreUtilities { * @param chain the sequence of certificates starting with the public key certificate for this key and extending to the root CA cert. */ fun KeyStore.addOrReplaceKey(alias: String, key: Key, password: CharArray, chain: CertPath) { - val converter = JcaX509CertificateConverter() - addOrReplaceKey(alias, key, password, chain.certificates.map { it -> converter.getCertificate(it) }.toTypedArray()) + addOrReplaceKey(alias, key, password, chain.certificates.map { it.cert }.toTypedArray()) } /** diff --git a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt index 49aba9f0b9..47c6361b4c 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt @@ -147,9 +147,8 @@ object X509Utilities { fun validateCertificateChain(trustedRoot: X509CertificateHolder, vararg certificates: Certificate) { require(certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } - val converter = JcaX509CertificateConverter() val certFactory = CertificateFactory.getInstance("X509") - val params = PKIXParameters(setOf(TrustAnchor(converter.getCertificate(trustedRoot), null))) + val params = PKIXParameters(setOf(TrustAnchor(trustedRoot.cert, null))) params.isRevocationEnabled = false val certPath = certFactory.generateCertPath(certificates.toList()) val pathValidator = CertPathValidator.getInstance("PKIX") @@ -281,6 +280,7 @@ val X500Name.orgName: String? get() = getRDNs(BCStyle.O).firstOrNull()?.first?.v val X500Name.location: String get() = getRDNs(BCStyle.L).first().first.value.toString() val X500Name.locationOrNull: String? get() = try { location } catch (e: Exception) { null } val X509Certificate.subject: X500Name get() = X509CertificateHolder(encoded).subject +val X509CertificateHolder.cert: X509Certificate get() = JcaX509CertificateConverter().getCertificate(this) class CertificateStream(val input: InputStream) { private val certificateFactory = CertificateFactory.getInstance("X.509") diff --git a/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt b/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt index ffe0feca28..8915ccd955 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.jce.provider.BouncyCastleProvider import org.junit.Test import java.security.KeyStore @@ -17,7 +16,6 @@ import kotlin.test.assertTrue class X509NameConstraintsTest { private fun makeKeyStores(subjectName: X500Name, nameConstraints: NameConstraints): Pair { - val converter = JcaX509CertificateConverter() val rootKeys = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootCACert = X509Utilities.createSelfSignedCACertificate(X509Utilities.getDevX509Name("Corda Root CA"), rootKeys) @@ -30,7 +28,7 @@ class X509NameConstraintsTest { val keyPass = "password" val trustStore = KeyStore.getInstance(KeyStoreUtilities.KEYSTORE_TYPE) trustStore.load(null, keyPass.toCharArray()) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, converter.getCertificate(rootCACert)) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCACert.cert) val tlsKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientCAKeyPair, subjectName, tlsKey.public) @@ -38,7 +36,7 @@ class X509NameConstraintsTest { val keyStore = KeyStore.getInstance(KeyStoreUtilities.KEYSTORE_TYPE) keyStore.load(null, keyPass.toCharArray()) keyStore.addOrReplaceKey(X509Utilities.CORDA_CLIENT_TLS, tlsKey.private, keyPass.toCharArray(), - Stream.of(tlsCert, clientCACert, intermediateCACert, rootCACert).map(converter::getCertificate).toTypedArray()) + Stream.of(tlsCert, clientCACert, intermediateCACert, rootCACert).map { it.cert }.toTypedArray()) return Pair(keyStore, trustStore) } diff --git a/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt b/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt index 0bb55a8246..6ebaa7e919 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt @@ -12,7 +12,6 @@ import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x509.BasicConstraints import org.bouncycastle.asn1.x509.Extension import org.bouncycastle.asn1.x509.KeyUsage -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder import org.junit.Rule import org.junit.Test @@ -84,7 +83,6 @@ class X509UtilitiesTest { fun `storing EdDSA key in java keystore`() { val tmpKeyStore = tempFile("keystore.jks") - val converter = JcaX509CertificateConverter() val keyPair = generateKeyPair(EDDSA_ED25519_SHA512) val selfSignCert = createSelfSignedCACertificate(X500Name("CN=Test"), keyPair) @@ -93,7 +91,7 @@ class X509UtilitiesTest { // Save the EdDSA private key with self sign cert in the keystore. val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tmpKeyStore, "keystorepass") keyStore.setKeyEntry("Key", keyPair.private, "password".toCharArray(), - Stream.of(selfSignCert).map(converter::getCertificate).toTypedArray()) + Stream.of(selfSignCert).map { it.cert }.toTypedArray()) keyStore.save(tmpKeyStore, "keystorepass") // Load the keystore from file and make sure keys are intact. @@ -116,10 +114,9 @@ class X509UtilitiesTest { val edDSACert = X509Utilities.createCertificate(CertificateType.TLS, ecDSACert, ecDSAKey, X500Name("CN=TestEdDSA"), edDSAKeypair.public) // Save the EdDSA private key with cert chains. - val converter = JcaX509CertificateConverter() val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tmpKeyStore, "keystorepass") keyStore.setKeyEntry("Key", edDSAKeypair.private, "password".toCharArray(), - Stream.of(ecDSACert, edDSACert).map(converter::getCertificate).toTypedArray()) + Stream.of(ecDSACert, edDSACert).map { it.cert }.toTypedArray()) keyStore.save(tmpKeyStore, "keystorepass") // Load the keystore from file and make sure keys are intact. @@ -344,7 +341,6 @@ class X509UtilitiesTest { trustStoreFilePath: Path, trustStorePassword: String ): KeyStore { - val converter = JcaX509CertificateConverter() val rootCAKey = generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) val rootCACert = createSelfSignedCACertificate(X509Utilities.getDevX509Name("Corda Node Root CA"), rootCAKey) @@ -354,19 +350,19 @@ class X509UtilitiesTest { val keyPass = keyPassword.toCharArray() val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(keyStoreFilePath, storePassword) - keyStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, rootCAKey.private, keyPass, arrayOf(converter.getCertificate(rootCACert) as Certificate)) + keyStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, rootCAKey.private, keyPass, arrayOf(rootCACert.cert)) keyStore.addOrReplaceKey(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateCAKeyPair.private, keyPass, - Stream.of(intermediateCACert, rootCACert).map(converter::getCertificate).toTypedArray()) + Stream.of(intermediateCACert, rootCACert).map { it.cert }.toTypedArray()) keyStore.save(keyStoreFilePath, storePassword) val trustStore = KeyStoreUtilities.loadOrCreateKeyStore(trustStoreFilePath, trustStorePassword) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, converter.getCertificate(rootCACert)) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_INTERMEDIATE_CA, converter.getCertificate(intermediateCACert)) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCACert.cert) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateCACert.cert) trustStore.save(trustStoreFilePath, trustStorePassword) @@ -375,11 +371,10 @@ class X509UtilitiesTest { @Test fun `Get correct private key type from Keystore`() { - val converter = JcaX509CertificateConverter() val keyPair = generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) val selfSignCert = createSelfSignedCACertificate(X500Name("CN=Test"), keyPair) val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword") - keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(converter.getCertificate(selfSignCert))) + keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(selfSignCert.cert)) val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray()) val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword") diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index e16cabe21c..426da799fb 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -58,7 +58,6 @@ import net.corda.node.utilities.transaction import org.apache.activemq.artemis.utils.ReusableLatch import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.jetbrains.exposed.sql.Database import org.slf4j.Logger import rx.Observable @@ -819,9 +818,8 @@ private class KeyStoreWrapper(private val storePath: Path, private val storePass } fun save(serviceName: X500Name, privateKeyAlias: String, keyPair: KeyPair) { - val converter = JcaX509CertificateConverter() val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, storePassword) - val cert = converter.getCertificate(X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public)) + val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public).cert keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), arrayOf(cert, *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) keyStore.save(storePath, storePassword) } diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index db776916a1..227d0f5a35 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -2,6 +2,7 @@ package net.corda.node.services.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.requireThat +import net.corda.core.crypto.cert import net.corda.core.crypto.subject import net.corda.core.crypto.toStringShort import net.corda.core.identity.AbstractParty @@ -14,7 +15,6 @@ import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import java.security.InvalidAlgorithmParameterException import java.security.PublicKey import java.security.cert.* @@ -35,7 +35,7 @@ class InMemoryIdentityService(identities: Iterable, val trustRoot: X509Certificate?) : SingletonSerializeAsToken(), IdentityService { constructor(identities: Iterable = emptySet(), certPaths: Map = emptyMap(), - trustRoot: X509CertificateHolder?) : this(identities, certPaths, trustRoot?.let { JcaX509CertificateConverter().getCertificate(it) }) + trustRoot: X509CertificateHolder?) : this(identities, certPaths, trustRoot?.cert) companion object { private val log = loggerFor() } @@ -61,8 +61,7 @@ class InMemoryIdentityService(identities: Iterable, } else { // TODO: We should always require a full chain back to a trust anchor, but until we have a network // trust anchor everywhere, this will have to do. - val converter = JcaX509CertificateConverter() - PKIXParameters(setOf(TrustAnchor(converter.getCertificate(party.certificate), null))) + PKIXParameters(setOf(TrustAnchor(party.certificate.cert, null))) } val validator = CertPathValidator.getInstance("PKIX") validatorParameters.isRevocationEnabled = false @@ -142,8 +141,7 @@ class InMemoryIdentityService(identities: Iterable, } else { // TODO: We should always require a full chain back to a trust anchor, but until we have a network // trust anchor everywhere, this will have to do. - val converter = JcaX509CertificateConverter() - PKIXParameters(setOf(TrustAnchor(converter.getCertificate(fullParty.certificate), null))) + PKIXParameters(setOf(TrustAnchor(fullParty.certificate.cert, null))) } validatorParameters.isRevocationEnabled = false val result = validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index 13f8040a37..9701203d45 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -6,7 +6,6 @@ import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_CA import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_TLS import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA import net.corda.node.services.config.NodeConfiguration -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.cert.path.CertPath import org.bouncycastle.openssl.jcajce.JcaPEMWriter import org.bouncycastle.util.io.pem.PemObject @@ -72,13 +71,12 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService: println("Node private key and certificate stored in ${config.nodeKeystore}.") println("Generating SSL certificate for node messaging service.") - val converter = JcaX509CertificateConverter() val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val caCert = caKeyStore.getX509Certificate(CORDA_CLIENT_CA) val sslCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, keyPair, caCert.subject, sslKey.public) val sslKeyStore = KeyStoreUtilities.loadOrCreateKeyStore(config.sslKeystore, keystorePassword) sslKeyStore.addOrReplaceKey(CORDA_CLIENT_TLS, sslKey.private, privateKeyPassword.toCharArray(), - arrayOf(converter.getCertificate(sslCert), *certificates)) + arrayOf(sslCert.cert, *certificates)) sslKeyStore.save(config.sslKeystore, config.keyStorePassword) println("SSL private key and certificate stored in ${config.sslKeystore}.") // All done, clean up temp files. diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index a9657ccaed..1a2dfa6569 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -10,7 +10,6 @@ import net.corda.core.utilities.ALICE import net.corda.testing.TestNodeConfiguration import net.corda.testing.getTestX509Name import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -31,9 +30,8 @@ class NetworkRegistrationHelperTest { "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA") .map { getTestX509Name(it) } - val converter = JcaX509CertificateConverter() val certs = identities.stream().map { X509Utilities.createSelfSignedCACertificate(it, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) } - .map(converter::getCertificate).toTypedArray() + .map { it.cert }.toTypedArray() val certService: NetworkRegistrationService = mock { on { submitRequest(any()) }.then { id }