Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 客户端证书握手失败的TLS_Java_Ssl_Https_Certificate_Client Certificates - Fatal编程技术网

Java 客户端证书握手失败的TLS

Java 客户端证书握手失败的TLS,java,ssl,https,certificate,client-certificates,Java,Ssl,Https,Certificate,Client Certificates,我不知道我到底需要在哪里包含客户机证书。现在,我的第一个问题是我不信任服务器。我尝试使用默认的Java密钥库文件(cacerts),其中包含Thawte和Digicert,这些是我试图与之通信的服务器的根权限。我使用System.setProperty(“javax.net.ssl.keystore”,“…”)将该cacerts文件设置为密钥库,它不起作用,我将其设置为信任库,它不起作用。我还有 找不到请求目标的有效证书路径 因此,我使用AlwaysTrustSSLConnectionFacto

我不知道我到底需要在哪里包含客户机证书。现在,我的第一个问题是我不信任服务器。我尝试使用默认的Java密钥库文件(cacerts),其中包含Thawte和Digicert,这些是我试图与之通信的服务器的根权限。我使用
System.setProperty(“javax.net.ssl.keystore”,“…”)
将该cacerts文件设置为密钥库,它不起作用,我将其设置为信任库,它不起作用。我还有

找不到请求目标的有效证书路径

因此,我使用
AlwaysTrustSSLConnectionFactory()
暂时解决了这个问题

现在的问题是服务器不信任我。我有一个客户机证书,我尝试将它添加到密钥库和信任库中,但不管我做什么,在服务器Hellodone之后,我得到了它

警告:找不到合适的证书-在没有客户端的情况下继续 认证

在Java的SSL调试消息和秘密和密钥消息后的握手失败中。以下是我日志的结尾:

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)
这是我目前的代码:

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();
我从API开发人员那里收到了格式为
.p12
的客户端证书,因此我将其转换为
.crt
,并使用Keytool将其添加到密钥库中。有人知道可能是什么问题吗?我的握手失败是因为我没有正确地包含客户端证书,还是因为我没有正确地将其添加到密钥库?据我所知,truststore需要包含受信任根权限的公钥,密钥库应该有我的客户端证书。这是正确的吗?我如何做到这一点


欢迎任何建议,我是TLS/HTTPS新手,不知道我在做什么。

从日志中可以看出,TLS cipher
TLS\u ECDHE\u RSA\u WITH_AES\u 256\u GCM\u SHA384
对于TLS客户端无效。您可能需要检查客户端支持的密码列表。如果密码列表中不包括密码
TLS\u ECDHE\u RSA\u和\u AES\u 256\u GCM\u SHA384
,您可能需要添加对它的支持

http-bio-8080-exec-3,读为:TLSv1.2警报,长度=2
http-bio-8080-exec-3,RECV TLSv1.2警报:致命,握手失败
%%无效:[会话7,TLS_ECDHE_RSA_与_AES_256_GCM_SHA384]

我从API开发人员那里收到了格式为.p12的客户端证书,所以我将其转换为.crt,并使用Keytool将其添加到密钥库中

这就是你错的地方。将其转换为.crt将提取公共证书。您需要做的是将.p12文件转换为java密钥库。网上有很多例子。看看怎么做

要确认它是否工作,请运行
keytool-list-keystore.jks
,并检查其中是否有
PrivateKeyEntry

检查时,将
-v
标志添加到
keytool-list
命令中,并检查颁发者字段是否为
CN=test,O=test
,因为我们可以从日志文件中看到,您的服务器需要由该机构颁发客户端证书


还要检查您的JDK是否配置了无限强度权限,因为要求您使用的密码需要它。

我忘了说我在
Postman
中尝试过使用客户机证书,它可以工作。证书有效。找不到合适的证书-如果没有客户端身份验证而继续,则表示客户端在密钥库中找不到服务器发送的CA证书列表的匹配证书。然后服务器可能会关闭连接,因为客户端证书尚未发送。确保所有证书和.p12的私钥都实际导入到JKS中,或者将.p12直接设置为
javax.net.ssl.keystore
中的密钥库。如果p12也不起作用,则获取服务器发送的CA列表,并将其与p12证书的颁发者进行比较。问题是我将.crt导入了从原始.p12客户端证书创建的密钥库中,因此我实际上只将公钥添加到了我的存储中。新手犯的错误。据《密码》称,TLS\u ECDHE\u RSA\u WITH\u AES\u 256\u GCM\u SHA384是服务器最喜欢的密码。它列为
密码
套件部分的第一个。问题是,我的客户机在
ClientHello
中发送它支持的密码列表,这就是服务器在ServerHello中选择的密码。从日志:
***ServerHello,TLSv1.2 RandomCookie:GMT:-752143001 bytes=会话ID:Cipher Suite:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
是的。如果密码不匹配,将出现类似
无共享密码
的错误。谢谢,但问题似乎出在其他地方,我假设我包括这些证书存储,因为我仍然收到
警告:未找到合适的证书-继续,无需客户端身份验证
。刚刚发现我甚至不需要将.p12转换为.jks,因为它们都是密钥库。使用pkcs12文件可以得到与使用.jks相同的结果。@lovrodoe我不建议在不转换为jks的情况下使用.p12。我们曾经有人犯过这样的错误,这会影响java代码从私钥条目中提取证书部分的能力。您是否验证了发卡机构是否正确,是否与服务器请求的单个发卡机构匹配?…如果您尚未验证,请务必放弃
setsssocketfactory()
调用。如果您遇到主机名不匹配的问题,请使用
setHostnameVerifier
和一个简单的
return true
实现。Andy干杯,谢谢您的回复。事实上,你们让我走上了解决这个问题的道路,所以我会选择你们的答案。我不再设置SSL套接字工厂,尽管我使用的是他们发给我的原始.p12密钥库。您能否澄清一下影响Java代码提取证书部分能力的部分?它的性能是否比Java专有jks的性能更差?我还没有注意到任何重大问题