2

I have a java method on a server attempting to connect to the server's SMTP mail server, and I'm getting this error:

stack trace: org.apache.commons.mail.EmailException: Sending the email
to the following server failed : mail.mycompanyname.com:465

After retrieving the full stack trace, I notice the following line, which repeated 3 times/attempts:

 nested 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

The server has a certificate installed on Apache Server. However, I use GlassFish as app server for the web app (at client) that accesses the java method, and GlassFish sits behind Apache Server. I haven't adjusted anything on GlassFish for this certificate.

I see some other questions and answers similar such as here, but I don't understand how to implement it:

PKIX path building failed: unable to find valid certification path to requested target

Also, there's this as well, but again I don't know how to use it in my situation, if appropriate:

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

So my question is, what do I need to do, from a Java perspective, to clear this error?

Do I just need to create a properties file, as shown here?:

Which is the default location for keystore/truststore of Java applications?

Or, do I also need to set a TrustStore?

Do I need to set anything on GlassFish?

Hoping someone can help me with the basics here. Thanks in advance for any comments.

UPDATE:

OK, finally figured it out with Hiro2K's excellent help below. All that was missing was to import the certificate used by the Apache Webserver's SMTP mail server into GlassFish. Hiro2k's commands below worked fine, but my trouble was finding the right certificate.

Using WHM, I could see the mail server, which is Exim in my case, referred to host1.mycompany.com, so I naturally went for the certification name host1.mycompany.com.crt, which is self-signed. However, this certificate was expired, so it didn't work. I had to go into the configuration files for Exim to locate its certificate, which was named exim.crt, and import that one into GlassFish. Then it worked.

Note also there are many many cert's on the server, including ones for imap (e.g. imapd.pem) and pop3 (pop3.pem), etc. Very confusing.

Community
  • 1
  • 1
ggkmath
  • 4,188
  • 23
  • 72
  • 129

1 Answers1

3

So port 465 is used by SMTP SSL, which means that in order for the client to connect to the server, it must trust the server's certificate. Java and Glassfish have a default truststore which will work for any certificate signed by any of the big Cetificate Authorities (Thawt, Verisign, etc..), and since it's not working as is this leads me to believe that your server is using a self signed SSL certificate.

This isn't a problem, and is fully supported by lots of internal applications that don't want to pay for those certs. The issue is that GlassFish doesn't know about that self signed certificate so you must import it into the default glassfish truststore. You will find it at $GLASFISH_INSTALL_DIR$/domains/domain1/config/cacerts.jks

To import a certificate you can use the keytool that comes with the java.

keytool -importcert -v -noprompt -alias smtp.server.name -file 
/path/to/smtp.server.der -keystore
$GLASFISH_INSTALL_DIR$/domains/domain1/config/cacerts.jks -storepass changeit

The only thing you need to be careful of is the format of the certificate. Keytool only supports the binary DER format, and a lot of linux servers use the OpenSSL text format called PEM. It's easy to convert from one to the other using OpenSSL.

openssl x509 -in input.crt -inform PEM –out output.der -outform DER
Hiro2k
  • 5,254
  • 4
  • 23
  • 28
  • Thanks Hiro2k, I have purchased a certificate previously, and it is installed in Apache Webserver. GlassFish doesn't talk directly to clients. However, the Java method probably uses GlassFish to talk to Apache Webserver. Do I need to set system properties in my java method, such as listed by karthik, here? http://stackoverflow.com/questions/5871279/java-ssl-and-cert-keystore – ggkmath Jun 26 '13 at 16:48
  • When the certificate expires, and I get a new one, do I need to repeat this procedure to import the certificate to GlassFish? – ggkmath Jun 26 '13 at 17:55
  • 2
    You shouldn't have to set any system properties, GlassFish already has them. You need to import the cert into the GlassFish truststore like I said. Also you will have to repeat this process if that's the case. – Hiro2k Jun 26 '13 at 19:18
  • 2
    I created a self-signed certificate, changed formatting from .crt to .der, ran `keytool` which imported the cert fine. Yet I still get the same java exception thrown. Do I need to update the alias inside GlassFish somewhere? I'm keeping the default changeit password. No errors appear in the GlassFish log file. – ggkmath Jun 26 '13 at 21:03
  • 2
    You can't create a self-signed certificate, you have to get the certificate that you're trying to communicate with. In this case the SMTP server's. – Hiro2k Jun 26 '13 at 21:27
  • I don't understand, can you explain more? The only cert I have is a paid cert for the domain `www.mycompany.com` installed on Apache WebServer so clients can feel safe. I thought internal processes required a cert for the host (e.g. `host1.mycompany.com`). Should I import the cert installed on Apache WebServer to GlassFish? Or, do are we talking about a cert for the mail server, that is, `mail.mycompany.com`? Or, is there something like `smpt.mycompany.com`? Confused... – ggkmath Jun 26 '13 at 21:35
  • Where did the stack trace in your original question come from? Sending the email to the following server failed : mail.mycompanyname.com:465 ? The software that is trying to communicate with your email server is the one that needs the mail servers certificate installed in it's truststore. – Hiro2k Jun 26 '13 at 21:41
  • Yes, the stack trace referred to `mail.mycompany.com:465`, for example. This should be a self-signed cert if it exists. OK, so it CAN be a self-signed cert, as you suggesteed earlier, it just needs to be the correct one. And now I need to track down that one... – ggkmath Jun 26 '13 at 21:43
  • 1
    Exactly, and if the software that talks to that mail server is running on GlassFish, then you need to add that self signed certificate to GlassFish's truststore. I'm guess your company didn't purchase an SSL certificate for it's email server. – Hiro2k Jun 26 '13 at 21:44
  • 2
    Right, no purchase of SSL cert for email server. So... I just need to repeat everything I did above to import the cert to GlassFish truststore, but using the cert for `mail.mycompany.com`, right? Do I need to update GlassFish Admin console (Configurations > Network Config Network Listeners > http-listener-2; SSL tab) and change the default Certification Nickname from "s1as" to the alias I used above when issuing the keytool command? – ggkmath Jun 26 '13 at 21:45
  • 1
    Yes, just repeat those steps with you're mail server's certificate. Also don't touch any of the GlassFish network listeners. It has no bearing on the truststore. – Hiro2k Jun 26 '13 at 22:12
  • 1
    Excellent, finally got it working -- thanks for your patience Hiro2K! – ggkmath Jun 26 '13 at 23:03