Custom SSL Engine not being called

Using latest play (2.8ish) I’m trying to use a custom SSL Engine to improve my server’s https security, but the engine doesn’t seem to be getting called.

By default, forward secrecy isn’t present in play, so as recommended in docs, I added a custom SSL engine.

class CustomSSLEngineProvider @Inject()(appProvider: ApplicationProvider)
    extends SSLEngineProvider {

    val priorityCipherSuites = List(
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
    )


    def readPassword(): Array[Char] = {
        System.getProperty("play.server.https.keyStore.password").toCharArray
    }

    def readKeyInputStream(): java.io.InputStream = {
        val keyPath = FileSystems.getDefault.getPath(System.getProperty("play.server.https.keyStore.path"))
        Files.newInputStream(keyPath)
    }

    def readKeyManagers(): Array[KeyManager] = {
        val password = readPassword()
        val keyInputStream = readKeyInputStream()
        try {
            val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
            keyStore.load(keyInputStream, password)
            val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
            kmf.init(keyStore, password)

            kmf.getKeyManagers
        } finally {
            keyInputStream.close()
        }
    }

    def createSSLContext(): SSLContext = {
        val keyManagers = readKeyManagers()
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(keyManagers, Array.empty, null)
        sslContext
    }

    override def sslContext(): SSLContext = createSSLContext()

    override def createSSLEngine(): SSLEngine = {

        val ctx = createSSLContext()
        val sslEngine = ctx.createSSLEngine
        val cipherSuites = sslEngine.getEnabledCipherSuites.toList
        val orderedCipherSuites =
            priorityCipherSuites.filter(cipherSuites.contains) ::: cipherSuites.filterNot(priorityCipherSuites.contains)
        sslEngine.setEnabledCipherSuites(orderedCipherSuites.toArray)
        val params = sslEngine.getSSLParameters
        params.setUseCipherSuitesOrder(true)
        sslEngine.setSSLParameters(params)
        //sslEngine
        throw new RuntimeException("test")
    }
}

You’ll notice the last line throws a runtime exception, but that exception never gets thrown, which is the reason why I don’t think this engine is being used. (Also the server still doesn’t support forward secrecy).

Added this via:

-Dplay.server.https.engineProvider=controllers.util.CustomSSLEngineProvider

Does anyone have any ideas?

bumpty bump

I think @wsargent knows a lot about these topics…

The thing I’d do off the bat is compare with the scala-tls example and see if you’re doing anything different there:

https://developer.lightbend.com/start/?group=play&project=play-samples-play-scala-tls-example

Also you don’t specify how you’re adding this to the build.sbt – if you’re adding it as a custom JVM parameter in Universal, for example, then you’ll only see it when you build it using sbt stage and then run the script from there (or runProd, which I don’t like because it’s less obvious what’s going on).

If things aren’t working, you should turn on debugging – see https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/ReadDebug.html or add debugjsse in as your provider to see what’s going on https://github.com/tersesystems/debugjsse and that should help.

Thanks @wsargent ,

Also you don’t specify how you’re adding this to the build.sbt

I’m just running sbt dist to build the binary, then calling the binary and passing in the -Dplay.server.https.engineProvider=controllers.util.CustomSSLEngineProvider property as an argument.

Before I dig into the SSL debugging, I just want to confirm that Play is indeed calling my custom engine and is using it (and not overwriting / ignoring it). The exception at the end of my createSSLEngine() not doing anything is giving me doubt if that’s the case. Is it possible to confirm if Play isn’t ignoring it, and then I can dig into the SSL debugging?

Re the TLS example, they’re doing enablePlugins(PlayScala, PlayAkkaHttp2Support) whereas I’m just doing enablePlugins(PlayScala), could that be a factor? (Want to confirm before I change stuff on prod)

Thanks.

Hi,
in my case, but in Play 2.7.4, i extend play.core.server.ssl.DefaultSSLEngineProvider and only override

class SaferSSLEngineProvider(serverConfig: ServerConfig,
                             appProvider: ApplicationProvider) extends DefaultSSLEngineProvider(serverConfig, appProvider) {
override def createSSLEngine(): SSLEngine = {
    val SSLContext = sslContext
    // Start off with a clone of the default SSL parameters...
    val sslParameters = SSLContext.getDefaultSSLParameters

    // Tells the server to ignore client's cipher suite preference.
    // http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#cipher_suite_preference
    // https://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html
    sslParameters.setUseCipherSuitesOrder(true) // you want this one
  

    // Clone and modify the default SSL parameters.
    val engine = SSLContext.createSSLEngine
    engine.setSSLParameters(sslParameters)

    engine
  }

then in application.conf:
javaOptions in Universal ++= Seq(
“-Dplay.server.https.engineProvider=SaferSSLEngineProvider”
)

Hopes this helps somehow.

The default behaviour of SSLEngineProvider appears to change between version 2.7.x and 2.8.x, almost certainly due to the HTTP implementation shifting from Netty to Akka.

In 2.8.x (Akka implementation) invokes the “sslContext” method, but not the “createSSLEngine” method like the 2.7.x (Netty implementation) does.

You either need to “work-around” this, by downgrading to 2.7.x or changing the internal HTTP Implementation Play 2.8.x uses to Netty instead of Akka.

From what I understand, the new preferred way of setting Protocols / Cipher selection/restriction going forward is via System Properties (or Security Properties) instead of doing this kind of stuff in a class - it may be worth investigating that instead as preferred approach going forward. The documentation for the Play 2.8.x docs should perhaps reflect this better and the “createSSLEngine” method which isn’t getting invoked should perhaps be deprecated.

I’ve created a issue ticket: https://github.com/playframework/playframework/issues/10388

1 Like

Thanks for confirming Charles. I seem to be having the same issue - createSSLEngine doesn’t seem to be getting invoked.

I’ll watch the issue.

The answer for Play 2.8.x is to “strictly” follow instructions found over on this site and these pages:

https://lightbend.github.io/ssl-config/CipherSuites.html
https://lightbend.github.io/ssl-config/Protocols.html

This includes a combination of setting Play Config, System Properties and Security Properties.

Do not attempt to set a custom SSLEngineProvider at all.