【问题标题】:need help understanding certificate chains需要帮助了解证书链
【发布时间】:2011-12-10 23:09:11
【问题描述】:

目前我正在编写一个 java 库来访问 pointhq.com 的 REST API。

在开发 Android 客户端时,我意识到默认情况下不接受 SSL 证书,因此我编写了自定义 TrustManager 并添加了 pointhq.com 证书,如本文所述:Trusting all certificates using HttpClient over HTTPS

使用此 Trustmanager 和我导入的 bks 文件尝试连接时出现以下错误:IssuerName(CN=GeoTrust Global CA, O=GeoTrust Inc., C=US) does not match SubjectName(CN=RapidSSL CA, O="GeoTrust, Inc.", C=US) of signing certificate.

那么我做错了什么?我导入了 pointhq.com、rapidssl.com、geotrust.com 证书。但什么都没有改变。是否有一种我必须注意的证书分类?我是否缺少根证书?

编辑:这是导入证书的列表:

类型:BKS 提供者:不列颠哥伦比亚省 条目:3

条目别名:geotrust global ca 创建日期:19.10.2011 15:44:35 MESZ 类型:可信证书 证书:1

Certificate 1 of 1
Version: 3
Subject: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Serial Number: 0002 3456
Valid From: 21.05.2002 06:00:00
Valid Until: 21.05.2022 06:00:00
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: DE:28:F4:A4:FF:E5:B9:2F:A3:C5:03:D1:A3:49:A7:F9:96:2A:82:12
MD5 Fingerprint: F7:75:AB:29:FB:51:4E:B7:77:5E:FF:05:3C:99:8E:F5

条目别名:pointhq.com (rapidssl ca) 创建日期:29.09.2011 18:55:12 MESZ 类型:可信证书 证书:1

Certificate 1 of 1
Version: 3
Subject: CN=pointhq.com, OU=Domain Control Validated - RapidSSL(R), OU=See www.rapidssl.com/resources/cps (c)11, OU=GT70151377, O=pointhq.com, C=GB, SERIALNUMBER=8Dvj7qRSYLjGZiX2tHocE2FDaqAp8RwO
Issuer: CN=RapidSSL CA, O="GeoTrust, Inc.", C=US
Serial Number: 8971
Valid From: 31.01.2011 13:20:09
Valid Until: 03.02.2013 09:15:38
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: BB:04:D0:3E:1A:36:02:F7:C3:8C:85:99:1D:67:2A:6B:CF:C1:BC:C5
MD5 Fingerprint: 21:9D:DF:72:E6:4A:33:47:E1:BA:D6:52:86:1E:59:B4

条目别名:rapidssl ca (geotrust global ca) 创建日期:29.09.2011 18:54:49 MESZ 类型:可信证书 证书:1

Certificate 1 of 1
Version: 3
Subject: CN=RapidSSL CA, O="GeoTrust, Inc.", C=US
Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Serial Number: 0002 36D1
Valid From: 19.02.2010 23:45:05
Valid Until: 18.02.2020 23:45:05
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: C0:39:A3:26:9E:E4:B8:E8:2D:00:C5:3F:A7:97:B5:A1:9E:83:6F:47
MD5 Fingerprint: 1B:EE:28:5E:8F:F8:08:5F:79:CC:60:8B:92:99:A4:53

我现在编写了一个 SSL 测试应用程序。结果令人困惑。 正如您在随附的屏幕截图中看到的那样,有时接受 ssl 连接,有时则不接受!即使它是我连接到的同一个网站。

https://ssltest12.bbtest.net/ 是我使用的 RapidSSL 证书的演示站点。正如您在 Android 2.1 屏幕截图中看到的那样,第一次连接没有被接受,但第二次尝试工作得很好,而最后一次则无法再次工作。怎么会这样?

顺便说一句:从 Android 2.3.3 开始,无需任何自定义代码即可接受 RapidSSL 证书!

截图:

【问题讨论】:

  • 您还可以发布您已导入的证书吗?看起来好像名字不匹配。
  • 您的配置似乎缺少证书链中的 RapidSSL 中间证书。有没有办法强制你的链在 TrustManager 中?
  • @kroonwijk 应该缺少哪一个? “强制你的链条”是什么意思?我想我的 BKS 文件中的证书顺序可能是错误的?我会尝试重新排列它们...
  • 似乎有时 SSL 连接被接受,而有时却没有!?这可能是 REST SSL 服务器的错误配置吗?

标签: java android ssl certificate bouncycastle


【解决方案1】:

是的,链中证书的顺序很重要。基本上,您希望将证书从您的证书订购到 CA。浏览器会为你做这件事,但 Java 不会。我遇到了链中无序证书的问题,最后我编写了一个简单的 X509TrustManager 实现:

    public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
    if ((certificates != null) && LOG.isDebugEnabled()) {
        LOG.debug("Server certificate chain:");
        for (int i = 0; i < certificates.length; i++) {
            LOG.debug("X509Certificate[" + i + "]=" + certificates[i]);
        }
    }
    if ((certificates != null) && (certificates.length == 1)) {
        certificates[0].checkValidity();
    } else {
        List<X509Certificate> certs = new ArrayList<X509Certificate>();
        certs.addAll(Arrays.asList(certificates));
        X509Certificate certChain = certs.get(0);
        certs.remove(certChain);
        LinkedList<X509Certificate> chainList= new LinkedList<X509Certificate>();
        chainList.add(certChain);
        Principal certIssuer = certChain.getIssuerDN();
        Principal certSubject = certChain.getSubjectDN();
        while(!certs.isEmpty()){
            List<X509Certificate> tempcerts = new ArrayList<X509Certificate>();
            tempcerts.addAll(certs);
            for (X509Certificate cert : tempcerts){
                if(cert.getIssuerDN().equals(certSubject)){
                    chainList.addFirst(cert);
                    certSubject = cert.getSubjectDN();
                    certs.remove(cert);
                    continue;
                }

                if(cert.getSubjectDN().equals(certIssuer)){
                    chainList.addLast(cert);
                    certIssuer = cert.getIssuerDN();
                    certs.remove(cert);
                    continue;
                }
            }
        }
    standardTrustManager.checkServerTrusted(chainList.toArray(new X509Certificate[]{}),authType);

    }
}

注意排序“while”循环。

【讨论】:

  • 小心。如果您在提供的链中有任何废话(如旧版本的服务器证书),这将以一个繁忙的循环结束。是的,我遇到了...浏览器等根本忽略了附加证书。
  • 据我所知,certificates[0].checkValidity(); 不足以防止中间人攻击,因为它只检查证书有效的时间间隔。我想也应该在if ((certificates != null) &amp;&amp; (certificates.length == 1)) { 分支上使用standardTrustManager 进行检查。
猜你喜欢
  • 1970-01-01
  • 2017-06-19
  • 2016-05-03
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多