简体   繁体   English

相互SSL-使用Java作为客户端时的客户端证书链为空

[英]Mutual SSL - client certificate chain emtpy when using java as a client

We are using java client(openJDK 1.8.0) to call an api that needs mutual authentication. 我们正在使用Java客户端(openJDK 1.8.0)来调用需要相互认证的api。 For this we are using java standard JKS file as a keystore and truststore (same file for containing both trustcerts and identity certs/privatekey). 为此,我们使用Java标准JKS文件作为密钥库和信任库(包含trustcerts和Identity certs / privatekey的相同文件)。 Sample java we are using to test is as below :: 我们用来测试的示例Java如下:

KeyStore clientKeyStore = KeyStore.getInstance("JKS");
            clientKeyStore.load(new FileInputStream("./client.keystore"),
                    password.toCharArray());

            // create a client connection manager to use in creating httpclients
            PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();


            SSLContext sslContext = SSLContextBuilder.create()
                    .loadKeyMaterial(clientKeyStore, password.toCharArray())
                    .loadTrustMaterial(clientKeyStore, null).build();

            // create the client based on the manager, and use it to make the call
            CloseableHttpClient httpClient = HttpClientBuilder.create()
                    .setConnectionManager(mgr)
                    .setSslcontext(sslContext)
                    .setSSLHostnameVerifier(new NoopHostnameVerifier())
                    .build();


            HttpPost httppost = new HttpPost("https://someUrl");

            String params = "";
            StringEntity param = new StringEntity(params);
            httppost.setEntity(param);
            System.out.println("Sending request...............");
            HttpResponse response = httpClient.execute(httppost);

During SSL handshake as a last step of "serverhello", server is requesting client's identity by issuing "certificaterequest" - please find below request :: 在SSL握手过程中,作为“ serverhello”的最后一步,服务器正在通过发出“ certificaterequest”来请求客户端的身份-请在下面的请求中找到::

    *** CertificateRequest
Cert Types: RSA, ECDSA, DSS
Supported Signature Algorithms: SHA512withRSA, Unknown (hash:0x6, signature:0x2), SHA512withECDSA, SHA384withRSA, Unknown (hash:0x5, signature:0x2), SHA384withECDSA, SHA256withRSA, SHA256withDSA, SHA256withECDSA, SHA224withRSA, SHA224withDSA, SHA224withECDSA, SHA1withRSA, SHA1withDSA, SHA1withECDSA
Cert Authorities:
<CN=Intermediate CA, OU=ourCA.com, O=ourCA Inc, C=US>

Right after this, we are seeing below lines indicating java's keyManager is not able to find anything signed with the same signer. 在此之后,我们看到以下几行表明Java的keyManager无法找到使用相同签名者签名的任何内容。

*** ServerHelloDone
[read] MD5 and SHA1 hashes:  len = 4
0000: 0E 00 00 00                                        ....
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***

We have validated that the certificate is present in the keystore and its a valid certificate( by opening it in windows box, it wont open if its invalid cert). 我们已经验证了密钥库中存在该证书及其有效证书(通过在Windows框中打开它,如果证书无效,则它不会打开)。 So our keystore has an chain : myIdentity >> signed by Intermediate CA >>signed by Root CA 因此我们的密钥库有一个链:myIdentity >>由中间CA签名>>由根CA签名

A few things we have tried(without any luck) is : 我们尝试过的一些事情(没有任何运气)是:

  • Tried overriding keystoremanager to return a hardcoded alias ie alias of the certificate in keystore.jks 尝试覆盖keystoremanager以返回硬编码别名,即keystore.jks中证书的别名
  • Tried splitting identity certs and CA certs in two separate files ie separate keystore.jks and truststore.jks 尝试在两个单独的文件(即单独的keystore.jks和truststore.jks)中拆分身份证书和CA证书

Its worth sharing that the same connectivity works well if we are using cURL. 值得分享的是,如果我们使用cURL,则相同的连接性会很好地工作。 In case of cURL, we have to pass client certificate explicitly as an argument ( cURL has no concept of keystore) and we are using linux default keystore (/etc/pki/tls/certs/ca-bundle.crt) 在使用cURL的情况下,我们必须显式传递客户端证书作为参数(cURL没有密钥库的概念),并且我们使用的是Linux默认密钥库(/etc/pki/tls/certs/ca-bundle.crt)

