I'm trying to connect to a mail server which uses StartTLS with a self signed certificate via Java mail API. And that seems to be a problem, because i can't find any way to set accepted certificates or a truststore for StartTLS.
Properties props = new Properties();
props.put("mail.imap.starttls.enable", "true");
props.put("mail.imap.starttls.required", "true");
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
store.connect(hostName, port, userName, userPassword);
When i run my application as is, i get this PKIX path 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 would prefer not to use VM parameters like "-Djavax.net.ssl.trustStore"
because i want to be able to control trusted certificates per access.
Sidenote: I've seen people use "mail.imap.socketFactory.class"
to set their own implementation of SocketFactory
with a self defined TrustManager
.
But when i do that my connection fails with
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
I think this is because setting the socket factory will actually use SMTP over SSL instead of StartTLS (which starts as a plain text connection and switches to TLS later).
The STARTTLS support is available in the standard "imap" and "smtp" protocols, but must be enabled by setting the appropriate property, mail. imap. starttls. enable or mail.
TrustStore is used to store certificates from Certified Authorities (CA) that verify the certificate presented by the server in an SSL connection. While Keystore is used to store private key and identity certificates that a specific program should present to both parties (server or client) for verification.
The truststore is a file that contains the root certificates for Certificate Authorities (CA) that issue certificates such as GoDaddy, Verisign, Network Solutions, and others. The truststore comes bundled with the JDK/JRE and is located in $JAVA_HOME/lib/security/cacerts .
I have this working for an SMTP connection (not IMAP) using com.sun.mail:javax.mail:1.5.5
and (root) certificates loaded from a (not so standard) pfx-file. The properties given to Session.getInstance(props)
are build in the following manner (see also the API-docs here and here, I think you can simply replace smtp
with imap
for most of the properties):
"mail.transport.protocol", "smtp"
"mail.smtp.host", "hostname"
"mail.smtp.port", "25"
"mail.smtp.connecttimeout", "5000" // 5 seconds
"mail.smtp.timeout", "50000" // 50 seconds
"mail.smtp.ssl.protocols", "TLSv1.2"
"mail.smtp.starttls.required", "true"
Now build a SSL Socket Factory using com.sun.mail.util.MailSSLSocketFactory
(read the API-docs in the link):
MailSSLSocketFactory sslSocketFactory = new MailSSLSocketFactory("TLSv1.2");
Create and intialize a (default) KeyManagerFactory kmf
(e.g. by loading a keystore).
Create and intialize a (default) TrustManagerFactory tmf
.
Call sslSocketFactory.setKeyManagers(kmf.getKeyManagers())
and sslSocketFactory.setTrustManagers(tmf.getTrustManagers())
Set property "mail.smtp.ssl.socketFactory" to the sslSocketFactory
instance (use the props.put(k,v)
-method). Note that the socket factory instance that was created and configured is set, not some String or class. Javamail will use the set socket factory instance directly.
Use the properties to create a session.
Make sure you have logging configured properly and set it to TRACE for com.sun.mail. Logging shows exactly what is "going over the line" and in my case shows for example:
DEBUG com.sun.mail.smtp - Found extension "STARTTLS", arg ""
...
TRACE com.sun.mail.smtp.protocol - STARTTLS
TRACE com.sun.mail.smtp.protocol - 220 Ready to start TLS
On a side note: creating a default keystore and trustore can be done using this SslUtils
class, methods loadKeyStore(null)
and createDefaultTrustStore()
(I created this utility class a while ago to help me load the not-so-standard pfx-files).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With