2

I have a Java desktop application with which I was able to successfully GET data from an API at an https URL. The client had their own PKI, and in my app, they entered their pki password and their path to their truststore and pki to run the app, and system properties (keystore, truststore, etc) were set in the code to accept these values. Everything worked fine.

Now, I'm trying to implement the same thing via ssl using glassfish in a Java web app, but I am getting a javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca (this is the specific exc currently; before debugging, it was "PKIX path building failed...unable to find valid certification path to requested target")

I researched how to debug, including...

1) Java HTTPS client certificate authentication

Solution: Client already has a pkcs12 keystore, but ticket solved by using openssl to re(?)generate pkcs12, then use keytool to generate truststore.

(my comment: My clients already have certs in p12/pfx format, plus a truststore jks file containing trusted entities to use directly, so this solution doesn't seem to fit)

2) Using browser's certificate in java program

Solution: Add server certs to truststore

(my comment: this guidance seems opposite of the one directly below. I assume that these 'server certs' are for the https api servers?. My client truststore contains entries for https api sites to be accessed. It makes sense to me to add them to glassfish truststore since glassfish is server side; however, this is what i'm doing (i.e., -Djavax.net.ssl.trustStore=clientPathTo/truststore.jks in glassfish JVM) and getting exception at bottom)

3) Unable to find valid certification path to requested target - error even after cert imported

Solution: Add client cert to -Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks

