2

HTTPS RPC と通信するアプリがあります。
HTTP サーバーは、CAcert 署名付き証明書を使用しています。

証明書の検証にカスタム TrustManager を使用しています。

  • 確信が持てないため、CAcert はすべてのデバイスの信頼できるキー ストアに含まれています。
  • CAcert のみがこの接続の証明書に署名できるようにしたいためです。

ただし、Google のベスト プラクティスに従っています。私が変更した唯一のことは次のとおりです。

  • ファイルの代わりに静的な byte[] から CAcert ルート証明書をロードします
  • サンプルコードがファイルをロードする最後の部分を に置き換えますHttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());。UrlConnection の上に JSONRPC2 API があります。

テスト済みのデバイス:

  • Nexus 4 / mako running API18 / CM10.2 に取り組んでいます
  • API18エミュレータで作業中
  • API17エミュレータで作業中
  • API14エミュレータで作業中
  • API10 / CM7 を実行している HTC G2では動作しません。*
  • API8 エミュレーターで動作しない

低 API デバイスでは、SSL ハンドシェイク中に証明書の検証に失敗します。API18でこれを読み込も
うとすると、トラスト アンカーが見つからないため、期待どおりに失敗します。 したがって、基本的に、このコードは機能するはずで、すべてのメソッドは API1 です... 私は、UrlConnection が一部の下位 API で壊れていることを知っています。https://google.comTrustManager

これを修正するにはどうすればよいですか?

コード:

/**
 * Trust only CAcert's CA. CA cert is injected as byte[]. Following best practices from
 * https://developer.android.com/training/articles/security-ssl.html#UnknownCa
 */
private static void trustCAcert() {
    try {
        // Load CAs from an InputStream
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        ByteArrayInputStream is = new ByteArrayInputStream(CACERTROOTDER);

        Certificate ca;
        try {
            ca = cf.generateCertificate(is);
            Log.d(TAG, "ca=", ((X509Certificate) ca).getSubjectDN());
        } finally {
            is.close();
        }

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        HttpsURLConnection.setDefaultSSLSocketFactory(
            sslContext.getSocketFactory());

        // added for testing only
        URL u = new URL(
            "https://myremoteapiurlsignedwiththesamecert.com/v1/doc.html");
        HttpsURLConnection con = (HttpsURLConnection) u.openConnection();
        con.setSSLSocketFactory(sslContext.getSocketFactory());
        BufferedReader r = new BufferedReader(
            new InputStreamReader(
                con.getInputStream())); // the exception is thrown here
        // because verification fails
        String l;
        while ((l = r.readLine()) != null) {
            Log.d(TAG, "l: ", l);
        }
    } catch (IOException e) { // none of the exceptions is thrown during setup
        Log.e(TAG, "IOException", e);
    } catch (CertificateException e) {
        Log.e(TAG, "CertificateException", e);
    } catch (NoSuchAlgorithmException e) {
        Log.e(TAG, "NoSuchAlgorithmException", e);
    } catch (KeyStoreException e) {
        Log.e(TAG, "KeyStoreException", e);
    } catch (KeyManagementException e) {
        Log.e(TAG, "KeyManagementException", e);
    }
}

ログ:

APIUtils  D  ca=OID.1.2.840.113549.1.9.1=#1612737570706F7274406361636572742E6F7267, CN=CA Cert Signing Authority, OU=http://www.cacert.org, O=Root CA
          E  IOException
          E  javax.net.ssl.SSLException: Not trusted server certificate
          E         at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
          E         at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)
          E         at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)
          E         at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1152)
          E         at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:253)
          E         at de.terminbuddy.android.network.APIUtils.trustCAcert(APIUtils.java:294)
          E         at de.terminbuddy.android.network.APIUtils.initRpcSession(APIUtils.java:243)
          E         at de.terminbuddy.android.network.APIUtils.runRPC(APIUtils.java:323)
          E         at de.terminbuddy.android.network.AsyncJSONRPCTask.doInBackground(AsyncJSONRPCTask.java:55)
          E         at de.terminbuddy.android.network.AsyncJSONRPCTask.doInBackground(AsyncJSONRPCTask.java:17)
          E         at android.os.AsyncTask$2.call(AsyncTask.java:185)
          E         at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
          E         at java.util.concurrent.FutureTask.run(FutureTask.java:137)
          E         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
          E         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
          E         at java.lang.Thread.run(Thread.java:1096)
          E  Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Could not validate certificate signature.
          E         at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
          E         at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
          E         ... 15 more
          E  Caused by: java.security.cert.CertPathValidatorException: Could not validate certificate signature.
          E         at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:342)
          E         at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
          E         at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
          E         ... 16 more
          E  Caused by: java.security.SignatureException: Signature was not verified.
          E         at org.apache.harmony.security.provider.cert.X509CertImpl.fastVerify(X509CertImpl.java:601)
          E         at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:544)
          E         at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:337)
          E         ... 18 more
4

1 に答える 1