握手失败客户端密钥交换,使用证书链。

4

我正在尝试使用Java建立与Web服务的双向TSL连接。我已经获得了一个带有私钥和3个证书的证书链的pfx证书。以下是使用Spring框架的Java代码:

    @Bean
public Client weatherClient(Jaxb2Marshaller marshaller) throws Exception {
    Client client = new Client();
    client.setDefaultUri(".....");
    client.setMarshaller(marshaller);
    client.setUnmarshaller(marshaller);

    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(keyStore.getInputStream(), keyStorePassword.toCharArray());

    LOGGER.info("Loaded keystore: " + keyStore.getURI().toString());
    System.out.println("Loaded keystore: " + keyStore.getURI().toString());

    keyStore.getInputStream().close();


    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());//KeyManagerFactory.getDefaultAlgorithm()
    keyManagerFactory.init(ks, keyStorePassword.toCharArray());

    KeyStore ts = KeyStore.getInstance("PKCS12");
    ts.load(trustStore.getInputStream(), trustStorePassword.toCharArray());//
    LOGGER.info("Loaded trustStore: " + trustStore.getURI().toString());
    System.out.println("Loaded trustStore: " + trustStore.getURI().toString());

    trustStore.getInputStream().close();

    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(ts);

    HttpsUrlConnectionMessageSender messageSender = new HttpsUrlConnectionMessageSender();
    messageSender.setKeyManagers(keyManagerFactory.getKeyManagers());
    messageSender.setTrustManagers(trustManagerFactory.getTrustManagers()); 
    client.setMessageSender(messageSender);
    return client;
}

目前我收到了一个客户端hello和一个服务器hello,服务器hello发送了一个证书,我也获得了可信的证书。然后就是证书请求,但是没有找到任何证书。

*** CertificateRequest 
Cert Types: RSA, DSS 
Cert Authorities:
<CN=Thawte SSL CA, O="Thawte, Inc.", C=US>
....
....
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client  authentication
*** Certificate chain
<Empty>
***

我已经将证书单独添加到了lib/security/cacerts中。似乎第一个证书交换是从cacerts密钥库中进行的,如果只有在此处添加了证书,则会出现相同的行为。尽管我已将其作为带有私钥和证书链的pkcs12导入KeyStore对象,但似乎请求正在寻找证书链但无法找到。如有任何帮助,将不胜感激。
更新:客户端密钥交换后我收到了握手失败的消息,我认为这可能是由于上述警告引起的,但我可能错了。
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
main, WRITE: TLSv1 Handshake, length = 269
SESSION KEYGEN:
PreMaster Secret:
....
....
0000: B0 E2 38 5E 40 4E 7C C5                            ..8^@N..
Server write IV:
0000: 44 40 45 E1 82 45 15 9B                            D@E..E..
main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data:  { 109, 220, 225, 98, 98, 233, 48, 215, 61, 50, 58, 207 }
***
main, WRITE: TLSv1 Handshake, length = 40
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-1, SSL_RSA_WITH_3DES_EDE_CBC_SHA]

更新

如果我将密钥库添加为变量-Djavax.net.ssl.keyStore=,则双向身份验证可以正常工作,但是如果没有将密钥库添加为变量,则会出现以下情况。代码中指定的密钥库和信任库被找到,并且证书链和信任库在调试中显示。

***
found key for : devcert
chain [0] = [
[
  Version: V3 ......

***
adding as trusted cert:
  Subject: 

然后会显示一个空的密钥库,并且 JVM cacerts 会被用作信任证书。

keyStore is : 
keyStore type is : jks
keyStore provider is : 
init keystore
init keymanager of type SunX509
trustStore is: /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts
trustStore type is : jks
trustStore provider is : 
init truststore
adding as trusted cert:
  Subject: CN=ubuntu

接下来是服务器hello *** ServerHello, TLSv1 证书已找到

    ***
    Found trusted certificate:
but the Certificate Request does find a matching certificate as above, unless it is added as a variable 
*** CertificateRequest 
Cert Types: RSA, DSS 
Cert Authorities:
<CN=Thawte SSL CA, O="Thawte, Inc.", C=US>
....
....
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client  authentication
*** Certificate chain
<Empty>
***

将密钥库作为变量添加后的行为:-Djavax.net.ssl.keyStore=


*** ServerHelloDone
matching alias: devcert
*** Certificate chain
chain [0] = [
[
  Version: V3

我希望能够在程序代码中使用密钥库和信任库,因为我想后续能够动态更改它们。


关于您的编辑,您需要查看服务器SSL日志以了解出现了什么问题。如果客户端发送了“证书”消息,则客户端证书已经起作用。 - user207421
谢谢,这很有用。我没有访问服务器的权限,但我猜测在客户端密钥交换后的某些数据交换导致了错误。可能是向服务器传递了错误的数据。 - Bryan E
1个回答

1
您不应该被给予私钥。这已经是一个重大的安全漏洞。实际问题在于证书要么没有由 CertificateRequest 消息中提到的 CA 签名,要么它不是其中提到的类型。

我收到了一个带有私钥的.pfx文件。我可以使用SoapUI连接到服务并使用证书。这些证书的类型是密钥算法:RSA。 - Bryan E
没有由 Thawte 签名。 - user207421
谢谢,我通过浏览器获取了Thawte证书并将其导入到cacerts密钥库中。如果没有它,在serverHello阶段会出现致命错误,描述为certificate_unknown。 - Bryan E

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接