简体   繁体   English

带有客户端证书的 TLS 握手失败

[英]TLS with client certificate failing handshake

I am confused as to where exactly I need to include client certificate.我对在哪里需要包含客户端证书感到困惑。 Now, my first issue is that I don't trust the server.现在,我的第一个问题是我不信任服务器。 I tried using default Java keystore file (cacerts) which has both Thawte and Digicert in it, and those are the root authorities of the server I'm trying to communicate with.我尝试使用默认的 Java 密钥库文件 (cacerts),其中包含 Thawte 和 Digicert,这些是我尝试与之通信的服务器的根权限。 I set that cacerts file as keystore using System.setProperty("javax.net.ssl.keyStore", "...") , it didn't work, I set it as truststore, it didn't work.我使用System.setProperty("javax.net.ssl.keyStore", "...")将该 cacerts 文件设置为密钥库,它不起作用,我将其设置为信任库,它不起作用。 I still got我还有

unable to find valid certification path to requested target无法找到到请求目标的有效认证路径

So I sorted that out temporarily by using AlwaysTrustSSLConnectionFactory() .所以我通过使用AlwaysTrustSSLConnectionFactory()暂时解决了AlwaysTrustSSLConnectionFactory()

Now the issue is that the server doesn't trust me.现在的问题是服务器不信任我。 I have a client certificate and I tried adding it to both keystore and truststore, but regardless of what I do, after ServerHelloDone I get我有一个客户端证书,我尝试将它添加到密钥库和信任库中,但无论我做什么,在 ServerHelloDone 之后我都得到了

Warning: no suitable certificate found - continuing without client authentication警告:未找到合适的证书 - 无需客户端身份验证即可继续

in Java's SSL debug messages and a handshake failure after secret and key messages.在 Java 的 SSL 调试消息和秘密和密钥消息之后的握手失败中。 Here is the end of my log:这是我的日志的结尾:

http-bio-8080-exec-3, WRITE: TLSv1.2 Handshake, length = 40
http-bio-8080-exec-3, READ: TLSv1.2 Alert, length = 2
http-bio-8080-exec-3, RECV TLSv1.2 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-7, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
http-bio-8080-exec-3, called closeSocket()
http-bio-8080-exec-3, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)

Here is my current code:这是我当前的代码:

System.setProperty("javax.net.ssl.keyStore", "C:/Users/Lovro/Desktop/certs/api/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");

URL url = new URL(urlRequest);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(new AlwaysTrustSSLContextFactory());
conn.connect();

I recieved my client certificate from API developers in format .p12 , so I converted it to .crt and added that to keystore with Keytool .我从 API 开发人员那里收到了格式为.p12客户端证书,因此我将其转换为.crt并使用Keytool将其添加到密钥库中。 Does anyone know what could be the issue and is my handshake failing because I have not included client certificate properly or if I didn't add it to keystore properly?有谁知道可能是什么问题,我的握手失败是因为我没有正确包含客户端证书,或者我没有正确地将它添加到密钥库? As far as I understand, truststore needs to contain public keys of trusted root authorities and keystore should have my client certificate.据我了解,truststore 需要包含受信任的根权限的公钥,keystore 应该有我的客户端证书。 Is this correct?这样对吗? How do I achieve this?我如何实现这一目标?

Any suggestion is welcome, I am new to TLS/HTTPS and have no idea what am I doing.欢迎任何建议,我是 TLS/HTTPS 的新手,不知道我在做什么。

I recieved my client certificate from API developers in format .p12, so I converted it to .crt and added that to keystore with Keytool我从 API 开发人员那里收到了格式为 .p12 的客户端证书,因此我将其转换为 .crt 并使用 Keytool 将其添加到密钥库

This is where you went wrong.这就是你出错的地方。 Converting it to .crt extracts the public certificate.将其转换为 .crt 会提取公共证书。 What you need to do is convert the .p12 file to a java keystore.您需要做的是.p12 文件转换为 java 密钥库。 There are many examples on the net.网上有很多例子。 See this SO answer for how.有关如何操作,请参阅此 SO 答案

To confirm that it's worked, run keytool -list -keystore <yourkeystore>.jks and check that you have a PrivateKeyEntry in there.要确认它是否有效,请运行keytool -list -keystore <yourkeystore>.jks并检查其中是否有PrivateKeyEntry

While you're checking things, add the -v flag to the keytool -list command and check that the Issuer field is CN=test, O=test because we can see from your log file that your server requires a client certificate to be issued by that authority.在检查时,将-v标志添加到keytool -list命令并检查颁发者字段是否为CN=test, O=test因为我们可以从您的日志文件中看到您的服务器需要颁发客户端证书由那个权威。

Also check that your JDK is configured with the Unlimited Strength Jurisdiction Policy Files because the cipher you're being asked to use requires it.还要检查您的 JDK 是否配置了 Unlimited Strength Jurisdiction Policy Files,因为您被要求使用的密码需要它。

From the log, it seems that TLS cipher TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is invalidated for TLS client.从日志来看,TLS 密码TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384对于 TLS 客户端似乎无效。 You may need to check which cipher list client supports.您可能需要检查客户端支持哪种密码列表。 If the cipher TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is not included in the cipher list, you may need to add support for it.如果密码TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384未包含在密码列表中,您可能需要添加对它的支持。

http-bio-8080-exec-3, READ: TLSv1.2 Alert, length = 2 http-bio-8080-exec-3,阅读:TLSv1.2 警报,长度 = 2
http-bio-8080-exec-3, RECV TLSv1.2 ALERT: fatal, handshake_failure http-bio-8080-exec-3,RECV TLSv1.2 警报:致命,handshake_failure
%% Invalidated: [Session-7, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] %% 无效:[Session-7,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]

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

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