java - 如何在 Java 中获取 SSLHandshakeException 之后的 certificates?

如何获取 SSLHandshakeException 的详细信息?我尝试让 certificates 查看异常的原因,但它只抛出 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)

回答1

如果握手失败,您将无法从 HttpsURLConnection 获取任何 SSL/TLS 级别的数据。

如果您使用 SSLSocket (或 SSLEngine ,但工作量更大),我认为您可以在握手结束之前但在对等方的 Certificate 消息已处理并验证证书链之后获得对等方 certificates 。当然,在那种情况下,任何握手失败都不是由 certificates 引起的,因此如果您想要“查看异常的原因”,那么查看 certificates 是浪费时间。

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

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

补充:您可以使用 keytool -printcert -sslserver $host[:$port] 在命令行中查看服务器的 certificates ——但这不是编程并且是题外话。 (请注意,尽管操作 printcert 在语法上是单数的,但它实际上完成了整个链。)

相似文章