title: Options for Programmatically Adding Certificates to Java KeyStore
body: <p>I was getting an SSL Handshake Exception error: PKIX "path does not chain" (<a href="https://stackoverflow.com/questions/23775155/pkix-path-does-not-chain-with-any-of-the-trust-anchors-error-in-windows-environm">described here</a>).
  I fixed it by importing a certificate chain using openssl:</p>
  
  <p><code>openssl s_client -host www.envmgr.com -port 443 -showcerts &gt; cert_chain.crt</code></p>
  
  <p>and installed it into my JDK's keystore:</p>
  
  <pre><code>keytool -import -alias envmgrchain -file cert_chain.crt -keystore cacerts -storepass changeit
  </code></pre>
  
  <p>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.</p>
  
  <p>I thought, "no problem, I'll just add this certificate chain to the keystore programmatically" so I removed it from my JVM:</p>
  
  <pre><code>keytool -delete -alias envmgrchain -keystore cacerts -storepass changeit
  </code></pre>
  
  <p>and added this code:</p>
  
  <pre><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()&gt;0) {
          Collection&lt;? extends Certificate&gt; certs = cf.generateCertificates(bis);
          Iterator&lt;? extends Certificate&gt; iter = certs.iterator();
          //Add each cert in the chain one at a time
          for(int i=0; i&lt;certs.size(); i++) {
              Certificate cert = iter.next();
              String alias = "chaincert"+((i&gt;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);
  </code></pre>
  
  <p>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.</p>
  
  <p>FYI: I am also attempting to address this issue by implementing an X509TrustManager.</p>