使用HttpClient进行客户端身份验证

5

尝试实现客户端密钥认证(使用自签名的 CA)。

代码如下:

KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("client.p12"), "changeit".toCharArray())

SSLContext sslcontext = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustSelfSignedStrategy()) //DONT DO THAT, IT'S JUST TO SIMPLIFY THIS EXAMPLE. USE REAL TrustStore WITH REAL SERVER CERTIFICATE IMPORTED. DONT TRUST SELF SIGNED
            .loadKeyMaterial(keyStore, "changeit".toCharArray())
            .build();
socketFactory = new SSLConnectionSocketFactory(
            sslcontext,
            new String[] {"TLSv1.2", "TLSv1.1"},
            null,
            new NoopHostnameVerifier()
);
HttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(socketFactory)
            .build();

使用-Djavax.net.debug=all,我可以看到它正确选择了我的证书,我看到了签名、证书请求和ECDHClientKeyExchange等内容,一切看起来都很好。

但是无论如何,我仍然从Nginx获得以下响应(状态码为400):

<head><title>400 The SSL certificate error</title></head>

请注意,对于不正确的证书/密钥,nginx通常会丢弃会话,而不在明文响应中提供任何详细信息。
这个client.p12可以通过命令行工作,例如:
$ curl -ivk --cert client.p12:changeit https://192.168.1.1


* Rebuilt URL to: https://192.168.1.1/
*   Trying 192.168.1.1...
* Connected to 192.168.1.1 (192.168.1.1) port 443 (#0)
* WARNING: SSL: Certificate type not set, assuming PKCS#12 format.
* Client certificate: client-es.certs.my
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
* Server certificate: server.certs.my
* Server certificate: ca.my
> GET / HTTP/1.1
> Host: 192.168.1.1
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK

所以这个密钥肯定是有效的。但为什么它在Java中不起作用?我在Java SSL配置中是否有遗漏?


你的证书已导入到密钥库中了吗? - STaefi
它直接从 client.p12 加载。我也尝试将其导入到密钥库中,但这并没有改变任何东西。 - Igor Artamonov
1个回答

2
问题在于我的客户端密钥中还包括签名证书链。不仅包括我的客户端证书(用于身份验证),而且还包括整个证书链(当然没有私钥,只有证书)。
具体来说:
> Root CA cert -> Client CA cert -> Client key + cert

我猜Java在这种情况下使用了错误的证书,可能是CA或中间证书。

通过仅添加客户端的密钥和证书而不包含中间证书来解决问题。将其添加到p12keychain中即可。

不应该-certfile选项(我之前有过)。只需客户端密钥/证书。正确的导出命令是:

openssl pkcs12 -export \
    -in client.crt -inkey client.key \
    -out client.p12

然后,这个 client.p12 文件可以导入到钥匙串中:

keytool -importkeystore \
    -deststorepass changeit -destkeystore keystore \
    -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass changeit

并且适用于自定义身份验证,运行良好。


我认为这与NGINX有关。我们有一个F5和一个NGINX。我们只需要对NGINX进行更改以进行通信。我想学习可以对NGINX进行哪些更改来修复它,而不是更改我的证书。 - Daniel Kaplan

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