From 30dd29752c9cd5f0e53cd27175f9442a2368eb26 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 30 Mar 2017 15:56:36 +0100 Subject: [PATCH] Clarify exceptions thrown from loading a key store Clarify exceptions thrown from loading a key store as a general cleanup. Also tightens the exceptions caught when loading key stores from AbstractNode, so in case of an unexpected error we don't silently drop the exception. --- .../main/kotlin/net/corda/core/crypto/X509Utilities.kt | 7 +++++++ .../main/kotlin/net/corda/node/internal/AbstractNode.kt | 9 +++++++-- .../node/services/messaging/ArtemisMessagingServer.kt | 6 ++++++ .../node/services/messaging/ArtemisMessagingTests.kt | 2 ++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt index c29454b74c..853fcdabec 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt @@ -27,6 +27,7 @@ import java.io.ByteArrayInputStream import java.io.FileReader import java.io.FileWriter import java.io.InputStream +import java.io.IOException import java.math.BigInteger import java.net.InetAddress import java.nio.file.Path @@ -151,7 +152,10 @@ object X509Utilities { * @param storePassword password to open the store. This does not have to be the same password as any keys stored, * but for SSL purposes this is recommended. * @return returns the KeyStore opened + * @throws IOException if there was an error reading the key store from the file. + * @throws KeyStoreException if the password is incorrect or the key store is damaged. */ + @Throws(KeyStoreException::class, IOException::class) fun loadKeyStore(keyStoreFilePath: Path, storePassword: String): KeyStore { val pass = storePassword.toCharArray() val keyStore = KeyStore.getInstance(KEYSTORE_TYPE) @@ -165,7 +169,10 @@ object X509Utilities { * @param storePassword password to open the store. This does not have to be the same password as any keys stored, * but for SSL purposes this is recommended. * @return returns the KeyStore opened + * @throws IOException if there was an error reading the key store from the stream. + * @throws KeyStoreException if the password is incorrect or the key store is damaged. */ + @Throws(KeyStoreException::class, IOException::class) fun loadKeyStore(input: InputStream, storePassword: String): KeyStore { val pass = storePassword.toCharArray() val keyStore = KeyStore.getInstance(KEYSTORE_TYPE) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 5827d4d74b..c22b3e6d40 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -53,9 +53,11 @@ import net.corda.node.utilities.databaseTransaction import org.apache.activemq.artemis.utils.ReusableLatch import org.jetbrains.exposed.sql.Database import org.slf4j.Logger +import java.io.IOException import java.nio.file.FileAlreadyExistsException import java.nio.file.Path import java.security.KeyPair +import java.security.KeyStoreException import java.time.Clock import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -312,9 +314,12 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, private fun hasSSLCertificates(): Boolean { val keyStore = try { - // This will throw exception if key file not found or keystore password is incorrect. + // This will throw IOException if key file not found or KeyStoreException if keystore password is incorrect. X509Utilities.loadKeyStore(configuration.keyStoreFile, configuration.keyStorePassword) - } catch (e: Exception) { + } catch (e: IOException) { + null + } catch (e: KeyStoreException) { + log.warn("Certificate key store found but key store password does not match configuration.") null } return keyStore?.containsAlias(X509Utilities.CORDA_CLIENT_CA) ?: false diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 120fb44a4e..37bd2a8bc4 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -50,6 +50,7 @@ import rx.Subscription import java.io.IOException import java.math.BigInteger import java.security.KeyStore +import java.security.KeyStoreException import java.security.Principal import java.util.* import java.util.concurrent.Executor @@ -113,6 +114,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, * The server will make sure the bridge exists on network map changes, see method [updateBridgesOnNetworkChange] * We assume network map will be updated accordingly when the client node register with the network map server. */ + @Throws(IOException::class, KeyStoreException::class) fun start() = mutex.locked { if (!running) { configureAndStartServer() @@ -130,6 +132,9 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, running = false } + // TODO: Maybe wrap [IOException] on a key store load error so that it's clearly splitting key store loading from + // Artemis IO errors + @Throws(IOException::class, KeyStoreException::class) private fun configureAndStartServer() { val config = createArtemisConfig() val securityManager = createArtemisSecurityManager() @@ -225,6 +230,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, deleteNonDurableQueue, manage, browse) } + @Throws(IOException::class, KeyStoreException::class) private fun createArtemisSecurityManager(): ActiveMQJAASSecurityManager { val ourCertificate = X509Utilities .loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA) diff --git a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt index 2c887923f6..63f4aad323 100644 --- a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt @@ -88,6 +88,8 @@ class ArtemisMessagingTests { fun cleanUp() { messagingClient?.stop() messagingServer?.stop() + messagingClient = null + messagingServer = null dataSource.close() LogHelper.reset(PersistentUniquenessProvider::class) }