From 8f00ec03a3566dd7f5d6c9d8f130b8a16901e6db Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Thu, 22 Sep 2016 15:38:19 +0100 Subject: [PATCH] Checks for SSL certificate on Node startup --- .../kotlin/com/r3corda/node/driver/Driver.kt | 1 + .../com/r3corda/node/internal/AbstractNode.kt | 18 +++++++++++++++++ .../kotlin/com/r3corda/node/internal/Node.kt | 2 -- .../node/services/config/NodeConfiguration.kt | 20 +++++++++++++++++++ .../messaging/ArtemisMessagingComponent.kt | 20 +------------------ 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt b/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt index 058511a13b..3a30fa7ae6 100644 --- a/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt @@ -3,6 +3,7 @@ package com.r3corda.node.driver import com.google.common.net.HostAndPort import com.r3corda.core.ThreadBox import com.r3corda.core.crypto.Party +import com.r3corda.core.crypto.X509Utilities import com.r3corda.core.crypto.generateKeyPair import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.NetworkMapCache diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index a541c59756..304de8a0ef 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -6,6 +6,7 @@ import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.SettableFuture import com.r3corda.core.RunOnCallerThread import com.r3corda.core.crypto.Party +import com.r3corda.core.crypto.X509Utilities import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.createMessage import com.r3corda.core.messaging.runOnNextMessage @@ -158,6 +159,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val networkMap open fun start(): AbstractNode { require(!started) { "Node has already been started" } + + if (configuration.devMode) { + log.warn("Corda node is running in dev mode.") + configuration.configureWithDevSSLCertificate() + } + require(hasSSLCertificates()) { "SSL certificates not found." } + log.info("Node starting up ...") // Do all of this in a database transaction so anything that might need a connection has one. @@ -226,6 +234,16 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val networkMap return this } + private fun hasSSLCertificates(): Boolean { + val keyStore = try { + // This will throw exception if key file not found or keystore password is incorrect. + X509Utilities.loadKeyStore(configuration.keyStorePath, configuration.keyStorePassword) + } catch (e: Exception) { + null + } + return keyStore?.containsAlias(X509Utilities.CORDA_CLIENT_CA) ?: false + } + // Specific class so that MockNode can catch it. class DatabaseConfigurationException(msg: String) : Exception(msg) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 9b7544ff34..7edf11f73d 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -133,7 +133,6 @@ class Node(val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, override fun startMessagingService() { // Start up the embedded MQ server messageBroker?.apply { - configureWithDevSSLCertificate() // TODO: Create proper certificate provisioning process runOnStop += Runnable { messageBroker?.stop() } start() bridgeToNetworkMapService(networkMapService) @@ -141,7 +140,6 @@ class Node(val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, // Start up the MQ client. (net as NodeMessagingClient).apply { - configureWithDevSSLCertificate() // TODO: Client might need a separate certificate start() } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt index 0257ad964d..88815410bb 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt @@ -1,6 +1,7 @@ package com.r3corda.node.services.config import com.google.common.net.HostAndPort +import com.r3corda.core.crypto.X509Utilities import com.r3corda.core.div import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.services.ServiceType @@ -14,6 +15,7 @@ import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigRenderOptions import org.slf4j.LoggerFactory +import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.time.Clock @@ -29,6 +31,24 @@ interface NodeSSLConfiguration { val certificatesPath: Path val keyStorePath: Path get() = certificatesPath / "sslkeystore.jks" val trustStorePath: Path get() = certificatesPath / "truststore.jks" + + /** + * Strictly for dev only automatically construct a server certificate/private key signed from + * the CA certs in Node resources. Then provision KeyStores into certificates folder under node path. + */ + fun configureWithDevSSLCertificate() { + Files.createDirectories(certificatesPath) + if (!Files.exists(trustStorePath)) { + Files.copy(javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordatruststore.jks"), + trustStorePath) + } + if (!Files.exists(keyStorePath)) { + val caKeyStore = X509Utilities.loadKeyStore( + javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordadevcakeys.jks"), + "cordacadevpass") + X509Utilities.createKeystoreForSSL(keyStorePath, keyStorePassword, keyStorePassword, caKeyStore, "cordacadevkeypass") + } + } } interface NodeConfiguration : NodeSSLConfiguration { diff --git a/node/src/main/kotlin/com/r3corda/node/services/messaging/ArtemisMessagingComponent.kt b/node/src/main/kotlin/com/r3corda/node/services/messaging/ArtemisMessagingComponent.kt index aa973ec1ac..89658018bf 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/messaging/ArtemisMessagingComponent.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/messaging/ArtemisMessagingComponent.kt @@ -2,10 +2,8 @@ package com.r3corda.node.services.messaging import com.google.common.annotations.VisibleForTesting import com.google.common.net.HostAndPort -import com.r3corda.core.crypto.X509Utilities import com.r3corda.core.crypto.parsePublicKeyBase58 import com.r3corda.core.crypto.toBase58String -import com.r3corda.core.div import com.r3corda.core.messaging.MessageRecipients import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.serialization.SingletonSerializeAsToken @@ -16,8 +14,6 @@ import org.apache.activemq.artemis.api.core.TransportConfiguration import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants -import java.nio.file.Files -import java.nio.file.Path import java.security.KeyStore import java.security.PublicKey @@ -154,21 +150,7 @@ abstract class ArtemisMessagingComponent(val config: NodeSSLConfiguration) : Sin ) ) - /** - * Strictly for dev only automatically construct a server certificate/private key signed from - * the CA certs in Node resources. Then provision KeyStores into certificates folder under node path. - */ fun configureWithDevSSLCertificate() { - Files.createDirectories(config.certificatesPath) - if (!Files.exists(config.trustStorePath)) { - Files.copy(javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordatruststore.jks"), - config.trustStorePath) - } - if (!Files.exists(config.keyStorePath)) { - val caKeyStore = X509Utilities.loadKeyStore( - javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordadevcakeys.jks"), - "cordacadevpass") - X509Utilities.createKeystoreForSSL(config.keyStorePath, config.keyStorePassword, config.keyStorePassword, caKeyStore, "cordacadevkeypass") - } + config.configureWithDevSSLCertificate() } }