parent
3e55aa5555
commit
ff78b84233
4 changed files with 50 additions and 75 deletions
|
|
@ -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 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(path)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue