证书/CRL 目录的哈希算法

Hash algorithm for certificate / CRL directory

OpenSSL 能够为 CA 证书和 CRL 使用特定的目录结构。如果将目录名称作为第三个参数传递给 SSL_CTX_load_verify_locations (as described in this question), it will look for CA certificates in this directory in order to verify client certificates. It finds the correct CA certificate by taking the hash of the issuer of the client certificate and appending an integer, e.g. 34bb8598.0. Usually, those names are symlinks pointing to the real files, and the symlinks are created using the c_rehash 工具。

同样,OpenSSL可以将证书吊销列表存储在这些目录中,如this question中所述,并通过证书颁发者的哈希值查找正确的吊销列表。

现在,我需要让一个程序重新使用这样的 CRL 目录。该程序不使用 OpenSSL,因此我需要以其他方式生成这些哈希值。生成这些散列文件名的算法是什么?

哈希格式没有记录,所以这很可能会改变——事实上,它已经改变过一次。 x509 command 支持选项 -subject_hash-issuer_hash 以及 -subject_hash_old-issuer_hash_old。此描述适用于 OpenSSL 1.0.1f 的“新”哈希格式。

X509_subject_name_hash and X509_issuer_name_hash functions just call X509_NAME_hash on the corresponding certificate attribute. That function 采用名称“规范编码”的 SHA-1 散列,将其前四个字节视为 little-endian 32 位整数,然后 returns (有效地反转散列的前四个字节)。

那么什么是“规范编码”?它是发行者名称的 DER 表示的变异,由函数 x509_name_canon 生成。 DER 是一种标签-长度-值编码。我们表示的对象树如下所示:

  • rdnSequence,带标签 0x31(十进制 49)
    • 一个或多个 RelativeDistinguishedName 项目,每个项目带有标签 0x30(十进制 48)
      • 一种类型,表示为 OID,带有标记 0x06
      • 一个字符串值——这就是它变得有趣的地方

证书中给出的字符串值可以用多种不同的类型表示,例如带有标签 0x13 的“可打印字符串”、带有标签 0x16 的“IA5 字符串”或带有标签 0x0c.

的 UTF-8 字符串

生成“规范编码”时,RDNSequence 中每个项目的值都会转换为 UTF-8,并重新编码为带有标签 0x0c 的 UTF-8 字符串。这发生在 asn1_string_canon function。此外,还应用了以下转换:

  • 任何开头和结尾的白色space 都被删除。任何设置了高位的字节都将不加改变地通过,因此“whitespace”在此上下文中表示 space、换页、换行、回车 return、水平制表符和垂直制表符。
  • 在字符串中,一个或多个白色 space 字符的任何 运行 被替换为单个 space (0x20).
  • 字符被转换为小写。由于任何设置了高位的字节都将被忽略,这仅适用于 ASCII 字母 A 到 Z。

这就是您需要做的。

请注意,某些相关字段的 ASN.1 定义不允许使用 UTF-8 字符串(例如,国家/地区代码仅限于“可打印字符串”),因此您可能无法使用您的直接使用ASN.1编码库。