SOAP客户端无法使用相互的tl进行身份验证



我有一个Apache CXF客户端,它正在连接SOAP服务,并使用双向TLS进行身份验证。客户端在TLS握手期间失败,因为服务向服务器发送了一个空的客户端证书列表。我正在用自签名证书测试这一点,我可以证明我的服务器可以处理curl请求和poster。我非常确信证书设置正确,并且我确信我在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

我用CCD_ 1为服务器和服务器设置了调试;客户。

当我使用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 repo中运行了ws安全性示例,并在该示例中使用了我的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

最后一个错误在使用演示应用程序时不存在,而是返回证书。

对于任何偶然发现这个问题的人,以下是我如何解决的。

一旦我开始使用CXF演示代码,我就能够将其简化为只有最少量的依赖项和配置。从那时起,我就能够发现这是我的项目中缺失的一个依赖性问题。

首先,我们使用dropwizard作为服务器,并且我们对dropwizardjaxws有一个依赖关系,它引入了cxf依赖关系。我通过删除所有层发现,只有当cxf-rt-transports-http-jetty在依赖项列表中时,演示应用程序才能工作。

dropwizardjaxws包括的可传递依赖项有:

cxf-rt-frontend-jaxws
cxf-rt-transports-http

我还依赖于我的客户端中的所有dropwizard核心,它可能已经实现了cxf-rt-transports-http-jetty实现的一些SPI接口(推测(。一旦我简化了依赖项并包含了一个缺失的依赖项,我就有了一个可重复的、有效的解决方案。

相关内容

最新更新