Сертификат не работает с OkHttp на Android

Используя com.squareup.okhttp:okhttp:2.4.0 с com.squareup.retrofit:retrofit:1.9.0 в приложении для Android, пытающийся связаться с сервером REST API через HTTPS, который использует самоподписанный сертификат.

У сервера keystore есть закрытый ключ и 2 сертификата, серверный и корневой сертификат. Выход openssl s_client

 Certificate chain 0 s:/C=...OU=Dev/CN=example.com i:/C=... My CA/emailAddress=info@example.com 1 s:/C=... My CA/emailAddress=info@example.com i:/C=... My CA/emailAddress=info@example.com 

В Android-приложении OkHttp инициализируется сигнатурой SHA1 корневого сертификата –

 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(); 

Но при попытке отправить запрос сбой исключается –

 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) 

Он com.squareup.okhttp.internal.http.SocketConnector при com.squareup.okhttp.internal.http.SocketConnector при попытке sslSocket.startHandshake() , даже до того, как CertificatePinner используется для проверки полученных сертификатов.

Я убедился, что сервер правильно установил сертификаты с помощью openssl и с curl --cacert root.pem .

Итак, почему OkHttp генерирует исключение, прежде чем пытаться проверить, соответствуют ли сертификаты?

OkHttp не поддерживает самоподписанные сертификаты.

При использовании сертификата, подписанного известным ЦС, рукопожатия преуспевают, а затем CertificatePinner гарантирует, что цепочка сертификатов содержит хотя бы одну из предоставленных подписей. Если ни один из них не появляется, он выдает исключение, останавливая запрос.

Таким образом, можно использовать сертификат, подписанный известным ЦС, и подключить один из сертификатов, чтобы убедиться, что мы разговариваем с правильным сервером.

OkHttp поддерживает самоподписанные сертификаты.

Проверьте этот ответ, чтобы узнать, как создать SslSocket который доверяет только вашему сертификату.