[英]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.0
和com.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
. 我确保服务器使用
openssl
和curl --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.