javahttpscertificatesslhandshakeexception

How to get the certificates after SSLHandshakeException in Java?


How to get the details of an SSLHandshakeException? I try to get the certificates to see the cause of the exception but it throw only a NullPointerException.

    URL url = new URL( "https://localhost:9443/" );
    HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
    try {
        connection.getInputStream();
    } catch( SSLHandshakeException e ) {
        for( Certificate certificate : connection.getServerCertificates() ) {
            System.err.println( certificate );
        }
    }

but it throw only a NullPointerException.

Exception in thread "main" java.lang.NullPointerException
    at java.base/sun.net.www.protocol.https.HttpsClient.getServerCertificates(HttpsClient.java:695)
    at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getServerCertificates(AbstractDelegateHttpsURLConnection.java:272)
    at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getServerCertificates(HttpsURLConnectionImpl.java:212)
    at TestSSL.main(TestSSL.java:18)

Solution

  • From HttpsURLConnection you cannot get any SSL/TLS-level data if the handshake fails.

    If you use SSLSocket (or SSLEngine but that's much more work) I think you can get peer certificates before the handshake ends but after the peer's Certificate message has been processed and the cert chain validated. Of course in that situation any handshake failure is not caused by the certificates, so looking at the certificates is a waste of time if what you want is to 'see the cause of the exception'.

    In fact in general many handshake failures (and exceptions) are not caused by certificates at all, and when they are are often that cause cannot be seen by looking at the certificates.

    In general to see the cause of this exception, like many, you should look at the exception. In particular, e.getMessage() usually tells you the cause (at least the cause experienced by JSSE, which may differ from the original or 'ultimate' cause). In addition e.getCause() if nonnull can contain useful details (though often among greater clutter). And this works at both URLConnection and JSSE levels (and also the j11+ HttpClient).

    Added: you can see the server's certificates at commandline with keytool -printcert -sslserver $host[:$port] -- but that's not programming and is offtopic. (Note even though the operation printcert is grammatically singular, it actually does the whole chain.)