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:
Created a file
req.conf
for configuration[req] prompt=no distinguished_name = req_distinguished_name [ req_distinguished_name ] O=selfSignedO CN=selfSignedCn DC=selfSignedDc
Generated server private key and the self-signed certificate
openssl req \ -config req.conf \ -x509 \ -newkey rsa:4096 \ -keyout server/server-private-key.pem \ -out server/server.crt \ -days 3650 \ -nodes
Created PKCS12 keystore containing the private key and certificate created in the previous step
openssl pkcs12 \ -export \ -out server/server-key-store.p12 \ -inkey server/server-private-key.pem \ -in server/server.crt
let's say the password I used was
123456
Generated a client private key and a certificate signing request
openssl req \ -config req.conf \ -new \ -newkey rsa:4096 \ -out client/client-request.csr \ -keyout client/client-private-key.pem \ -nodes
Signed the client's certificate signing request with the server's private key and certificate
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
Created a PKCS12 keystore containing the client's private key and certificate certificate created in the previous step.
openssl pkcs12 \ -export \ -out client/client-keystore.p12 \ -inkey client/client-private-key.pem \ -in client/client-signed-cert.crt \ -certfile server/server.crt
we used
123456
as password again.Generated server trust store containing the client signed certificate
keytool \ -import \ -trustcacerts \ -alias root \ -file client/client-signed-cert.crt \ -keystore server/server-trust-store.jks
password?
123456
Curl is working, but only with
-k
curl -k \ --cert client/client-signed-cert.crt \ --key client/client-private-key.pem \ https://localhost:443:/my/endpoint
without the
-k
I get the error: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.
Configured Apache HTTPClient:
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(); }
(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.)
but when trying to send the same request as with Curl I'm getting:
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)