简体   繁体   English

证书固定不适用于Android上的OkHttp

[英]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. 在Android应用上使用com.squareup.okhttp:okhttp:2.4.0com.squareup.retrofit:retrofit:1.9.0 ,尝试通过HTTPS与服务器REST API通信,该API使用自签名证书。

Server keystore has a private key and 2 certificates, the server's and a root certificate. 服务器密钥库有一个私钥和2个证书,服务器和根证书。 openssl s_client output - 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

At the Android app, OkHttp is initialised with the root certificate's SHA1 signature - 在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();

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. 在尝试sslSocket.startHandshake() ,它会在com.squareup.okhttp.internal.http.SocketConnector抛出,甚至在使用CertificatePinner检查收到的证书之前。

I've made sure server has certificates installed correctly using openssl and with curl --cacert root.pem . 我确保服务器使用opensslcurl --cacert root.pem正确安装了证书。

So why does OkHttp throw an exception before even trying to check if provided certificates are OK? 那么为什么OkHttp在尝试检查提供的证书是否正常之前会抛出异常?

OkHttp does not support self signed certificates. OkHttp不支持自签名证书。

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. 使用由已知CA签名的证书时,握手成功,然后CertificatePinner确保证书链至少包含一个提供的签名。 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. 因此,可以使用由已知CA签名的证书并固定其中一个证书,以确保我们正在与正确的服务器通信。

OkHttp does support self-signed certificates. OkHttp支持自签名证书。

Please check this answer to learn how to create a SslSocket that trusts only your certificate. 请查看此答案以了解如何创建仅信任您的证书的SslSocket

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM