如何在 Java 中的 SSLHandshakeException 之后获取证书?

How to get the certificates after SSLHandshakeException in Java?

如何获取 SSLHandshakeException 的详细信息?我尝试获取证书以查看异常原因,但它仅抛出 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 );
        }
    }

但它只抛出 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)

如果握手失败,您无法从 HttpsURLConnection 获取 任何 SSL/TLS-level 数据。

如果你使用 SSLSocket(或 SSLEngine 但那需要更多工作)我 认为 你可以在握手结束之前但在握手结束之后获得对等证书对等方的证书消息已被处理并且证书链已验证。当然在那种情况下任何握手失败都不是由证书引起的,所以如果你想要 'see the cause of the exception'.

查看证书是浪费时间

事实上,一般来说,许多握手失败(和异常)根本不是由证书引起的,而当它们通常是通过查看证书无法发现原因时。

一般要看这个异常的原因,像很多一样,你应该看异常。特别是,e.getMessage() 通常会告诉您原因(至少是 JSSE 遇到的原因,这可能与原始或 'ultimate' 原因不同)。此外 e.getCause() if nonnull 可以包含有用的细节(尽管通常在更大的混乱中)。这适用于 URLConnection 和 JSSE 级别(以及 j11+ HttpClient)。

添加: 您可以使用 keytool -printcert -sslserver $host[:$port] 在命令行中 查看 服务器的证书——但这不是编程而且是离题的. (请注意,尽管操作 printcert 在语法上是单数的,但它实际上执行了整个链。)