opensslによるサーバー証明書失効リスト (CRL) 確認

以前 d:id:i_k_b:20090714:1247565189 で書いた情報に不足があったため補足。

openssl s_client サブコマンドは SSL 上で SMTP や POP、 HTTP を通すためのクライアントコマンドで、その際にサーバー証明書の検証が実施される。単純には下記コマンドで server.com の port ポートに接続して対話待ちに入る。

$ openssl s_client -connect server.com:port

HTTP を話しているならこれに以下を入力することでトップページのサイズや更新日などを取得でき(詳しくは HTTP プロトコルを参照)、あわせてサーバー証明書の検証がなされる。

HEAD / HTTP/1.0<改行>
<改行>

ただし、この状態では PKI の信頼の基点となるルート証明機関 (CA: Certificate Authority) の証明書を参照しないため検証に失敗する。

CA 証明書を参照させるには -CApath オプション、あるいは -CAfile オプションを使う。規定では /usr/lib/ssl/certs/ ディレクトリーに有名どころの CA 証明書が配置されている。これを参照して、たとえば twitter.com のサーバー証明書を検証してみる。

$ openssl s_client -connect twitter.com:443 -CApath /usr/lib/ssl/certs << EOF
> HEAD / HTTP/1.0
> 
> EOF

少々長くなるが、上記コマンドを実行すると以下の応答が返ってくる。

CONNECTED(00000003)
depth=1 /C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1
verify return:1
depth=0 /C=US/O=twitter.com/OU=GT09721236/OU=See www.rapidssl.com/resources/cps (c)09/OU=Domain Control Validated - RapidSSL(R)/CN=twitter.com
verify return:1
---
Certificate chain
 0 s:/C=US/O=twitter.com/OU=GT09721236/OU=See www.rapidssl.com/resources/cps (c)09/OU=Domain Control Validated - RapidSSL(R)/CN=twitter.com
   i:/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDQzCCAqygAwIBAgIDC7XxMA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNVBAYTAlVT
MRwwGgYDVQQKExNFcXVpZmF4IFNlY3VyZSBJbmMuMS0wKwYDVQQDEyRFcXVpZmF4
IFNlY3VyZSBHbG9iYWwgZUJ1c2luZXNzIENBLTEwHhcNMDkwNTI2MTkzNDQ4WhcN
MTAwNTI4MTY1ODEzWjCBsjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC3R3aXR0ZXIu
Y29tMRMwEQYDVQQLEwpHVDA5NzIxMjM2MTEwLwYDVQQLEyhTZWUgd3d3LnJhcGlk
c3NsLmNvbS9yZXNvdXJjZXMvY3BzIChjKTA5MS8wLQYDVQQLEyZEb21haW4gQ29u
dHJvbCBWYWxpZGF0ZWQgLSBSYXBpZFNTTChSKTEUMBIGA1UEAxMLdHdpdHRlci5j
b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAObNJ9AKUT3V3ls5J3Cxvs5R
OqQO7h+DZ2aBppy2GZFPWza3rhnRk/PBIvasRx82aKL7rAFtVyXggivp32XVZwCy
io74Br+cdVV7SgMwMhZgpUKsQTBwQ3InKuuczNyd9qdMF9t/TIf+HpfEXmHTxHIn
fJYv8OT5zfE0Fl9iACjTAgMBAAGjgb0wgbowDgYDVR0PAQH/BAQDAgTwMB0GA1Ud
DgQWBBQrGm3fNiHRrszg4IuqhAFAK6bWBzA7BgNVHR8ENDAyMDCgLqAshipodHRw
Oi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL2dsb2JhbGNhMS5jcmwwHwYDVR0jBBgw
FoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
AQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQADgYEAebTa/jX//SrR
Gt8kccVQvohpKnegZC1HFSfgWfqSOEPjnQQQa7D65znFciw/fD4JS6vbphk5ZeXv
jzyk27jdEvJ+02qwr22L2PpgJIndmyNeaBphp72PB604S82j29hfbfzmZy6LIiT8
DHwb3GjhBKhGy1+NLYyWV6T0UaQcLSk=
-----END CERTIFICATE-----
subject=/C=US/O=twitter.com/OU=GT09721236/OU=See www.rapidssl.com/resources/cps (c)09/OU=Domain Control Validated - RapidSSL(R)/CN=twitter.com
issuer=/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1
---
No client certificate CA names sent
---
SSL handshake has read 1403 bytes and written 316 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 1024 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: E04B582CC4E49B97EBB48D4EB32E53CFE435066E7BA34564FF22A0E852A910EF
    Session-ID-ctx:
    Master-Key: 6FA1F87C58175103277AB134E94C48F84B420B988683B578B73F580D582469104D4F775E8D2EF3280F2FB0CC3EDAB45B
    Key-Arg   : None
    Start Time: 1263290066
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
DONE