curl -vvv GET https://api.someone.com/some/path -E /home/certificates/client.test.pem --key /home/certificates/client.test.key

I am not sure what other details can add value but I'll be happy to share all the possible details needed ( except my private key :-P ) 我不确定还有哪些其他细节可以增加价值,但我很乐意分享所需的所有可能细节(我的私钥:-P除外)

I had the same problem as you described. 我遇到了与您描述的问题相同的问题。 The issue I had was that I loaded the keystore in Java using: 我遇到的问题是我使用以下命令在Java中加载了密钥库:

System.setProperty("javax.net.ssl.keyStore", "/path/key.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");

When the server requested a ClientCertificate all a got was: 当服务器请求ClientCertificate时,得到的是:

*** CertificateRequest 
Cert Types: RSA, DSS Supported Signature Algorithms: SHA512withRSA, SHA512withECDSA, SHA384withRSA, SHA384withECDSA, SHA256withRSA, SHA256withECDSA, Unknown (hash:0x4,signature:0x2), SHA224withRSA, SHA224withECDSA, Unknown (hash:0x3,signature:0x2), SHA1withRSA, SHA1withECDSA, SHA1withDSA 
Cert Authorities: 
&ltCN=HB Internal Issuing CA, DC=domainx, DC=hb, DC=bis>
*** ServerHelloDone 
Warning: no suitable certificate found - continuing without client authentication

The solution for this was to load the keystore in a different way as described by: Java SSLHandshakeException "no cipher suites in common" 解决此问题的方法是按如下所述的不同方式加载密钥库: Java SSLHandshakeException“没有共同的密码套件”

Basically what I did was to change how I created the SSLContext: 基本上,我所做的就是更改创建SSLContext的方式:

From: 从:

System.setProperty("javax.net.ssl.keyStore", "/path/key.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");

System.setProperty("javax.net.ssl.trustStore", "/path/trust.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(null, null, null);

To: 至:

// instantiate a KeyStore with type JKS
KeyStore ks = KeyStore.getInstance("JKS");

// load the contents of the KeyStore
final char[] keyPasswd = "pass".toCharArray();
ks.load(new FileInputStream("/path/key.jks"), keyPasswd);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

keyManagerFactory.init(ks, keyPasswd);

SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(keyManagerFactory.getKeyManagers(), null, null);

and the result then was: 结果是:

*** CertificateRequest
Cert Types: RSA, DSS
Supported Signature Algorithms: SHA512withRSA, SHA512withECDSA, SHA384withRSA, SHA384withECDSA, SHA256withRSA, SHA256withECDSA, Unknown (hash:0x4, signature:0x2), SHA224withRSA, SHA224withECDSA, Unknown (hash:0x3, signature:0x2), SHA1withRSA, SHA1withECDSA, SHA1withDSA
Cert Authorities:
&ltCN=HB Internal Issuing CA, DC=domainx, DC=hb, DC=bis>
*** ServerHelloDone
matching alias: ibmwebspheremq01

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

相关问题 Weblogic/Java 在与 IIS 的相互 SSL 集成中不发送客户端证书 - Weblogic/Java not sending Client Certificate in Mutual SSL Integration with IIS Java - 使用客户端证书身份验证时取消Ssl流 - Java - Ssl stream is cancelled when using client certificate authentication 相互SSL:unsupported_certificate和客户端证书格式 - Mutual SSL: unsupported_certificate and client certificate format 使用Java客户端进行SSL证书验证 - SSL certificate validation using Java client 在 Java 中选择 SSL 客户端证书 - Choosing SSL client certificate in Java Java Spring Webflux:javax.net.ssl.SSLHandshakeException:空客户端证书链 - Java Spring Webflux: javax.net.ssl.SSLHandshakeException: Empty client certificate chain 使用自签名证书的Java ssl / https客户端 - Java ssl/https client using a self-signed certificate 具有SSL相互身份验证的Jersey客户端 - Jersey Client with SSL Mutual Authentication 泽西岛客户端SSL相互认证 - Jersey client SSL mutual authentication Android客户端上的SSL相互身份验证FAIL接受服务器证书,但服务器未获得客户端证书 - SSL mutual authentication FAIL on Android Client accepts servers certificate but server does not get the client cert
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM