How can I use different certificates on specific connections?
Create an SSLSocket
factory yourself, and set it on the HttpsURLConnection
before connecting.
...
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslFactory);
conn.setMethod("POST");
...
You'll want to create one SSLSocketFactory
and keep it around. Here's a sketch of how to initialize it:
/* Load the keyStore that includes self-signed cert as a "trusted" entry. */
KeyStore keyStore = ...
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();
If you need help creating the key store, please comment.
Here's an example of loading the key store:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, trustStorePassword);
trustStore.close();
To create the key store with a PEM format certificate, you can write your own code using CertificateFactory
, or just import it with keytool
from the JDK (keytool won't work for a "key entry", but is just fine for a "trusted entry").
keytool -import -file selfsigned.pem -alias server -keystore server.jks
I read through LOTS of places online to solve this thing. This is the code I wrote to make it work:
ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = "alias";//cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(trustStore, null);
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
URL url = new URL(someURL);
conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());
app.certificateString is a String that contains the Certificate, for example:
static public String certificateString=
"-----BEGIN CERTIFICATE-----\n" +
"MIIGQTCCBSmgAwIBAgIHBcg1dAivUzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE" +
"BhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBE" +
... a bunch of characters...
"5126sfeEJMRV4Fl2E5W1gDHoOd6V==\n" +
"-----END CERTIFICATE-----";
I have tested that you can put any characters in the certificate string, if it is self signed, as long as you keep the exact structure above. I obtained the certificate string with my laptop's Terminal command line.