调用Webservice时RootCA与SubCA证书握手异常问题求助
问题解决:Webservice握手错误——导入子CA到JDK信任库后仍使用根证书的问题
问题背景
连接Webservice时出现握手错误:已将子CA证书(CN=Data License SubCA)导入JDK默认信任库,但Java代码调用时,发送给服务端的却是根证书(CN=DigiCert High Assurance EV Root),导致握手失败。仅将该子CA作为独立信任库时可正常工作,但需兼容JDK默认信任库中的其他证书。
已执行操作:
- 将提供商P12证书导出为CRT格式:
keytool -exportcert -keystore ~/local/ssl/XXCert.p12 -storetype PKCS12 -storepass ourpassword -alias 220220210652062728 -file /opt/ac/common/xxx/home/XXXCert2.crt
- 将CRT证书导入JDK默认信任库:
keytool -import -trustcacerts -alias 220220210652062728 -file /opt/ac/common/xx/home/XXXCert2.crt -keystore /opt/ac/common/xxx/local/java/jdk1.8.0_341/jre/lib/security/cacerts
服务器日志显示子CA已添加为信任证书,但请求时仍选择根证书触发错误,推测问题出在根CA与子CA的证书链匹配逻辑上。
解决步骤
1. 确认子CA证书的链完整性
先验证导出的子CA证书是否正确关联根CA:
keytool -printcert -file /opt/ac/common/xxx/home/XXXCert2.crt
检查输出中的Issuer字段是否为CN=DigiCert High Assurance EV Root,确保子CA确实由目标根CA签发。
2. 重新导入子CA证书(避免冲突)
先删除原有导入的同名证书,再用更清晰的别名重新导入,确保信任链关联正确:
# 删除原有证书 keytool -delete -alias 220220210652062728 -keystore /opt/ac/common/xxx/local/java/jdk1.8.0_341/jre/lib/security/cacerts -storepass changeit # 重新导入子CA,使用有意义的别名 keytool -import -trustcacerts -alias data-license-subca -file /opt/ac/common/xxx/home/XXXCert2.crt -keystore /opt/ac/common/xxx/local/java/jdk1.8.0_341/jre/lib/security/cacerts -storepass changeit
3. 代码层面强制指定子CA证书(兼容默认信任库)
如果JDK自动选择证书链的逻辑仍有问题,可在调用该Webservice时,单独指定子CA作为信任源,同时保留默认信任库的其他证书:
import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import com.sun.xml.ws.developer.JAXWSProperties; import javax.xml.ws.BindingProvider; // 加载子CA证书 CertificateFactory cf = CertificateFactory.getInstance("X.509"); FileInputStream in = new FileInputStream("/opt/ac/common/xxx/home/XXXCert2.crt"); X509Certificate subCaCert = (X509Certificate) cf.generateCertificate(in); in.close(); // 创建包含子CA的临时信任库,同时保留默认信任库 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); trustStore.setCertificateEntry("data-license-subca", subCaCert); // 初始化信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); // 创建自定义SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); // 绑定到Webservice客户端(以JAX-WS为例) YourWebservicePortType webservicePort = new YourWebserviceService().getYourWebservicePort(); ((BindingProvider) webservicePort).getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, sslContext.getSocketFactory());
4. 启用SSL调试日志排查细节
若问题仍存在,添加JVM启动参数开启SSL调试,查看证书链选择过程:
-Djavax.net.debug=ssl:handshake:verbose
重点查看日志中Certificate chain相关输出,确认Java发送的证书链是否符合服务端要求,以及服务端返回的信任链验证逻辑。
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

