web-dev-qa-db-ja.com

Android)でOkHttpで証明書のピン留めが機能しない

Androidアプリで_com.squareup.okhttp:okhttp:2.4.0_と_com.squareup.retrofit:retrofit:1.9.0_を使用し、サーバーと通信しようとしていますREST API over HTTPS、自己使用署名された証明書。

サーバーキーストアには、秘密鍵と2つの​​証明書、サーバーとルート証明書があります。 _openssl s_client_出力-

_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]
_

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)
_

sslSocket.startHandshake()を試行すると、受信した証明書をチェックするためにCertificatePinnerが使用される前であっても、_com.squareup.okhttp.internal.http.SocketConnector_でスローされます。

opensslと_curl --cacert root.pem_を使用して、サーバーに証明書が正しくインストールされていることを確認しました。

では、提供された証明書に問題がないかどうかを確認する前に、OkHttpが例外をスローするのはなぜですか?

14
Kof

OkHttpは自己署名証明書をサポートしていません。

既知のCAによって署名された証明書を使用する場合、ハンドシェイクは成功し、CertificatePinnerは、証明書チェーンに提供された署名の少なくとも1つが含まれていることを確認します。何も表示されない場合は、例外がスローされ、リクエストが停止します。

したがって、既知のCAによって署名された証明書を使用し、証明書の1つを固定して、適切なサーバーと通信していることを確認することができます。

5
Kof

OkHttpは自己署名証明書をサポートします。

証明書のみを信頼するSslSocketを作成する方法については、 この回答 を確認してください。

4
Paulo Avelar