I\'m trying to pin my server\'s self-signed certificate. My OkHttpClient takes two parameters, the first one is the ssl Socket Factory :
final TrustManager[]
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
The TrustManager, CertificatePinner and Hostname verification all do different but important things. If you want to use self-signed certificates but still have security, as opposed to self-signed certificates purely for ease of local development then you probably want to create a valid TrustManager.
e.g. https://github.com/yschimke/oksocial/blob/3757196cde420b9d0fe37cf385b66f4cdafb1ae1/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java#L19
public static X509TrustManager load(List<File> serverCerts)
throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {
return trustManagerForKeyStore(keyStoreForCerts(serverCerts));
}
public static X509TrustManager trustManagerForKeyStore(KeyStore ks)
throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
return (X509TrustManager) tmf.getTrustManagers()[0];
}
public static KeyStore keyStoreForCerts(List<File> serverCerts)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
for (int i = 0; i < serverCerts.size(); i++) {
try (InputStream is = new FileInputStream(serverCerts.get(i))) {
X509Certificate caCert = (X509Certificate) cf.generateCertificate(is);
ks.setCertificateEntry("cacrt." + i, caCert);
}
}
return ks;
}
This will start off with the system certificates loaded, so your client can still be used to load externally hosted images etc.
Then on top of that you can use CertificatePinner to require that only your trusted self-signed certificates are used for your domain.