Java - javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

phiip picture phiip · Feb 28, 2012 · Viewed 28.9k times · Source

I'm trying to connect to my own SSL Server with my own SSL Client, but i get the following error:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated at sun.security.ssl.SSLSessionImpl.getPeerCertificateChain(SSLSessionImpl.java:420) at server.run(Server.java:70) at server.main(Server.java:22)

I've searched for the same problem here on stackoverflow but I can only find people who are using this in Apache or other HTTPS "systems".

Here is my server code:

    /* Server SSL */


import javax.net.ssl.*;
import java.io.*;
import java.net.InetAddress;
import java.security.KeyStore;
//import java.security.cert.X509Certificate;
import java.util.Date;
import javax.security.cert.X509Certificate;

class server {

    ObjectOutputStream out;
    ObjectInputStream in;

    public static void main(String[] args) {    
        new server().run();
    }

    void run() {

    Date date = new Date();


        try {

            // Security test (to avoid starting from the command line)c

            char[] passphrase = "password".toCharArray();

           KeyStore keystore = KeyStore.getInstance("JKS");


           keystore.load(new FileInputStream("/home/ME/CERT/keystore"), passphrase);


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


           SSLContext context = SSLContext.getInstance("TLS");
           KeyManager[] keyManagers = kmf.getKeyManagers();

           context.init(keyManagers, null, null);


            // -- End of security test

        // 1. Create a server Socket
            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(9999);

         // TBH im not sure what the following code does, but I need it?

                    String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
                    sslserversocket.setEnabledCipherSuites(enabledCipherSuites);



        // 2. Wait for connection.
        System.out.println("Waiting for connection. ");
            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();

           SSLSession session = sslsocket.getSession();
           X509Certificate cert = (X509Certificate)session.getPeerCertificateChain()[0];
           String subject = cert.getSubjectDN().getName();
           System.out.println(subject);


        // 2.1 Prints information about client, this could be (very) valuable to save in a file.
        System.out.println("Connection received: ");
        System.out.println("   Hostname: " + sslsocket.getInetAddress().getHostName());
        sslsocket.getInetAddress();
        System.out.println("         IP: " + InetAddress.getLocalHost().getHostAddress());
        System.out.println("          @  " + date.toString());
        System.out.println();

        // 3. Create input and output streams.



        // for some reason i cant make the out/in-variable without using it as global?

        out = new ObjectOutputStream(sslsocket.getOutputStream());
        out.flush();
        in = new ObjectInputStream(sslsocket.getInputStream());

        sendMessage("Connection successful");

        // 4. Client and server talks via the input and output streams

        String message;

        do {
        message = (String)in.readObject();
        System.out.println(" Client says:  " + message);
        if (message.equals("bye")) {
            sendMessage("bye");
        }

        }while(!message.equals("bye"));

        // 5. Closing connection

        in.close();
        out.close();
        sslsocket.close();
System.out.println("Server terminated. ");

        } catch (Exception exception) {
            exception.printStackTrace();

        }
    }
    void sendMessage(String msg) throws Exception
    {
    out.writeObject(msg);
    out.flush();
    System.out.println("  You(server) says: " + msg);
    }


}

And here is my Client code:

/* Java SSL Client */

import javax.net.ssl.*;
import java.io.*;
import java.security.KeyStore;
import java.util.*;

class client {

String message;
ObjectOutputStream out;
ObjectInputStream in;


public static void main(String[] args) {
    new client().run();
}

void run() {

System.out.println();

int port = 9999;

String host = "127.0.0.1";

try {

    // Security test (to avoid starting with the command line)
    char[] passphrase = "trustword".toCharArray();

    KeyStore keystore = KeyStore.getInstance("JKS");
    keystore.load(new FileInputStream("/home/ME/CERT/truststore"), passphrase);

   TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
   tmf.init(keystore);


   SSLContext context = SSLContext.getInstance("TLS");
   TrustManager[] trustManagers = tmf.getTrustManagers();

   context.init(null, trustManagers, null);



    // --- End of security test



    System.out.println("Connecting to " + host + " on port " + port);

    // 1. Create a client socket. 
    SSLSocketFactory sslFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
    SSLSocket sslSocket = (SSLSocket)sslFactory.createSocket(host, port);

    // TBH im not sure what the following code does, but I need it?
    String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
    sslSocket.setEnabledCipherSuites(enabledCipherSuites);


    System.out.println("Connected.");

    // 2. Create input and output streams
    out = new ObjectOutputStream(sslSocket.getOutputStream());
    out.flush();
    in = new ObjectInputStream(sslSocket.getInputStream());

    // 3. Client and server talks via the input and output streams

    Scanner input = new Scanner(System.in);

    message = (String)in.readObject();
    System.out.println(" Server says: " + message);

    sendMessage("Hello Server! ");

    do {
    // Sends input text
    System.out.print("Enter text to send: ");
    message = input.nextLine();
    sendMessage(message);

    if (message.equals("bye")) {
        message = (String)in.readObject();
        System.out.println(" Server says: " + message);
    }

    } while(!message.equals("bye"));

    // 4. Closing connection

    in.close();
    out.close();
    sslSocket.close();
    System.out.println("Client terminated. ");
}

catch (Exception exception) {
    exception.printStackTrace();

}

}

void sendMessage(String msg) throws Exception
{
out.writeObject(msg);
out.flush();
System.out.println("  You(client) says: " + msg);
}

}

I deeply appreciate an answer, or a push in the right direction!

Answer

user207421 picture user207421 · Feb 28, 2012

There are two problems here.

  1. You are restricting the cipher suites to SSL_DH_anon_WITH_RC4_128_MD5, which is an anonymous cipher suite, so there is no authentication. Just remove this, you don't need it.

  2. You aren't calling setWantClientAuth(true) or setNeedClientAuth(true) at the server, so the client is never being asked to send its certificate, so it isn't sending one. So having the server ask for the peer certificate is pointless. Have the client ask for it.

At this point you need to decide whether you really need client authentication or not. If you do, you have to call one of the above methods, and you also need to provide the client with a private key and a signed certificate in a keystore, and arrange that the server's truststore trusts this keystore, either by export/import or by having the client certificate signed by a CA. It's not immediately clear that you need any of this.