RekaB
RekaB

Reputation: 448

OkHttp load signed certificate

I need to emulate client api requests for testing purposes. Our server now uses https and I was recommended to use OkHttpClient instead of our original BaseHttpClient implementation. I have found that I need to add .sslSocketFactory(sslSocketFactory, x509TrustManager) to my client builder and I also found helpful code to load a certificate:

private X509TrustManager trustManagerForCertificates(InputStream in)
{
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
    char[] password = "password".toCharArray(); // Any password will work.
    KeyStore keyStore = newEmptyKeyStore(password);
    int index = 0;
    for (Certificate certificate : certificates) {
      String certificateAlias = Integer.toString(index++);
      keyStore.setCertificateEntry(certificateAlias, certificate);
    }
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, password);
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    return (X509TrustManager) trustManagers[0];
}

My issue is that my certificate has a key and I can't find a way to provide the contents of the .crt and .key files as a pair. If I were to curl it, I could do

curl --tlsv1.2 --insecure -v --key ./client.key --cert ./client.crt  https://myserver/api/request

Is there a way to do something similar with OkHttp? Or do i have to generate a new certificate using the existing one and its key?

Upvotes: 2

Views: 528

Answers (1)

RekaB
RekaB

Reputation: 448

In the end I managed to get this to work using code from this site, using BouncyCastle's libraries.

To get it working, I also needed the ca.crt (it's included in the example - the curl command can do without this thanks to the --insecure switch). A lot of the sites I went through lead me to think that I need to create a certificate chain using the ca and client certificates but as you can see from the linked code, the solution is to have two key stores: one for the CA, to be used for the TrustManager and one for the client certificate, to be used for the KeyManager. The SSLContext can then be initialised with these two.

The last hurdle I came across was an exception:

java.lang.ClassNotFoundException: org.bouncycastle.jcajce.JcaJceHelper

This was due to more than one version of bouncycastle being imported from various sources. Making sure I used the correct versions of bcprov and bcpkix solved this issue.

Upvotes: 0

Related Questions