Using Java to connect with SSLSocket, trusting all certificates

So I wanted to make a little test client that would connect to a web server via SSL.
The problem is that in this experiment I don’t really care about the security, so I want the client to accept all certificates, even self signed ones and very old ones.
Credits to my good friend Maboroshi who helped me find the final solution that solved the last problem with the invalid certs.

So the first thing I did was to write the following.
This is a safe code that does NOT accept invalid certificates of any kind.

SAFE

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
import java.net.Socket;

public class test {	
    public static void main(String[] arstring) {
        try {
            //Connect without SSL
            Socket clientSocket = new Socket("google.com", 80);
            DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            outToServer.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("No SSL - " + inFromServer.readLine());
            clientSocket.close();
        	
            //Connect with SSL
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);

            DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
            BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));

            outToServerSSL.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("SSL - " + inFromServerSSL.readLine());
            
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

The problem with the above code for me, was that when connecting to a server with an invalid certificate, I got the following error.

Exception in thread “main” 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
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)

Thus, that solution wont cut it!
I needed something else, so I tried to write some code that would accept all certs as well.
Please note that ALL of the code from here on is UNSAFE, and should NOT be used in a production environment.


Reference to solution

UNSAFE

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.Socket;
import javax.net.ssl.TrustManager;
import java.security.cert.X509Certificate;

public class ssl {
    public static void main(String[] arstring) {
    	
        try {
            //Connect without SSL
            Socket clientSocket = new Socket("google.com", 80);
            DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
 
            outToServer.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("No SSL - " + inFromServer.readLine());
            clientSocket.close();
               
            //Connect with SSL
            // Create a trust manager that does not validate certificate chains
    		TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
    				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    					return null;
    				}
    				
    				@Override
    				public void checkClientTrusted(X509Certificate[] certs, String authType) {
    				}
    				
    				@Override
    				public void checkServerTrusted(X509Certificate[] certs, String authType) {
    				}
    			}
    		};

            // Install the all-trusting trust manager
    	    SSLContext sc = SSLContext.getInstance("SSL");
    	    sc.init(null, trustAllCerts, new java.security.SecureRandom());
            
            
            SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);
 
            DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
            BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));
 
            outToServerSSL.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("SSL - " + inFromServerSSL.readLine());
           
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

But, now this gives me a different error because this invalid certificate is broken/old!

javax.net.ssl.SSLProtocolException: no more data allowed for version 1 certificate
at sun.security.ssl.HandshakeMessage$CertificateMsg.(HandshakeMessage.java:431)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:963)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1208)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:674)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:119)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:133)
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
at ssl.main(ssl.java:93)
Caused by: java.security.cert.CertificateParsingException: no more data allowed for version 1 certificate
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:710)
at sun.security.x509.X509CertInfo.(X509CertInfo.java:169)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1751)
at sun.security.x509.X509CertImpl.(X509CertImpl.java:196)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:107)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:322)
at sun.security.ssl.HandshakeMessage$CertificateMsg.(HandshakeMessage.java:429)
… 10 more

Ok, so this is where it got tricky to solve.
I googled around for some time but I couldn’t really find a solution (since usually this is not the kind of thing you want to do).

But then a friend of mine (Maboroshi), pointed me to this site

Which brought me to this final solution.
The only real change here was to use the BouncyCastle provider

Security.insertProviderAt(new BouncyCastleProvider(), 1);

Which can be found HERE

Another requirement that I came to think about, is that this change requires Java 6 since Java 7 doesn’t support MD2. There is a solution if you are running Java 7 though.

Just open this file

JDK_HOME/jre/lib/security/java.security

And comment out the following line

jdk.certpath.disabledAlgorithms=MD2

That should do the trick.
Solution was found HERE

UNSAFE

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.Socket;
import javax.net.ssl.TrustManager;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.cert.X509Certificate;
import java.security.Security;
 
public class ssl {
    public static void main(String[] arstring) {
    	Security.insertProviderAt(new BouncyCastleProvider(), 1);
    	
        try {
            //Connect without SSL

            Socket clientSocket = new Socket("google.com", 80);
            DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
 
            outToServer.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("No SSL - " + inFromServer.readLine());
            clientSocket.close();
               
            //Connect with SSL
            
            // Create a trust manager that does not validate certificate chains
    		TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
    				@Override
					public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    					return null;
    				}
    				
    				@Override
    				public void checkClientTrusted(X509Certificate[] certs, String authType) {
    				}
    				
    				@Override
    				public void checkServerTrusted(X509Certificate[] certs, String authType) {
    				}
    			}
    		};

    		// Install the all-trusting trust manager
    		SSLContext sc = SSLContext.getInstance("SSL");
    		sc.init(null, trustAllCerts, new java.security.SecureRandom());
            
            
            SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);
 
            DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
            BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));
 
            outToServerSSL.writeBytes("GET / HTTP/1.1nHost: google.comnn");
            System.out.println("SSL - " + inFromServerSSL.readLine());
           
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

Now I got the output I wanted 🙂

No SSL – HTTP/1.1 200 OK
SSL – HTTP/1.1 200 OK

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.