Reputation: 471
This is a topic that has taken me quite some time to figure out. There are bits and pieces of information scattered and one has to put everything together. I was hoping that with this post I could help others quickly assemble a working solution.
I have a certificate.pem
, key.pem
. I need to use them in my Java client to access a remote REST API using JERSEY client.
Things I tried so far:
Converted pem files into JKS.
openssl pkcs12 -export -in certificate.pem -inkey key.pem -out client.jks -passout pass:CLIENT -name myClient
Added to truststore
keytool -importkeystore -destkeystore truststore.jks -deststoretype JKS -deststorepass CLIENT -srckeystore pathtoJKS://client.jks -srcstorepass CLIENT -srcstoretype JKS
Added properties as below
-Djavax.net.ssl.keyStore=client.jks
-Djavax.net.ssl.keyStorePassword=CLIENT
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.trustStorePassword=CLIENT
but for some reason the remote API still thinks like, I'm not sending the correct certificates.
Can someone help me what's missing here?
EDIT :- Added the code of the HTTP client.
String keyStorePath = "client.jks"; // File is present in main/resources folder
String trustStorePath = "truststore.jks"; // File is present in main/resources folder
char[] keyStorePassword = "CLIENT".toCharArray();
char[] trustStorePassword = "CLIENT".toCharArray();
KeyStore keyStore = KeyStore.getInstance("JKS");
KeyStore trustStore = KeyStore.getInstance("JKS");
try(InputStream keyStoreInputStream = Application.class.getClassLoader().getResourceAsStream(keyStorePath);
InputStream trustStoreInputStream = Application.class.getClassLoader().getResourceAsStream(trustStorePath)) {
Objects.requireNonNull(keyStoreInputStream);
Objects.requireNonNull(trustStoreInputStream);
keyStore.load(keyStoreInputStream, keyStorePassword);
trustStore.load(trustStoreInputStream, trustStorePassword);
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keyManagers,trustManagers, new java.security.SecureRandom());
Client client = ClientBuilder.newBuilder()
.sslContext(sslcontext)
.hostnameVerifier(new TrustAllHostNameVerifier())
.build();
Upvotes: 0
Views: 6324
Reputation: 78
Please share your source code with us, because its problematic to trace the problem that you are currently facing. At first glance, your configuration files are good. However, there are some small improvements you can do:
javax.net.ssl
are defined during runtimeUpvotes: 0
Reputation: 3861
I am not quite sure if adding the keystore/truststore properties in that way will work. I am used to configuring the client configuration directly while creating an instance, and that works for sure.
Below is an example Jersey SSL Client configuration:
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial("client.jks", "CLIENT".toCharArray())
.withTrustMaterial("truststore.jks", "CLIENT".toCharArray())
.build();
Client client = ClientBuilder.newBuilder()
.sslContext(sslFactory.getSslContext())
.hostnameVerifier(sslFactory.getHostnameVerifier())
.build();
Jersey requires a configured instance of SSLContext. The above example uses SSLFactory from SSLContext Kickstart, which is maintained by me. There are also other ways to create an instance of SSLContext, see here for all the possible ways I know: Mutual Authentication in Scala with Akka
Could you try the above snippet and drop here the results of it?
Upvotes: 1