末尾行近くの "Verify return code: 0 (ok)" が、証明書が (ただしく) 検証できたというしるしである。

この時点でサーバー証明書について確認された事項は以下のとおりである。

  1. サブジェクト名
  2. 有効期間
  3. 証明書チェイン (信頼するルート CA 証明書までたどれる証明書であること)

サーバー証明書を厳密に確認するには、これに加えて「失効されていないこと」も見なければならない。サーバー証明書の失効とは、証明書を発行した機関が情報漏えいやハッキングその他の理由で発行済みの証明書を無効にすることで、 CRL (Certificate Revocation List) の公開という方法で失効が伝えられる。この証明書失効確認を追加するオプションが -crl_check および -crl_check_all である。 -crl_check は末端の証明書の失効確認を、 _all は証明書チェイン上の証明書すべての失効を確認するオプションである。

さて、先のコマンドに -crl_check_all オプションを追加して実行してみよう。

$ openssl s_client -connect twitter.com:443 -CApath /usr/lib/ssl/certs \
> -crl_check_all << EOF
> HEAD / HTTP/1.0
>
> EOF
CONNECTED(00000003)
(snip)
    Verify return code: 3 (unable to get certificate CRL)
    • -
DONE

残念ながら失敗する。エラーコードが示すとおり、証明書失効リストが取得できないことが原因である。

ここで先の twitter.com の証明書に何が書かれているか見てみよう。

