Checks for SSL certificate on Node startup

This commit is contained in:
Patrick Kuo 2016-09-22 15:38:19 +01:00
parent 46d6749616
commit 8f00ec03a3
5 changed files with 40 additions and 21 deletions

View File

@ -3,6 +3,7 @@ package com.r3corda.node.driver
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.core.ThreadBox import com.r3corda.core.ThreadBox
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.X509Utilities
import com.r3corda.core.crypto.generateKeyPair import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.NetworkMapCache

View File

@ -6,6 +6,7 @@ import com.google.common.util.concurrent.MoreExecutors
import com.google.common.util.concurrent.SettableFuture import com.google.common.util.concurrent.SettableFuture
import com.r3corda.core.RunOnCallerThread import com.r3corda.core.RunOnCallerThread
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.X509Utilities
import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.messaging.createMessage import com.r3corda.core.messaging.createMessage
import com.r3corda.core.messaging.runOnNextMessage import com.r3corda.core.messaging.runOnNextMessage
@ -158,6 +159,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val networkMap
open fun start(): AbstractNode { open fun start(): AbstractNode {
require(!started) { "Node has already been started" } 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 ...") log.info("Node starting up ...")
// Do all of this in a database transaction so anything that might need a connection has one. // 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 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. // Specific class so that MockNode can catch it.
class DatabaseConfigurationException(msg: String) : Exception(msg) class DatabaseConfigurationException(msg: String) : Exception(msg)

View File

@ -133,7 +133,6 @@ class Node(val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
override fun startMessagingService() { override fun startMessagingService() {
// Start up the embedded MQ server // Start up the embedded MQ server
messageBroker?.apply { messageBroker?.apply {
configureWithDevSSLCertificate() // TODO: Create proper certificate provisioning process
runOnStop += Runnable { messageBroker?.stop() } runOnStop += Runnable { messageBroker?.stop() }
start() start()
bridgeToNetworkMapService(networkMapService) bridgeToNetworkMapService(networkMapService)
@ -141,7 +140,6 @@ class Node(val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
// Start up the MQ client. // Start up the MQ client.
(net as NodeMessagingClient).apply { (net as NodeMessagingClient).apply {
configureWithDevSSLCertificate() // TODO: Client might need a separate certificate
start() start()
} }
} }

View File

@ -1,6 +1,7 @@
package com.r3corda.node.services.config package com.r3corda.node.services.config
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.core.crypto.X509Utilities
import com.r3corda.core.div import com.r3corda.core.div
import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.services.ServiceType 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.ConfigParseOptions
import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigRenderOptions
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.time.Clock import java.time.Clock
@ -29,6 +31,24 @@ interface NodeSSLConfiguration {
val certificatesPath: Path val certificatesPath: Path
val keyStorePath: Path get() = certificatesPath / "sslkeystore.jks" val keyStorePath: Path get() = certificatesPath / "sslkeystore.jks"
val trustStorePath: Path get() = certificatesPath / "truststore.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 { interface NodeConfiguration : NodeSSLConfiguration {

View File

@ -2,10 +2,8 @@ package com.r3corda.node.services.messaging
import com.google.common.annotations.VisibleForTesting import com.google.common.annotations.VisibleForTesting
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.core.crypto.X509Utilities
import com.r3corda.core.crypto.parsePublicKeyBase58 import com.r3corda.core.crypto.parsePublicKeyBase58
import com.r3corda.core.crypto.toBase58String import com.r3corda.core.crypto.toBase58String
import com.r3corda.core.div
import com.r3corda.core.messaging.MessageRecipients import com.r3corda.core.messaging.MessageRecipients
import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.serialization.SingletonSerializeAsToken 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.NettyAcceptorFactory
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants 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.KeyStore
import java.security.PublicKey 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() { fun configureWithDevSSLCertificate() {
Files.createDirectories(config.certificatesPath) config.configureWithDevSSLCertificate()
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")
}
} }
} }