Pinpointing which public SSL cert is being used by REST endpoint - java

I have one webapp that I am running on Tomcat in two environments, Dev and Test. The apps are identical, but the server config and security levels are not. The webapp connects to a an external customer's REST endpoint over https, which they have secured using a public cert. Same endpoint in both environments.
The Dev app works fine, the Test app fails with this:
SSLHandshakeException ... 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)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
When I curl the endpoint, I see the customer is using a public certificate. I assume that the version of the cert I have in my Dev server is up to date, and my Test server is expired. However, when I examine the two servers' cacerts files in KeyStore Explorer, I don't find the cert at all.
I assume I just do not know how to find the relationship between a specific cert and its parent (parent cert? global cert?). So, either via commands or code, how do I find which entry in my Dev cacerts file represents the cert from the endpoint?

Related

Wildfly does not pass intermediate certificate to HTTPS client

So I have this certificate chain made of 3 certificates:
Root cert (installed in all clients)
Intermediate cert (installed in my browser, but not in other clients/Java apps accessing webservices)
Domain wildcard certificate
Wildfly is configured to use a keystore that holds intermediate and domain certificates in JKS format, along with the private key for the domain cert. When I send a HTTPS request from my browser, the certificate is validated just fine and everything seems OK. But when the Java client application I am working on tries to establish a connection, it cannot build a valid certificate chain:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I checked the certificates delivered by Wildfly using openssl (openssl s_client -showcerts -connect <servername>) and confirmed that the intermediate certificate is NOT transmitted even though it is present in the keystore. Now I can work around this in my development environment by adding the intermediate cert to my local trust store, however that is not an acceptable long-term solution for production.
In my Wildfly's standalone.xml I have specified the keystore and the alias of the wildcard certificate.
<server-identities>
<ssl>
<keystore path="/path/to/keytsore.jks" keystore-password="supersecure" alias="*.redacted.com"/>
</ssl>
</server-identities>
Searching through the Wildfly admin docs I saw no mention of intermediate certificates. I tried to add an additional element to the config (same path and password, but alias of the intermediate certificate), but Wildfly would not start up with that.
Any idea how I can get Wildfly to present the intermediate certificate to connecting clients? Does it need to have a specific alias name? Or is there another way to tell Wildfly the alias of any intermediate cert?

How to debug SSLHandshakeException?

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)

Setting up SSL in Java 6 (GlassFish 3 server)

