如何计算X.509证书的SHA-1指纹?

我正在尝试从头开始实现X.509证书生成器(我知道现有的,但我还需要另一个)。 我无法理解的是如何计算证书的SHA-1(或任何其他)指纹。

RFC5280表示签名函数的输入是DER编码的tbsCertificate字段。 不幸的是,我计算的哈希值与OpenSSL产生的哈希值不同。 这是一个循序渐进的例子。

  1. 使用OpenSSL的x509工具生成证书(以二进制DERforms, 而不是 ASCII PEM)
  2. 使用openssl x509 -fingerprint计算其SHA-1哈希值
  3. 使用dd(或其他任何东西)提取TBS字段并将其存储在单独的文件中; 使用sha1sum实用程序计算其哈希值

现在,我在第2步和第3步得到的哈希值是不同的。 有人可以给我一个提示我可能做错了吗?

好吧,事实certificate,OpenSSL计算的指纹只是整个证书的散列(在其DER二进制编码中, 而不是 ASCII PEM!),而不仅仅是TBS部分,正如我所想的那样。

对于任何关心计算证书摘要的人来说,它是以不同的方式完成的:哈希是通过DER编码(再次, 不是 PEM字符串)TBS部分计算的,包括其ASN.1头(ID 0x30 == ASN1_SEQUENCE | ASN1_CONSTRUCTED和长度字段)。 请注意,不考虑证书的ASN.1标头。

指纹类似于.net中的术语“指纹”。 下面的代码片段应该可以帮助您计算指纹:

  public String generateFingerPrint(X509Certificate cert) throws CertificateEncodingException,NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("SHA-1"); byte[] hash = digest.digest(cert.getEncoded[]); final char delimiter = ':'; // Calculate the number of characters in our fingerprint // ('# of bytes' * 2) chars + ('# of bytes' - 1) chars for delimiters final int len = hash.length * 2 + hash.length - 1; // Typically SHA-1 algorithm produces 20 bytes, ie len should be 59 StringBuilder fingerprint = new StringBuilder(len); for (int i = 0; i < hash.length; i++) { // Step 1: unsigned byte hash[i] &= 0xff; // Steps 2 & 3: byte to hex in two chars // Lower cased 'x' at '%02x' enforces lower cased char for hex value! fingerprint.append(String.format("%02x", hash[i])); // Step 4: put delimiter if (i < hash.length - 1) { fingerprint.append(delimiter); } } return fingerprint.toString(); }