mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
ENT-2610: Separate passwords for store and for private keys in Corda OS. (#4090)
* ENT-2610: Separate passwords for store and for private keys in Corda OS. When it comes to KeyStores there are *2* passwords: 1 for the keyStore as a whole and separately there is one private keys within this keyStore. Unfortunately, those 2 passwords have to be the same due to Artemis limitation, for more details please see: `org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport.loadKeyManagerFactory` where it is calling `KeyManagerFactory.init()` with store password. Before change in this PR, throughout our codebase there are multiple places where we assume that storePassword is the same as keyPassword, even in the classes that have nothing to do with Artemis. This is of course less than ideal as TLS communication may be used not only for Artemis connectivity (e.g. Bridge/Float interaction in Ent) and it is unfair to impose same passwords constraint on that communication channel. Therefore this PR is removing this limitation and properly separating storePassword from keyPassword. Linked Jira(https://r3-cev.atlassian.net/browse/ENT-2610) has for more background info. Suggest to start review from `net.corda.core.crypto.X509NameConstraintsTest` to get an idea about the nature of the changes made. * ENT-2610: Address PR input from @kchalkias * ENT-2610: Address PR input from @kchalkias, s/privateKeyPassword/entryPassword/ * ENT-2610: Address PR input from @kchalkias, s/keyPassword/entryPassword/ In the implementation of `CertificateStoreSupplier`
This commit is contained in:
parent
dd60ae27f2
commit
88f368134f
@ -11,23 +11,31 @@ import org.bouncycastle.asn1.x509.GeneralSubtree
|
||||
import org.bouncycastle.asn1.x509.NameConstraints
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.Test
|
||||
import java.security.UnrecoverableKeyException
|
||||
import java.security.cert.CertPathValidator
|
||||
import java.security.cert.CertPathValidatorException
|
||||
import java.security.cert.PKIXParameters
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class X509NameConstraintsTest {
|
||||
|
||||
companion object {
|
||||
private const val storePassword = "storePassword"
|
||||
private const val keyPassword = "entryPassword"
|
||||
}
|
||||
|
||||
private fun makeKeyStores(subjectName: X500Name, nameConstraints: NameConstraints): Pair<X509KeyStore, X509KeyStore> {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
|
||||
val trustStore = X509KeyStore("password").apply {
|
||||
|
||||
val trustStore = X509KeyStore(storePassword).apply {
|
||||
setCertificate(X509Utilities.CORDA_ROOT_CA, rootCa.certificate)
|
||||
}
|
||||
|
||||
val keyStore = X509KeyStore("password").apply {
|
||||
val keyStore = X509KeyStore(storePassword).apply {
|
||||
val nodeCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
@ -43,7 +51,7 @@ class X509NameConstraintsTest {
|
||||
nodeCaKeyPair,
|
||||
X500Principal(subjectName.encoded),
|
||||
tlsKeyPair.public)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, nodeCaCert, intermediateCa.certificate, rootCa.certificate))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, nodeCaCert, intermediateCa.certificate, rootCa.certificate), keyPassword)
|
||||
}
|
||||
|
||||
return Pair(keyStore, trustStore)
|
||||
@ -90,7 +98,6 @@ class X509NameConstraintsTest {
|
||||
.map { GeneralSubtree(GeneralName(X500Name(it))) }.toTypedArray()
|
||||
|
||||
val nameConstraints = NameConstraints(acceptableNames, arrayOf())
|
||||
Crypto.ECDSA_SECP256R1_SHA256
|
||||
val pathValidator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME)
|
||||
|
||||
assertFailsWith(CertPathValidatorException::class) {
|
||||
@ -127,4 +134,20 @@ class X509NameConstraintsTest {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test private key retrieval`() {
|
||||
val acceptableNames = listOf("CN=Bank A TLS, UID=", "O=Bank A")
|
||||
.map { GeneralSubtree(GeneralName(X500Name(it))) }.toTypedArray()
|
||||
|
||||
val nameConstraints = NameConstraints(acceptableNames, arrayOf())
|
||||
val (keystore, _) = makeKeyStores(X500Name("CN=Bank A"), nameConstraints)
|
||||
|
||||
val privateKey = keystore.getPrivateKey(X509Utilities.CORDA_CLIENT_TLS, keyPassword)
|
||||
assertEquals(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME.algorithmName, privateKey.algorithm)
|
||||
|
||||
assertFailsWith(UnrecoverableKeyException::class) {
|
||||
keystore.getPrivateKey(X509Utilities.CORDA_CLIENT_TLS, "gibberish")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,9 +161,9 @@ class RaftUniquenessProvider(
|
||||
.withSsl()
|
||||
.withSslProtocol(SslProtocol.TLSv1_2)
|
||||
.withKeyStorePath(config.keyStore.path.toString())
|
||||
.withKeyStorePassword(config.keyStore.password)
|
||||
.withKeyStorePassword(config.keyStore.storePassword)
|
||||
.withTrustStorePath(config.trustStore.path.toString())
|
||||
.withTrustStorePassword(config.trustStore.password)
|
||||
.withTrustStorePassword(config.trustStore.storePassword)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ object DevIdentityGenerator {
|
||||
/** Install a node key store for the given node directory using the given legal name. */
|
||||
fun installKeyStoreWithNodeIdentity(nodeDir: Path, legalName: CordaX500Name): Party {
|
||||
val certificatesDirectory = nodeDir / "certificates"
|
||||
val signingCertStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "nodekeystore.jks", "cordacadevpass")
|
||||
val p2pKeyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "sslkeystore.jks", "cordacadevpass")
|
||||
val p2pTrustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "truststore.jks", "trustpass")
|
||||
val signingCertStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "nodekeystore.jks", DEV_CA_KEY_STORE_PASS, DEV_CA_KEY_STORE_PASS)
|
||||
val p2pKeyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "sslkeystore.jks", DEV_CA_KEY_STORE_PASS, DEV_CA_KEY_STORE_PASS)
|
||||
val p2pTrustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "truststore.jks", DEV_CA_TRUST_STORE_PASS, DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS)
|
||||
val p2pSslConfig = SslConfiguration.mutual(p2pKeyStore, p2pTrustStore)
|
||||
|
||||
certificatesDirectory.createDirectories()
|
||||
@ -77,13 +77,16 @@ object DevIdentityGenerator {
|
||||
publicKey)
|
||||
}
|
||||
val distServKeyStoreFile = (nodeDir / "certificates").createDirectories() / "distributedService.jks"
|
||||
X509KeyStore.fromFile(distServKeyStoreFile, "cordacadevpass", createNew = true).update {
|
||||
X509KeyStore.fromFile(distServKeyStoreFile, DEV_CA_KEY_STORE_PASS, createNew = true).update {
|
||||
setCertificate("$DISTRIBUTED_NOTARY_ALIAS_PREFIX-composite-key", compositeKeyCert)
|
||||
setPrivateKey(
|
||||
"$DISTRIBUTED_NOTARY_ALIAS_PREFIX-private-key",
|
||||
keyPair.private,
|
||||
listOf(serviceKeyCert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate),
|
||||
"cordacadevkeypass")
|
||||
DEV_CA_KEY_STORE_PASS // Unfortunately we have to use the same password for private key due to Artemis limitation, for more details please see:
|
||||
// org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport.loadKeyManagerFactory
|
||||
// where it is calling `KeyManagerFactory.init()` with store password
|
||||
/*DEV_CA_PRIVATE_KEY_PASS*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ fun CertificateStore.registerDevSigningCertificates(legalName: CordaX500Name,
|
||||
devNodeCa: CertificateAndKeyPair = createDevNodeCa(intermediateCa, legalName)) {
|
||||
|
||||
update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, devNodeCa.keyPair.private, listOf(devNodeCa.certificate, intermediateCa.certificate, rootCert))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, devNodeCa.keyPair.private, listOf(devNodeCa.certificate, intermediateCa.certificate, rootCert),
|
||||
this@registerDevSigningCertificates.entryPassword)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +40,8 @@ fun CertificateStore.registerDevP2pCertificates(legalName: CordaX500Name,
|
||||
update {
|
||||
val tlsKeyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, devNodeCa.certificate, devNodeCa.keyPair, legalName.x500Principal, tlsKeyPair.public)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, devNodeCa.certificate, intermediateCa.certificate, rootCert))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, devNodeCa.certificate, intermediateCa.certificate, rootCert),
|
||||
this@registerDevP2pCertificates.entryPassword)
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,15 +49,14 @@ fun CertificateStore.storeLegalIdentity(alias: String, keyPair: KeyPair = Crypto
|
||||
val identityCertPath = query {
|
||||
val nodeCaCertPath = getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
|
||||
// Assume key password = store password.
|
||||
val nodeCaCertAndKeyPair = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val nodeCaCertAndKeyPair = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, this@storeLegalIdentity.entryPassword)
|
||||
// Create new keys and store in keystore.
|
||||
val identityCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, nodeCaCertAndKeyPair.certificate, nodeCaCertAndKeyPair.keyPair, nodeCaCertAndKeyPair.certificate.subjectX500Principal, keyPair.public)
|
||||
// TODO: X509Utilities.validateCertificateChain()
|
||||
// Assume key password = store password.
|
||||
listOf(identityCert) + nodeCaCertPath
|
||||
}
|
||||
update {
|
||||
setPrivateKey(alias, keyPair.private, identityCertPath)
|
||||
setPrivateKey(alias, keyPair.private, identityCertPath, this@storeLegalIdentity.entryPassword)
|
||||
}
|
||||
return PartyAndCertificate(X509Utilities.buildCertPath(identityCertPath))
|
||||
}
|
||||
@ -96,6 +97,7 @@ const val DEV_CA_KEY_STORE_FILE: String = "cordadevcakeys.jks"
|
||||
const val DEV_CA_KEY_STORE_PASS: String = "cordacadevpass"
|
||||
const val DEV_CA_TRUST_STORE_FILE: String = "cordatruststore.jks"
|
||||
const val DEV_CA_TRUST_STORE_PASS: String = "trustpass"
|
||||
const val DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS: String = "trustpasskeypass"
|
||||
|
||||
// We need a class so that we can get hold of the class loader
|
||||
internal object DevCaHelper {
|
||||
@ -104,6 +106,8 @@ internal object DevCaHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDevCaKeyStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource("certificates/$DEV_CA_KEY_STORE_FILE", DEV_CA_KEY_STORE_PASS, classLoader)
|
||||
fun loadDevCaKeyStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource(
|
||||
"certificates/$DEV_CA_KEY_STORE_FILE", DEV_CA_KEY_STORE_PASS, DEV_CA_PRIVATE_KEY_PASS, classLoader)
|
||||
|
||||
fun loadDevCaTrustStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource("certificates/$DEV_CA_TRUST_STORE_FILE", DEV_CA_TRUST_STORE_PASS, classLoader)
|
||||
fun loadDevCaTrustStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource(
|
||||
"certificates/$DEV_CA_TRUST_STORE_FILE", DEV_CA_TRUST_STORE_PASS, DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS, classLoader)
|
||||
|
@ -14,17 +14,18 @@ interface CertificateStore : Iterable<Pair<String, X509Certificate>> {
|
||||
|
||||
companion object {
|
||||
|
||||
fun of(store: X509KeyStore, password: String): CertificateStore = DelegatingCertificateStore(store, password)
|
||||
fun of(store: X509KeyStore, password: String, entryPassword: String): CertificateStore = DelegatingCertificateStore(store, password, entryPassword)
|
||||
|
||||
fun fromFile(storePath: Path, password: String, createNew: Boolean): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromFile(storePath, password, createNew), password)
|
||||
fun fromFile(storePath: Path, password: String, entryPassword: String, createNew: Boolean): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromFile(storePath, password, createNew), password, entryPassword)
|
||||
|
||||
fun fromInputStream(stream: InputStream, password: String): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromInputStream(stream, password), password)
|
||||
fun fromInputStream(stream: InputStream, password: String, entryPassword: String): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromInputStream(stream, password), password, entryPassword)
|
||||
|
||||
fun fromResource(storeResourceName: String, password: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore = fromInputStream(classLoader.getResourceAsStream(storeResourceName), password)
|
||||
fun fromResource(storeResourceName: String, password: String, entryPassword: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore = fromInputStream(classLoader.getResourceAsStream(storeResourceName), password, entryPassword)
|
||||
}
|
||||
|
||||
val value: X509KeyStore
|
||||
val password: String
|
||||
val entryPassword: String
|
||||
|
||||
fun writeTo(stream: OutputStream) = value.internal.store(stream, password.toCharArray())
|
||||
|
||||
@ -79,4 +80,4 @@ interface CertificateStore : Iterable<Pair<String, X509Certificate>> {
|
||||
}
|
||||
}
|
||||
|
||||
private class DelegatingCertificateStore(override val value: X509KeyStore, override val password: String) : CertificateStore
|
||||
private class DelegatingCertificateStore(override val value: X509KeyStore, override val password: String, override val entryPassword: String) : CertificateStore
|
@ -18,7 +18,7 @@ interface CertificateStoreSupplier {
|
||||
}
|
||||
|
||||
// TODO replace reference to FileBasedCertificateStoreSupplier with CertificateStoreSupplier, after coming up with a way of passing certificate stores to Artemis.
|
||||
class FileBasedCertificateStoreSupplier(val path: Path, val password: String) : CertificateStoreSupplier {
|
||||
class FileBasedCertificateStoreSupplier(val path: Path, val storePassword: String, val entryPassword: String) : CertificateStoreSupplier {
|
||||
|
||||
override fun get(createNew: Boolean) = CertificateStore.fromFile(path, password, createNew)
|
||||
override fun get(createNew: Boolean) = CertificateStore.fromFile(path, storePassword, entryPassword, createNew)
|
||||
}
|
@ -151,7 +151,7 @@ private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set
|
||||
|
||||
private fun ConfigException.Missing.relative(path: String, nestedPath: String?): ConfigException.Missing {
|
||||
return when {
|
||||
nestedPath != null -> throw ConfigException.Missing("$nestedPath.$path")
|
||||
nestedPath != null -> throw ConfigException.Missing("$nestedPath.$path", this)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
@ -53,17 +53,17 @@ class X509KeyStore private constructor(val internal: KeyStore, private val store
|
||||
return uncheckedCast(certArray.asList())
|
||||
}
|
||||
|
||||
fun getCertificateAndKeyPair(alias: String, keyPassword: String = storePassword): CertificateAndKeyPair {
|
||||
fun getCertificateAndKeyPair(alias: String, keyPassword: String): CertificateAndKeyPair {
|
||||
val cert = getCertificate(alias)
|
||||
val publicKey = Crypto.toSupportedPublicKey(cert.publicKey)
|
||||
return CertificateAndKeyPair(cert, KeyPair(publicKey, getPrivateKey(alias, keyPassword)))
|
||||
}
|
||||
|
||||
fun getPrivateKey(alias: String, keyPassword: String = storePassword): PrivateKey {
|
||||
fun getPrivateKey(alias: String, keyPassword: String): PrivateKey {
|
||||
return internal.getSupportedKey(alias, keyPassword)
|
||||
}
|
||||
|
||||
fun setPrivateKey(alias: String, key: PrivateKey, certificates: List<X509Certificate>, keyPassword: String = storePassword) {
|
||||
fun setPrivateKey(alias: String, key: PrivateKey, certificates: List<X509Certificate>, keyPassword: String) {
|
||||
internal.setKeyEntry(alias, key, keyPassword.toCharArray(), certificates.toTypedArray())
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,9 @@ internal fun initialiseTrustStoreAndEnableCrlChecking(trustStore: CertificateSto
|
||||
return CertPathTrustManagerParameters(pkixParams)
|
||||
}
|
||||
|
||||
fun KeyManagerFactory.init(keyStore: CertificateStore) = init(keyStore.value.internal, keyStore.password.toCharArray())
|
||||
// As per Javadoc in: https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/KeyManagerFactory.html `init` method
|
||||
// 2nd parameter `password` - the password for recovering keys in the KeyStore
|
||||
fun KeyManagerFactory.init(keyStore: CertificateStore) = init(keyStore.value.internal, keyStore.entryPassword.toCharArray())
|
||||
|
||||
fun TrustManagerFactory.init(trustStore: CertificateStore) = init(trustStore.value.internal)
|
||||
|
||||
|
@ -235,8 +235,9 @@ class X509UtilitiesTest {
|
||||
signingCertStore.get(createNew = true).also { it.registerDevSigningCertificates(MEGA_CORP.name, rootCa.certificate, intermediateCa, nodeCa) }
|
||||
p2pSslConfig.keyStore.get(createNew = true).also { it.registerDevP2pCertificates(MEGA_CORP.name, rootCa.certificate, intermediateCa, nodeCa) }
|
||||
// Load back server certificate
|
||||
val serverKeyStore = signingCertStore.get().value
|
||||
val (serverCert, serverKeyPair) = serverKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val certStore = signingCertStore.get()
|
||||
val serverKeyStore = certStore.value
|
||||
val (serverCert, serverKeyPair) = serverKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, certStore.entryPassword)
|
||||
|
||||
serverCert.checkValidity()
|
||||
serverCert.verify(intermediateCa.certificate.publicKey)
|
||||
@ -244,7 +245,7 @@ class X509UtilitiesTest {
|
||||
|
||||
// Load back SSL certificate
|
||||
val sslKeyStoreReloaded = p2pSslConfig.keyStore.get()
|
||||
val (sslCert) = sslKeyStoreReloaded.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, p2pSslConfig.keyStore.password) }
|
||||
val (sslCert) = sslKeyStoreReloaded.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, sslKeyStoreReloaded.entryPassword) }
|
||||
|
||||
sslCert.checkValidity()
|
||||
sslCert.verify(serverCert.publicKey)
|
||||
|
@ -20,8 +20,10 @@ class SSLHelperTest {
|
||||
val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
|
||||
keyManagerFactory.init(CertificateStore.fromFile(sslConfig.keyStore.path, sslConfig.keyStore.password, false))
|
||||
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(CertificateStore.fromFile(sslConfig.trustStore.path, sslConfig.trustStore.password, false), false))
|
||||
val keyStore = sslConfig.keyStore
|
||||
keyManagerFactory.init(CertificateStore.fromFile(keyStore.path, keyStore.storePassword, keyStore.entryPassword, false))
|
||||
val trustStore = sslConfig.trustStore
|
||||
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(CertificateStore.fromFile(trustStore.path, trustStore.storePassword, trustStore.entryPassword, false), false))
|
||||
|
||||
val sslHandler = createClientSslHelper(NetworkHostAndPort("localhost", 1234), setOf(legalName), keyManagerFactory, trustManagerFactory)
|
||||
val legalNameHash = SecureHash.sha256(legalName.toString()).toString().take(32).toLowerCase()
|
||||
|
@ -25,7 +25,7 @@ class NodeKeystoreCheckTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `node should throw exception if cert path doesn't chain to the trust root`() {
|
||||
fun `node should throw exception if cert path does not chain to the trust root`() {
|
||||
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
|
||||
// Create keystores.
|
||||
val keystorePassword = "password"
|
||||
@ -49,9 +49,9 @@ class NodeKeystoreCheckTest {
|
||||
// Self signed root.
|
||||
val badRootKeyPair = Crypto.generateKeyPair()
|
||||
val badRoot = X509Utilities.createSelfSignedCACertificate(X500Principal("O=Bad Root,L=Lodnon,C=GB"), badRootKeyPair)
|
||||
val nodeCA = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val nodeCA = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, signingCertStore.entryPassword)
|
||||
val badNodeCACert = X509Utilities.createCertificate(CertificateType.NODE_CA, badRoot, badRootKeyPair, ALICE_NAME.x500Principal, nodeCA.keyPair.public)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, nodeCA.keyPair.private, listOf(badNodeCACert, badRoot))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, nodeCA.keyPair.private, listOf(badNodeCACert, badRoot), signingCertStore.entryPassword)
|
||||
}
|
||||
|
||||
assertThatThrownBy {
|
||||
|
@ -423,17 +423,17 @@ class CertificateRevocationListNodeTests {
|
||||
val signingCertificateStore = first
|
||||
val p2pSslConfiguration = second
|
||||
val nodeKeyStore = signingCertificateStore.get()
|
||||
val (nodeCert, nodeKeys) = nodeKeyStore.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA) }
|
||||
val (nodeCert, nodeKeys) = nodeKeyStore.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, nodeKeyStore.entryPassword) }
|
||||
val newNodeCert = replaceCrlDistPointCaCertificate(nodeCert, CertificateType.NODE_CA, INTERMEDIATE_CA.keyPair, nodeCaCrlDistPoint)
|
||||
val nodeCertChain = listOf(newNodeCert, INTERMEDIATE_CA.certificate, *nodeKeyStore.query { getCertificateChain(X509Utilities.CORDA_CLIENT_CA) }.drop(2).toTypedArray())
|
||||
nodeKeyStore.update {
|
||||
internal.deleteEntry(X509Utilities.CORDA_CLIENT_CA)
|
||||
}
|
||||
nodeKeyStore.update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, nodeKeys.private, nodeCertChain)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, nodeKeys.private, nodeCertChain, nodeKeyStore.entryPassword)
|
||||
}
|
||||
val sslKeyStore = p2pSslConfiguration.keyStore.get()
|
||||
val (tlsCert, tlsKeys) = sslKeyStore.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS) }
|
||||
val (tlsCert, tlsKeys) = sslKeyStore.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, sslKeyStore.entryPassword) }
|
||||
val newTlsCert = replaceCrlDistPointCaCertificate(tlsCert, CertificateType.TLS, nodeKeys, tlsCrlDistPoint, X500Name.getInstance(ROOT_CA.certificate.subjectX500Principal.encoded))
|
||||
val sslCertChain = listOf(newTlsCert, newNodeCert, INTERMEDIATE_CA.certificate, *sslKeyStore.query { getCertificateChain(X509Utilities.CORDA_CLIENT_TLS) }.drop(3).toTypedArray())
|
||||
|
||||
@ -441,7 +441,7 @@ class CertificateRevocationListNodeTests {
|
||||
internal.deleteEntry(X509Utilities.CORDA_CLIENT_TLS)
|
||||
}
|
||||
sslKeyStore.update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeys.private, sslCertChain)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeys.private, sslCertChain, sslKeyStore.entryPassword)
|
||||
}
|
||||
return newNodeCert
|
||||
}
|
||||
|
@ -105,11 +105,11 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
|
||||
val clientTLSCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientKeyPair, CordaX500Name("MiniCorp", "London", "GB").x500Principal, tlsKeyPair.public)
|
||||
|
||||
signingCertStore.get(createNew = true).update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, clientKeyPair.private, listOf(clientCACert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, clientKeyPair.private, listOf(clientCACert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate), signingCertStore.entryPassword)
|
||||
}
|
||||
|
||||
p2pSslConfig.keyStore.get(createNew = true).update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(clientTLSCert, clientCACert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(clientTLSCert, clientCACert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate), p2pSslConfig.keyStore.entryPassword)
|
||||
}
|
||||
|
||||
val attacker = clientTo(alice.node.configuration.p2pAddress, p2pSslConfig)
|
||||
|
@ -862,7 +862,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
keyStore.storeLegalIdentity(privateKeyAlias, generateKeyPair())
|
||||
}
|
||||
|
||||
val (x509Cert, keyPair) = keyStore.query { getCertificateAndKeyPair(privateKeyAlias) }
|
||||
val (x509Cert, keyPair) = keyStore.query { getCertificateAndKeyPair(privateKeyAlias, keyStore.entryPassword) }
|
||||
|
||||
// TODO: Use configuration to indicate composite key should be used instead of public key for the identity.
|
||||
val compositeKeyAlias = "$id-composite-key"
|
||||
|
@ -86,9 +86,9 @@ fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500N
|
||||
}
|
||||
|
||||
if (keyStore.getOptional() == null || signingCertificateStore.getOptional() == null) {
|
||||
val signingKeyStore = FileBasedCertificateStoreSupplier(signingCertificateStore.path, signingCertificateStore.password).get(true).also { it.registerDevSigningCertificates(myLegalName) }
|
||||
val signingKeyStore = FileBasedCertificateStoreSupplier(signingCertificateStore.path, signingCertificateStore.storePassword, signingCertificateStore.entryPassword).get(true).also { it.registerDevSigningCertificates(myLegalName) }
|
||||
|
||||
FileBasedCertificateStoreSupplier(keyStore.path, keyStore.password).get(true).also { it.registerDevP2pCertificates(myLegalName) }
|
||||
FileBasedCertificateStoreSupplier(keyStore.path, keyStore.storePassword, keyStore.entryPassword).get(true).also { it.registerDevP2pCertificates(myLegalName) }
|
||||
|
||||
// Move distributed service composite key (generated by IdentityGenerator.generateToDisk) to keystore if exists.
|
||||
val distributedServiceKeystore = certificatesDirectory / "distributedService.jks"
|
||||
@ -97,7 +97,7 @@ fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500N
|
||||
signingKeyStore.update {
|
||||
serviceKeystore.aliases().forEach {
|
||||
if (serviceKeystore.internal.isKeyEntry(it)) {
|
||||
setPrivateKey(it, serviceKeystore.getPrivateKey(it, DEV_CA_PRIVATE_KEY_PASS), serviceKeystore.getCertificateChain(it))
|
||||
setPrivateKey(it, serviceKeystore.getPrivateKey(it, DEV_CA_KEY_STORE_PASS), serviceKeystore.getCertificateChain(it), signingKeyStore.entryPassword)
|
||||
} else {
|
||||
setCertificate(it, serviceKeystore.getCertificate(it))
|
||||
}
|
||||
|
@ -260,12 +260,16 @@ data class NodeConfigurationImpl(
|
||||
override val certificatesDirectory = baseDirectory / "certificates"
|
||||
|
||||
private val signingCertificateStorePath = certificatesDirectory / "nodekeystore.jks"
|
||||
override val signingCertificateStore = FileBasedCertificateStoreSupplier(signingCertificateStorePath, keyStorePassword)
|
||||
|
||||
private val p2pKeystorePath: Path get() = certificatesDirectory / "sslkeystore.jks"
|
||||
private val p2pKeyStore = FileBasedCertificateStoreSupplier(p2pKeystorePath, keyStorePassword)
|
||||
|
||||
// TODO: There are two implications here:
|
||||
// 1. "signingCertificateStore" and "p2pKeyStore" have the same passwords. In the future we should re-visit this "rule" and see of they can be made different;
|
||||
// 2. The passwords for store and for keys in this store are the same, this is due to limitations of Artemis.
|
||||
override val signingCertificateStore = FileBasedCertificateStoreSupplier(signingCertificateStorePath, keyStorePassword, keyStorePassword)
|
||||
private val p2pKeyStore = FileBasedCertificateStoreSupplier(p2pKeystorePath, keyStorePassword, keyStorePassword)
|
||||
|
||||
private val p2pTrustStoreFilePath: Path get() = certificatesDirectory / "truststore.jks"
|
||||
private val p2pTrustStore = FileBasedCertificateStoreSupplier(p2pTrustStoreFilePath, trustStorePassword)
|
||||
private val p2pTrustStore = FileBasedCertificateStoreSupplier(p2pTrustStoreFilePath, trustStorePassword, trustStorePassword)
|
||||
override val p2pSslOptions: MutualSslConfiguration = SslConfiguration.mutual(p2pKeyStore, p2pTrustStore)
|
||||
|
||||
override val rpcOptions: NodeRpcOptions
|
||||
|
@ -161,7 +161,7 @@ open class NetworkRegistrationHelper(private val certificatesDirectory: Path,
|
||||
println("Private key '$keyAlias' and certificate stored in node signing keystore.")
|
||||
}
|
||||
|
||||
private fun CertificateStore.loadOrCreateKeyPair(alias: String, privateKeyPassword: String = password): KeyPair {
|
||||
private fun CertificateStore.loadOrCreateKeyPair(alias: String, entryPassword: String = password): KeyPair {
|
||||
// Create or load self signed keypair from the key store.
|
||||
// We use the self sign certificate to store the key temporarily in the keystore while waiting for the request approval.
|
||||
if (alias !in this) {
|
||||
@ -170,11 +170,11 @@ open class NetworkRegistrationHelper(private val certificatesDirectory: Path,
|
||||
val selfSignCert = X509Utilities.createSelfSignedCACertificate(myLegalName.x500Principal, keyPair)
|
||||
// Save to the key store.
|
||||
with(value) {
|
||||
setPrivateKey(alias, keyPair.private, listOf(selfSignCert), keyPassword = privateKeyPassword)
|
||||
setPrivateKey(alias, keyPair.private, listOf(selfSignCert), keyPassword = entryPassword)
|
||||
save()
|
||||
}
|
||||
}
|
||||
return query { getCertificateAndKeyPair(alias, privateKeyPassword) }.keyPair
|
||||
return query { getCertificateAndKeyPair(alias, entryPassword) }.keyPair
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,7 +281,9 @@ class NodeRegistrationHelper(
|
||||
}
|
||||
|
||||
private fun createSSLKeystore(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>, tlsCertCrlIssuer: X500Name?) {
|
||||
config.p2pSslOptions.keyStore.get(createNew = true).update {
|
||||
val keyStore = config.p2pSslOptions.keyStore
|
||||
val certificateStore = keyStore.get(createNew = true)
|
||||
certificateStore.update {
|
||||
println("Generating SSL certificate for node messaging service.")
|
||||
val sslKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val sslCert = X509Utilities.createCertificate(
|
||||
@ -293,9 +295,9 @@ class NodeRegistrationHelper(
|
||||
crlDistPoint = config.tlsCertCrlDistPoint?.toString(),
|
||||
crlIssuer = tlsCertCrlIssuer)
|
||||
logger.info("Generated TLS certificate: $sslCert")
|
||||
setPrivateKey(CORDA_CLIENT_TLS, sslKeyPair.private, listOf(sslCert) + certificates)
|
||||
setPrivateKey(CORDA_CLIENT_TLS, sslKeyPair.private, listOf(sslCert) + certificates, certificateStore.entryPassword)
|
||||
}
|
||||
println("SSL private key and certificate stored in ${config.p2pSslOptions.keyStore.path}.")
|
||||
println("SSL private key and certificate stored in ${keyStore.path}.")
|
||||
}
|
||||
|
||||
private fun createTruststore(rootCertificate: X509Certificate) {
|
||||
|
@ -845,10 +845,10 @@ class DriverDSLImpl(
|
||||
config += "baseDirectory" to configuration.baseDirectory.toAbsolutePath().toString()
|
||||
|
||||
config += "keyStorePath" to configuration.p2pSslOptions.keyStore.path.toString()
|
||||
config += "keyStorePassword" to configuration.p2pSslOptions.keyStore.password
|
||||
config += "keyStorePassword" to configuration.p2pSslOptions.keyStore.storePassword
|
||||
|
||||
config += "trustStorePath" to configuration.p2pSslOptions.trustStore.path.toString()
|
||||
config += "trustStorePassword" to configuration.p2pSslOptions.trustStore.password
|
||||
config += "trustStorePassword" to configuration.p2pSslOptions.trustStore.storePassword
|
||||
|
||||
return config
|
||||
}
|
||||
|
@ -1,215 +0,0 @@
|
||||
package net.corda.testing.common.internal
|
||||
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.createFile
|
||||
import net.corda.core.internal.deleteIfExists
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.nodeapi.internal.config.FileBasedCertificateStoreSupplier
|
||||
import net.corda.nodeapi.internal.config.SslConfiguration
|
||||
import net.corda.nodeapi.internal.config.MutualSslConfiguration
|
||||
import net.corda.nodeapi.internal.crypto.*
|
||||
import org.apache.commons.io.FileUtils
|
||||
import sun.security.tools.keytool.CertAndKeyGen
|
||||
import sun.security.x509.X500Name
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.time.Instant.now
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
class UnsafeCertificatesFactory(
|
||||
defaults: Defaults = defaults(),
|
||||
private val keyType: String = defaults.keyType,
|
||||
private val signatureAlgorithm: String = defaults.signatureAlgorithm,
|
||||
private val keySize: Int = defaults.keySize,
|
||||
private val certificatesValidityWindow: CertificateValidityWindow = defaults.certificatesValidityWindow,
|
||||
private val keyStoreType: String = defaults.keyStoreType) {
|
||||
|
||||
companion object {
|
||||
private const val KEY_TYPE_RSA = "RSA"
|
||||
private const val SIG_ALG_SHA_RSA = "SHA1WithRSA"
|
||||
private const val KEY_SIZE = 1024
|
||||
private val DEFAULT_DURATION = Duration.of(365, ChronoUnit.DAYS)
|
||||
private const val DEFAULT_KEYSTORE_TYPE = "JKS"
|
||||
|
||||
fun defaults() = Defaults(KEY_TYPE_RSA, SIG_ALG_SHA_RSA, KEY_SIZE, CertificateValidityWindow(now(), DEFAULT_DURATION), DEFAULT_KEYSTORE_TYPE)
|
||||
}
|
||||
|
||||
data class Defaults(
|
||||
val keyType: String,
|
||||
val signatureAlgorithm: String,
|
||||
val keySize: Int,
|
||||
val certificatesValidityWindow: CertificateValidityWindow,
|
||||
val keyStoreType: String)
|
||||
|
||||
fun createSelfSigned(name: X500Name): UnsafeCertificate = createSelfSigned(name, keyType, signatureAlgorithm, keySize, certificatesValidityWindow)
|
||||
|
||||
fun createSelfSigned(name: CordaX500Name) = createSelfSigned(name.asX500Name())
|
||||
|
||||
fun createSignedBy(subject: X500Principal, issuer: UnsafeCertificate): UnsafeCertificate = issuer.createSigned(subject, keyType, signatureAlgorithm, keySize, certificatesValidityWindow)
|
||||
|
||||
fun createSignedBy(name: CordaX500Name, issuer: UnsafeCertificate): UnsafeCertificate = issuer.createSigned(name, keyType, signatureAlgorithm, keySize, certificatesValidityWindow)
|
||||
|
||||
fun newKeyStore(password: String) = UnsafeKeyStore.create(keyStoreType, password)
|
||||
|
||||
fun newKeyStores(keyStorePassword: String, trustStorePassword: String): KeyStores = KeyStores(newKeyStore(keyStorePassword), newKeyStore(trustStorePassword))
|
||||
}
|
||||
|
||||
class KeyStores(val keyStore: UnsafeKeyStore, val trustStore: UnsafeKeyStore) {
|
||||
fun save(directory: Path = Files.createTempDirectory(null)): AutoClosableSSLConfiguration {
|
||||
val keyStoreFile = keyStore.toTemporaryFile("sslkeystore", directory = directory)
|
||||
val trustStoreFile = trustStore.toTemporaryFile("truststore", directory = directory)
|
||||
|
||||
val sslConfiguration = sslConfiguration(keyStoreFile, trustStoreFile)
|
||||
|
||||
return object : AutoClosableSSLConfiguration {
|
||||
override val value = sslConfiguration
|
||||
|
||||
override fun close() {
|
||||
keyStoreFile.close()
|
||||
trustStoreFile.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sslConfiguration(keyStoreFile: TemporaryFile, trustStoreFile: TemporaryFile): MutualSslConfiguration {
|
||||
|
||||
val keyStore = FileBasedCertificateStoreSupplier(keyStoreFile.file, keyStore.password)
|
||||
val trustStore = FileBasedCertificateStoreSupplier(trustStoreFile.file, trustStore.password)
|
||||
return SslConfiguration.mutual(keyStore, trustStore)
|
||||
}
|
||||
}
|
||||
|
||||
interface AutoClosableSSLConfiguration : AutoCloseable {
|
||||
val value: MutualSslConfiguration
|
||||
}
|
||||
|
||||
typealias KeyStoreEntry = Pair<String, UnsafeCertificate>
|
||||
|
||||
data class UnsafeKeyStore(private val delegate: KeyStore, val password: String) : Iterable<KeyStoreEntry> {
|
||||
companion object {
|
||||
private const val JKS_TYPE = "JKS"
|
||||
|
||||
fun create(type: String, password: String) = UnsafeKeyStore(newKeyStore(type, password), password)
|
||||
|
||||
fun createJKS(password: String) = create(JKS_TYPE, password)
|
||||
}
|
||||
|
||||
operator fun plus(entry: KeyStoreEntry) = set(entry.first, entry.second)
|
||||
|
||||
override fun iterator(): Iterator<Pair<String, UnsafeCertificate>> = delegate.aliases().toList().map { alias -> alias to get(alias) }.iterator()
|
||||
|
||||
operator fun get(alias: String): UnsafeCertificate {
|
||||
return when {
|
||||
delegate.isKeyEntry(alias) -> delegate.getCertificateAndKeyPair(alias, password).unsafe()
|
||||
else -> UnsafeCertificate(delegate.getX509Certificate(alias), null)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun set(alias: String, certificate: UnsafeCertificate) {
|
||||
delegate.setCertificateEntry(alias, certificate.value)
|
||||
delegate.setKeyEntry(alias, certificate.privateKey, password.toCharArray(), arrayOf(certificate.value))
|
||||
}
|
||||
|
||||
fun save(path: Path) = delegate.save(path, password)
|
||||
|
||||
fun toTemporaryFile(fileName: String, fileExtension: String? = delegate.type.toLowerCase(), directory: Path): TemporaryFile {
|
||||
return TemporaryFile("$fileName.$fileExtension", directory).also { save(it.file) }
|
||||
}
|
||||
}
|
||||
|
||||
class TemporaryFile(fileName: String, val directory: Path) : AutoCloseable {
|
||||
val file: Path = (directory / fileName).createFile().toAbsolutePath()
|
||||
|
||||
init {
|
||||
file.toFile().deleteOnExit()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
file.deleteIfExists()
|
||||
}
|
||||
}
|
||||
|
||||
data class UnsafeCertificate(val value: X509Certificate, val privateKey: PrivateKey?) {
|
||||
val keyPair = KeyPair(value.publicKey, privateKey)
|
||||
|
||||
val principal: X500Principal get() = value.subjectX500Principal
|
||||
|
||||
val issuer: X500Principal get() = value.issuerX500Principal
|
||||
|
||||
fun createSigned(subject: X500Principal, keyType: String, signatureAlgorithm: String, keySize: Int, certificatesValidityWindow: CertificateValidityWindow): UnsafeCertificate {
|
||||
val keyGen = keyGen(keyType, signatureAlgorithm, keySize)
|
||||
|
||||
return UnsafeCertificate(X509Utilities.createCertificate(
|
||||
certificateType = CertificateType.TLS,
|
||||
issuer = value.subjectX500Principal,
|
||||
issuerKeyPair = keyPair,
|
||||
validityWindow = certificatesValidityWindow.datePair,
|
||||
subject = subject,
|
||||
subjectPublicKey = keyGen.publicKey
|
||||
), keyGen.privateKey)
|
||||
}
|
||||
|
||||
fun createSigned(name: CordaX500Name, keyType: String, signatureAlgorithm: String, keySize: Int, certificatesValidityWindow: CertificateValidityWindow) = createSigned(name.x500Principal, keyType, signatureAlgorithm, keySize, certificatesValidityWindow)
|
||||
}
|
||||
|
||||
data class CertificateValidityWindow(val from: Instant, val to: Instant) {
|
||||
constructor(from: Instant, duration: Duration) : this(from, from.plus(duration))
|
||||
|
||||
val duration = Duration.between(from, to)!!
|
||||
|
||||
val datePair = Date.from(from) to Date.from(to)
|
||||
}
|
||||
|
||||
private fun createSelfSigned(name: X500Name, keyType: String, signatureAlgorithm: String, keySize: Int, certificatesValidityWindow: CertificateValidityWindow): UnsafeCertificate {
|
||||
val keyGen = keyGen(keyType, signatureAlgorithm, keySize)
|
||||
return UnsafeCertificate(keyGen.getSelfCertificate(name, certificatesValidityWindow.duration.toMillis()), keyGen.privateKey)
|
||||
}
|
||||
|
||||
private fun CordaX500Name.asX500Name(): X500Name = X500Name.asX500Name(x500Principal)
|
||||
|
||||
private fun CertificateAndKeyPair.unsafe() = UnsafeCertificate(certificate, keyPair.private)
|
||||
|
||||
private fun keyGen(keyType: String, signatureAlgorithm: String, keySize: Int): CertAndKeyGen {
|
||||
val keyGen = CertAndKeyGen(keyType, signatureAlgorithm)
|
||||
keyGen.generate(keySize)
|
||||
return keyGen
|
||||
}
|
||||
|
||||
private fun newKeyStore(type: String, password: String): KeyStore {
|
||||
val keyStore = KeyStore.getInstance(type)
|
||||
// Loading creates the store, can't do anything with it until it's loaded
|
||||
keyStore.load(null, password.toCharArray())
|
||||
|
||||
return keyStore
|
||||
}
|
||||
|
||||
fun withKeyStores(server: KeyStores, client: KeyStores, action: (brokerSslOptions: MutualSslConfiguration, clientSslOptions: MutualSslConfiguration) -> Unit) {
|
||||
val serverDir = Files.createTempDirectory(null)
|
||||
FileUtils.forceDeleteOnExit(serverDir.toFile())
|
||||
|
||||
val clientDir = Files.createTempDirectory(null)
|
||||
FileUtils.forceDeleteOnExit(clientDir.toFile())
|
||||
|
||||
server.save(serverDir).use { serverSslConfiguration ->
|
||||
client.save(clientDir).use { clientSslConfiguration ->
|
||||
action(serverSslConfiguration.value, clientSslConfiguration.value)
|
||||
}
|
||||
}
|
||||
clientDir.deleteIfExists()
|
||||
serverDir.deleteIfExists()
|
||||
}
|
||||
|
||||
fun withCertificates(factoryDefaults: UnsafeCertificatesFactory.Defaults = UnsafeCertificatesFactory.defaults(), action: (server: KeyStores, client: KeyStores, createSelfSigned: (name: CordaX500Name) -> UnsafeCertificate, createSignedBy: (name: CordaX500Name, issuer: UnsafeCertificate) -> UnsafeCertificate) -> Unit) {
|
||||
val factory = UnsafeCertificatesFactory(factoryDefaults)
|
||||
val server = factory.newKeyStores("serverKeyStorePass", "serverTrustKeyStorePass")
|
||||
val client = factory.newKeyStores("clientKeyStorePass", "clientTrustKeyStorePass")
|
||||
action(server, client, factory::createSelfSigned, factory::createSignedBy)
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
package net.corda.testing.internal.stubs
|
||||
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS
|
||||
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PASS
|
||||
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS
|
||||
import net.corda.nodeapi.internal.config.FileBasedCertificateStoreSupplier
|
||||
import net.corda.nodeapi.internal.config.SslConfiguration
|
||||
import net.corda.nodeapi.internal.config.MutualSslConfiguration
|
||||
@ -11,28 +14,27 @@ class CertificateStoreStubs {
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_CERTIFICATES_DIRECTORY_NAME = "certificates"
|
||||
|
||||
@JvmStatic
|
||||
fun withStoreAt(certificateStorePath: Path, password: String): FileBasedCertificateStoreSupplier = FileBasedCertificateStoreSupplier(certificateStorePath, password)
|
||||
}
|
||||
|
||||
class Signing {
|
||||
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_STORE_FILE_NAME = "nodekeystore.jks"
|
||||
const val DEFAULT_STORE_PASSWORD = "cordacadevpass"
|
||||
private const val DEFAULT_STORE_FILE_NAME = "nodekeystore.jks"
|
||||
private const val DEFAULT_STORE_PASSWORD = DEV_CA_KEY_STORE_PASS
|
||||
|
||||
@JvmStatic
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD,
|
||||
keyPassword: String = password, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
|
||||
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,10 +44,13 @@ class CertificateStoreStubs {
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD): MutualSslConfiguration {
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME,
|
||||
keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, keyPassword: String = keyStorePassword,
|
||||
trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD, trustStoreKeyPassword: String = TrustStore.DEFAULT_KEY_PASSWORD,
|
||||
useOpenSsl: Boolean = false): MutualSslConfiguration {
|
||||
|
||||
val keyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / keyStoreFileName, keyStorePassword)
|
||||
val trustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / trustStoreFileName, trustStorePassword)
|
||||
val keyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / keyStoreFileName, keyStorePassword, keyPassword)
|
||||
val trustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / trustStoreFileName, trustStorePassword, trustStoreKeyPassword)
|
||||
return SslConfiguration.mutual(keyStore, trustStore)
|
||||
}
|
||||
|
||||
@ -61,18 +66,20 @@ class CertificateStoreStubs {
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_STORE_FILE_NAME = "sslkeystore.jks"
|
||||
const val DEFAULT_STORE_PASSWORD = "cordacadevpass"
|
||||
const val DEFAULT_STORE_PASSWORD = DEV_CA_KEY_STORE_PASS
|
||||
|
||||
@JvmStatic
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
|
||||
certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
|
||||
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,18 +89,21 @@ class CertificateStoreStubs {
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_STORE_FILE_NAME = "truststore.jks"
|
||||
const val DEFAULT_STORE_PASSWORD = "trustpass"
|
||||
const val DEFAULT_STORE_PASSWORD = DEV_CA_TRUST_STORE_PASS
|
||||
const val DEFAULT_KEY_PASSWORD = DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS
|
||||
|
||||
@JvmStatic
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD,
|
||||
keyPassword: String = DEFAULT_KEY_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = DEFAULT_KEY_PASSWORD,
|
||||
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
|
||||
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
|
||||
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user