zkat’s diary

技術ブログ

CRLSetsには何が書かれているか

概要

ChromiumならびにGoogle Chromeが証明書の失効状態を確認するために使っているCRLSetsについて、 中身に何が書かれているのか確認してみたいと思います。

Chromeが、OCSP(Online Certificate Status Protocol)やCRL(Certificate Revocation List)を主には使用していない理由などは ググると沢山でてくるので、ここでは純粋にCRLSetsに何が書かれているのかに着目してみたいと思います。

CRLsetsの中身をみるためには

Chromium Projectに下記の通り記載されているツールを使います。

The current CRLSet can be fetched and dumped out using the code at https://github.com/agl/crlset-tools

dev.chromium.org

ということで、こちらのgo実装のツールをビルドします。

$ git clone https://github.com/agl/crlset-tools.git
$ cd crlset-tools
$ go build crlset.go

これで、最新版のCRLSetsをダウンロードしてくることができます。

$ ./crlset fetch > crlset.raw

何がかいてあるか

上記ツールのdumpコマンドで見てみます。

$ ./crlset dump ./crlset.raw 

手元では以下のように表示されました。

Sequence: 5785
Parents: 194

006cb226a772c7182d7772383e373f0f229e7dfe3444810a8d6e50905d20d661
  01a657
023c81cce8e7c64fa942d3c15048707d35d9bb5b87f4f544c5bf1bc5643af2fa
  07c7fb087254a95dd56ab78b3c4fb690
026f0a8e207f05f1f172db713dc22d0f43c8ff0d69724aa6fac6a8393df62508
  01e123522e1808cf312623b0a8
  01e707cde1f486c97bfec41758
  01f240410bf98509385f57d41d
  01f240411672b1bca5a37fe50a
  45d3e5c0c2bdaa7a9df7817ab6c1
  45d3e5c49afce8834a6e40e4db10
03cb44b933d7e14551e52ddbfc335a4d57bf65a703667b57ac961de31e3a106d
  329cab52a80a2e3f
  35c18872ba36292e
  5c923b50b4bac6ff
  7f8dcef53b9a951f
(以下略)

この表示に関して、先のツールのGithubのreadmeには次のように書いてありました。

Revocations are grouped by the SHA-256 hash of the issuing certificate's SubjectPublicKeyInfo and listed as serial numbers.

どうやら、失効した証明書のシリアル番号が、Issuer証明書(信頼の連鎖的に上位の証明書)のSubjectPublicKeyInfoの値(sha256したもの)でグルーピングされているみたいです。

そこで、本当にそのようになっているのか確認してみます。 上記のリストに表示されていた、こちらで確かめます。

03cb44b933d7e14551e52ddbfc335a4d57bf65a703667b57ac961de31e3a106d
  329cab52a80a2e3f

まず、329cab52a80a2e3fが証明書のシリアル番号を示しているようなので、https://crt.sh で検索してみますと、次のように見つかります。

f:id:zkat:20200402005914j:plain
crt.sh-serial-number-search
詳細を表示してみると、実際にCRLSetsで失効扱いになっていることをcrt.shでも確認できます。
f:id:zkat:20200402005828j:plain
crt.sh-revocation-status

上記crt.shの検索結果により、上位の証明書がC=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Organisatie Persoon CA - G3であることが分かりましたので、 この証明書をPEMでダウンロードしてきます。これは、SubjectPublicKeyInfoの値を知りたいからです。詳細は割愛しますが、crt.shから持ってこれます。

証明書中の何バイト目から、SubjectPublicKeyInfoが始まるか確認したいので、ASN.1形式にダンプしてみます。

