Question

When SMTP client connects to remote SMTP server and issues STARTTLS command, which has self-signed certificate - I get the error in client side:

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

There is one solution to trust all certificates like:

SSLContext trustAllSSLContext;

TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }};

            try {
                trustAllSSLContext = SSLContext.getInstance("SSL");
                trustAllSSLContext.init(null, trustAllCerts, null);
            } catch (NoSuchAlgorithmException | KeyManagementException ex) {
                //...
            }

But this causes security vulnerabilities. I think maybe this is better than to send unencrypted data in this case?

Was it helpful?

Solution

Compared to unencrypted, it does protect against a passive attacker who can only eavesdrop, but not an active one.

Basically duplicate of How to handle invalid SSL certificates with Apache HttpClient? but that includes quite a bit you don't need.

The best approach of course is for the server to get a 'real' cert. Without that, to trust their selfsigned cert but not anybody else's, get their cert by some process that you are sure isn't tampered with and put it in your truststore.

If this is a personal machine, or a personal install of Java, the JSSE default truststore is the file JRELOC/lib/security/jssecacerts if it exists, and SAME/cacerts otherwise. The cacerts file comes in the Java package and includes several dozen well-known public CAs like Verisign, GoDaddy, etc., so connections you make to nearly any public host on the internet (which use those CAs) will work, but you can add to or delete from it as you wish. In this case get the desired cert in either DER or PEM format in a file and:

keytool -keystore JRELOC/lib/security/cacerts -importcert -file the_added_cert 
# or JRELOC/bin/keytool if that directory isn't in your search path
# enter changeit for the password, and confirm that you want to trust this cert

If this (machine and) Java is shared with other users, changing the default truststore affects them also. If you or they don't want that, create your own file (by copying the standard one and modifying) and then use that truststore by running the program with -Djavax.net.ssl.trustStore=filename (as described in http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization) or if you don't run the 'java' yourself tell whatever does to set that system property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top