Certificate Pinning fails even with CA-signed cert

1.7k Views Asked by At

I'm trying to use certificate pinning on Android with Retrofit. I'm trying to evaluate a valid Verisign-signed certificate.

I get the following error:

HTTP FAILED: javax.net.ssl.SSLPeerUnverifiedException: Failed to find a trusted cert that signed Certificate.

Why can't the certificate pinner not evaluate against the device's CA root certs? Does it not have access to the device trust? Or perhaps the device trust does not contain the whole certificate chain. But then why doesn't my SSL communication fail?

// Pin Certificate
CertificatePinner certificatePinner = new CertificatePinner.Builder()
        .add("www.mydomain.com", "sha256/somerandompublickeystring")
        .build();

// To handle self-signed cert
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();

OkHttpClient client = clientBuilder.connectTimeout(120, TimeUnit.SECONDS)
        .writeTimeout(120, TimeUnit.SECONDS)
        .readTimeout(120, TimeUnit.SECONDS)
        .certificatePinner(certificatePinner)
        .build();
1

There are 1 best solutions below

3
On

Found the answer. I can get a hold of the Root trust as shown below and use that in the sslSocketFactory call. This worked for me.

OkHttpClient client = clientBuilder.connectTimeout(120, TimeUnit.SECONDS)
        .writeTimeout(120, TimeUnit.SECONDS)
        .readTimeout(120, TimeUnit.SECONDS)
        .sslSocketFactory(getSystemDefaultSSLSocketFactory(app))
        .certificatePinner(certificatePinner)
        .build();

private static SSLSocketFactory getSystemDefaultSSLSocketFactory(Application app) {
    SSLContext sslContext = null;
    try
    {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
        }
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagers, null);

    }
    catch(Exception ex)
    {
        Log.e("TAG",ex.getMessage());
    }
    return sslContext.getSocketFactory();

}