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

StackOverflow https://stackoverflow.com/questions/11736304

Frage

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!


This is my SSLServer class:

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;
    private static final Character EOL = '\n';
    private static final Character EOF = '\u0017';

    public SSLServer() throws IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, UnrecoverableKeyException
    {
        char[] passphrase = "changeit".toCharArray();
        this.keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        this.keystore.load(new FileInputStream("keystore.ks"), passphrase);

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(this.keystore, passphrase);

        this.sslContext = SSLContext.getInstance("TLS");

        this.keyManagers = keyManagerFactory.getKeyManagers();

        this.sslContext.init(this.keyManagers, null, null);

        this.sslServerSocketFactory = this.sslContext.getServerSocketFactory();
        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");

            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());

            inputStream = (InputStream) this.sslSocket.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream);
            input = new BufferedReader(inputStreamReader);

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

            System.out.println("  Server -> receiving...");
            StringBuffer receiver = new StringBuffer();
            Character serverReceived;
            while ((serverReceived = (char)input.read()) != EOF)
            {
                receiver.append(serverReceived);
            }
            System.out.println("    Server received: " + serverReceived);

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

            String serverSendSuccess = "Hello client, how are you?" + EOL + EOF;
            String serverSendFail = "Who are you?" + EOL + EOF;

            if (receiver.toString().contains("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) {}
            System.out.println("Server ended");
        }
    }
}

This is my client class:

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;
    private static final Character EOL = '\n';
    private static final Character EOF = '\u0017';

    public SSLClient() throws UnknownHostException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, NoSuchProviderException, UnrecoverableKeyException
    {
        char[] passphrase = "changeit".toCharArray();        
        this.keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        this.keystore.load(new FileInputStream("keystore.ks"), passphrase);

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(this.keystore, passphrase);

        this.sslContext = SSLContext.getInstance("TLS");

        this.keyManagers = keyManagerFactory.getKeyManagers();

        this.trustManagers = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers()
                {
                    return null;
                }
                public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                {

                }
                public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                {

                }
            }
        };

        this.sslContext.init(this.keyManagers, this.trustManagers, new SecureRandom());

        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!" + EOL + EOF;

                output.println(clientSend);
----->          output.flush(); // exception occurs here!

                System.out.println("    Client sent: " + clientSend);

                StringBuffer receiver = new StringBuffer();
                Character clientReceived;
                while ((clientReceived = (char)input.read()) != EOF)
                {
                    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) {}
            System.out.println("End client");
        }
    }
}

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---
War es hilfreich?

Lösung

Get the SSLSocketFactory from the SSLContext you so carefully constructed, not the default context.

Calling isConnected() where you do is futile. It cannot possibly be false at that point. An exception would have been thrown if there was a connect problem.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top