Java OkHttpClient双向认证失败:无客户端证书问题排查
SSL双向认证Java迁移问题:无客户端证书导致认证失败
我正在将一段连接SSL双向认证远程Web服务的PHP代码迁移到Java。服务提供方已提供服务器证书、客户端证书及调用所需私钥。
已执行操作
- 生成信任库:
keytool -import -alias WS_SERVER -file WS_SERVER_CERT.pem -keystore truststore.jks -deststorepass somepassword - 生成客户端密钥库:先将证书转为PKCS12格式,再导入JKS密钥库:
openssl pkcs12 -export -in CLIENT_CERT.pem -inkey CLIENT_PK.pem -out certificate.p12 -name client_certificatekeytool -importkeystore -srckeystore certificate.p12 -srcstoretype pkcs12 -destkeystore cert.jks - 使用OkHttpClient编写连接代码:
SSLFactory sslFactory = SSLFactory.builder() .withIdentityMaterial(Path.of("src/main/resources/cert/cert.jks"), "somepassword".toCharArray()) .withTrustMaterial(Path.of("src/main/resources/cert/truststore.jks"), "somepassword".toCharArray()) .build(); OkHttpClient httpClient = new OkHttpClient.Builder() .sslSocketFactory(sslFactory.getSslSocketFactory(), sslFactory.getTrustManager().orElseThrow()) .hostnameVerifier(sslFactory.getHostnameVerifier()) .build(); final String payload = Files.readString(Path.of("src/test/resources/payload.xml")); String wsUrl = "https://server.ws"; final Request request = new Request.Builder() .url(wsUrl) .post(RequestBody.create(payload, MediaType.parse("text/xml"))) .build(); final Call call = httpClient.newCall(request); final Response response = call.execute(); System.out.println("Response: " + response.body().string());
问题现象
上述代码执行后出现认证错误,但使用curl命令可正常连接服务:
curl --cert CLIENT_CERT.pem --key CLIENT_CERT_PK.pem --cacert WS_SERVER_CERT.pem -H "Content-type: text/xml" https://server.ws -d 'some payload'
后续尝试
- 使用sslcontext-kickstart库直接加载PEM文件,仍失败:
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(Paths.get("src/main/resources/cert/CLIENT_CERT.pem"), Paths.get("src/main/resources/cert/CLIENT_PK.pem")); X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(Paths.get("src/main/resources/cert/SERVER_CERT.pem")); SSLFactory sslFactory = SSLFactory.builder() .withIdentityMaterial(keyManager) .withTrustMaterial(trustManager) .build(); ConnectionSpec requireTls12 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2) .build(); OkHttpClient httpClient = new OkHttpClient.Builder() .sslSocketFactory(sslFactory.getSslSocketFactory(), sslFactory.getTrustManager().orElseThrow()) .connectionSpecs(Arrays.asList(requireTls12)) .hostnameVerifier(sslFactory.getHostnameVerifier()) .build(); - 强制Java使用与curl相同的TLS1.3及加密套件,问题依旧;
- 开启
javax.net.debug=all调试,日志提示:No X.509 certificate for client authentication, use empty Certificate message instead,即Java未找到用于客户端认证的X.509证书,发送了空证书消息。
请问该流程中哪里出现问题?为何会出现无客户端证书的提示?
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

