我有一个 Apache CXF 客户端,它连接 SOAP 服务,并使用双向 TLS 进行身份验证。客户端在 TLS 握手期间失败,因为服务向服务器发送了一个空的客户端证书列表。我正在使用自签名证书对此进行测试,并且可以证明我的服务器可以使用 curl 请求和邮递员。我很确定证书设置正确,并且我确定我缺少 CXF 客户端中的配置步骤。
这是我的客户端设置方式
// setting up certs & keystores
String keystore = "client-keystore.jks";
String keystorePassword = "changeit"; // local self-signed certs
String trustStore = "truststore.jks";
String trustStorePassword = "changeit"; // local self-signed certs
// client keystore
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keystore), keystorePassword.toCharArray());
// ca truststore
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream(trustStore), trustStorePassword.toCharArray());
// key managers
var kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keystorePassword.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
// trust managers
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
TrustManager[] tms = tmf.getTrustManagers();
TLSClientParameters param = new TLSClientParameters();
param.setSecureSocketProtocol("TLSv1.2");
param.setDisableCNCheck(false);
param.setTrustManagers(tms);
param.setKeyManagers(kms);
// Get the client & setup the tls parameters
BindingProvider bp = (BindingProvider) port;
var client = ClientProxy.getClient(bp);
HTTPConduit https = (HTTPConduit)client.getConduit();
https.setTlsClientParameters(param);
这是我创建证书的方式。我的 java 版本是 azul zulu openjdk 11。
# Create the CA Authority that both the client and server can trust
openssl req -new -x509 -nodes -days 365 -subj '/CN=my-ca' -keyout ca.key -out ca.crt
# Create the server's key, certificate signing request, and certificate
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj '/CN=localhost' -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -out server.crt
# Create the client's key, certificate signing request, and certificate
openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj '/CN=my-client' -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -out client.crt
openssl x509 --in client.crt -text --noout
# Create the root truststore
keytool -import -alias my-ca -file ca.crt -keystore truststore.jks
# Create pkcs12 file for key and cert chain
openssl pkcs12 -export -name server-tls -in server.crt -inkey server.key -out server.p12
# Create JKS for server
keytool -importkeystore -destkeystore server-keystore.jks -srckeystore server.p12 -srcstoretype pkcs12 -alias server-tls
# Create pkcs12 file for key and cert chain
openssl pkcs12 -export -name client-tls -in client.crt -inkey client.key -out client.p12
# Create JKS for client
keytool -importkeystore -destkeystore client-keystore.jks -srckeystore client.p12 -srcstoretype pkcs12 -alias client-tls
-Djavax.net.debug=ssl,handshake,data
我为服务器和客户端设置了调试。
当我使用 CXF 客户端向服务器发出请求时,它会启动相互 tls 握手,但服务器失败Fatal (BAD_CERTIFICATE): Empty server certificate chain
,客户端失败Fatal (HANDSHAKE_FAILURE): Couldn't kickstart handshaking...readHandshakeRecord
,因为它确实事先发送了一个空证书列表。
Produced client Certificate handshake message (
"Certificates": <empty list>
)
我尝试了许多不同的东西,但我似乎无法让客户工作。
更新 出于好奇,我从 CXF 存储库运行了ws-security 示例,并在示例中使用了我的 ca 证书、客户端和服务器证书。那行得通,它是通过 xml bean 配置的。我在本地尝试了同样的事情,但仍然失败。
演示和我的客户端之间的区别在于,当它查找 x.509 RSA 证书时,它对我的客户端失败,但在演示应用程序中成功。我的配置基本相同。
javax.net.ssl|ALL|01|main|2021-07-02 14:17:32.039 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|01|main|2021-07-02 14:17:32.040 EDT|CertificateMessage.java:1066|Unavailable authentication scheme: ecdsa_secp256r1_sha256
javax.net.ssl|ALL|01|main|2021-07-02 14:17:32.040 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|01|main|2021-07-02 14:17:32.040 EDT|CertificateMessage.java:1066|Unavailable authentication scheme: ecdsa_secp384r1_sha384
javax.net.ssl|ALL|01|main|2021-07-02 14:17:32.040 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|01|main|2021-07-02 14:17:32.040 EDT|CertificateMessage.java:1066|Unavailable authentication scheme: ecdsa_secp521r1_sha512
javax.net.ssl|ALL|01|main|2021-07-02 14:17:32.040 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|01|main|2021-07-02 14:17:32.040 EDT|CertificateMessage.java:1066|Unavailable authentication scheme: rsa_pss_rsae_sha256
使用演示应用程序时不存在最后一个错误,而是返回证书。