From ff78b8423301ffc1ac264aa433fc296c4c6e9101 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 28 Oct 2016 11:45:48 +0200 Subject: [PATCH] =rem #13874 cleanup SSLSettings (#21746) --- .../transport/netty/NettySSLSupport.scala | 88 +++++++------------ .../scala/akka/remote/RemoteConfigSpec.scala | 14 +-- .../remote/Ticket1978CommunicationSpec.scala | 9 +- .../akka/remote/Ticket1978ConfigSpec.scala | 14 +-- 4 files changed, 50 insertions(+), 75 deletions(-) diff --git a/akka-remote/src/main/scala/akka/remote/transport/netty/NettySSLSupport.scala b/akka-remote/src/main/scala/akka/remote/transport/netty/NettySSLSupport.scala index 49846cb6da..d6a478d189 100644 --- a/akka-remote/src/main/scala/akka/remote/transport/netty/NettySSLSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/transport/netty/NettySSLSupport.scala @@ -20,34 +20,20 @@ import scala.util.Try * INTERNAL API */ private[akka] class SSLSettings(config: Config) { + import config.{ getString, getStringList } - import config._ + val SSLKeyStore = getString("key-store") + val SSLTrustStore = getString("trust-store") + val SSLKeyStorePassword = getString("key-store-password") + val SSLKeyPassword = getString("key-password") - private def emptyIsNone(s: String): Option[String] = Option(s).filter(_.length > 0) - - val SSLKeyStore = emptyIsNone(getString("key-store")) - val SSLTrustStore = emptyIsNone(getString("trust-store")) - val SSLKeyStorePassword = emptyIsNone(getString("key-store-password")) - val SSLKeyPassword = emptyIsNone(getString("key-password")) - - val SSLTrustStorePassword = emptyIsNone(getString("trust-store-password")) + val SSLTrustStorePassword = getString("trust-store-password") val SSLEnabledAlgorithms = immutableSeq(getStringList("enabled-algorithms")).to[Set] - val SSLProtocol = emptyIsNone(getString("protocol")) + val SSLProtocol = getString("protocol") - val SSLRandomNumberGenerator = emptyIsNone(getString("random-number-generator")) - - if (SSLProtocol.isEmpty) throw new ConfigurationException( - "Configuration option 'akka.remote.netty.ssl.enable-ssl is turned on but no protocol is defined in 'akka.remote.netty.ssl.security.protocol'.") - if (SSLKeyStore.isEmpty && SSLTrustStore.isEmpty) throw new ConfigurationException( - "Configuration option 'akka.remote.netty.ssl.enable-ssl is turned on but no key/trust store is defined in 'akka.remote.netty.ssl.security.key-store' / 'akka.remote.netty.ssl.security.trust-store'.") - if (SSLKeyStore.isDefined && SSLKeyStorePassword.isEmpty) throw new ConfigurationException( - "Configuration option 'akka.remote.netty.ssl.security.key-store' is defined but no key-store password is defined in 'akka.remote.netty.ssl.security.key-store-password'.") - if (SSLKeyStore.isDefined && SSLKeyPassword.isEmpty) throw new ConfigurationException( - "Configuration option 'akka.remote.netty.ssl.security.key-store' is defined but no key password is defined in 'akka.remote.netty.ssl.security.key-password'.") - if (SSLTrustStore.isDefined && SSLTrustStorePassword.isEmpty) throw new ConfigurationException( - "Configuration option 'akka.remote.netty.ssl.security.trust-store' is defined but no trust-store password is defined in 'akka.remote.netty.ssl.security.trust-store-password'.") + val SSLRandomNumberGenerator = getString("random-number-generator") } /** @@ -65,26 +51,28 @@ private[akka] object NettySSLSupport { def apply(settings: SSLSettings, log: LoggingAdapter, isClient: Boolean): SslHandler = if (isClient) initializeClientSSL(settings, log) else initializeServerSSL(settings, log) - def initializeCustomSecureRandom(rngName: Option[String], log: LoggingAdapter): SecureRandom = { + def initializeCustomSecureRandom(rngName: String, log: LoggingAdapter): SecureRandom = { val rng = rngName match { - case Some(r @ ("AES128CounterSecureRNG" | "AES256CounterSecureRNG")) ⇒ + case r @ ("AES128CounterSecureRNG" | "AES256CounterSecureRNG") ⇒ log.debug("SSL random number generator set to: {}", r) SecureRandom.getInstance(r, AkkaProvider) - case Some(r @ ("AES128CounterInetRNG" | "AES256CounterInetRNG")) ⇒ + case r @ ("AES128CounterInetRNG" | "AES256CounterInetRNG") ⇒ log.warning("SSL random number generator {} is deprecated, " + "use AES128CounterSecureRNG or AES256CounterSecureRNG instead", r) SecureRandom.getInstance(r, AkkaProvider) - case Some(s @ ("SHA1PRNG" | "NativePRNG")) ⇒ + case s @ ("SHA1PRNG" | "NativePRNG") ⇒ log.debug("SSL random number generator set to: " + s) // SHA1PRNG needs /dev/urandom to be the source on Linux to prevent problems with /dev/random blocking // However, this also makes the seed source insecure as the seed is reused to avoid blocking (not a problem on FreeBSD). SecureRandom.getInstance(s) - case Some(unknown) ⇒ - log.warning("Unknown SSLRandomNumberGenerator [{}] falling back to SecureRandom", unknown) - new SecureRandom - case None ⇒ + + case "" ⇒ log.debug("SSLRandomNumberGenerator not specified, falling back to SecureRandom") new SecureRandom + + case unknown ⇒ + log.warning("Unknown SSLRandomNumberGenerator [{}] falling back to SecureRandom", unknown) + new SecureRandom } rng.nextInt() // prevent stall on first access rng @@ -113,21 +101,14 @@ private[akka] object NettySSLSupport { case e: GeneralSecurityException ⇒ throw new RemoteTransportException("Client SSL connection could not be established because SSL context could not be constructed", e) } - ((settings.SSLTrustStore, settings.SSLTrustStorePassword, settings.SSLProtocol) match { - case (Some(trustStore), Some(password), Some(protocol)) ⇒ constructClientContext(settings, log, trustStore, password, protocol) - case (trustStore, password, protocol) ⇒ throw new GeneralSecurityException( - "One or several SSL trust store settings are missing: [trust-store: %s] [trust-store-password: %s] [protocol: %s]".format( - trustStore, - password, - protocol)) - }) match { + constructClientContext(settings, log, settings.SSLTrustStore, settings.SSLTrustStorePassword, settings.SSLProtocol) match { case Some(context) ⇒ log.debug("Using client SSL context to create SSLEngine ...") new SslHandler({ val sslEngine = context.createSSLEngine sslEngine.setUseClientMode(true) sslEngine.setEnabledCipherSuites(settings.SSLEnabledAlgorithms.toArray) - sslEngine.setEnabledProtocols(settings.SSLProtocol.toArray) + sslEngine.setEnabledProtocols(Array(settings.SSLProtocol)) sslEngine }) case None ⇒ @@ -154,30 +135,25 @@ private[akka] object NettySSLSupport { keyStore }, keyPassword.toCharArray) - val trustManagers: Option[Array[TrustManager]] = settings.SSLTrustStore map { - path ⇒ - val pwd = settings.SSLTrustStorePassword.map(_.toCharArray).orNull - val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) - trustManagerFactory.init({ - val trustStore = KeyStore.getInstance(KeyStore.getDefaultType) - val fin = new FileInputStream(path) - try trustStore.load(fin, pwd) finally Try(fin.close()) - trustStore - }) - trustManagerFactory.getTrustManagers + val trustManagers: Array[TrustManager] = { + val pwd = settings.SSLTrustStorePassword.toCharArray + val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) + trustManagerFactory.init({ + val trustStore = KeyStore.getInstance(KeyStore.getDefaultType) + val fin = new FileInputStream(settings.SSLTrustStore) + try trustStore.load(fin, pwd) finally Try(fin.close()) + trustStore + }) + trustManagerFactory.getTrustManagers } - Option(SSLContext.getInstance(protocol)) map { ctx ⇒ ctx.init(factory.getKeyManagers, trustManagers.orNull, rng); ctx } + Option(SSLContext.getInstance(protocol)) map { ctx ⇒ ctx.init(factory.getKeyManagers, trustManagers, rng); ctx } } catch { case e: FileNotFoundException ⇒ throw new RemoteTransportException("Server SSL connection could not be established because key store could not be loaded", e) case e: IOException ⇒ throw new RemoteTransportException("Server SSL connection could not be established because: " + e.getMessage, e) case e: GeneralSecurityException ⇒ throw new RemoteTransportException("Server SSL connection could not be established because SSL context could not be constructed", e) } - ((settings.SSLKeyStore, settings.SSLKeyStorePassword, settings.SSLKeyPassword, settings.SSLProtocol) match { - case (Some(keyStore), Some(storePassword), Some(keyPassword), Some(protocol)) ⇒ constructServerContext(settings, log, keyStore, storePassword, keyPassword, protocol) - case (keyStore, storePassword, keyPassword, protocol) ⇒ throw new GeneralSecurityException( - s"SSL key store settings went missing. [key-store: $keyStore] [key-store-password: $storePassword] [key-password: $keyPassword] [protocol: $protocol]") - }) match { + constructServerContext(settings, log, settings.SSLKeyStore, settings.SSLKeyStorePassword, settings.SSLKeyPassword, settings.SSLProtocol) match { case Some(context) ⇒ log.debug("Using server SSL context to create SSLEngine ...") val sslEngine = context.createSSLEngine diff --git a/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala b/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala index 626dbf7bc2..7a60c82909 100644 --- a/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala @@ -122,14 +122,14 @@ class RemoteConfigSpec extends AkkaSpec( "contain correct ssl configuration values in reference.conf" in { val sslSettings = new SSLSettings(system.settings.config.getConfig("akka.remote.netty.ssl.security")) - sslSettings.SSLKeyStore should ===(Some("keystore")) - sslSettings.SSLKeyStorePassword should ===(Some("changeme")) - sslSettings.SSLKeyPassword should ===(Some("changeme")) - sslSettings.SSLTrustStore should ===(Some("truststore")) - sslSettings.SSLTrustStorePassword should ===(Some("changeme")) - sslSettings.SSLProtocol should ===(Some("TLSv1.2")) + sslSettings.SSLKeyStore should ===("keystore") + sslSettings.SSLKeyStorePassword should ===("changeme") + sslSettings.SSLKeyPassword should ===("changeme") + sslSettings.SSLTrustStore should ===("truststore") + sslSettings.SSLTrustStorePassword should ===("changeme") + sslSettings.SSLProtocol should ===("TLSv1.2") sslSettings.SSLEnabledAlgorithms should ===(Set("TLS_RSA_WITH_AES_128_CBC_SHA")) - sslSettings.SSLRandomNumberGenerator should ===(None) + sslSettings.SSLRandomNumberGenerator should ===("") } "have debug logging of the failure injector turned off in reference.conf" in { diff --git a/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala b/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala index 78a9d1389b..46179a33ea 100644 --- a/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala @@ -66,17 +66,16 @@ object Configuration { val rng = NettySSLSupport.initializeCustomSecureRandom(settings.SSLRandomNumberGenerator, NoLogging) rng.nextInt() // Has to work - settings.SSLRandomNumberGenerator foreach { - sRng ⇒ rng.getAlgorithm == sRng || (throw new NoSuchAlgorithmException(sRng)) - } + val sRng = settings.SSLRandomNumberGenerator + rng.getAlgorithm == sRng || (throw new NoSuchAlgorithmException(sRng)) val engine = NettySSLSupport.initializeClientSSL(settings, NoLogging).getEngine val gotAllSupported = enabled.toSet diff engine.getSupportedCipherSuites.toSet val gotAllEnabled = enabled.toSet diff engine.getEnabledCipherSuites.toSet gotAllSupported.isEmpty || (throw new IllegalArgumentException("Cipher Suite not supported: " + gotAllSupported)) gotAllEnabled.isEmpty || (throw new IllegalArgumentException("Cipher Suite not enabled: " + gotAllEnabled)) - engine.getSupportedProtocols.contains(settings.SSLProtocol.get) || - (throw new IllegalArgumentException("Protocol not supported: " + settings.SSLProtocol.get)) + engine.getSupportedProtocols.contains(settings.SSLProtocol) || + (throw new IllegalArgumentException("Protocol not supported: " + settings.SSLProtocol)) CipherConfig(true, config, cipher, localPort, remotePort) } catch { diff --git a/akka-remote/src/test/scala/akka/remote/Ticket1978ConfigSpec.scala b/akka-remote/src/test/scala/akka/remote/Ticket1978ConfigSpec.scala index f3948da4b2..eeaaed300e 100644 --- a/akka-remote/src/test/scala/akka/remote/Ticket1978ConfigSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/Ticket1978ConfigSpec.scala @@ -13,14 +13,14 @@ class Ticket1978ConfigSpec extends AkkaSpec(""" "be able to parse these extra Netty config elements" in { val settings = new SSLSettings(system.settings.config.getConfig("akka.remote.netty.ssl.security")) - settings.SSLKeyStore should ===(Some("keystore")) - settings.SSLKeyStorePassword should ===(Some("changeme")) - settings.SSLKeyPassword should ===(Some("changeme")) - settings.SSLTrustStore should ===(Some("truststore")) - settings.SSLTrustStorePassword should ===(Some("changeme")) - settings.SSLProtocol should ===(Some("TLSv1.2")) + settings.SSLKeyStore should ===("keystore") + settings.SSLKeyStorePassword should ===("changeme") + settings.SSLKeyPassword should ===("changeme") + settings.SSLTrustStore should ===("truststore") + settings.SSLTrustStorePassword should ===("changeme") + settings.SSLProtocol should ===("TLSv1.2") settings.SSLEnabledAlgorithms should ===(Set("TLS_RSA_WITH_AES_128_CBC_SHA")) - settings.SSLRandomNumberGenerator should ===(Some("AES128CounterSecureRNG")) + settings.SSLRandomNumberGenerator should ===("AES128CounterSecureRNG") } } }