繁体   English   中英

带有客户端证书的 Android Http 请求

[英]Android Http request with Client Certificate

我正在尝试使用以下代码向具有客户端证书身份验证的服务器发出请求:

try {
    /*** CA Certificate ***/

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = getResources().openRawResource(R.raw.caserver);
    Certificate ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

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

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

    /*** Client Certificate ***/

    KeyStore keyStore12 = KeyStore.getInstance("PKCS12");
    InputStream certInput12 = getResources().openRawResource(R.raw.p12client);
    keyStore12.load(certInput12, "123456key".toCharArray());

    // Create a KeyManager that uses our client cert
    String algorithm = KeyManagerFactory.getDefaultAlgorithm();
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
    kmf.init(keyStore12, null);


    /*** SSL Connection ***/

    // Create an SSLContext that uses our TrustManager and our KeyManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    URL url = new URL("https://myurl/test.json");
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());

    System.out.println("Weeeeeeeeeee");
    InputStream in = urlConnection.getInputStream(); // this throw exception
}
catch (Exception e) {
    e.printStackTrace();
}

当执行到达最后一行InputStream in = urlConnection.getInputStream();时,我获得下一个异常InputStream in = urlConnection.getInputStream(); .

System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

我花了很多时间试图修复这个错误,但我找不到任何信息。 当我使用带有客户端证书的 Web 浏览器发出相同的请求时,一切正常。

有什么帮助吗? 提前致谢。

编辑

我按照以下步骤生成证书:

> openssl req -config openssl.cnf -new -x509 -extensions v3_ca -days 3650 -keyout private/caserver.key -out certs/caserver.crt
> openssl req -config openssl.cnf -new -nodes -keyout private/client.key -out client.csr -days 1095
> openssl ca -config openssl.cnf -cert certs/caserver.crt -policy policy_anything -out certs/client.crt -infiles csr/client.csr
> openssl pkcs12 -export -clcerts -in certs/client.crt  -inkey private/client.key -out p12client.p12

在我的代码中,我使用 caserver.crt 和 p12client.p12。

我不知道为什么输入流无法从Assets文件夹读取证书。 我有同样的问题。 为了克服,我已将证书放在raw文件夹中并通过它访问

InputStream caInput = getResources().openRawResource(R.raw.mycertificate);

并且运行良好!

您似乎专注于客户端证书和可能存在的问题,但我认为该错误与服务器证书有关。

你有InputStream caInput = getResources().openRawResource(R.raw.caserver); 它以 CA 的 CA 证书作为输入,可以验证服务器证书是否有效(例如,caserver 可能是一个 DER 文件)。 正如您的代码所说,您希望信任该 CA。

因此,问题可能在于该文件不是该 CA 的正确证书。

或者,它可能真的是该 CA 的证书。 但是该 CA 可能没有直接签署您的服务器证书。 通常,存在一条信任链​​,其中一个 CA 可能会签名,然后该 CA 被另一个 CA 信任,依此类推,一直到根 CA 或您信任的其他 CA。

那么,为什么具有相同服务器证书的同一个网站可以在浏览器中运行? 您的浏览器可能拥有更多信任的 CA,因此能够对服务器进行身份验证。 而您的 android 应用程序可能不信任信任链中的一个或多个中间 CA。 因此,“未找到认证路径的信任锚”。

你能做些什么呢? 有关如何处理未知 CA 或缺少中间 CA 等的情况,请参阅google 指南

暂无
暂无

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

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