【问题标题】:how to prove that one certificate is issuer of another certificates如何证明一个证书是另一个证书的颁发者
【发布时间】:2013-07-26 11:46:49
【问题描述】:

我有两个证书。一个证书是另一个证书的颁发者。

如何使用 java 代码看到我的颁发者证书确实是颁发者?

我知道我的证书的 AuthorityKeyIdentifier 和颁发者证书的 SubjectKeyIdentifie 必须相同。我检查过,它们相同

但是使用 java 代码我得到了这个结果:

    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

    InputStream usrCertificateIn = new FileInputStream("/usr.cer");
    X509Certificate cert = (X509Certificate) certFactory.generateCertificate(usrCertificateIn);

    InputStream SiningCACertificateIn = new FileInputStream("/siningCA.cer");
    X509Certificate issuer = (X509Certificate) certFactory.generateCertificate(SiningCACertificateIn);

    byte[] octets = (ASN1OctetString.getInstance(cert.getExtensionValue("2.5.29.35")).getOctets());     
    System.out.println(Arrays.toString(octets) + " bouncycastle, AuthorityKeyIdentifier");
    System.out.println(Arrays.toString(cert.getExtensionValue("2.5.29.35")) + "java.security, AuthorityKeyIdentifier");

    octets = ASN1OctetString.getInstance(issuer.getExtensionValue("2.5.29.14")).getOctets();
    System.out.println((Arrays.toString(octets) + "bouncycastle, SubjectKeyIdentifie "));
    System.out.println(Arrays.toString(issuer.getExtensionValue("2.5.29.14")) + "java.security, SubjectKeyIdentifie ");

结果是:

[48, 22, -128, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31 , 66, -55, -86, -79, 113] bouncycastle, AuthorityKeyIdentifier

[4, 24, 48, 22, -128, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113]java.security, AuthorityKeyIdentifier

另一个字节数组必须相同,但不是另一个字节被添加到数组的开头。

[4、20、52、-105、49、-70、-24、78、127、-113、-25、55、39、99、46、6、31、66、-55 , -86, -79, 113]bouncycastle, SubjectKeyIdentifie

[4, 22, 4, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113]java.security, SubjectKeyIdentifie

问题 1) 我可以计算关键标识符以获得相同的数组吗?

问题 2) 还有其他方法可以证明一个证书是另一个证书的颁发者

【问题讨论】:

    标签: certificate x509certificate bouncycastle x509 digital-certificate


    【解决方案1】:

    AuthorityKeyIdentifierSubjectKeyIdentifier 的定义不同:

    AuthorityKeyIdentifier ::= SEQUENCE {
      keyIdentifier             [0] KeyIdentifier           OPTIONAL,
      authorityCertIssuer       [1] GeneralNames            OPTIONAL,
      authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }
    
    SubjectKeyIdentifier ::= KeyIdentifier
    
    KeyIdentifier ::= OCTET STRING
    

    RFC 5280 的第 4.2.1.1 和 4.2.1.2 节)

    因此,仅比较扩展值是行不通的,您必须提取 KeyIdentifier 内容并进行比较,例如使用 BouncyCastle ASN.1 辅助类。

    顺便说一句,实际的密钥标识符字节只有

    52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113
    

    前面的 4, 20 表示一个八进制字符串,长度为 20 个字节。在 AuthorityKeyIdentifier 中,由于隐式标记,4 被标记 [0](字节 -128)替换。

    AuthorityKeyIdentifier 中的 48、22 表示(构造的)序列,22 个字节长。

    等等。等等

    因此,

    我可以计算关键标识符得到相同的数组吗?

    是的,深入到实际的 KeyIdentifier OCTET STRING 值。

    还有其他方法可以证明一个证书是另一个证书的颁发者

    那么,您可以通过验证证书的公钥来检查证书中的签名是否由与假定的颁发者证书关联的私钥签名。

    PS:关于cmets中的问题

    密钥标识符的长度总是 20 吗?是固定的吗?可能不是,不是吗?

    不,不是。前面提到的RFC 5280 说:

    For CA certificates, subject key identifiers SHOULD be derived from
    the public key or a method that generates unique values.  Two common
    methods for generating key identifiers from the public key are:
    
      (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
           value of the BIT STRING subjectPublicKey (excluding the tag,
           length, and number of unused bits).
      (2) The keyIdentifier is composed of a four-bit type field with
           the value 0100 followed by the least significant 60 bits of
           the SHA-1 hash of the value of the BIT STRING
           subjectPublicKey (excluding the tag, length, and number of
           unused bits).
    
    Other methods of generating unique numbers are also acceptable.
    

    我假设您的 CA 使用方法 1(160 位 = 20 字节),但这只是一种常用方法, 甚至不是明确推荐的方法, 更不用说 需要。因此,不,您不能指望标识符有 20 个字节长。

    PPS:关于cmets中的问题

    签名不是真正证明一个证书是由另一个证书颁发的唯一方法吗?

    这也不是 issuer-issuedBy 关系的证明,它仅证明(至少在一定程度上)与假定的颁发者证书相关联的私钥签署了检查的证书,但存在在多个证书中使用相同的私钥-公钥对的情况。

    本质上,您需要进行多项互补测试,即使如此,您也必须相信 CA 不会做奇怪的事情。不久前 例如Swisscom 更改了他们的一个 CA 证书以包含额外的扩展名或关键属性(我必须查看详细信息;我认为有人证明他们要求更改),并且通过证书签名验证测试旧签名者证书现在似乎由新的 CA 证书颁发,即使签名者证书的所有者可能不知道新的扩展/关键属性。

    因此,最终现实生活并不像人们希望的那样简单......

    【讨论】:

    • 谢谢。并且密钥标识符的长度总是20?是固定的吗?可能不是,不是吗?
    • "深入到实际的 KeyIdentifier OCTET STRING 值。" - 可以举个例子吗?
    • @LadyBird 是密钥标识符的长度始终为 20 - 不,大小可能会有所不同。
    • @LadyBird 一个如何深入研究的示例 - 不幸的是,我对 BC 不太了解,我在工作中使用其他商业 ASN.1 助手。但就像您使用 ASN1OctetString.getInstance(...).getOctets() 从 OCTET STRING 中检索字节一样,肯定还有其他类似的助手可以从 SEQUENCE 中提取元素或检查某个元素是否具有标签 [0]。
    • 签名不是真正证明一个证书是由另一个证书颁发的唯一方法吗? “已颁发”证书中的 AKI 可能是伪造的,对吧?
    【解决方案2】:

    要证明一个证书是由另一个证书颁发的,您应该证明它是由与颁发证书中的公钥对应的私钥签名的。

    让我们调用 2 个证书 caCertissuedCert。这些是X509Certificate 类型。

    证明issuedCert是由caCert代表的实体签名的Java代码相当简单。

    PublicKey caPubKey = caCert.getPublicKey();
    
    issuedCert.verify(caPubKey);
    

    如果verify方法返回没有抛出异常,那么issuedCert是由caCert中的公钥对应的私钥签名的。

    【讨论】:

      猜你喜欢
      • 2021-08-25
      • 2021-04-13
      • 1970-01-01
      • 2018-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多