6

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

我怎样才能看到 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)是否有另一种方法可以证明一个证书是另一个证书的颁发者

4

2 回答 2

8

AuthorityKeyIdentifier并且SubjectKeyIdentifier定义不同:

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 表示一个 OCTET STRING,20 字节长。由于隐式标记,在 AuthorityKeyIdentifier 中,4 被标记 [0](字节 -128)替换。

AuthorizationKeyIdentifier 之前的 48、22 表示(构造的)序列,22 个字节长。

等等等等。

因此,

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

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

是否有另一种方法可以证明一个证书是另一个证书的颁发者

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

PS:关于评论中的问题

密钥标识符的长度是否始终为 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:关于评论中的问题

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

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

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

所以最终现实生活并不像人们想象的那么简单......

于 2013-07-26T09:50:12.410 回答
5

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

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

要证明的 Java 代码issuedCert是由 所代表的实体签名的,caCert非常简单。

PublicKey caPubKey = caCert.getPublicKey();

issuedCert.verify(caPubKey);

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

于 2013-07-26T21:24:15.593 回答