I was getting an SSL Handshake Exception error: PKIX "path does not chain" (described here). I fixed it by importing a certificate chain using openssl:
openssl s_client -host www.envmgr.com -port 443 -showcerts > cert_chain.crt
and installed it into my JDK's keystore:
keytool -import -alias envmgrchain -file cert_chain.crt -keystore cacerts -storepass changeit
Well this works. Hooray. The problem is we'll be putting our application up on a cloud server like rackspace or AWS and I think there is a good chance that we won't have access to modify the keystore of the JVM to add this chain.
I thought, "no problem, I'll just add this certificate chain to the keystore programmatically" so I removed it from my JVM:
keytool -delete -alias envmgrchain -keystore cacerts -storepass changeit
and added this code:
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; i<certs.size(); i++) {
Certificate cert = iter.next();
String alias = "chaincert"+((i>0)?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);
But when I run it, the PKIX error reappears. Is the above code not equivalent to keytool -import? I feel like I'm either adding certificates to the KeyStore incorrectly, or I'm not installing the Keystore into the TrustManager in the right way.
FYI: I am also attempting to address this issue by implementing an X509TrustManager.