Client Authentication Using HttpClient

An attempt to implement client key authentication (with ca self-subscription).

The code looks like this:

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 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 see that it selects my certificate correctly, I see the signatures, I see the certificate request, and there ECDHClientKeyExchange, etc. everything looks fine.

But anyway, I get the following response from Nginx (with status 400):

 <head><title>400 The SSL certificate error</title></head> 

Note that for an invalid certificate / key, nginx usually disconnects the session without providing any details in the text response.

This client.p12 works from the command line, for example:

 $ 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 does this not work for Java? Is there something I missed in java ssl config?

+5
source share
1 answer

The problem was that my client key also included signing the certificates in the key chain. Not only my client certificate (which is required for authentication), but a whole chain of certificates (without keys, of course, only certificates)

It was:

 > Root CA cert -> Client CA cert -> Client key + cert 

I assume that Java uses the wrong certificate in this case, perhaps a CA or an intermediate certificate.

Fixed by adding in p12 or keychain only the client key and certificate without intermediate products.

It should not have the -certfile options (which I had before). Only client key / certificate. The correct export command:

 openssl pkcs12 -export \ -in client.crt -inkey client.key \ -out client.p12 

This client.p12 can then be imported into the keychain:

 keytool -importkeystore \ -deststorepass changeit -destkeystore keystore \ -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass changeit 

And it worked great for user authentication.

+2
source

Source: https://habr.com/ru/post/1242433/


All Articles