【问题标题】:Can't get root CA certificate from the chain in Android无法从 Android 中的链获取根 CA 证书
【发布时间】:2017-06-28 22:44:08
【问题描述】:

我想做的事情很简单——我想在从 iOS 和 Android 应用程序连接到服务器时获得完整的证书链。

在 iOS 中,我使用 NSURLSession 并覆盖 URLSession:didReceiveChallenge: 方法,在该方法中我可以获得证书链,在这种情况下看起来像预期的那样:

[leaf certificate] - [intermediate certificate] - [root certificate]

可爱的。

现在我尝试在 Android 设备上使用HttpsURLConnection 做同样的事情。连接到服务器后,我使用getServerCertificates() 方法获取证书链(或者至少我希望这是它的方法)。这将返回给我 Certificate[] 对象,我在其中得到了如下所示的链:

[leaf certificate] - [intermediate certificate]

因此,Android 设备上没有根证书。

你知道如何在 Android 中从链中获取根证书吗?

提前谢谢你。

【问题讨论】:

    标签: android ios ssl ssl-certificate x509certificate


    【解决方案1】:

    您的问题显然很简单。我正在查看 TLS 规范中的服务器证书部分。看到这个post

    服务器必须发送一个 orderer 证书链,从服务器证书和中间体开始但 CA 根是可选的,因为标准要求根证书独立分发.服务器通常不包含 CA 根

    客户端验证在信任库中寻找根 CA 的链。验证由X509TrustManager 执行

     public void checkServerTrusted(X509Certificate[] chain, String authType)
    

    已编辑 - 如何从 HTTPS 连接获取受信任的根

    您可以使用可用的受信任证书列表验证中间证书,以检查其中哪个是颁发者。 (从herehere中提取代码

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
    // Initialise the TMF as you normally would, for example:
    tmf.init((KeyStore)null); 
    
    //get default X509TrustManager
    TrustManager[] trustManagers = tmf.getTrustManagers();
    final X509TrustManager x509Tm = (X509TrustManager)trustManagers[0];
    
    //trusted certificate issuers
    X509Certificate issuers[] = x509Tm.getAcceptedIssuers();
    
    //Perform connection...
    HttpsURLConnection conn =....
    
    //get the last intermediate certificate from server certificates. 
    //Fixme: if the server returns alsothe root certificate...
    Certificate cert[] = conn.getServerCertificates();
    X509Certificate intermediate = (X509Certificate)cert[cert.length-1];
    
    for (int i = 0; i < issuers.length;i++){
        try{
            intermediate.verify(issuers[i].getPublicKey());
                //Verification ok. issuers[i] is the issuer
                return issuers[i];
            } catch (Exception e){}
        }
    }
    

    【讨论】:

    • 感谢您的回答。你有什么解释为什么我在 iOS 案例中获得根证书,但在 Android 上没有?在这两种情况下,我都将请求发送到相同的端点。
    • 假设服务器没有在链中提供根CA(你可以在ssllabs.com查看),iOS正在使用信任库的匹配证书构建完整的证书链,而Android是验证相同但不添加根证书。在我看来,Android(和 Java)应该提供这些信息。
    • 是的,谢谢你的信息,有道理。我试图覆盖X509TrustManager,但仍然没有运气。您是否知道 Android 中是否有一种方法可以从用于验证链中的中间证书的设备获取根证书? (几乎是获取iOS在其API中返回的这个根,但可能从设备本身读取它)
    • 连接成功后,您可以使用可用的受信任证书列表验证中间证书,以检查其中哪个是颁发者。使用certificate.verify(trustedCertificate.getPublicKey())可以通过getAcceptedIssuers()方法从当前X509TrustManager获取受信任的发行者列表
    • 你是绝地武士。正是我需要的。非常感谢!
    猜你喜欢
    • 2019-11-14
    • 1970-01-01
    • 2018-09-15
    • 2019-12-19
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多