Trying to implement client key authentication (with self signed ca).
Code looks like:
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("client.p12"), "changeit".toCharArray())
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy()) //DONT DO THAT, IT'S JUST TO SIMPLIFY THIS EXAMPLE. USE REAL TrustStore WITH REAL SERVER CERTIFICATE IMPORTED. DONT TRUST SELF SIGNED
.loadKeyMaterial(keyStore, "changeit".toCharArray())
.build();
socketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[] {"TLSv1.2", "TLSv1.1"},
null,
new NoopHostnameVerifier()
);
HttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
With -Djavax.net.debug=all
I can see it correctly chooses my certificate, i see signatures, I see certificate request, and there ECDHClientKeyExchange, etc, all looks fine.
But anyway I'm getting following response from Nginx (with status 400):
<head><title>400 The SSL certificate error</title></head>
Notice, that for incorrect certificate/key nginx usually drops session, w/o providing any details in plain text response.
This client.p12
works from command line, like:
$ curl -ivk --cert client.p12:changeit https://192.168.1.1
* Rebuilt URL to: https://192.168.1.1/
* Trying 192.168.1.1...
* Connected to 192.168.1.1 (192.168.1.1) port 443 (#0)
* WARNING: SSL: Certificate type not set, assuming PKCS#12 format.
* Client certificate: client-es.certs.my
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
* Server certificate: server.certs.my
* Server certificate: ca.my
> GET / HTTP/1.1
> Host: 192.168.1.1
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
So this key is definitely valid. But why it doesn't work for Java? Is there're anything i've missed in java ssl config?
The problem was that my client key was also including signing certificates in key chain. Not only my client certificate (which is required for authentication), but whole chain of certificates (without keys of course, just certificates)
It was:
> Root CA cert -> Client CA cert -> Client key + cert
I guess Java uses a wrong certificate at this case, maybe CA or intermediate certificate.
Fixed by adding to p12
or keychain
only client's key and certificate, without intermediates.
It should not have -certfile
options (which I had before). Just client key/cert. Correct export command is:
openssl pkcs12 -export \
-in client.crt -inkey client.key \
-out client.p12
This client.p12
then could be imported into keychain:
keytool -importkeystore \
-deststorepass changeit -destkeystore keystore \
-srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass changeit
And worked fine for custom authentication.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With