Java - 使用客户端证书身份验证时取消 SSL 流

标签 java ssl nginx client-certificates

我想不通这个。

我有一个单元测试使用客户端证书身份验证执行与我的服务的连接。

// generate a valid client cert and store it in a keystore
String keystorePassword = "xxx";
InputStream pkcs12 = UnitTests.generatePkcs12ForUser(user, keystorePassword, 3600);
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(pkcs12, keystorePassword.toCharArray());


String url = getBaseServerUrl();

// prepare a ssl context that has the keystore with client cert and key
SSLContext sslContext = SSLContexts.custom()
                                   .loadKeyMaterial(ks, keystorePassword.toCharArray())
                                   // trust all SSL certs
                                   .loadTrustMaterial((X509Certificate[] chain, String authType) -> true)
                                   .build();

// validate any hostname, and don't follow 3XX responses
HttpClient httpClient = HttpClients.custom()
                                   .setSSLContext(sslContext)
                                   .setSSLHostnameVerifier((a,b) -> true)
                                   .disableRedirectHandling()
                                   .build();

// this fails catastrophically
HttpResponse response = httpClient.execute(new HttpGet(url));

我使用的是 Java 8,我的服务器位于使用 Nginx 的反向代理后面。

我的单元测试失败,出现如下异常:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1002)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
[...]
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(InputRecord.java:505)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
    ... 43 more

我可以在 Nginx error.log 中看到以下行:

2018/05/18 15:34:12 [crit] 42#42: *327 SSL_do_handshake() failed (SSL: error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error) while SSL handshaking, client: 172.18.0.1, server: 0.0.0.0:443

我已经搜索了互联网以查找此错误的原因,我觉得我已经用尽了所有资源。

我尝试过的事情的非详尽列表:

  • 强制 java 使用 TlsV1.1 -Dhttps.protocols=Tlsv1.1 -> 仍然失败
  • 试图为 loadTrustMaterial 指定“关键策略”始终使用我自己的 key -> 仍然失败
  • 使用具有相同 Ssl/Keystore 参数集的 Jersey 客户端 -> 仍然失败
  • 尝试了 1.8 的所有 JDK 版本:OpenJDK、Oracle 和 Oracle with Crypto Extensions (JCE)
  • 搜索 nginx 错误似乎暗示传递的证书不正确,所以我...
  • ...在调试器和 curl 中将 key 和证书转储到几个 PEM 文件中编辑了相同的地址 -> 它有效?!
  • Wireshark 连接并检查 TLS 协商。将其与工作示例(上面的简单 curl -k <url> 完美运行)进行比较:
    • 看到了关于 ALPN 的信息但在 Java 中启用它并不能解决异常。
    • 看到公布了不同的加密算法,但没有什么突出的

你们有什么想法吗?我开始发疯了。我有一种预感,我没有正确设置我的连接,但我看不到哪里。

最佳答案

对于那些没有阅读评论的人:我想通了:我使用 subjectAltName 来存储不是替代名称的东西。

Java 似乎对此不满意并拒绝连接。

关于Java - 使用客户端证书身份验证时取消 SSL 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50415299/

相关文章:

Nginx 子目录 404

java - 使用 Oracle、Java 和 AngularJS 构建实时数据网格的策略

java - Java 1.7 中的 JAX-WS HTTP 日志记录

java - 获取知道包名称的应用程序名称

android - 未找到 Android SSL 连接的信任 anchor

ssl - X509_NAME - 如何获取实际缓冲区?

tomcat - ssl tomcat证书错误

nginx - kubernetes k3s 代理无法连接到主 CA/SSL 错误

nginx - 如果应用程序映射到子目录,如何在 Nginx + Flask 设置中加载静态文件

java - 设置 Apache 服务器以测试 Web 应用程序