title: How can I use different certificates on specific connections?
body: <p>A module I'm adding to our large Java application has to converse with another company's SSL-secured website.  The problem is that the site uses a self-signed certificate.  I have a copy of the certificate to verify that I'm not encountering a man-in-the-middle attack, and I need to incorporate this certificate into our code in such a way that the connection to the server will be successful.</p>
  
  <p>Here's the basic code:</p>
  
  <pre><code>void sendRequest(String dataPacket) {
    String urlStr = "https://host.example.com/";
    URL url = new URL(urlStr);
    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    conn.setMethod("POST");
    conn.setRequestProperty("Content-Length", data.length());
    conn.setDoOutput(true);
    OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
    o.write(data);
    o.flush();
  }
  </code></pre>
  
  <p>Without any additional handling in place for the self-signed certificate, this dies at conn.getOutputStream() with the following exception:</p>
  
  <pre><code>Exception in thread "main" 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
  ....
  Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  ....
  Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  </code></pre>
  
  <p>Ideally, my code needs to teach Java to accept this one self-signed certificate, for this one spot in the application, and nowhere else.</p>
  
  <p>I know that I can import the certificate into the JRE's certificate authority store, and that will allow Java to accept it.  That's not an approach I want to take if I can help; it seems very invasive to do on all of our customer's machines for one module they may not use; it would affect all other Java applications using the same JRE, and I don't like that even though the odds of any other Java application ever accessing this site are nil.  It's also not a trivial operation: on UNIX I have to obtain access rights to modify the JRE in this way.</p>
  
  <p>I've also seen that I can create a TrustManager instance that does some custom checking.  It looks like I might even be able to create a TrustManager that delegates to the real TrustManager in all instances except this one certificate.  But it looks like that TrustManager gets installed globally, and I presume would affect all other connections from our application, and that doesn't smell quite right to me, either.</p>
  
  <p>What is the preferred, standard, or best way to set up a Java application to accept a self-signed certificate?  Can I accomplish all of the goals I have in mind above, or am I going to have to compromise?  Is there an option involving files and directories and configuration settings, and little-to-no code?</p>