31

I am trying to write an SSL client that sends mail using the javax.mail API. The problem I am having is that the server request that I use SSL, but the server is also configured with a non-standard SSL certificate. The web pages I have found say that I need to install the certificate into the trust store. I don't want to do that (I don't have the necessary permissions.)

  1. Is there a way to get Java to just ignore the certificate error and accept it?
  2. Failing that, is there a way to have the trust store be local for my program, and not installed for the whole JVM?
vy32
  • 28,461
  • 37
  • 122
  • 246
  • Just to clarify, can you change the server code, or just the client? – Bill the Lizard Aug 02 '09 at 16:48
  • Ignoring the certificate verification step is a bad idea. There's hardly any point talking *secretly* to someone if you haven't made sure who it is in the first place. Option 2 (a local trust store) is easy enough to use. – Bruno Jan 18 '12 at 02:24
  • 1
    Ignoring verification step is fine in some circumstances---for example, if you are on an isolated network and SSL is the only enabled service not because of policy, but because your admin doesn't know how to enable the non-SSL service. – vy32 Jan 19 '12 at 03:10
  • I don't think it is good idea to by-pass cert truststore validation. Especially if the remote server is outside your control. For your case maybe self-sign cert issue. If you validated the issuer, then you can just adds to truststore using keytool. This is better than using custom TrustManager that blindly accept certificates. – Awan Biru Oct 23 '18 at 08:35

5 Answers5

39

Working code ( in jdk1.6.0_23) for #1.

Imports

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

The actual trust all TrustManager code.

TrustManager trm = new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

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

    }

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

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { trm }, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
RustyTheBoyRobot
  • 5,891
  • 4
  • 36
  • 55
so_mv
  • 3,939
  • 5
  • 29
  • 40
  • Thanks, this worked great for me. The only problem with this is that it globally sets the settings to trust any certs.... A safer approach might be to cast the URLConnection back to a HttpsURLConnection and the call setSSLSocketFactory on that. Nevertheless this is a GREAT answer, several other ones said it was impossible to bypass the trust check and it was necessary to add a cert or tweak some JVM options – Cervo Apr 28 '12 at 01:29
  • 7
    This may be needed too, in case the hostname doesn't match the certificate: HostnameVerifier nullVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(nullVerifier); – seanf Jan 09 '13 at 01:45
  • 3
    This should be accepted answer since it does not use sun specific packages. – Kumar Vaibhav Mar 26 '18 at 18:48
  • In my case what helped was to force the client to use TLSv1 instead of TLS1.2. See this post: https://stackoverflow.com/a/30455363/2239549 – vivanov Dec 14 '18 at 10:38
  • 1
    You might want getAcceptedIssuers() to return new X509Certificate[0] instead of null, if you're using newer versions of OkHttp. Otherwise it will run into a NullPointerException. – Kutzi Jan 10 '19 at 16:56
19

You need to create a fake TrustManager that accepts all certificates, and register it as a manager. Something like this:

public class MyManager implements com.sun.net.ssl.X509TrustManager {
  public boolean isClientTrusted(X509Certificate[] chain) { return true; }
  public boolean isHostTrusted(X509Certificate[] chain) { return true; }
  ...
}


com.sun.net.ssl.TrustManager[] managers =
  new com.sun.net.ssl.TrustManager[] {new MyManager()};

com.sun.net.ssl.SSLContext.getInstance("SSL").
       .init(null, managers, new SecureRandom());
Zed
  • 57,028
  • 9
  • 76
  • 100
  • 12
    All of this should really be done using the JSSE public API rather than tweaking the hidden `com.sun.*` classes. (See so_mv answer.) – Bruno Jan 18 '12 at 02:21
8

Try this (answer to question 2):

System.setProperty("javax.net.ssl.trustStore", "/path/to/truststore");

You can also specify this as an additional command line parameter:

java -Djavax.net.ssl.trustStore=/path/to/truststore <remaining arguments>

On Fedora this could be the system wide java trust store in /etc/pki/java/cacerts

René
  • 904
  • 13
  • 26
HMM
  • 2,987
  • 1
  • 20
  • 30
6

Just add -Dtrust_all_cert=true to VM arguments. This argument tells java to ignore all certificate checks.

willome
  • 3,062
  • 19
  • 32
Ayman Hussain
  • 255
  • 2
  • 2
  • That's pretty frightening, but it seems like a good answer! I would like to do it within Java, though, and perhaps have a bit more control moving forward. – vy32 Nov 21 '16 at 15:18
  • 22
    That is not a VM argument and will not work in general. – René Mar 06 '17 at 13:30
  • I tried. This works on JDK8. This is really helpful when you trusts all the URLs JVM is hitting. e.g. OWASP's dependency-check tool – UmeshPathak Jan 16 '20 at 04:26
  • @UmeshPathak - The string "trust_all_cert" is not in the OpenJDK 8 source codebase ... anywhere. (Or any other OpenJDK version, starting from Java 6!) So if this "worked for you" then the propoerty is being recognized by the *application* that you are running, not by the JVM itself. – Stephen C May 06 '23 at 05:52
-8

In Command Line you can add argument -noCertificationCheck to java to ignore the certificate checks.

Navaneetha
  • 93
  • 1
  • 7