0x00 绪言
通过 java 执行 https 请求时可能出现以下错误:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这是因为 java 在执行 SSL/TLS 通讯时使用特定的数据识别 Certificate Authorities(CA),如果你试图发起的 SSL/TLS 连接使用不属于这些根证书机构所颁发的证书,就会抛出
SunCertPathBuilderException: unable to find valid certification path to requested target
因此,如果你使用自签名证书,或者根证书机构不在 JRE 默认信任列表中,则需要向 JRE 导入根证书。
最近我们有个项目使用了沃通的免费 SSL 证书,因其根证书属于 StartSSL 并不在 JRE 默认信任列表中,因此简单记录下导入过程。
0x01 导入根证书到 JRE
首先,我们需要获取根证书:
mkdir ~/tmp
cd ~/tmp
curl http://www.startssl.com/certs/ca.crt -O
curl http://www.startssl.com/certs/sub.class1.server.ca.crt -O
curl http://www.startssl.com/certs/sub.class2.server.ca.crt -O
curl http://www.startssl.com/certs/sub.class3.server.ca.crt -O
curl http://www.startssl.com/certs/sub.class4.server.ca.crt -O
然后,将证书导入到 JRE 信任列表:
sudo keytool -import -trustcacerts -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -noprompt -alias startcom.ca -file ca.crt
sudo keytool -import -trustcacerts -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -noprompt -alias startcom.ca.sub.class1 -file sub.class1.server.ca.crt
sudo keytool -import -trustcacerts -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -noprompt -alias startcom.ca.sub.class2 -file sub.class2.server.ca.crt
sudo keytool -import -trustcacerts -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -noprompt -alias startcom.ca.sub.class3 -file sub.class3.server.ca.crt
sudo keytool -import -trustcacerts -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -noprompt -alias startcom.ca.sub.class4 -file sub.class4.server.ca.crt
别奇怪,"changeit" 只是个默认密码而已。
最后,验证一下导入是否成功:
keytool -keystore "/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/security/cacerts" -storepass changeit -list | grep start
输出:
startcom.ca, 2015-11-3, trustedCertEntry,
startcom.ca.sub.class4, 2015-11-3, trustedCertEntry,
startcom.ca.sub.class3, 2015-11-3, trustedCertEntry,
startcom.ca.sub.class2, 2015-11-3, trustedCertEntry,
startcom.ca.sub.class1, 2015-11-3, trustedCertEntry,
It's OK!