我收到了SSL握手异常错误:PKIX"路径不链"(此处描述).我通过使用openssl导入证书链来修复它:
openssl s_client -host www.envmgr.com -port 443 -showcerts > cert_chain.crt
并将其安装到我的JDK密钥库中:
keytool -import -alias envmgrchain -file cert_chain.crt -keystore cacerts -storepass changeit
这很有效.万岁.问题是我们将把我们的应用程序放在像rackspace或AWS这样的云服务器上,我认为我们很有可能无法修改JVM的密钥库来添加这个链.
我想,"没问题,我只是以编程方式将此证书链添加到密钥库"所以我将其从JVM中删除:
keytool -delete -alias envmgrchain -keystore cacerts -storepass changeit
并添加了此代码:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); //Create an empty keystore that we can load certificate into trustStore.load(null); InputStream fis = new FileInputStream("cert_chain.crt"); BufferedInputStream bis = new BufferedInputStream(fis); CertificateFactory cf = CertificateFactory.getInstance("X.509"); while(bis.available()>0) { Collection extends Certificate> certs = cf.generateCertificates(bis); Iterator extends Certificate> iter = certs.iterator(); //Add each cert in the chain one at a time for(int i=0; i0)?i:""); trustStore.setCertificateEntry(alias, cert); } } bis.close(); fis.close(); //Add custom keystore to TrustManager TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); SSLContext ctx = SSLContext.getInstance("TLSv1"); ctx.init(null, tmf.getTrustManagers(), null);
但是当我运行它时,PKIX错误再次出现.上面的代码不等同于keytool -import吗?我觉得我要么错误地向KeyStore添加证书,要么我没有以正确的方式将Keystore安装到TrustManager中.
仅供参考:我也试图通过实施X509TrustManager来解决这个问题.
这是您可以使用的代码,以便客户端在运行时以编程方式添加CA. 您无需将其放在任何商店中 - 只需随身携带PEM编码文件即可.您甚至可以将其硬编码到您的程序中,因此无需管理单独的文件.
static String CA_FILE = "ca-cert.pem"; ... FileInputStream fis = new FileInputStream(CA_FILE); X509Certificate ca = (X509Certificate) CertificateFactory.getInstance("X.509") .generateCertificate(new BufferedInputStream(fis)); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(null, null); ks.setCertificateEntry(Integer.toString(1), ca); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); ...
您需要一个受信任的分发渠道,以确保您的程序在坐在等待挑选的服务器上或在安装时沿着网络传输时不会被修改.
openssl s_client -host www.envmgr.com -port 443 -showcerts> cert_chain.crt
您应该只需要信任根证书,而不是整个链.服务器负责发送构建链所需的所有中间证书.如果服务器未发送构建链所需的所有中间证书,则服务器配置错误.
您遇到的问题称为"哪个目录"问题.它是PKI中众所周知的问题.从本质上讲,这意味着客户端不知道从哪里获取缺少的中间证书.您可以通过让服务器发送所有必需的中间产品以及服务器的证书来解决它.请参阅OWASP的TLS备忘单和规则 - 始终提供所有需要的证书.
只是自行车脱落,但是Java中有一整套蠕虫(特别是Java 7及更低版本):
SSLContext ctx = SSLContext.getInstance("TLSv1"); ctx.init(null, tmf.getTrustManagers(), null);
如果需要,您可以改进它.见SSLSocketFactoryEx
在哪个密码套件启用SSL套接字?.它弥补了Java中默认提供的协议版本,密码套件等方面的一些空白SSLSocketFactory
.