Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Certificate pinning not working with OkHttp on Android

Using com.squareup.okhttp:okhttp:2.4.0 with com.squareup.retrofit:retrofit:1.9.0 on an Android app, trying to communicate with an server REST API over HTTPS, that uses a self signed certificate.

Server keystore has a private key and 2 certificates, the server's and a root certificate. openssl s_client output -

Certificate chain
 0 s:/C=...OU=Dev/CN=example.com
   i:/C=... My CA/[email protected]
 1 s:/C=... My CA/[email protected]
   i:/C=... My CA/[email protected]

At the Android app, OkHttp is initialised with the root certificate's SHA1 signature -

CertificatePinner certificatePinner = new CertificatePinner.Builder()
        .add("example.com", "sha1/5d...3b=")
        .build();

OkHttpClient client = new OkHttpClient();
client.setCertificatePinner(certificatePinner);

RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint("https://example.com")
        .setClient(new OkClient(client))
        .build();

But when trying to send a request fails with exception -

retrofit.RetrofitError: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:395)
        at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
        at java.lang.reflect.Proxy.invoke(Proxy.java:397)
        at $Proxy1.report(Unknown Source)
        ...
        at android.os.AsyncTask$2.call(AsyncTask.java:288)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
 Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:306)
        at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
        at com.squareup.okhttp.Connection.connect(Connection.java:143)
        at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
        at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
        at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)

It's thrown at com.squareup.okhttp.internal.http.SocketConnector when trying sslSocket.startHandshake(), even before CertificatePinner is used to check the received certificates.

I've made sure server has certificates installed correctly using openssl and with curl --cacert root.pem.

So why does OkHttp throw an exception before even trying to check if provided certificates are OK?

like image 309
Kof Avatar asked Aug 30 '15 14:08

Kof


People also ask

What is certificate Pinner?

public final class CertificatePinner extends Object. Constrains which certificates are trusted. Pinning certificates defends against attacks on certificate authorities. It also prevents connections through man-in-the-middle certificate authorities either known or unknown to the application's user.

How does SSL pinning work android?

SSL pinning allows the application to only trust the valid or pre-defined certificate or Public Key. The application developer uses SSL pinning technique as an additional security layer for application traffic. As normally, application trusts custom certificate and allows application to intercept the traffic.

Is certificate pinning necessary Android?

Caution: Certificate Pinning is not recommended for Android applications due to the high risk of future server configuration changes, such as changing to another Certificate Authority, rendering the application unable to connect to the server without receiving a client software update.

Is certificate pinning still used?

HPKP got deprecated in 2018 after intents of removing it started in 2017. Almost all browsers no longer support it as attacks against HPKP surfaced. HPKP is being replaced by the reactive Certificate Transparency framework coupled with the Expect-CT header.


1 Answers

OkHttp does not support self signed certificates.

When using a certificate which is signed by a known CA, handshakes succeeds and then CertificatePinner makes sure the certificate chain contains at least one of the provided signatures. If none appear, it will throw an exception, stopping the request.

So it is possible to use a cert signed by a known CA and pin one of the certificates to make sure we're talking to the right server.

like image 89
Kof Avatar answered Sep 17 '22 18:09

Kof