简体   繁体   English

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

[英]Java - Ssl stream is cancelled when using client certificate authentication

I cannot figure this one out. 我无法想出这个。

I have a unit test that performs a connection to my service using a client certificate authentication. 我有一个单元测试,使用客户端证书身份验证执行与我的服务的连接。

// 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));

I'm using Java 8 and my server is behind a reverse proxy that uses Nginx. 我使用的是Java 8,而我的服务器是使用Nginx的反向代理。

My unit test fails with an exception like this: 我的单元测试失败,出现如下异常:

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

And I can see in the Nginx error.log the following line: 我可以在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

I have SCOURGED the internet to find the reason for this error, and I feel like I have exhausted all recourse. 我已经SCOURGED互联网找到了这个错误的原因,我觉得我已经筋疲力尽了所有的追索权。

Non exhaustive list of things I have tried: 我尝试过的非详尽列表:

  • Force java to use TlsV1.1 with -Dhttps.protocols=Tlsv1.1 -> still fails 强制java使用TlsV1.1和-Dhttps.protocols=Tlsv1.1 - >仍然失败
  • Tried to specify the "key strategy" for the loadTrustMaterial to always use my own key -> still fails 试图为loadTrustMaterial指定“关键策略”以始终使用我自己的密钥 - >仍然失败
  • Used a Jersey client with the same set of Ssl /Keystore params -> still fails 使用具有相同Ssl / Keystore参数集的Jersey客户端 - >仍然失败
  • Tried all JDK versions of 1.8: OpenJDK, Oracle, and Oracle with Crypto Extensions (JCE) 通过Crypto Extensions(JCE)尝试了所有JDK版本的1.8:OpenJDK,Oracle和Oracle
  • Searching the nginx error seems to imply that the passed cert wasn't correct, so I... 搜索nginx错误似乎意味着传递的证书不正确,所以我......
  • ...dumped the key and cert into a couple of PEM files while in debugger and curl ed the same address -> it works ?! ...在调试器中将密钥和证书转储到几个PEM文件中并且curl相同的地址 - >它有效吗?
  • Wiresharked the connection and examined the TLS negotiation. Wireshark连接并检查TLS协商。 Compared it with a working sample (the simple curl -k <url> above which works flawlessly): 将它与工作样本(上面简单的curl -k <url>完美无瑕地工作)进行比较:
    • Saw something about ALPN but enabling it in Java doesn't fix the exception. 看到有关ALPN的东西,但在Java中启用它并不能解决异常问题。
    • Saw different crypto algorithms announced but nothing stands out 看到了不同的加密算法,但没有什么突出的

Do you guys have any idea? 你们有什么想法吗? I'm starting to get crazy. 我开始变得疯狂。 I have a hunch that I'm not setting my connection correctly, but I can't see where. 我有预感,我没有正确设置我的连接,但我看不到在哪里。

For those that didn't read the comments: I figured it out: I was using the subjectAltName as a storage for something that isn't an alternative name. 对于那些没有阅读评论的人:我想通了:我使用subjectAltName作为存储而不是替代名称。

It seems that Java is not happy with this and refuses the connection. 似乎Java对此不满意并拒绝连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM