Java HTTPS客户端与Let’s Encrypt证书服务器通信失败问题解决
问题背景
我有一套基于Let’s Encrypt TLS/SSL证书的Java服务端与客户端程序,此前运行正常,但在2024年7月7日Let’s Encrypt颁发新证书后,客户端突然无法通信,报错:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
推测问题由Let’s Encrypt更新信任链导致,回滚至旧证书可恢复正常。尝试以下操作但未解决:
- 将Java从17升级至22
- 下载Let’s Encrypt的X1、R10中间证书,手动添加至JRE或客户端
- 从对应URL获取证书
Chrome可正常访问使用同证书的网站,且已验证Java 22的JRE信任库包含匹配Let’s Encrypt官网的最新证书,指纹如下:
9D7C3F1AA6AD2B2EC0D5CF1E246F8D9AE6CBC9FD0755AD37BB974B1F2FB603F3
34C44664C5257A38FFAFAC3A2130138FFE22CE972F3660C788FDA87FA0B670F3
96BCEC06264976F37460779ACF28C5A7CFE8A3C0AAE11A8FFCEE05C0BDDF08C6
密钥库中的相关证书信息:
$JAVA_HOME/bin/keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit: letsencrypt_r10, Jul 25, 2024, trustedCertEntry, Certificate fingerprint (SHA-256): 9D:7C:3F:1A:A6:AD:2B:2E:C0:D5:CF:1E:24:6F:8D:9A:E6:CB:C9:FD:07:55:AD:37:BB:97:4B:1F:2F:B6:03:F3 letsencryptisrgx1 [jdk], Jul 25, 2024, trustedCertEntry, Certificate fingerprint (SHA-256): 96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6 webpage-cert, Jul 25, 2024, trustedCertEntry, Certificate fingerprint (SHA-256): 34:C4:46:64:C5:25:7A:38:FF:AF:AC:3A:21:30:13:8F:FE:22:CE:97:2F:36:60:C7:88:FD:A8:7F:A0:B6:70:F3
经网站检测工具验证证书状态正常但信任链不完整,Python脚本也出现相同连接问题。
解决方法
排查发现PKCS12转换为JKS时丢失了根证书,需手动添加至JKS,步骤如下:
- 用Let’s Encrypt的fullchain.pem和privkey.pem生成PKCS12文件:
openssl pkcs12 -export -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -inkey /etc/letsencrypt/live/$DOMAIN/privkey.pem -out combined_keys.p12 -name $DOMAIN -passout pass:changeit
- 将PKCS12文件转换为JKS文件:
keytool -importkeystore -deststorepass changeit -destkeypass changeit -destkeystore $DOMAIN.jks -srckeystore combined_keys.p12 -srcstoretype PKCS12 -srcstorepass changeit -alias $DOMAIN
- 执行以下命令检查JKS文件是否缺少证书:
keytool -list -v -keystore $DOMAIN.jks -storepass changeit
- 拆分fullchain.pem为单个证书文件:
sudo cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem | awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > "/tmp/cert" n ".pem"}'
- 列出拆分后的证书文件:
ls /tmp/cert*.pem
- 通过以下命令识别每个拆分后证书的类型:
openssl x509 -in /tmp/FILE_NAME.pem -text -noout
- 导入缺失的根证书到JKS文件:
sudo keytool -import -trustcacerts -alias root -file /tmp/FILE_NAME.pem -keystore $DOMAIN.jks -storepass changeit
内容的提问来源于stack exchange,提问作者Max Doss
相关产品推荐
相关产品推荐

