Why does Java try to validate the certification path although I explictly set up a trust manager which does not validate any certificates?
===

I have a question concerning a simple communcation over SSL using Sockets and Java 7.

So far, I have created two *Runnables* - one for the server and one for the client. Eventually, I want to create a simple test in which my application sends data to a mock-up server using SSL. All the server is supposed to do is receiving the string sent by the client, comparing it with the contents of a file and sending a response String back which depends on whether the comparison was successful or not.

However, I'm stuck on a *javax.net.ssl.SSLHandshakeException* although I explictly *don't* want the client to be authenticated! On client side, I create a trust manager which does not validate any certificate. On server side, setting *this.sslServerSocket.setWantClientAuth(false)* and/or *this.sslServerSocket.setNeedClientAuth(false)* does not help either.
For test purposes, both, client and server use the same key sore file called "keystore.ks".

I marked the point where the exception occurs with an arrow (----->) below. Maybe somebody can give me a hint what is wrong there!

Thanks in advance

Walter

This is my SSLServer class:

    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocket;

    public class SSLServer implements Runnable
    {    
        private SSLServerSocketFactory sslServerSocketFactory;
        private SSLServerSocket sslServerSocket;
        private SSLSocket sslSocket;
        private KeyStore keystore;
        private KeyManager[] keyManagers;
        private SSLContext sslContext;
        private SSLSession sslSession;
        private int port = 8081;
    
        public SSLServer() throws IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, UnrecoverableKeyException
        {
            // Create a key store
            char[] passphrase = "changeit".toCharArray();
            this.keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            this.keystore.load(new FileInputStream("keystore.ks"), passphrase);
        
            // Create a key manager factory
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(this.keystore, passphrase);
        
            // Set up SSL context
            // IMPORTANT: the context must be generated before creating ANY managers!
            this.sslContext = SSLContext.getInstance("TLS");
        
            // Create key managers
            this.keyManagers = keyManagerFactory.getKeyManagers();
        
            // Install the key manager
            this.sslContext.init(this.keyManagers, null, null);
        
            // Create SSL server socket factory
            this.sslServerSocketFactory = this.sslContext.getServerSocketFactory();
        
            // Create and initialize SSL server socket
            this.sslServerSocket = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket(this.port);
            this.sslServerSocket.setSoTimeout(30000);
            this.sslServerSocket.setEnabledProtocols(new String [] { "TLSv1", "TLSv1.1", "TLSv1.2" });
            this.sslServerSocket.setUseClientMode(false);
            this.sslServerSocket.setWantClientAuth(false);
            this.sslServerSocket.setNeedClientAuth(false);
        }
    
        @Override
        public void run()
        {
            InputStream inputStream = null;
            InputStreamReader inputStreamReader = null;
            BufferedReader input = null;
            OutputStream outputStream = null;
            PrintWriter output = null;

            try
            {
                System.out.println("Server started");

                // Wait for a connection
                System.out.println("  Waiting for connection from client...");
                this.sslSocket = (SSLSocket) this.sslServerSocket.accept();

                // Connection was accepted
                System.out.println("  Accepted connection from " + this.sslSocket.getInetAddress().getHostAddress() + ", port " + this.sslSocket.getPort());
            
                // set up a SSL session
                this.sslSession = this.sslSocket.getSession();
                System.out.println("  Cipher suite used for this session: " + this.sslSession.getCipherSuite());
            
                // get input stream
                inputStream = (InputStream) this.sslSocket.getInputStream();
                inputStreamReader = new InputStreamReader(inputStream);
                input = new BufferedReader(inputStreamReader);

                // get output stream
                outputStream = this.sslSocket.getOutputStream();
                output = new PrintWriter(outputStream);

                // receive String from client
                System.out.println("  Server -> receiving...");
                StringBuffer receiver = new StringBuffer();
                String serverReceived;
                while ((serverReceived = input.readLine()) != null)
                {
                    receiver.append(serverReceived);
                }
                System.out.println("    Server received: " + serverReceived);

                System.out.println("  Server -> sending...");

                String serverSendSuccess = "Hello client, how are you?";
                String serverSendFail = "Who are you, man?";

                if (receiver.toString().equalsIgnoreCase("Hello server! I am the client!"))
                {
                    System.out.println("    Server sent: " + serverSendSuccess);
                    output.println(serverSendSuccess);
                    output.flush();
                }
                else
                {
                    System.out.println("    Server sent: " + serverSendFail);
                    output.println(serverSendFail);
                    output.flush();
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
            finally
            {
                try
                {
                    inputStream.close();
                    outputStream.close();
                    this.sslSocket.close();
                }
                catch(Exception ex) {
                    //ignore
                }
                System.out.println("Server ended");
            }
        }
    }

This is my client class:

    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.UnknownHostException;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    import javax.net.ssl.X509TrustManager;

    public class SSLClient implements Runnable
    {
        private SSLSocketFactory sslSocketFactory;
        private SSLSocket sslSocket;
        private KeyStore keystore;
        private KeyManager[] keyManagers;
        private TrustManager[] trustManagers;
        private SSLContext sslContext;
        private String hostname = "localhost";
        private int port = 8081;
    
        public SSLClient() throws UnknownHostException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, NoSuchProviderException, UnrecoverableKeyException
        {
            // Create a key store
            char[] passphrase = "changeit".toCharArray();        
            this.keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            this.keystore.load(new FileInputStream("keystore.ks"), passphrase);
        
            // Create a key manager factory
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(this.keystore, passphrase);
        
            // Set up SSL context
            // IMPORTANT: the context must be generated before creating ANY managers!
            this.sslContext = SSLContext.getInstance("TLS");
            
            // Create key managers
            this.keyManagers = keyManagerFactory.getKeyManagers();
            
            // Create trust managers that DO NOT VALIDATE certificate chains
            this.trustManagers = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers()
                    {
                        return null;
                    }
                    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                    {
                        // NOp
                    }
                    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                    {
                        // NOp
                    }
                }
            };

            // Install the trust manager
            this.sslContext.init(this.keyManagers, this.trustManagers, new SecureRandom());
        
            // Get socket factory
            this.sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
        }
    
        @Override
        public void run()
        {
            InputStream inputStream = null;
            InputStreamReader inputStreamReader = null;
            BufferedReader input = null;
            OutputStream outputStream = null;
            PrintWriter output = null;
        
            try
            {
                System.out.println("Start client");
            
                this.sslSocket = (SSLSocket) this.sslSocketFactory.createSocket(this.hostname, this.port);
                    
                
                if(this.sslSocket.isConnected())
                {
                    inputStream = (InputStream) this.sslSocket.getInputStream();
                    inputStreamReader = new InputStreamReader(inputStream);
                    input = new BufferedReader(inputStreamReader);
        
                    outputStream = this.sslSocket.getOutputStream();                
                    output = new PrintWriter(outputStream);
    
                    System.out.println("  Client -> sending...");
        
                    String clientSend = "Hello server! I am the client!";
                
                    output.println(clientSend);
    ----->          output.flush(); // exception occurs here!
                
                    System.out.println("    Client sent: " + clientSend);

                    StringBuffer receiver = new StringBuffer();
                    String clientReceived;
                    while ((clientReceived = input.readLine()) != null)
                    {
                        receiver.append(clientReceived);
                    }
                
                    System.out.println("    Client received: " + receiver.toString());
                }
                else
                {
                    System.err.println("Connection to server lost!");
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
            finally
            {
                try
                {
                    inputStream.close();
                    outputStream.close();
                    this.sslSocket.close();
                }
                catch(Exception ex) {
                    //ignore
                }
                System.out.println("End client");
            }
        }
    }

This is my Test class:

    public class SSLTest
    {
        public static void main(String[] args)
        {
            Runnable server, client;
            Thread serverThread = null, clientThread = null;
            
            System.out.println("---Start test---");
            
            try
            {
                server = new SSLServer();
                client = new SSLClient();
                
                System.out.println(">> Start server thread");
                serverThread = new Thread(server, "Server Thread");
                serverThread.start();
                
                System.out.println(">> Start client thread");
                clientThread = new Thread(client, "Client Thread");
                clientThread.start();
            }
            catch (Exception ex)
            {
                ex.printStackTrace();            
            }
            finally
            {
                try
                {
                    serverThread.join();
                    clientThread.join();
                }
                catch(InterruptedException ex) {}
            }
            
            System.out.println("---End test---");
        }
    }

Finally, the output:

    ---Start test---
    >> Start server thread
    >> Start client thread
    Start client
    Server started
      Waiting for connection from client...
      Accepted connection from 127.0.0.1, port 55287
      Client -> sending...
        Client sent: Hello server! I am the client!
      Cipher suite used for this session: SSL_NULL_WITH_NULL_NULL
      Server -> receiving...
    javax.net.ssl.SSLException: Connection has been shutdown: 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 sun.security.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1458)
        [...]
    Caused by: 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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        [...]
    Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
        [...]
    Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
        [...]
    Server ended
    End client
    ---End test---