Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Client authentication with HttpClient

Tags:

java

nginx

ssl

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?

like image 665
Igor Artamonov Avatar asked Oct 30 '22 10:10

Igor Artamonov


1 Answers

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.

like image 157
Igor Artamonov Avatar answered Nov 13 '22 04:11

Igor Artamonov