title: Client server authentication with self signed certificate - Curl is working but Apache HttpClient throws exception
body: <p>I'm trying to implement client and server authentication with Apache HTTPClient,
  and to test it with a self signed certificate.
  I've tried to follow several tutorials and answers to similar questions here but
  with no success. I've tried to detail as much as possible all the steps that I've
  been doing, hopefully someone can point out what I'm doing wrong:</p>
  
  <ol>
  <li><p>Created a file <code>req.conf</code> for configuration</p>
  
  <pre><code>[req]
  prompt=no
  distinguished_name = req_distinguished_name
  
  [ req_distinguished_name ]
  O=selfSignedO
  CN=selfSignedCn
  DC=selfSignedDc
  </code></pre></li>
  <li><p>Generated server private key and the self-signed certificate</p>
  
  <pre><code>openssl req \
   -config req.conf \
   -x509 \
   -newkey rsa:4096 \
   -keyout server/server-private-key.pem \
   -out server/server.crt \
   -days 3650 \
   -nodes 
  </code></pre></li>
  <li><p>Created PKCS12 keystore containing the private key and certificate created in the previous step</p>
  
  <pre class="lang-sh prettyprint-override"><code> openssl pkcs12 \
   -export \
   -out server/server-key-store.p12 \
   -inkey server/server-private-key.pem \
   -in server/server.crt
  </code></pre>
  
  <p>let's say the password I used was <code>123456</code></p></li>
  <li><p>Generated a client private key and a certificate signing request</p>
  
  <pre class="lang-sh prettyprint-override"><code>openssl req \
   -config req.conf \
   -new \
   -newkey rsa:4096 \
   -out client/client-request.csr \
   -keyout client/client-private-key.pem \
   -nodes
  </code></pre></li>
  <li><p>Signed the client's certificate signing request with the server's private key 
  and certificate</p>
  
  <pre class="lang-sh prettyprint-override"><code>openssl x509 \
   -req \
   -days 360 \
   -in client/client-request.csr \
   -CA server/server.crt \
   -CAkey server/server-private-key.pem \
   -CAcreateserial \
   -out client/client-signed-cert.crt \
   -sha256
  </code></pre></li>
  <li><p>Created a PKCS12 keystore containing the client's private key and certificate certificate created in the previous step.</p>
  
  <pre class="lang-sh prettyprint-override"><code> openssl pkcs12 \
    -export \
    -out client/client-keystore.p12 \
    -inkey client/client-private-key.pem \
    -in client/client-signed-cert.crt \
    -certfile server/server.crt
  </code></pre>
  
  <p>we used <code>123456</code> as password again.</p></li>
  <li><p>Generated server trust store containing the client signed certificate</p>
  
  <pre class="lang-sh prettyprint-override"><code>keytool \
   -import \
   -trustcacerts \
   -alias root \
   -file client/client-signed-cert.crt \
   -keystore server/server-trust-store.jks
  </code></pre>
  
  <p>password? <code>123456</code></p></li>
  <li><p>Curl is working, but only with <code>-k</code></p>
  
  <pre class="lang-sh prettyprint-override"><code>curl -k \
     --cert client/client-signed-cert.crt \
     --key client/client-private-key.pem \
     https://localhost:443:/my/endpoint
  </code></pre>
  
  <p>without the <code>-k</code> I get the error:</p>
  
  <pre class="lang-sh prettyprint-override"><code>curl: (60) SSL certificate problem: self signed certificate
  More details here: https://curl.haxx.se/docs/sslcerts.html
  
  curl performs SSL certificate verification by default, using a "bundle"
   of Certificate Authority (CA) public keys (CA certs). If the default
   bundle file isn't adequate, you can specify an alternate file
   using the --cacert option.
  If this HTTPS server uses a certificate signed by a CA represented in
   the bundle, the certificate verification probably failed due to a
   problem with the certificate (it might be expired, or the name might
   not match the domain name in the URL).
  If you'd like to turn off curl's verification of the certificate, use
   the -k (or --insecure) option.
  HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.
  </code></pre></li>
  <li><p>Configured Apache HTTPClient:</p>
  
  <pre class="lang-java prettyprint-override"><code>private HttpClient createClient() throws Exception {
      String keyPassword = "123456";
      KeyStore ks = KeyStore.getInstance("PKCS12");
      ks.load(resourceAsStream("/client/client-key-store.p12"), keyPassword.toCharArray());
      SSLContext sslContext = new SSLContextBuilder()
          .setProtocol("TLSv1.2")
          .loadKeyMaterial(ks, keyPassword.toCharArray())
          .loadTrustMaterial(null, new TrustSelfSignedStrategy())
          .build()
      return HttpClients.custom()
              .setSSLContext(sslContext)
              .setSSLHostnameVerifier(new NoopHostnameVerifier())
              .build();
  }
  </code></pre>
  
  <p>(The construction is done via multiple methods that I squeezed here to one, so if something is weird or missing please let me know, perhaps I miscopy-pasted something.)    </p></li>
  </ol>
  
  <p>but when trying to send the same request as with Curl I'm getting:</p>
  
  <pre><code>Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
      at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2038)
      at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135)
      at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1779)
      at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124)
      at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1156)
      at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1266)
      at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1178)
      at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348)
      at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
      at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
      at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
      at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
      at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
      at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
      at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
      at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
      at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
      at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
      at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:394)
      at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
      at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
      at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
      at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
      at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
      at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
      at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
      at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
  </code></pre>