How can I use different certificates on specific connections? How can I use different certificates on specific connections? java java

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.


If creating a SSLSocketFactory is not an option, just import the key into the JVM

  1. Retrieve the public key:$openssl s_client -connect dev-server:443, then create a file dev-server.pem that looks like

    -----BEGIN CERTIFICATE----- lklkkkllklklklklllkllklkllklkkkllklklklklllkllklkllklkkkllklk....-----END CERTIFICATE-----
  2. Import the key: #keytool -import -alias dev-server -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev-server.pem.Password: changeit

  3. Restart JVM

Source: How to solve javax.net.ssl.SSLHandshakeException?