java - 证书链中的 SSLHandshakeException 行为

标签 java ssl

我已经使用此证书链的存储证书实现了证书锁定:

  • 证书1:云平台
  • 证书 2:Verizon(中级 CA)
  • 证书 3:巴尔的摩(根 CA)

不过我注意到了一个奇怪的行为:

  • 行为 1(预期):如果我只固定证书 1,我会得到一个 SSLHandshakeException 错误,因为我需要包括所有 链中的证书。
  • 行为 2(意外?):如果我只固定证书 2,即 中间 CA,我根本不会收到任何 SSLHandshakeException 错误。

您是否知道行为 2 是否符合预期?如果是,为什么?我的印象是应该使用链中的所有证书,否则我会得到一个 SSLHandshakeException。谢谢!

已更新代码

class SSLPinning {

void exec() {

    // Open InputStreams for each certificate
    InputStream baltimoreInputStream = getClass().getResourceAsStream("baltimore.cer");
    InputStream hcpmsInputStream = getClass().getResourceAsStream("hcpms_cert.cer");
    InputStream verizonInputStream = getClass().getResourceAsStream("verizon.cer");

    try {

        // CertificateFactory has the method that generates certificates from InputStream
        // Default type for getInstance is X.509
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        // Create Certificate objects for each certificate
        Certificate baltimoreCertificate = cf.generateCertificate(baltimoreInputStream);
        Certificate hcpmsCertificate = cf.generateCertificate(hcpmsInputStream);
        Certificate verizonCertificate = cf.generateCertificate(verizonInputStream);

        // Create KeyStore and load it with our certificates
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        //keyStore.setCertificateEntry("hcpms", hcpmsCertificate);
        keyStore.setCertificateEntry("intermediate", verizonCertificate); //surprisingly, it works with just using the intermediate CA
        //keyStore.setCertificateEntry("root", baltimoreCertificate);

        // Create a TrustManagerFactory using KeyStore -- this is responsible in authenticating the servers
        // against our stored certificates
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);

        // Create an SSLContext using TrustManagerFactory -- this will generate the SSLSocketFactory we will use
        // during HTTPS connection
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        URL url = new URL("https://account.hanatrial.ondemand.com/");
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection();
        httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
        httpsURLConnection.connect();
        System.out.print("Server authentication successful");

    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (SSLHandshakeException e) {
        System.out.println("Server authentication failed");
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }

}

最佳答案

您的主要问题是,为了验证证书,必须存在可信链(可信证书和服务器/叶证书之前的所有中间证书)。然而,大多数 SSL/TLS 服务器不会向您发送完整的链。您有时只会获得叶证书(没有中间证书或根证书;您可以在 Wireshark 流量转储中看到这一点)。

其他服务器可能会向您发送叶证书和所有/一些中间证书,但没有根证书。

在这种情况下,您的本地信任库包含缺失的证书以构建完整的链是至关重要的。

根据您的观察,我假设服务器只发送没有中间证书和根证书的叶证书。因此,为了成功验证,您的信任库必须包含中间证书作为受信任的证书才能使其正常工作(否则该证书将丢失)。我建议将根证书和中间证书都包含到您的信任库中。

顺便说一句:服务器不发送中间 CA 证书也可能是服务器配置问题。通常我会建议配置一个服务器来发送叶证书和中间证书。

关于java - 证书链中的 SSLHandshakeException 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39999559/

相关文章:

wordpress - 执行 HTTP 请求时出错 : error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure.(Managewp 到保管箱备份)

java - JAXB 对象未实现可序列化的后果是什么?

java - 在 Java 中从 SOAPBody 获取原始 XML(对于 Camel 流?)

java - SSLHandshakeException 可以是可重试的异常吗?

java - SSL 加密和 Cassandra

ssl - Python 'requests' [SSL : CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl. c:590)

ssl - 在 HTTPS 连接中的 SSL 握手期间,客户端如何在加密传输开始之前安全地向服务器发送 secret

java - 按照这个简单的 GSON 示例,等效的客户端 RestyGWT 是什么样子?

java - 使用循环创建子字符串

Java 捕获文件中的 telnet 输出