1

I am trying to connect to a https secured restwebservice using httpclient 4.0.3 with Java7. My code looks like this:

    public static void main(String[] args) throws Exception {

    ClientRequest req = new ClientRequest("https://127.0.0.16:8443/rest/lstgs/create", new ApacheHttpClient4Executor(doSSLBlackMagic()));

    // ... random stuff that has nothing to do with SSL

    ClientResponse<String> response = req.post(String.class);
    if (response.getStatus() != 201) {
        throw new RuntimeException("error, status: " + response.getStatus() + " / " + response.getEntity());
    } else {
        System.out.println(response.getEntity());
    }
}

public static KeyStore loadTrustStore() throws Exception {
    KeyStore trustStore = KeyStore.getInstance("jks");
    trustStore.load(new FileInputStream(new File("path-to-truststore")), "password".toCharArray());
    return trustStore;
}

protected static TrustManager[] getTrustManagers() throws Exception {
    KeyStore trustStore = loadTrustStore();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(trustStore);
    return tmf.getTrustManagers();
}

public static HttpClient doSSLBlackMagic() throws Exception {
    SSLContext ctx = SSLContext.getInstance("TLS");
    TrustManager[] trustManagers = getTrustManagers();
    ctx.init(null, trustManagers, new SecureRandom());
    SSLSocketFactory factory = new SSLSocketFactory(ctx);

    HttpClient client = new DefaultHttpClient();
    ClientConnectionManager manager = client.getConnectionManager();
    manager.getSchemeRegistry().register(new Scheme("https", factory, 8443));

    return client;
}

As far as I understand this should result in the HttpClient to use my Truststore to ensure that the server's certificate is valid. This fails. I keep getting this exception:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

I've tried multiple keystore/truststores or a plain URLConnection Java-Solution. Nothing works. Is there any way to validate a given keystore and truststore with each other? Is there some other way to set the truststore? How can I debug this?

EDIT: Full Stacktrace:

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:399)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:143)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
at org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor.execute(ApacheHttpClient4Executor.java:87)
at org.jboss.resteasy.core.interception.ClientExecutionContextImpl.proceed(ClientExecutionContextImpl.java:39)
at org.jboss.resteasy.plugins.interceptors.encoding.AcceptEncodingGZIPInterceptor.execute(AcceptEncodingGZIPInterceptor.java:40)
at org.jboss.resteasy.core.interception.ClientExecutionContextImpl.proceed(ClientExecutionContextImpl.java:45)
at org.jboss.resteasy.client.ClientRequest.execute(ClientRequest.java:473)
at org.jboss.resteasy.client.ClientRequest.httpMethod(ClientRequest.java:704)
at org.jboss.resteasy.client.ClientRequest.post(ClientRequest.java:595)
at org.jboss.resteasy.client.ClientRequest.post(ClientRequest.java:600)
at TestLstgCreation.main(TestLstgCreation.java:49)

EDIT2: I've tried this piece of pure Code without HttpClient:

    public static void main(String[] args) throws Exception {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            System.err.println("foobar");
            return null;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) {
            System.err.println("foobar");
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            System.err.println("foobar");
        }
    } };

    // Install the all-trusting trust manager
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            System.err.println("foobar");
            return true;
        }
    };

    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

    URL url = new URL("https://127.0.0.16:8443/rest/lstgs/ofclient/23891");

    HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
    con.connect();
}

It fails and does not print foobar at all:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1837)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1019)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1203)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1230)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1214)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at ScrewYouApacheHttpClient.main(ScrewYouApacheHttpClient.java:48)

The certifciate that the server is using was only "valid" until 2010, maybe that is a problem? Yesterday I did try to use another certificate that I created for this test and got the same results, though.

1
  • 1
    Please post the full stack trace. Commented May 22, 2013 at 18:43

2 Answers 2

3

I just found the solution: We just recently switched to Java 7 and the Eclipseprojekt I used for this test still used Java 6. The Server I am working against however already uses Java 7. Running the Code above with Java 7 works for both snippets. :)

Sucks that the Exception gives no information about this, it cost me a few hours of my life :/

Sign up to request clarification or add additional context in comments.

Comments

0

It may be that your TrustManager is validating the certificate, but HTTPS hostname verification is failing. Consider adding

factory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.