Gangmax Blog

How to Use SSL Client Certificate with Apache HttpClient

In some case, the HTTPS server side requires the client side provides certificate. Here is the method how to make the client sends the client certificate to the server side when sending requrest with the Apache HttpClient library in Java.

Basically we need 2 steps:

  1. Convert the “pem” certificate file into the Java “keystore” format file.

  2. Write Java code to use the “keystore” file when connecting the HTTPS server.

Please check the details below.


1. Convert pem to jks

From here.

1
2
3
4
5
6
7
8
9
10
# Generate a pem file example(just for demo usage).
# Then concatenate the "key.pem" and "cert.pem" files into the "target.pem" file.
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
# Convert the pem format into the pkcs12 format.
openssl pkcs12 -export -out target.pkcs12 -in target.pem
# Create an empty keystore file.
keytool -genkey -keyalg RSA -alias manifest -keystore keystore.jks
keytool -delete -alias manifest -keystore keystore.jks
# Import the pkcs12 cert into the keystore file.
keytool -v -importkeystore -srckeystore target.pkcs12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS

2. Use the keystore file in code

From here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class MyClientCertTest {

private static final String KEYSTOREPATH = "/clientkeystore.jks"; // or .p12
private static final String KEYSTOREPASS = "keystorepass";
private static final String KEYPASS = "keypass";

KeyStore readStore() throws Exception {
try (InputStream keyStoreStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) {
KeyStore keyStore = KeyStore.getInstance("JKS"); // or "PKCS12"
keyStore.load(keyStoreStream, KEYSTOREPASS.toCharArray());
return keyStore;
}
}
@Test
public void readKeyStore() throws Exception {
assertNotNull(readStore());
}
@Test
public void performClientRequest() throws Exception {
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(readStore(), KEYPASS.toCharArray()) // use null as second param if you don't have a separate key password
.build();

HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
HttpResponse response = httpClient.execute(new HttpGet("https://slsh.iki.fi/client-certificate/protected/"));
assertEquals(200, response.getStatusLine().getStatusCode());
HttpEntity entity = response.getEntity();

System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
EntityUtils.consume(entity);
}
}

Here is a “pem” file example(generated by the “openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem” command):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDI1k3SB0bmrNEK
iSA850w4KRzGjZ8Wq+HaJQoXlRgTuXA6yPGD8pEemZZmwebDcnmT6ynhenPbIR2d
4Hx3BUpFVjYjs4MpUXFUWdlNhcwsAsQ96cdzFWpdRveV9EiYqabDs//1er25mn6f
cpF6Z0v2FHgXTXCx/0FyvrB/fDgcS087aXmx2bv5InwRxqiODQwxTLXld/lyjQsM
k2WlT7bRZG0ME6Y2xTNj7B9qFZe4xBvpUz0egWklx+7gGgsqhydV5ic8uijxAeQ4
PpdqaDZemTEqo1LhV2R56F8QlZoO/4aMGJhk6y22IPoB31GfjUjW90Ago5lpKBvr
alzPU22lAgMBAAECggEBAJ1MA31JB8XpenwW9DHfMjoWMRxtlTlLe8PAGMxpkIb6
SSUxdr9SP0jJIBvxKAzR3tj0aUPZBV6N7EVXqgQKF6aApDyH/2VgDTP0fxaRgVzC
+fJH5FeFYV4XFBjVT/qJfTxwATvBW1E/6IZ3U+ubdcoRNBGELIyskBUPturSXpwB
F3u0OcrJtRriBnIJhZeQ5KQNEnsMUyLGa+2Nqitdf0kEPcMGVaRL/7jimv521cf6
kcD//HkmFAnQARd4xnpwWZXEx9mYrXgkbFbwZwk0vusWFn5Elqua1wFBwUIGo/Nq
+m8sXo6qqNsXT1JhUIhiSDKjQFkX5aOdYeMJ2Ea3TOECgYEA9fetW5q9rT5kZ8a2
GBVpeYPlp/7Y7m4OK+zrJLBzA4klKiaceLtfNbnnEVWtBzi4I0UA0j/9TeHG6Z7+
66qtAU2s66eEpoRLQp31GBxNnDbEy7zGj9Q5UeKE3159zolJqvDoYPoxsHCpkwO5
uVg4FyHUWhyBgUE111q4qKCs+MkCgYEA0Qdjad6I3nFzlddtHO6RxEwwXUuT72L9
Xo1/Xj4YIeBBqU/d8gYPktGkra1g/06THLK8pwWf73n83dD5YNlEiQ/goL24JR7i
kXJS9qvakqfDJtmcR5nvZGZWpMSzmkGSiZ31FPGNxFLWPwzJauJwG8Nkpd21cccV
1fEbimULl/0CgYByRk/Ub2AQTRx42mlfZxNJ0W2xT0WaAKe04K2erhvBWMZbfvTT
YropS+V+uD9bS47BVB29kN0ugebYQ3ZMJ0+Ze20LTxjiBDSzDpAAU6X7HbbwsRPP
XtoCoSr6W/w3KLGBKcvMwnCzeKRQGTsAUWw90wnFk9jXJGTPWObR8VRrgQKBgDh1
zG5+Q24CKvxgUgKslgb1pWKt1WmlzVZK1gp4r0AHOPUos4R6Cp7XramT2U1cxfPM
e5SJumePBbRMi++TACYdeckxNZohO4WZ4brrNIDEe7v0r3fPpo/x7JlY4EJcT96I
IfjkPiy3S1OAeq86NpnpLzh2KFpxMf61v4CkRntpAoGBAKPwqUmBQk7Jxt4Sqzlf
PO6xHLBB9QPnB0mbJJM9iGt1GOvj94neelUJX7yxJmwqqblf4zsOau32VLhj1Oph
JL89nfYeH3Loxx38Nhaz9/ftbB4WMN7zbgo9+FrbqJgSFqAFpPmYP3KuFGs+C0hI
E+xki+zQUdbEgxwcuyjr3nfZ
-----END PRIVATE KEY-----