$ cat << EOF > twitter.pem
> -----BEGIN CERTIFICATE-----
> MIIDQzCCAqygAwIBAgIDC7XxMA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNVBAYTAlVT
> MRwwGgYDVQQKExNFcXVpZmF4IFNlY3VyZSBJbmMuMS0wKwYDVQQDEyRFcXVpZmF4
> IFNlY3VyZSBHbG9iYWwgZUJ1c2luZXNzIENBLTEwHhcNMDkwNTI2MTkzNDQ4WhcN
> MTAwNTI4MTY1ODEzWjCBsjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC3R3aXR0ZXIu
> Y29tMRMwEQYDVQQLEwpHVDA5NzIxMjM2MTEwLwYDVQQLEyhTZWUgd3d3LnJhcGlk
> c3NsLmNvbS9yZXNvdXJjZXMvY3BzIChjKTA5MS8wLQYDVQQLEyZEb21haW4gQ29u
> dHJvbCBWYWxpZGF0ZWQgLSBSYXBpZFNTTChSKTEUMBIGA1UEAxMLdHdpdHRlci5j
> b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAObNJ9AKUT3V3ls5J3Cxvs5R
> OqQO7h+DZ2aBppy2GZFPWza3rhnRk/PBIvasRx82aKL7rAFtVyXggivp32XVZwCy
> io74Br+cdVV7SgMwMhZgpUKsQTBwQ3InKuuczNyd9qdMF9t/TIf+HpfEXmHTxHIn
> fJYv8OT5zfE0Fl9iACjTAgMBAAGjgb0wgbowDgYDVR0PAQH/BAQDAgTwMB0GA1Ud
> DgQWBBQrGm3fNiHRrszg4IuqhAFAK6bWBzA7BgNVHR8ENDAyMDCgLqAshipodHRw
> Oi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL2dsb2JhbGNhMS5jcmwwHwYDVR0jBBgw
> FoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
> AQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQADgYEAebTa/jX//SrR
> Gt8kccVQvohpKnegZC1HFSfgWfqSOEPjnQQQa7D65znFciw/fD4JS6vbphk5ZeXv
> jzyk27jdEvJ+02qwr22L2PpgJIndmyNeaBphp72PB604S82j29hfbfzmZy6LIiT8
> DHwb3GjhBKhGy1+NLYyWV6T0UaQcLSk=
> -----END CERTIFICATE-----
> EOF
$ openssl x509 -noout -text -in twitter.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 767473 (0xbb5f1)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
        Validity
            Not Before: May 26 19:34:48 2009 GMT
            Not After : May 28 16:58:13 2010 GMT
        Subject: C=US, O=twitter.com, OU=GT09721236, OU=See www.rapidssl.com/resources/cps (c)09, OU=Domain Control Validated - RapidSSL(R), CN=twitter.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:e6:cd:27:d0:0a:51:3d:d5:de:5b:39:27:70:b1:
                    be:ce:51:3a:a4:0e:ee:1f:83:67:66:81:a6:9c:b6:
                    19:91:4f:5b:36:b7:ae:19:d1:93:f3:c1:22:f6:ac:
                    47:1f:36:68:a2:fb:ac:01:6d:57:25:e0:82:2b:e9:
                    df:65:d5:67:00:b2:8a:8e:f8:06:bf:9c:75:55:7b:
                    4a:03:30:32:16:60:a5:42:ac:41:30:70:43:72:27:
                    2a:eb:9c:cc:dc:9d:f6:a7:4c:17:db:7f:4c:87:fe:
                    1e:97:c4:5e:61:d3:c4:72:27:7c:96:2f:f0:e4:f9:
                    cd:f1:34:16:5f:62:00:28:d3
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            X509v3 Subject Key Identifier:
                2B:1A:6D:DF:36:21:D1:AE:CC:E0:E0:8B:AA:84:01:40:2B:A6:D6:07
            X509v3 CRL Distribution Points:
                URI:http://crl.geotrust.com/crls/globalca1.crl

            X509v3 Authority Key Identifier:
                keyid:BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C

            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha1WithRSAEncryption
        79:b4:da:fe:35:ff:fd:2a:d1:1a:df:24:71:c5:50:be:88:69:
        2a:77:a0:64:2d:47:15:27:e0:59:fa:92:38:43:e3:9d:04:10:
        6b:b0:fa:e7:39:c5:72:2c:3f:7c:3e:09:4b:ab:db:a6:19:39:
        65:e5:ef:8f:3c:a4:db:b8:dd:12:f2:7e:d3:6a:b0:af:6d:8b:
        d8:fa:60:24:89:dd:9b:23:5e:68:1a:61:a7:bd:8f:07:ad:38:
        4b:cd:a3:db:d8:5f:6d:fc:e6:67:2e:8b:22:24:fc:0c:7c:1b:
        dc:68:e1:04:a8:46:cb:5f:8d:2d:8c:96:57:a4:f4:51:a4:1c:
        2d:29

サーバー証明書失効リストは以下で配布されていることがわかる。

            X509v3 CRL Distribution Points:
                URI:http://crl.geotrust.com/crls/globalca1.crl

これを保存し、失効リストストアを作成する。

$ mkdir crl
$ pushd crl
$ curl -O http://crl.geotrust.com/crls/globalca1.crl
$ c_rehash .
$ popd

openssl s_client サブコマンドの -CApath は : 区切りでディレクトリーを複数指定できるので、今作成した失効リストストアを追加して検証してみよう。

$ openssl s_client -connect twitter.com:443 \
> -CApath /usr/lib/ssl/certs:`pwd`/crl \
> -crl_check_all << EOF
> HEAD / HTTP/1.0
>
> EOF
CONNECTED(00000003)
(snip)
    Verify return code: 0 (ok)
    • -
DONE

たしかに失効リストを使っての検証も通過した。