I have some confusion around how SSL settings are configured. By looking through the code, here is what I see happening:
Here is the API for ConnectionContext:
object ConnectionContext {
//#https-context-creation
// ConnectionContext
def https(
sslContext: SSLContext,
sslConfig: Option[AkkaSSLConfig] = None,
enabledCipherSuites: Option[immutable.Seq[String]] = None,
enabledProtocols: Option[immutable.Seq[String]] = None,
clientAuth: Option[TLSClientAuth] = None,
sslParameters: Option[SSLParameters] = None) =
new HttpsConnectionContext(sslContext, sslConfig, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
//#https-context-creation
// for binary-compatibility, since 2.4.7
def https(
sslContext: SSLContext,
enabledCipherSuites: Option[immutable.Seq[String]],
enabledProtocols: Option[immutable.Seq[String]],
clientAuth: Option[TLSClientAuth],
sslParameters: Option[SSLParameters]) =
new HttpsConnectionContext(sslContext, None, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
def noEncryption() = HttpConnectionContext
}
- In
HttpsConnectionContext
, a function is defined to create aNegotiateNewSession
instance:def firstSession = NegotiateNewSession(enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
from the last 4 parameters. - The above
ConnectionContext
ultimately goes to TLS. - Looking at TLS.scala. First, an
SSLEngine
is created from passed inSSLContext
. - Then,
config.sslEngineConfigurator.configure(engine, sslContext)
is called to prepare overrides for protocols and ciphers. Jumping insslEngineConfigurator
, :- If
ssl-config.default
is:true
: Create anSSLContext
from JVM defaultfalse
: Build anSSLContext
according toSSLConfigSettings
inAkkaSSLConfig
.
- Protocols and ciphers are retrieved from
SSLContext
, but re-ordered/filtered based on the configuration inSSLConfigSettings
inAkkaSSLConfig
.
- If
enabledProtocols
andenabledCipherSuites
inSSLEngine
are overridden with the values retrieved from the previous step by callingconfig.sslEngineConfigurator.configure(engine, sslContext)
. Jumping in theconfigure
methodDefaultSSLEngineConfigurator
.- Then,
TlsUtils.applySessionParameters(engine, finalSessionParameters)
is called to overrideenabledCipherSuites
,enabledProtocols
,clientAuth
,sslParameters
if they are defined inNegotiateNewSession
. Please note, these values come fromConnectionContext.https
parameters. Between,sslParameters
might havecipherSuites
,protocols
andclientAuth
defined. If so, they will ultimately override.
So, it looks like, the parameters of ConnectionContext.https
are already in order of configuration override. To summarize, here is what seems to be happennig to find out the ultimate value of cipherSuites
, for instance:
- If
cipherSuites
is defined insslParameters
, that's the ultimate value. If not, go to next step. - If
enabledCipherSuites
parameter is notNone
, that's the ultimate value. If not, go to next step. - If
sslConfig
isNone
, use the singletonAkkaSSLConfig
.- Create an
SSLContext
. IfsslConfig.default
is true, create from JVM default; otherwise from the configuration insslConfig
. - Get the
enabledCipherSuites
fromSSLContext
. Go to next step. - If
sslConfig.enabledCipherSuites
is notNone
, filter/orderenabledCipherSuites
fromSSLContext
accordingly, and this is the ultimate value. If not, go to the next step. - Filter/order
enabledCipherSuites
fromSSLContext
based on default recommended ciphers inCiphers.recommendedCiphers
of Typesafe SSLConfig project.
- Create an
This many layers of configuration and fallback is quite confusing to me.
I probably miss something to understand the reasoning behind this. I will appreciate if you can please explain. Or is this issue filed to simplify it overall?
I think this is a good way of summarizing it. There seems to be so many places doing the same thing, for instance the
enabledCipherSuites
to be configured. It is very confusing what takes precedence, until we invest the time into tracing down the code. Thanks!