-----BEGIN CERTIFICATE-----
MIIDODCCAiACCQCZIp9MJoDx0TANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJD
TjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzENMAsGA1UECgwE
VGVzdDENMAsGA1UECwwEVGVzdDENMAsGA1UEAwwEdGVzdDAeFw0yMDExMjMwMjAy
MzRaFw0zMDExMjEwMjAyMzRaMF4xCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlq
aW5nMRAwDgYDVQQHDAdCZWlqaW5nMQ0wCwYDVQQKDARUZXN0MQ0wCwYDVQQLDARU
ZXN0MQ0wCwYDVQQDDAR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAyNZN0gdG5qzRCokgPOdMOCkcxo2fFqvh2iUKF5UYE7lwOsjxg/KRHpmWZsHm
w3J5k+sp4Xpz2yEdneB8dwVKRVY2I7ODKVFxVFnZTYXMLALEPenHcxVqXUb3lfRI
mKmmw7P/9Xq9uZp+n3KRemdL9hR4F01wsf9Bcr6wf3w4HEtPO2l5sdm7+SJ8Ecao
jg0MMUy15Xf5co0LDJNlpU+20WRtDBOmNsUzY+wfahWXuMQb6VM9HoFpJcfu4BoL
KocnVeYnPLoo8QHkOD6Xamg2XpkxKqNS4VdkeehfEJWaDv+GjBiYZOsttiD6Ad9R
n41I1vdAIKOZaSgb62pcz1NtpQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCVaGr+
hfL1fCRoLP+79tAJy1cPvQE5/h/W0a3g/AslY3iQ1UX/pPN/6+VpDajMojcBfZwF
0Tyc7ZAs403GO6QqeNvnlXVRTNVdE6YnrCJdwFHJz2sbljL7ARQ3VLD2si7NYz73
DCyaOBX0tkdxwH52UXDa7Ug6tdmYKs6w5XAWKkU5UB8SnVRKTsmIBHOqllUcktX1
9q3QsFFX1WuHvKRmWvkSOY+kg+Oqz3No8B0WRRx/a5mx9hdHNAD0+pAq8ar1TmvL
5/If0CEy7c0W5+VaAgM5r79rLQNWrVB32bgvVVbj8cqfooyzJdfZ3ehwqOLA2U+v
8v8fkvdP2pL5akj8
-----END CERTIFICATE-----

More details about the “pem” file can be found here.

Comments