mirror of
https://github.com/corda/corda.git
synced 2025-06-17 14:48:16 +00:00
CORDA-1968 Ensure we check for the trustroot existence and alias validity. (#3917)
* Ensure we check for the trustroot existence and alias validity. * fix missing keystore message on integration test after changes. * adding more requirements to check for missing aliases to validateKeyStores * import X509Utilities const values (CORDA_ROOT_CA, CORDA_CLIENT_CA, CORDA_CLIENT_TLS) to AbstractNode. * address review comment: avoid using !! (not null)
This commit is contained in:
committed by
PokeyBot
parent
37c7fff8b1
commit
3ff7fc2585
@ -20,14 +20,14 @@ class NodeKeystoreCheckTest {
|
|||||||
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
|
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
startNode(customOverrides = mapOf("devMode" to false)).getOrThrow()
|
startNode(customOverrides = mapOf("devMode" to false)).getOrThrow()
|
||||||
}.hasMessageContaining("Identity certificate not found")
|
}.hasMessageContaining("One or more keyStores (identity or TLS) or trustStore not found.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `node should throw exception if cert path doesn't chain to the trust root`() {
|
fun `node should throw exception if cert path doesn't chain to the trust root`() {
|
||||||
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
|
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
|
||||||
// Create keystores
|
// Create keystores.
|
||||||
val keystorePassword = "password"
|
val keystorePassword = "password"
|
||||||
val certificatesDirectory = baseDirectory(ALICE_NAME) / "certificates"
|
val certificatesDirectory = baseDirectory(ALICE_NAME) / "certificates"
|
||||||
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, keystorePassword)
|
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, keystorePassword)
|
||||||
@ -46,7 +46,7 @@ class NodeKeystoreCheckTest {
|
|||||||
|
|
||||||
// Fiddle with node keystore.
|
// Fiddle with node keystore.
|
||||||
signingCertStore.get().update {
|
signingCertStore.get().update {
|
||||||
// Self signed root
|
// Self signed root.
|
||||||
val badRootKeyPair = Crypto.generateKeyPair()
|
val badRootKeyPair = Crypto.generateKeyPair()
|
||||||
val badRoot = X509Utilities.createSelfSignedCACertificate(X500Principal("O=Bad Root,L=Lodnon,C=GB"), badRootKeyPair)
|
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)
|
||||||
|
@ -69,7 +69,11 @@ import net.corda.node.utilities.NamedThreadFactory
|
|||||||
import net.corda.node.utilities.NodeBuildProperties
|
import net.corda.node.utilities.NodeBuildProperties
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
|
import net.corda.nodeapi.internal.config.CertificateStore
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
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.X509Utilities.DISTRIBUTED_NOTARY_ALIAS_PREFIX
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_ALIAS_PREFIX
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_ALIAS_PREFIX
|
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_ALIAS_PREFIX
|
||||||
import net.corda.nodeapi.internal.persistence.*
|
import net.corda.nodeapi.internal.persistence.*
|
||||||
@ -239,20 +243,20 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
return proxies.fold(ops) { delegate, decorate -> decorate(delegate) }
|
return proxies.fold(ops) { delegate, decorate -> decorate(delegate) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initKeyStore(): X509Certificate {
|
private fun initKeyStores(): X509Certificate {
|
||||||
if (configuration.devMode) {
|
if (configuration.devMode) {
|
||||||
configuration.configureWithDevSSLCertificate()
|
configuration.configureWithDevSSLCertificate()
|
||||||
}
|
}
|
||||||
return validateKeyStore()
|
return validateKeyStores()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun generateAndSaveNodeInfo(): NodeInfo {
|
open fun generateAndSaveNodeInfo(): NodeInfo {
|
||||||
check(started == null) { "Node has already been started" }
|
check(started == null) { "Node has already been started" }
|
||||||
log.info("Generating nodeInfo ...")
|
log.info("Generating nodeInfo ...")
|
||||||
val trustRoot = initKeyStore()
|
val trustRoot = initKeyStores()
|
||||||
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
|
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
|
||||||
startDatabase()
|
startDatabase()
|
||||||
val nodeCa = configuration.signingCertificateStore.get()[X509Utilities.CORDA_CLIENT_CA]
|
val nodeCa = configuration.signingCertificateStore.get()[CORDA_CLIENT_CA]
|
||||||
identityService.start(trustRoot, listOf(identity.certificate, nodeCa))
|
identityService.start(trustRoot, listOf(identity.certificate, nodeCa))
|
||||||
return database.use {
|
return database.use {
|
||||||
it.transaction {
|
it.transaction {
|
||||||
@ -279,8 +283,8 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
log.info("Node starting up ...")
|
log.info("Node starting up ...")
|
||||||
|
|
||||||
val trustRoot = initKeyStore()
|
val trustRoot = initKeyStores()
|
||||||
val nodeCa = configuration.signingCertificateStore.get()[X509Utilities.CORDA_CLIENT_CA]
|
val nodeCa = configuration.signingCertificateStore.get()[CORDA_CLIENT_CA]
|
||||||
initialiseJVMAgents()
|
initialiseJVMAgents()
|
||||||
|
|
||||||
schemaService.mappedSchemasWarnings().forEach {
|
schemaService.mappedSchemasWarnings().forEach {
|
||||||
@ -694,30 +698,50 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected open fun acceptableLiveFiberCountOnStop(): Int = 0
|
protected open fun acceptableLiveFiberCountOnStop(): Int = 0
|
||||||
|
|
||||||
private fun validateKeyStore(): X509Certificate {
|
private fun getCertificateStores(): AllCertificateStores? {
|
||||||
val containCorrectKeys = try {
|
return try {
|
||||||
// This will throw IOException if key file not found or KeyStoreException if keystore password is incorrect.
|
// The following will throw IOException if key file not found or KeyStoreException if keystore password is incorrect.
|
||||||
val sslKeystore = configuration.p2pSslOptions.keyStore.get()
|
val sslKeyStore = configuration.p2pSslOptions.keyStore.get()
|
||||||
val identitiesKeystore = configuration.signingCertificateStore.get()
|
val identitiesKeyStore = configuration.signingCertificateStore.get()
|
||||||
X509Utilities.CORDA_CLIENT_TLS in sslKeystore && X509Utilities.CORDA_CLIENT_CA in identitiesKeystore
|
val trustStore = configuration.p2pSslOptions.trustStore.get()
|
||||||
|
AllCertificateStores(trustStore, sslKeyStore, identitiesKeyStore)
|
||||||
} catch (e: KeyStoreException) {
|
} catch (e: KeyStoreException) {
|
||||||
log.warn("Certificate key store found but key store password does not match configuration.")
|
log.warn("At least one of the keystores or truststore passwords does not match configuration.")
|
||||||
false
|
null
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
log.error("IO exception while trying to validate keystore", e)
|
log.error("IO exception while trying to validate keystores and truststore", e)
|
||||||
false
|
null
|
||||||
}
|
}
|
||||||
require(containCorrectKeys) {
|
}
|
||||||
"Identity certificate not found. " +
|
|
||||||
"Please either copy your existing identity key and certificate from another node, " +
|
private data class AllCertificateStores(val trustStore: CertificateStore, val sslKeyStore: CertificateStore, val identitiesKeyStore: CertificateStore)
|
||||||
|
|
||||||
|
private fun validateKeyStores(): X509Certificate {
|
||||||
|
// Step 1. Check trustStore, sslKeyStore and identitiesKeyStore exist.
|
||||||
|
val certStores = requireNotNull(getCertificateStores()) {
|
||||||
|
"One or more keyStores (identity or TLS) or trustStore not found. " +
|
||||||
|
"Please either copy your existing keys and certificates from another node, " +
|
||||||
"or if you don't have one yet, fill out the config file and run corda.jar --initial-registration. " +
|
"or if you don't have one yet, fill out the config file and run corda.jar --initial-registration. " +
|
||||||
"Read more at: https://docs.corda.net/permissioning.html"
|
"Read more at: https://docs.corda.net/permissioning.html"
|
||||||
}
|
}
|
||||||
|
// Step 2. Check that trustStore contains the correct key-alias entry.
|
||||||
|
require(CORDA_ROOT_CA in certStores.trustStore) {
|
||||||
|
"Alias for trustRoot key not found. Please ensure you have an updated trustStore file."
|
||||||
|
}
|
||||||
|
// Step 3. Check that tls keyStore contains the correct key-alias entry.
|
||||||
|
require(CORDA_CLIENT_TLS in certStores.sslKeyStore) {
|
||||||
|
"Alias for TLS key not found. Please ensure you have an updated TLS keyStore file."
|
||||||
|
}
|
||||||
|
|
||||||
// Check all cert path chain to the trusted root
|
// Step 4. Check that identity keyStores contain the correct key-alias entry for Node CA.
|
||||||
val sslCertChainRoot = configuration.p2pSslOptions.keyStore.get().query { getCertificateChain(X509Utilities.CORDA_CLIENT_TLS) }.last()
|
require(CORDA_CLIENT_CA in certStores.identitiesKeyStore) {
|
||||||
val nodeCaCertChainRoot = configuration.signingCertificateStore.get().query { getCertificateChain(X509Utilities.CORDA_CLIENT_CA) }.last()
|
"Alias for Node CA key not found. Please ensure you have an updated identity keyStore file."
|
||||||
val trustRoot = configuration.p2pSslOptions.trustStore.get()[X509Utilities.CORDA_ROOT_CA]
|
}
|
||||||
|
|
||||||
|
// Step 5. Check all cert paths chain to the trusted root.
|
||||||
|
val trustRoot = certStores.trustStore[CORDA_ROOT_CA]
|
||||||
|
val sslCertChainRoot = certStores.sslKeyStore.query { getCertificateChain(CORDA_CLIENT_TLS) }.last()
|
||||||
|
val nodeCaCertChainRoot = certStores.identitiesKeyStore.query { getCertificateChain(CORDA_CLIENT_CA) }.last()
|
||||||
|
|
||||||
require(sslCertChainRoot == trustRoot) { "TLS certificate must chain to the trusted root." }
|
require(sslCertChainRoot == trustRoot) { "TLS certificate must chain to the trusted root." }
|
||||||
require(nodeCaCertChainRoot == trustRoot) { "Client CA certificate must chain to the trusted root." }
|
require(nodeCaCertChainRoot == trustRoot) { "Client CA certificate must chain to the trusted root." }
|
||||||
|
Reference in New Issue
Block a user