Karl Eriksson
Karl Eriksson

Reputation: 205

Including a .pem certificate in a Java HTTP request

I am currently able to access a web service that requires a client certificate using the following curl command:

curl -k -v --cert ./certificate.pem https://api.com/unit

How do I make this request in a Java application?

Notice that I need the -k flag which allows curl to make "insecure" SSL connections. This needs to be done in the Java application as well.

Upvotes: 2

Views: 9453

Answers (2)

Karl Eriksson
Karl Eriksson

Reputation: 205

The solution to this problem was to include the server's certificates in the Java trust store.

To download and import the above certificates of the server I used InstallCert Java code from GitHub.

The keyStore and trustStore were then defined in system properties like below:

-Djavax.net.ssl.keyStore=/home/wildfly/key.pfx
-Djavax.net.ssl.keyStorePassword=xxxx
-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts
-Djavax.net.ssl.trustStorePassword=xxxx
-Djavax.net.ssl.keyStoreType=PKCS12"

Upvotes: 0

veebee
veebee

Reputation: 391

The code below provides a "sendSSLRequest" method that sends an HTTP GET request with client SSL authentication.

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.HttpGet;

public class SSLExample {

   private final static String ENDPOINT_URL = "https://api.com/unit";

   public void sendSSLRequest() {

      final SSLContext sslContext = SSLContextLoader.initSSLContext();

      final HttpClient client = HttpClients.custom()
                                    .setSSLContext(sslContext)
                                    .build();
      final HttpGet request = new HttpGet(ENDPOINT_URL);

      try {
         client.execute(request);
      } catch (final IOException e) {
         //do some exception handling...
      }
   }
}

Now, the SSLContext: you need to initialize it somewhere. The "initSSLContext" method below will load key material from a given keystore, and trust material (certificates that are to be trusted) from a given truststore.

public class SSLContextLoader {

   private final static String clientKeyStorePath = "/path/to/client/keystore";
   private final static String trustStorePath = "/path/to/truststore";
   private final static String clientKeyStorePassword = "/password/for/client/keystore";
   private final static String trustStorePassword = "/password/for/truststore";
   private final static String keyPassword = "/passphrase/for/private/key";

   public static SSLContext initSSLContext () {
      try {
         final KeyStore clientKeystore = KeyStore.getInstance("JKS");
         clientKeystore.load(new FileInputStream(clientKeyStorePath), clientKeyStorePassword.toCharArray());
         final KeyStore trustStore = KeyStore.getInstance("JKS");
         trustStore.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());

         final SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(trustStore, null)
            .loadKeyMaterial(clientKeystore, keyPassword.toCharArray())
            .build();

         return sslContext;
      } catch (KeyStoreException e) {
         e.printStackTrace();
      } catch (CertificateException e) {
         e.printStackTrace();
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (UnrecoverableKeyException e) {
         e.printStackTrace();
      } catch (KeyManagementException e) {
         e.printStackTrace();
      }
     return null;
   }
}

Regarding the -k option, I invite you to have a look at the following question/answer: Trusting all certificates using HttpClient over HTTPS.

Upvotes: 1

Related Questions