We have a Java web application running inside GlassFish 3 web server.
Our application connects to a LDAP server for authentication. Now customer is running LDAP on SSL i.e ldaps.
So we fetched the certificate from their LDAP server and added it to our trusted certificate. But still we sometime gets:
exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
Further investigation by LDAP admin, his words:
"We added additional servers behind the load balancer. If they
trust just the server CERT instead of the CA then you would be
experiencing this problem. They should trust the CA or should not
perform any certificate validation"
Which means that there are many LDAP server running behind the load balancer and each server has different certificate, and we just trust on one particular certificate.
Now the resolution they say is to trust on the CA and not on individual certificate.
NOW at this point I am confused!
Is it the case that we can get a CA certificate and trust on it so that any certificate issued by that CA will be automatically trusted..
If so how to do that?
Will the CA certificate be fetched from the LDAP server or do we have to ask for it?
Or have I created a wrong mind model for this or is there a concept missing?
Also what is "trusted root certificate"?
What they are saying is that the servers are signed using a common CA (like Verisign, Thwate etc). All you need to do is trust that CA (you do this by importing the CA's trusted root certificate).
You will need to find out which CA is being used and then check your cacerts file to see if you already trust the CA (apparently you dont since you are receiving the error). There a number of ways you can find out the CA being used but you can simply ask your LDAP admin which CA is being used. Some companies also use a local CA and this could very well be how your ldap servers are setup.

Debian SSL certificates ERROR: cannot verify xxx certificate / javax.net.ssl.SSLHandshakeException

I have a strange problem (it's 100% server configuration problem,) for example I want to download something from Dropbox:
Resolving dl.dropboxusercontent.com... 23.23.160.146, 50.17.227.107,
54.221.248.69, ... Connecting to dl.dropboxusercontent.com|23.23.160.146|:443... connected. ERROR:
cannot verify dl.dropboxusercontent.com’s certificate, issued by
“/C=US/ST=CA/O=SonicWALL Inc./CN=SonicWALL Firewall DPI-SSL”:
Self-signed certificate encountered. To connect to
dl.dropboxusercontent.com insecurely, use ‘--no-check-certificate’.
Yes, I know that I can use --non-check-certificate but when I want to use SSL connection in Java app I have something like this:
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
This app works great in other servers or in local machines, any ideas what is wrong here?
/C=US/ST=CA/O=SonicWALL Inc./CN=SonicWALL Firewall DPI-SSL
Your traffic is visibly intercepted by a deep packet inspection firewall that acts as a MITM proxy to monitor your traffic.
This can generally be thought of as "legitimate" MITM attacker. (However legitimate this may be depends on a number of legal and ethical aspects.) Your local network administrator should be able to tell you a little bit about this. If this is part of a company network, this company is monitoring your traffic, including the contents of your HTTPS connection (so it's no longer secure from end-to-end). It the firewall does its job properly, it should still secure the connection from the firewall to the server (It's probably hard to know whether it check certificates properly.)
In general, such a firewall or proxy acts as its own Certification Authority, effectively forging each certificate as requested.
Most clients on the corporate network would trust certificates it issues (like the one you're facing) because system administrators would also install the CA certificate as a trusted certificate into each machine within that network. You probably have it the OS trusted root certificates.
However, it is likely that network administrators did not install this CA certificate into your JRE installation (which uses its own set of trust anchors by default).
Try to export that CA certificate (see the name above) from a reference machine and import it into the truststore you're using (either your JRE's default truststore: cacerts or a new truststore you build and pass to your application via the javax.net.trustStore properties).
Typically, you can use something like this (assuming you've exported the Firewall's CA as "firewallca.pem"):
keytool -import -file firewallca.pem -alias firewallca -keystore truststore.jks
If the truststore.jks file doesn't exist, it will be created. Otherwise, you can take a copy of the cacerts file in the lib/security directory of your JRE. You can also do this directly on the cacerts file (using -keystore /path/to/truststore.jks, provided you have write access to it).
If you choose not to do it on the default truststore (that cacerts file) but use a local truststore like truststore.jks, you'll can use it by using this system property when running your application: -Djavax.net.trustStore=/path/to/truststore.jks
For other ways of configuring your truststore, check this answer.
Another way to fix this is to tell Java to use your OS's truststore. I'll assume you're using Windows here. Using these system properties should work:
-Djavax.net.trustStore=NONE -Djavax.net.trustStoreType=WINDOWS-ROOT
(Try with WINDOWS-MY instead of WINDOWS-ROOT if this doesn't work.)
The WINDOWS-MY/WINDOWS-ROOT is a bit buggy in that it will miss some of the certificates in the Windows store: it uses the certificate "friendly name" (non unique) as the keystore alias (unique), so a certificate with a given friendly name will hide the others with the same name. (This effectively reduces the number of CA certificates that are trusted unfortunately.)
Since you're in an environment where presumably all the traffic goes through your DPI firewall, you'll probably only ever have to use one CA certificate at most. As long is it doesn't share its "friendly name" in the Windows list with any other cert, you should be fine.
You need to add the server's SSL certificate in your client's Java keystore. Take a look at this SO post:
Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?
TIP: This is because your client's JVM does not 'trust' the server's SSL cert. So you need to add the cert in your keystore.

Java mail TLS authentcation

I am trying to get a grasp on the fundamentals of Java Mail API and TLS. I have the following scenario:
There is an STMP server that uses TLS & SSL. If I log on to this server with some client, I can send authenticated &verified e-mails without any problems.
Then I try to run a web server on a different machine, that sends mail using the previously mentioned SMTP server. I still want to send TLS & SSL emails, however no matter how I configure the startup properties I get the following well known error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I found a lot of people having similar issues, however my question is this:
Considering the previuosly described scenario, do I have to get some kind of certificate to the web server (possible somewhere in the JRE), or should it just work fine since the mail server already has that certificate & authentication mechanizm running. Shouldn't it be possible to just use the certificate of the SMTP server? Anyway, if I have to install the certificate to the machine that uses the STMP server how can I get that certificate?
I'm pretty new to JavaMail API and I have seen lots of articles about this but I could not find the answer black & white for my question.
Your client (that is in your case the one running on the webserver) needs to verify the SSL certificate of the mail server. It seems that your java truststore doesn't contain that certificate.
So you either need to put that certificate into the default truststore of your JRE (what I wouldn't recommend) or define a different truststore for your application (that of course needs to contain the mail servers certificate). To do that set this VM parameter: Djavax.net.ssl.trustStore=<path-to-truststore>
Edit: Ah I missed some part of your question.
To get the certificate of the mail server use something like openssl. See for example:
https://serverfault.com/questions/139728/how-to-download-ssl-certificate-from-a-website
The answer is in the JavaMail FAQ.
Quoted text from the linked site:
Q: When connecting to my mail server over SSL I get an exception like "unable to find valid certification path to requested target".
A: Your server is probably using a test certificate or self-signed certificate instead of a certificate signed by a commercial Certificate Authority. You'll need to install the server's certificate into your trust store. The InstallCert program will help.
Alternatively, you can set the "mail.protocol.ssl.trust" property to the host name of your mail server. See the javadocs for the protocol provider packages for details.
Other common causes of this problem are:
There's a firewall or anti-virus program intercepting your request.
There's something wrong in your JDK installation preventing it from finding the certificates for the trusted certificate authorities.
You're running in an application server that has overridden the JDK's list of trusted certificate authorities.

Categories