Java - Okhttp code for adding client certificates

Your question may already have an answer on the community forum. Please search for related topics, and then read through the guidelines before creating a new topic.

Here’s an outline with best practices for making your inquiry.

My question:
I am able to invoke the required url using client certificates, I am having trouble to creating the same with Java - Okhttp But Code snippet is not providing any code relevant to adding certificates

Details (like screenshots):

I’ve already tried:
I am trying to make a simple GET request with the below certificate, key. I am facing the below issue with Java

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class Main {

  private static X509Certificate loadCertificateFromFile(File file)
      throws CertificateException, IOException {
    FileInputStream inputStream = new FileInputStream(file);
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    X509Certificate certificate =
        (X509Certificate) certificateFactory.generateCertificate(inputStream);
    inputStream.close();
    return certificate;
  }

  private static PrivateKey loadPrivateKeyFromFile(File file)
      throws GeneralSecurityException, IOException {
    FileInputStream inputStream = new FileInputStream(file);
    byte[] keyBytes = new byte[inputStream.available()];
    inputStream.read(keyBytes);
    inputStream.close();
    String keyBytesStr =
        new String(keyBytes)
            .replace("-----BEGIN PRIVATE KEY-----", "")
            .replace("-----END PRIVATE KEY-----", "")
            .replaceAll("\\s", "");

    // Assuming the private key is in PKCS#8 format
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyBytesStr));
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePrivate(keySpec);
  }

  public static void main(String[] args) throws GeneralSecurityException, IOException {

    File crtFile = new File("/oath/chain.crt");
    File keyFile = new File("/path/private.key");
    File serverFile = new File("/path/abc.com.pem");
    X509Certificate certificate = loadCertificateFromFile(crtFile);
    X509Certificate serverCertificate = loadCertificateFromFile(serverFile);
    // Load the private key from KEY file
    PrivateKey privateKey = loadPrivateKeyFromFile(keyFile);

    // Load the certificate and private key into KeyStore
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    keyStore.load(null, null);
    keyStore.setKeyEntry("alias", privateKey, null, new X509Certificate[] {certificate});
    keyStore.setCertificateEntry("server", serverCertificate);

    TrustManagerFactory trustManagerFactory =
        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);

    // Create SSLContext and configure it with KeyManager and TrustManager
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

    // Create OkHttpClient with the configured SSLContext
    OkHttpClient client =
        new OkHttpClient.Builder()
            .sslSocketFactory(
                sslContext.getSocketFactory(),
                (X509TrustManager) trustManagerFactory.getTrustManagers()[0])
            .build();

    // Make a request using the OkHttpClient
    Request request = new Request.Builder().url("<URL>").build();

    try (Response response = client.newCall(request).execute()) {
      // Process the response
      System.out.println(response.code());
      System.out.println(response.body().string());
    }
  }
}

ERROR MSG:

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

I am also facing similar issue. any solution?

I’m having the same problem, I tried other ways, but I wasn’t successful, could someone help?

Hi all!

To ensure the issue isn’t with the server or your certificates:

  • Use Postman’s ability to make requests with client-side certificates.
  • Go to Settings → Certificates and add your client certificates.
  • Make a request to the same URL. If Postman succeeds and your Java code doesn’t, the problem likely resides in your Java configuration.

As this looks like the case in your situation, @venkatakaushik1 ,

Try to run your application with the JVM argument -Djavax.net.debug=ssl to see detailed SSL handshake logs. This can provide more insights into what’s going wrong.

Additionally, if you have the client certificate and key in other formats, try converting them into a PKCS#12 format and use that with OkHttp. There are tools like OpenSSL that can assist with this conversion.


Other suggestions that I’ve come across:

  1. Validate Certificate Chain: Ensure that the certificate chain (root, intermediate(s), and leaf certificate) is correctly set up. Missing intermediate certificates or out-of-order certificates can cause this error.
  • If the chain.crt file includes multiple certificates, ensure they’re in the correct order.
  • The server’s certificate should be at the top, followed by any intermediates (in the order in which they were issued), ending with the root certificate.
  1. TrustStore vs. KeyStore:
  • You’ve added both client and server certificates to the same KeyStore and used it as a TrustManagerFactory. Usually, client-side certificates (for authentication) go into a KeyStore, while server certificates (to validate the server’s identity) go into a TrustStore.
  • Consider separating these and initializing the SSLContext with both KeyManager (from the KeyStore) and TrustManager (from the TrustStore).
  1. Update Java’s CA Certificates Store: If the server’s certificate is issued by a well-known Certificate Authority (CA) but Java doesn’t trust it, consider updating Java’s CA certificate store.