title: Handshake failure with Java when I try to do a POST
body: <p>I try to contact *** and send some data using POST.</p>
  
  <p>I use jersey-bundle-1.18.jar which I have imported into my Eclipse project. This is my code:</p>
  
  <pre><code>    Client client = Client.create();
      WebResource webResource = client.resource("https://somesite.com");
      MultivaluedMap&lt;String, String&gt; map = new MultivaluedMapImpl();
      map.putSingle("key_name", API_KEY_NAME);
      map.putSingle("key_value", API_KEY_VALUE);
      map.putSingle("message", "Test");
      map.putSingle("extension", "+0012345678");
      ClientResponse response = webResource.type("application/x-www-form-urlencoded")
                   .post(ClientResponse.class, map); // throws exception here
      return response.toString();
  </code></pre>
  
  <p>When I run my code I get javax.net.ssl.SSLHandshakeException. The certificate used by the site is from StartCom, and I don't think this CA is in Java's default truststore, at not least in Java 6, according to <a href="https://stackoverflow.com/a/7220130/1938742">this poster</a></p>
  
  <p>I ran my program with the JVM flag -Djavax.net.debug=all and this is what I got:</p>
  
  <pre><code>trigger seeding of SecureRandom
  done seeding SecureRandom
  Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
  Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
  Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
  Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
  Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
  Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
  Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
  Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
  Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
  Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
  Allow unsafe renegotiation: false
  Allow legacy hello messages: true
  Is initial handshake: true
  Is secure renegotiation: false
  main, setSoTimeout(0) called
  %% No cached client session
  *** ClientHello, TLSv1
  RandomCookie:  GMT: 1391505439 bytes = { 186, 52, 225, 5, 67, 137, 170, 128, 220, 41, 178, 86, 199, 17, 150, 190, 23, 47, 217, 126, 162, 34, 68, 40, 216, 221, 193, 108 }
  Session ID:  {}
  Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
  Compression Methods:  { 0 }
  Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
  Extension ec_point_formats, formats: [uncompressed]
  Extension server_name, server_name: [host_name: ***]
  ***
  [write] MD5 and SHA1 hashes:  len = 176
  0000: 01 00 00 AC 03 01 53 F1   B0 1F BA 34 E1 05 43 89  ......S....4..C.
  0010: AA 80 DC 29 B2 56 C7 11   96 BE 17 2F D9 7E A2 22  ...).V...../..."
  0020: 44 28 D8 DD C1 6C 00 00   2A C0 09 C0 13 00 2F C0  D(...l..*...../.
  0030: 04 C0 0E 00 33 00 32 C0   07 C0 11 00 05 C0 02 C0  ....3.2.........
  0040: 0C C0 08 C0 12 00 0A C0   03 C0 0D 00 16 00 13 00  ................
  0050: 04 00 FF 01 00 00 59 00   0A 00 34 00 32 00 17 00  ......Y...4.2...
  0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
  0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
  0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
  main, WRITE: TLSv1 Handshake, length = 176
  [Raw write]: length = 181
  0000: 16 03 01 00 B0 01 00 00   AC 03 01 53 F1 B0 1F BA  ...........S....
  0010: 34 E1 05 43 89 AA 80 DC   29 B2 56 C7 11 96 BE 17  4..C....).V.....
  0020: 2F D9 7E A2 22 44 28 D8   DD C1 6C 00 00 2A C0 09  /..."D(...l..*..
  0030: C0 13 00 2F C0 04 C0 0E   00 33 00 32 C0 07 C0 11  .../.....3.2....
  0040: 00 05 C0 02 C0 0C C0 08   C0 12 00 0A C0 03 C0 0D  ................
  0050: 00 16 00 13 00 04 00 FF   01 00 00 59 00 0A 00 34  ...........Y...4
  0060: 00 32 00 17 00 01 00 03   00 13 00 15 00 06 00 07  .2..............
  0070: 00 09 00 0A 00 18 00 0B   00 0C 00 19 00 0D 00 0E  ................
  0080: 00 0F 00 10 00 11 00 02   00 12 00 04 00 05 00 14  ................
  0090: 00 08 00 16 00 0B 00 02   01 00 00 00 00 17 00 15  ................
  [Raw read]: length = 5
  0000: 15 03 01 00 02                                     .....
  [Raw read]: length = 2
  0000: 02 28                                              .(
  main, READ: TLSv1 Alert, length = 2
  main, RECV TLSv1 ALERT:  fatal, handshake_failure
  main, called closeSocket()
  main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
  main, called close()
  main, called closeInternal(true)
  Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
  </code></pre>
  
  <p>What's wrong, and how can I make it work?</p>
  
  <p>EDIT: As mentioned below, I downloaded Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files, but for Java 7, since this is the version of Java I'm using and copied the jar files to /lib/security as per instructions.</p>
  
  <p>I ran the program again, and got stuck at another exception. I've copied a couple of rows from the Eclipse console:</p>
  
  <blockquote>
    <p>%% Invalidated:  [Session-1, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] main,
    SEND TLSv1 ALERT:  fatal, description = certificate_unknown main,
    WRITE: TLSv1 Alert, length = 2 [Raw write]: length = 7 0000: 15 03 01
    00 02 02 2E                               ....... main, called
    closeSocket() main, handling exception:
    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</p>
  </blockquote>
  
  <p>This time, it seems like the StartCom certificate in Java's truststore is missing at last. I'm sure it's possible to overcome this problem, but since I consider to deploy my code into a jar file that can be used by other people, I don't think it's a feasible solution to let people replace their JCE Policy files in order to use my library.</p>
  
  <p>I was a bit nonplussed when I first encountered this error because I had actually executed about the same code before with successful results, but when I think about it, I used OpenJDK and not Oracle's proprietary JDK. When I used OpenJDK I didn't had the encryption problem either. So, it seems like I've two bad choices here:</p>
  
  <p>1). Force users to switch their Java Development Kit to OpenJDK, or my service/library won't work.</p>
  
  <p>2). Force users to replace the JCE Policy files of their JRE and import the StartCom certificate into Java's keystore, e.g using keytool, or maybe I could load the certificate during runtime?</p>
  
  <p>Is this somewhat correct?</p>
  
  <p>EDIT2:</p>
  
  <p>Here's how I created my own truststore with the certificates available at <a href="http://www.startssl.com/certs/ca-bundle.crt" rel="nofollow noreferrer">http://www.startssl.com/certs/ca-bundle.crt</a></p>
  
  <pre><code>try {
      // Read the certificate bundle from disk
      CertificateFactory cf = CertificateFactory.getInstance("X.509");
      Certificate ca = cf.generateCertificate(getClass().getResourceAsStream("ca-bundle.crt")); // the file ca-bundle.crt should be in the same folder as your .java files
      // Create a KeyStore containing our trusted CAs
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null, null);
      keyStore.setCertificateEntry("ca", ca);
      // Create a TrustStore that trusts the CAs in our KeyStore
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      tmf.init(keyStore);
      // Create an SSLContext that uses our TrustManager
      sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, tmf.getTrustManagers(), null);
  } catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
          e.printStackTrace();
  }
  </code></pre>
  
  <p>It's now possible to communicate with the server securely. You can create a <a href="http://hc.apache.org/downloads.cgi" rel="nofollow noreferrer">HttpClient</a> with your custom SSLContext like this:</p>
  
  <pre><code>CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();
  </code></pre>