1

I have a akka-streams topology, where I make a POST call using akka-http.

I am getting following error when hitting the post request to a un-secure server(having self-signed certs). It is a internal server, so I am fine from security point of view.

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:813) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781) ~[?:1.8.0_131]
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:367) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doInbound(TLSActor.scala:290) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor$$anonfun$1.apply$mcV$sp(TLSActor.scala:225) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.Pump$class.pump(Transfer.scala:199) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.pump(TLSActor.scala:48) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.BatchingInputBuffer.enqueueInputElement(ActorProcessor.scala:90) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.BatchingInputBuffer$$anonfun$upstreamRunning$1.applyOrElse(ActorProcessor.scala:141) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:16) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.FanIn$InputBunch$$anonfun$subreceive$1.applyOrElse(FanIn.scala:234) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:16) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:12) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.PartialFunction$class.applyOrElse(PartialFunction.scala:123) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.applyOrElse(Transfer.scala:12) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:170) ~[scala-library-2.11.8.jar:?]
    at akka.actor.Actor$class.aroundReceive(Actor.scala:497) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.aroundReceive(TLSActor.scala:48) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.actor.ActorCell.invoke(ActorCell.scala:495) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.dispatch.Mailbox.run(Mailbox.scala:224) ~[akka-actor_2.11-2.4.17.jar:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[?:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[?:1.8.0_131]
    at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_131]
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) ~[?:1.8.0_131]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.runDelegatedTasks(TLSActor.scala:402) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:371) ~[akka-stream_2.11-2.4.17.jar:?]
    ... 24 more
Caused by: java.security.cert.CertificateException: No subject alternative names present
    at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:144) ~[?:1.8.0_131]
    at sun.security.util.HostnameChecker.match(HostnameChecker.java:93) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) ~[?:1.8.0_131]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.runDelegatedTasks(TLSActor.scala:402) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:371) ~[akka-stream_2.11-2.4.17.jar:?]

Some discussion happened here, and another solution here and here, but didn't worked for me and one unfinished discussion here. One solution is proposed here but not sure how to implement the same for akka-http. Few more relevant links:

akka-issue

Configuring Trust Stores

SO Question1

SO Question 2

Solution in Java

earlier I was using just following to execute it:

Http().superPool[MyTracker]()

I also tried following, getting inspiration from here and here, but problem persists:

    val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withAcceptAnyCertificate(true)))
    val badCtx = Http().createClientHttpsContext(badSslConfig)
    Http().superPool[MyTracker]()(httpMat)

Edit #1

I added one more flag, but got different error than earlier:

    val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withAcceptAnyCertificate(true).withDisableHostnameVerification(true)))
    val badCtx = Http().createClientHttpsContext(badSslConfig)
    Http().superPool[MyTracker]()(httpMat)

Error:

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[?:1.8.0_131]
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[?:1.8.0_131]
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[?:1.8.0_131]
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ~[?:1.8.0_131]
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) ~[?:1.8.0_131]
    at sun.security.validator.Validator.validate(Validator.java:260) ~[?:1.8.0_131]

Edit #2

Getting inspiration from this answer, not sure how to implement that with akka-httlp exactly, I tried following:

val trustStoreConfig = TrustStoreConfig(None, Some("/Users/user/path/my.cer")).withStoreType("PEM")
val trustManagerConfig = TrustManagerConfig().withTrustStoreConfigs(List(trustStoreConfig))

val sslConfig = AkkaSSLConfig().mapSettings { s =>
  s.withHostnameVerifierClass(classOf[DisabledComplainingHostnameVerifier])
  s.withTrustManagerConfig(trustManagerConfig)
  s
}
val badCtx = Http().createClientHttpsContext(sslConfig)
Http().superPool[RequestTracker](badCtx)(httpMat)

But still getting this error:

Caused by: java.security.cert.CertificateException: No subject alternative names present

at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:144) ~[?:1.8.0_131]

at sun.security.util.HostnameChecker.match(HostnameChecker.java:93) ~[?:1.8.0_131]

at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[?:1.8.0_131]

at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) ~[?:1.8.0_131] at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252) ~[?:1.8.0_131]

at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) ~[?:1.8.0_131]

at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ~[?:1.8.0_131]

Is this not possible in Akka?

Saurabh
  • 71,488
  • 40
  • 181
  • 244

1 Answers1

0

Finally, Getting inspiration from this answer, which seems way complicated, With following code snippet it worked:

val trustStoreConfig = TrustStoreConfig(None, Some("/etc/Project/keystore/my.cer")).withStoreType("PEM")
val trustManagerConfig = TrustManagerConfig().withTrustStoreConfigs(List(trustStoreConfig))

val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose
  .withAcceptAnyCertificate(true)
  .withDisableHostnameVerification(true)
).withTrustManagerConfig(trustManagerConfig))

val badCtx = Http().createClientHttpsContext(badSslConfig)

Http().superPool[RequestTracker](badCtx)(httpMat)

Not sure why it did not work with other attempts of mine, will like to understand this deeply, Please post an explanation if you know the internals.

Saurabh
  • 71,488
  • 40
  • 181
  • 244
  • ... and if you have the key in a string, and not in a file, you can use `TrustStoreConfig(Some(keyString), None)` instead – Georg Aug 21 '18 at 07:12
  • This is a super insecure solution disabling all security in HTTPS. But I agree it's somewhat hard to get right. We hope to publish better guides on for different TLS setups in the future. – jrudolph Aug 21 '18 at 10:41
  • @jrudolph, you are right, but I think methods like `withAcceptAnyCertificate` have been provided for such cases where we know and rely on the HTTP end-point. – Saurabh Aug 21 '18 at 12:26