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.
Related
Application on java. OkHttp version 2.7.5 is used. A request is made to another service and an error occurs.
SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
I do not have a certificate. It seems there are solutions for the version of okHttp3. But the version can not be changed. How to solve a problem?
Is it possible to disable ssl for https?
Literally, no.
Use of SSL is fundamental to the HTTPS protocol. If you don't want to use SSL at all, configure your server with an HTTP endpoint and use that instead of HTTPS.
Furthermore use of SSL requires a certificate that is (at least) syntactically well-formed. That is also fundamental to the HTTPS protocol.
Now if the problem is that your server certificate has expired, then a possible solution is to use the approach described in:
Make a connection to a HTTPS server from Java and ignore the validity of the security certificate.
And if the problem is that you cannot get a proper certificate for the server (e.g. you can't afford it) then an alternative solution is:
generate a self-signed certificate; see How to generate a self-signed certificate using Java Keytool,
install it on the server side,
configure the client as above to ignore certificate validity.
But note that doing either of those things has security issues.
There is a third solution that is more secure.
generate a self-signed certificate (as above)
install it on the server side,
use Keytool to add the certificate to the client app's keystore as a trusted certificate.
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)
I have to call a SOAP web service having client authentication over HTTPS.
I have imported the client certificate (got from company hosting the server) into by keyStore file. I also imported server certificate (downloaded from server) into my trustStore. I have set 'javax.net.ssl.keyStore' and 'javax.net.ssl.keyStorePassword' to the appropriate values.
When I call the web-service from a simple java client (including just some additional jars), the call works and I get a result from the server.
When I call the web-service from within glassfish-4 (same java, same keyStore, same trustStore, same 'javax.net.ssl.keyStore' value etc), I get an exception 'com.sun.xml.ws.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca'.
I use the same java, same keystore, same trustStore in both cases. The first version without glassfish works, so the certificates seems to be ok. The second version with glassfish does not.
Does glassfish-4 do anything specific?
Can it be a problem of other (third party) libraries?
Are there any additional HTTP/SSL settings that I can try out?
What else can it be?
Anybody an idea?
Thanks for help.
I have found the problem.
Glassfish needs the additional VM property 'com.sun.enterprise.security.httpsOutboundKeyAlias'.
This has to be set to the alias of the client certificate.
For standard this is set in domain.xml in the java-config area.
For standard this is set as -Dcom.sun.enterprise.security.httpsOutboundKeyAlias=s1as.
Change the value s1as to the alias of the certificate.
There is a server that is only sending it's own certificate and none of its issuers in the chain (note: it's not self-signed).
When I connect to this server in Google Chrome and I view the certificate I see the full chain in the Certification Path tab, but when I try to connect to this server with Java and I use -Djavax.net.debug=SSL I only see the server's own certificate.
I noticed that there is an extension on this certificate called "Authority Info Access" that has a field "Alternative Name" with a URL pointing to the issuer's certificate. I believe Chrome (or Windows maybe) is "aware" of this extension and Java is not "aware", is there a way to use this in Java? (Preferably without extra classes, but I realize there may be no simple way if it's not built in.)
If I only add the root certificate to Java's cacerts then I am unable to perform the TLS handshake (since the server only sends its own certificate and the root did not issue it, an intermediate did). This server is out of my control, I cannot make it send intermediate certificates. Since Chrome is able to resolve the intermediate ones (through AIA I suppose) I would suspect there may be a way to do this in Java without adding the intermediate certificate to the cacerts file, only the root, but I don't know how to make Java use this AIA extension to get the intermediate certificates.
You need to set the relevant System Property to enable Your Java App to download intermediate certificates of the root.
System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
I'm trying to consume a Webservice hosted under https security.
I'm using Java and glassfish and I'm getting the following error:
INFO: HTTP transport error: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching testdomain.com found
The thing is that this specific server is used for testing and it's using the production certificate (the one with CN=domain.com)
I already added the domain.com certificate to my glassfish domain's cacerts keystore using keytool -importcert and it didn't work.
I also tried creating a self signed certificate with the CN=testdomain.com and adding it to the cacerts keystore and it didn't work either...
So how do I configure Java/Glassfish to consume this Web Service?
The CN of the server certificate should match the domain in URL to which the client connects. If still doesn't work, I would check if the IP maps to this hostname too (reverse DNS). It is the client, who verifies it. If you want to bypass this hostname verification, see the example code in my article: http://jakubneubauer.wordpress.com/2011/09/06/java-webservice-over-ssl/
The priciple is that you provide your own HostnameVerifier to the service client proxy.
THe self-signed certificate needs to be installed in the keystore of the Web service, along with its private key, and imported into the truststore of Glassfish.
the self signed certificate needs to be installed in key store of your java client. and testdomain.com should be resolved using dns.