すると、265バイト目から814バイト目までがそれであることが分かります。

 265  546:     SEQUENCE {
 269   13:       SEQUENCE {
 271    9:         OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
 282    0:         NULL
         :         }
 284  527:       BIT STRING
         :         30 82 02 0A 02 82 02 01 00 BE 62 E8 19 3A 7A 2E
         :         BE F7 A1 C2 75 2D C4 04 91 81 70 DF 59 9F 7B CD
         :         45 17 B1 E0 84 63 6F 00 16 78 05 48 E9 24 77 F5
         :         1E 98 36 22 FF 94 E7 93 42 4B E7 5A C4 5B D5 CA
         :         56 48 50 82 2C 4C 58 EB 95 33 8F 0C 56 50 3F D0
         :         C3 9E 58 C7 FE AE C6 82 78 6D 88 C8 DF 75 1D 41
         :         9B 94 CB 1D 6F 6D FF 7B 77 82 9A 75 72 E9 8B 19
         :         30 6E CC 0B 32 E1 7A A3 E3 F8 BD DF 0A 97 46 44
         :         7E 81 48 EC AC B7 2E DE 99 D5 5D 6C DC 2D 83 D2
         :         C2 07 F8 4B F1 03 5E 37 B3 A8 A6 C2 44 45 CF 57
         :         DF 28 49 77 E0 3D 90 00 50 5C 21 4B 78 85 12 16
         :         F3 C7 A6 CB 44 02 0D 8F EB 42 33 89 BD F1 AE 06
         :         B9 D2 41 70 CB 54 34 06 87 FB C0 33 69 CB CF D8
         :         6B F6 9C FB B0 AF 8A C4 93 9A E0 F6 2A 4A 9C 20
         :         C8 F5 75 3B 6E 48 40 D5 3C 33 6D 8E 3D AB 24 43
         :         90 E1 69 6E F0 6A 15 D9 56 3A 01 84 92 6A 23 09
         :         79 09 55 93 89 D3 A1 F7 F3 78 27 D8 24 7D D2 E3
         :         F1 49 BD F4 10 29 7F 24 CB 49 97 57 CC 79 BD 14
         :         EB C9 07 66 E8 5C 92 EC 3A 89 E9 37 05 AD A9 DE
         :         BD 08 39 46 A9 A5 D5 9C 0A 54 2B 05 8D BC 0F 29
         :         BA 5F BE E8 9E 84 AE 8A C7 94 84 AE 4A 52 C3 50
         :         B9 43 C8 09 3A 2B 6C DD A8 AF 4E 8D 82 27 51 8D
         :         81 90 91 64 CA 0C D3 90 E8 E0 D2 86 BA DE 4B 25
         :         9F 53 5E 90 DF ED C9 70 C5 16 F1 59 07 52 10 43
         :         6E 11 AD 73 18 A9 73 7C 75 7F F0 5A EC 43 0C 28
         :         FE 96 64 32 32 37 F4 8F E4 33 71 52 48 1A 68 26
         :         D5 E6 4B 03 FF 70 41 64 72 A7 39 69 6F 2C A1 62
         :         9D 52 84 FC F3 B3 80 B2 40 1F 43 AA 9C C0 A2 19
         :         B7 F5 34 74 13 03 7A DC 06 93 36 5C 8E ED CE 33
         :         ED A2 15 BB 67 3B 6D 88 09 75 DD F4 27 A3 02 81
         :         6D 1D E9 ED DD EF E8 ED 1A DC 9F E2 38 4E 09 52
         :         B4 17 ED 95 97 91 EB 79 92 06 C5 36 05 0C 0F 85
         :         2A CA 4E 06 C7 BB C5 DE A7 02 03 01 00 01
         :       }
 815  261:     [3] {
 819  257:       SEQUENCE {

そこで、証明書をhexdumpして得られた265バイト目から814バイト目までのバイナリデータをSHA256にかけてみます。

$ echo -en "\x30\x82\x02\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d(省略)\xc5\xde\xa7\x02\x03\x01\x00\x01" | openssl sha256
(stdin)= 03cb44b933d7e14551e52ddbfc335a4d57bf65a703667b57ac961de31e3a106d

結果のハッシュが先の値に一致しましたので、IssuerのSPKIsのハッシュでグルーピングされていることが分かりました。

その他

crlsetのdumpコマンドで表示できるのは、CRLSetsファイルの一部のみであるようです。 生のCRLSetsファイルの構造がどのようになっているかは、体系的な説明を見つけることができなかったのですが、 例えば以下のソースコードのコメントに記載があり、参考になりました。

github.com

// CRLSet format:
//
// uint16le header_len
// byte[header_len] header_bytes
// repeated {
//   byte[32] parent_spki_sha256
//   uint32le num_serials
//   [num_serials] {
//     uint8 serial_length;
//     byte[serial_length] serial;
//   }
(省略)