(my comment: I have not tried this but does it make sense for a copy of the client cert to be located on the server?

One thing that is confusing is when people say 'server', I can't tell if they mean 'web server' or 'app server'.

Anyway, I ran Glassfish in debug mode and set javax.net.debug==ssl. In the logs, I can see the following:

  • client HELLO
  • server HELLO
  • server presents its certificate chain
  • server makes a certificate request
  • glassfish presents a certificate chain
  • glassfish attempts to generate a session key, data is exchanged, then it finishes with a data verification fatal ALERT: unknown ca, session invalidated
  • javax.net.ssl.SSLHandshakeException...

------UPDATE------


I am running glassfish 4.1.1.

Here is the full Exception

javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
atsun.security.ssl.Alerts.getSSLException(Alerts.java:192)
atsun.security.ssl.Alerts.getSSLException(Alerts.java:154)
atsun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
atsun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
atsun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
atsun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
atsun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
atsun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
atsun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
atsun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546)
atsun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1474)
atsun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
atbeans.ApiReader.sendGet(ApiReader.java:122)
atbeans.SelBeanController.showData(SelBeanController.java:43)
atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
atjava.lang.reflect.Method.invoke(Method.java:498)
atjavax.el.ELUtil.invokeMethod(ELUtil.java:332)
atjavax.el.BeanELResolver.invoke(BeanELResolver.java:537)
atjavax.el.CompositeELResolver.invoke(CompositeELResolver.java:256)
atcom.sun.el.parser.AstValue.invoke(AstValue.java:283)
atsom.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
atcom.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
atjavax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
atcome.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
atjavax.faces.component.UICommand.broadcast(UICommant.java:315)
atjavax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
atjavax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
atcome.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
atcome.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
atcome.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
atjavax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
atorg.apache.cataline.core.StandardWrapper.service(StandardWrapper.java:1682)
atorg.apache.cataline.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
atorg.apache.cataline.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
atorg.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
atorg.apache.cataline.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
atorg.apache.cataline.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
atorg.apache.cataline.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
atorg.apache.cataline.core.StandardContextValve.invoke(StandardContextValve.java:160)
atorg.apache.cataline.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
atorg.apache.cataline.core.StandardPipeline.invoke(StandardPipeline.java:673)
atcom.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
atorg.apache.cataline.core.StandardHostValve.invoke(StandardHostValve.java:174)
atorg.apache.cataline.CoyoteAdapter.doService(CoyoteAdapter.java:416)
atorg.apache.cataline.CoyoteAdapter.service(CoyoteAdapter.java:283)
atcom.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
atcom.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
atorg.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
atorg.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
atorg.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
atorg.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
atorg.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
atorg.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
atorg.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
atorg.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
atorg.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
atorg.glassfish.grizzly.nio.trasport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
atorg.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
atorg.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
atorg.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
atorg.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
atorg.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
atorg.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
atjava.lang.Thread.run(Thread.java:745)
chocalaca
  • 330
  • 2
  • 17
  • 1
    Can you please add the full `javax.net.ssl.SSLHandshakeException` message? Otherwise it would be guessing. – Karol Dowbecki Mar 05 '18 at 18:14
  • I agree with kdowbecki - can you post the stack trace of the exception? Also: [1] did you see this SO post: https://stackoverflow.com/questions/21076179/pkix-path-building-failed-and-unable-to-find-valid-certification-path-to-requ [2] What version of Glassfish are you using? – skomisa Mar 05 '18 at 19:15
  • 1
    Your client's cert is being rejected by the server. Look at the cert chain being sent (in your trace) to see if it is correct; in particular if your cert was issued by a CA that needs a chain cert or several, make sure the correct chain cert(s) is(are) included. If your chain is not valid, your client keystore is wrong -- fix it; if your chain is valid, the server is wrong -- fix it. PS: TLS actually generates _multiple_ session keys, and no data is exchanged at the point you describe, although Verify, CCS and Finished may look like data if you aren't familiar with the protocol. – dave_thompson_085 Mar 05 '18 at 21:59
  • @dave_thompson_085 The description here is confusing. I don't see how it is possible for a client to even send a certificate with an unrecognized CA without violating the RFC. Surely what is happening is that the server's certificate is being rejected by the client? – user207421 Mar 05 '18 at 23:14
  • Update with glassfish version and full Exception! – chocalaca Mar 06 '18 at 16:06
  • I don't think I mentioned yet that I currently have a JVM property for javax.net.ssl.trustStore set to the location of a jks file containing trusted cert entries. – chocalaca Mar 06 '18 at 16:42
  • @dave_thompson_085 - After the server hello, the cert chain presented is from glassfish. Do I need – chocalaca Mar 06 '18 at 17:36
  • @dave_thompson_085 - After the server hello, the cert chain presented is from glassfish. So, I need to import my cert there, correct? – chocalaca Mar 06 '18 at 17:49
  • @EJP: "received alert unknown_ca" in client means server sent the alert; plus OP sees Cert and CertReq from server then Cert from client which wouldn't happen if client didn't accept server cert. See rfc5246 7.4.4: server can send CertReq with empty certificate_authorities then "client MAY send any certificate of the appropriate ClientCertificateType, unless there is some external arrangement to the contrary." -- and JSSE can. – dave_thompson_085 Mar 07 '18 at 09:43
  • chocalaca: the trace should and according to your Q does have _two_ cert chains, one from server, _then_ one from client=glassfish. **Is the second one correct and complete?** – dave_thompson_085 Mar 07 '18 at 09:45
  • @skomisa: RE: "did you see this SO post: stackoverflow.com/questions/21076179/…". I had not before, but I was able to follow that guidance and import the server cacert into my Java JRE/JDK(JRE) cacert files. I ran it again and still got the error. Today, I had to reinstall glassfish, so I'll redo it and check again. What a mess... – chocalaca Mar 07 '18 at 18:56
  • @dave_thompson_085: "Is the second one correct and complete?" If the glassfish client chain should contain my cert, then no. I previously set the glassfish JVM truststore property to point to the truststore on my system, but I don't think that was correct. Instead of mucking around with JVM settings, I feel like I need to ensure the following... – chocalaca Mar 07 '18 at 18:58
  • - import user/client cert data into C:/PATH TO JRE/security/keystore and user/client truststore into C:/PATH TO JRE/security/cacert – chocalaca Mar 07 '18 at 19:01
  • - import user/client truststore data into /PATH TO GLASSFISH/config/keystore and user/client cert data into /PATH TO GLASSFISH/config/cacert – chocalaca Mar 07 '18 at 19:01
  • I am having system issues currently, but if the above is correct, I can work towards implementing that once the issues are done. – chocalaca Mar 07 '18 at 19:01

0 Answers0