通过需要客户端身份验证的 HttpsUrlConnection 方法 getServerCertificates() 获取服务器证书

问题描述

我使用以下代码获取在 TLS 1.2 握手期间发送的服务器证书:

public List<X509Certificate> getServerCertificates(String url) {
    HttpsURLConnection httpsUrlConnection = ...
    X509Certificate[] certs;
    try {
        httpsUrlConnection.connect(); // <- here
        certs = (X509Certificate[]) httpsUrlConnection.getServerCertificates();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return Arrays.asList(certs);
}

如果服务器需要客户端身份验证,即发送 CertificateRequest 消息作为 TLS 握手的一部分,并且客户端密钥库不包含服务器信任的证书,我用我的评论指出的行抛出 { {1}}。因此,代码不会在下一行中获得服务器证书。如果我尝试在 catch 块中调用 java.net.socketException: Connection reset,我会得到一个 httpsUrlConnection.getServerCertificates()

令我惊讶的是,如果需要,我无法找到通过 NullPointerException 获取服务器证书的方法,而无需对服务器进行身份验证。这让我感到惊讶的原因是服务器在向客户端请求证书之前发送其证书。所以即使服务器决定终止 TLS 握手,服务器证书也已经发送。

我对此进行了广泛的分析,发现在 Java 8、9 和 10 中就是这种情况。但是,在 Java 11、12、13 和 14 中,指示的行没有抛出任何异常,下面的行成功获得服务器证书,即使密钥库为空,也不会生成受信任的证书。这至少是一个有趣的行为,我在 Java 11 发行说明中没有发现这种变化。

问题:

  1. 在 Java 8-10 中,是否有一种不太明显的方法,即使用上述类而不是其他 Java 依赖项,在不生成客户端证书的情况下获取服务器证书?
  2. 在标准 Java 8-10 库或第 3 方依赖项中是否定义了任何其他 TLS 或 HTTPS 客户端类,这可以帮助我在服务器配置为需要客户端身份验证并且客户端不产生可信时获取服务器证书证书?
  3. Java 8-10 和 11-14 之间的这种行为差异是否应该被视为 Java 错误

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)