Reputation: 448
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
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