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:
Konstantinos Chalkias 2018-09-11 12:37:21 +01:00 committed by PokeyBot
parent 37c7fff8b1
commit 3ff7fc2585
2 changed files with 50 additions and 26 deletions

View File

@ -20,14 +20,14 @@ class NodeKeystoreCheckTest {
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
assertThatThrownBy {
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
fun `node should throw exception if cert path doesn't chain to the trust root`() {
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList())) {
// Create keystores
// Create keystores.
val keystorePassword = "password"
val certificatesDirectory = baseDirectory(ALICE_NAME) / "certificates"
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, keystorePassword)
@ -46,7 +46,7 @@ class NodeKeystoreCheckTest {
// Fiddle with node keystore.
signingCertStore.get().update {
// Self signed root
// 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)

View File

@ -69,7 +69,11 @@ import net.corda.node.utilities.NamedThreadFactory
import net.corda.node.utilities.NodeBuildProperties
import net.corda.nodeapi.internal.NodeInfoAndSigned
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.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.NODE_IDENTITY_ALIAS_PREFIX
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) }
}
private fun initKeyStore(): X509Certificate {
private fun initKeyStores(): X509Certificate {
if (configuration.devMode) {
configuration.configureWithDevSSLCertificate()
}
return validateKeyStore()
return validateKeyStores()
}
open fun generateAndSaveNodeInfo(): NodeInfo {
check(started == null) { "Node has already been started" }
log.info("Generating nodeInfo ...")
val trustRoot = initKeyStore()
val trustRoot = initKeyStores()
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
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))
return database.use {
it.transaction {
@ -279,8 +283,8 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
}
log.info("Node starting up ...")
val trustRoot = initKeyStore()
val nodeCa = configuration.signingCertificateStore.get()[X509Utilities.CORDA_CLIENT_CA]
val trustRoot = initKeyStores()
val nodeCa = configuration.signingCertificateStore.get()[CORDA_CLIENT_CA]
initialiseJVMAgents()
schemaService.mappedSchemasWarnings().forEach {
@ -694,30 +698,50 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
@VisibleForTesting
protected open fun acceptableLiveFiberCountOnStop(): Int = 0
private fun validateKeyStore(): X509Certificate {
val containCorrectKeys = try {
// This will throw IOException if key file not found or KeyStoreException if keystore password is incorrect.
val sslKeystore = configuration.p2pSslOptions.keyStore.get()
val identitiesKeystore = configuration.signingCertificateStore.get()
X509Utilities.CORDA_CLIENT_TLS in sslKeystore && X509Utilities.CORDA_CLIENT_CA in identitiesKeystore
private fun getCertificateStores(): AllCertificateStores? {
return try {
// The following will throw IOException if key file not found or KeyStoreException if keystore password is incorrect.
val sslKeyStore = configuration.p2pSslOptions.keyStore.get()
val identitiesKeyStore = configuration.signingCertificateStore.get()
val trustStore = configuration.p2pSslOptions.trustStore.get()
AllCertificateStores(trustStore, sslKeyStore, identitiesKeyStore)
} catch (e: KeyStoreException) {
log.warn("Certificate key store found but key store password does not match configuration.")
false
log.warn("At least one of the keystores or truststore passwords does not match configuration.")
null
} catch (e: IOException) {
log.error("IO exception while trying to validate keystore", e)
false
log.error("IO exception while trying to validate keystores and truststore", e)
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. " +
"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
val sslCertChainRoot = configuration.p2pSslOptions.keyStore.get().query { getCertificateChain(X509Utilities.CORDA_CLIENT_TLS) }.last()
val nodeCaCertChainRoot = configuration.signingCertificateStore.get().query { getCertificateChain(X509Utilities.CORDA_CLIENT_CA) }.last()
val trustRoot = configuration.p2pSslOptions.trustStore.get()[X509Utilities.CORDA_ROOT_CA]
// Step 4. Check that identity keyStores contain the correct key-alias entry for Node CA.
require(CORDA_CLIENT_CA in certStores.identitiesKeyStore) {
"Alias for Node CA key not found. Please ensure you have an updated identity keyStore file."
}
// 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(nodeCaCertChainRoot == trustRoot) { "Client CA certificate must chain to the trusted root." }