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)