如何证明一个证书是另一个证书的颁发者

gre*_*rep 5 bouncycastle certificate digital-certificate x509certificate x509

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

我如何看到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 ");
Run Code Online (Sandbox Code Playgroud)

结果是:

[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)是否有另一种方法来证明一个证书是另一个证书的发行者.

mkl*_*mkl 7

AuthorityKeyIdentifier并且SubjectKeyIdentifier定义不同:

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

SubjectKeyIdentifier ::= KeyIdentifier

KeyIdentifier ::= OCTET STRING
Run Code Online (Sandbox Code Playgroud)

(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
Run Code Online (Sandbox Code Playgroud)

之前的4,20表示OCTET STRING,长度为20个字节.在AuthorityKeyIdentifier中,由于隐式标记,4被标记[0](字节-128)替换.

在AuthorityKeyIdentifier之前的48,22意味着(构造)SEQUENCE,长度为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.
Run Code Online (Sandbox Code Playgroud)

我假设您的CA使用方法1(160位= 20字节),但这只是一种常见的方法,甚至没有明确建议的方法,更不用说需要了.因此,不,你不能指望长度为20个字节的标识符.

PPS:关于评论中的问题

签名是否真正证明一个证书是由另一个颁发的唯一途径?

这也不发行人发行的关系的证明,它只是证明(至少在某种程度上)与假定的发行人证书相关联的私钥签署了检查证书,但是存在相同的私钥 - 公钥对是用于多个证书.

从本质上讲,你需要做多个互补测试,甚至必须相信CA不要做奇怪的事情.不久前,例如Swisscom改变了他们的一个CA证书,包括一个额外的扩展或关键属性(我必须查找详细信息;我认为有人证明他们要求更改),并通过证书签名验证测试老签名者即使签名者证书的所有者可能不知道新的扩展/关键属性,证书现在似乎也由新的CA证书颁发.

所以最终现实生活并不像人们希望的那样简单......


gtr*_*rig 5

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

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

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

PublicKey caPubKey = caCert.getPublicKey();

issuedCert.verify(caPubKey);
Run Code Online (Sandbox Code Playgroud)

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