月別アーカイブ: 2010年6月

失効リスト (CRL)

失効リスト (CRL) が機能するためには、証明書に CRL Distribution Points が記載されていなければならないらしい。これは、失効リストの配布元を示す情報で、OpenSSL では openssl.cnf に crlDistributionPoints の設定をすることで、発行される証明書に CRL Distribution Points の情報が埋め込まれる。

問題はどこに記述するかだが……。とりあえず、[usr_cert] セクションにでも書いておくことにしよう。

(略)
[ user_cert ]
(略)
crlDistributionPoints = URI:http://www.uconst.org/CA/uconst-ca.crl
(略)

URI: の後に、crl のファイルを配布する URL を記述する。結果は次の通り。

$ ./CA.sh -sign
$ openssl x509 -noout -text -in newcert.pem
Certificate:
(略)
X509v3 extensions:
(略)
X509v3 CRL Distribution Points:
Full Name:
URI:http://www.uconst.org/CA/uconst-ca.crl
(略)

それで、失効リストを公開して、失効した証明書をサーバに設定して Firefox 3.6.3 で接続すると、普段と変りない。 Internet Exploler 6 (IE6) だと、「このサイトのセキュリティ証明書の取り消し情報は、使用できません。続行しますか?」などとでてくる。少なくとも IE6 では途中まではうまく行ってるようだ。

IE6 は、CRL の署名がオレオレ認証局になっているのが気に入らないらしい。オレオレ認証局の証明書をルート証明書のリストに追加してやると、「このサイトのセキュリティ証明書は、取り消されています。このサイトは信頼するべきではありません。」と出てくる。これがまさに期待通りの挙動だ。

とはいえ、オレオレ認証局の証明書をインストールするのは、はばかられるので、IE6 で CRL の動作が確認できたという結論をもって、インストールしたオレオレ認証局証明書をアンインストールした。

Firefox 3.6 では、どうするのだろう? 調べてみると、Online Certificate Status Protocol(OCSP)
というものを使うらしい。openssl ocsp で、OCSP のサーバを動かすことができるようだけれど、ど、実際動かしてみたらエラーが出た。エラーメッセージからはソケットをバインドするのに失敗しているように見えるけど、それがエラーの原因かどうかはよく分からない。

$  openssl ocsp -index index.txt -CA cacert.pem -rsigner cacert.pem -port 8888
Error setting up accept BIO
3148073508:error:02006016:system library:bind:Invalid argument:/u7/NetBSD/src/crypto/dist/openssl/crypto/bio/b_sock.c:759:port='8888'
3148073508:error:20069075:BIO routines:BIO_get_accept_socket:unable to bind socket:/u7/NetBSD/src/crypto/dist/openssl/crypto/bio/b_sock.c:761:
(追記)

どうも NetBSD 5.0.2 付属の OpenSSL (OpenSSL 0.9.9-dev 09 May 2008) のバグらしい。
FreeBSD 8.0 付属の OpenSSL 0.9.8k 25 Mar 2009 だとちゃんと動く。OpenSSL 本家のサイトから
OpenSSL 1.0.0a を持ってきてコンパイルしたら動作した。

(追記2)

動いたと思ったら、IPv6 アドレスの ::1 にしかバインドしてくれない。-url とかでホストを指定しても無視されてるっぽい。

Apache2.2 の SSL

Apache を 2.0 系列から 2.2 系列へ移行した。デフォルトの http.conf が機能別に分割されて、SSL 関連は httpd-ssl.conf で設定されるようになっている。以前の形式でも一部を修正すれば動くのだが、今後のメンテナンスを考慮して、新しい分割された記述に合わせるようにした。

デフォルトの http.conf では SSL 関連の設定を行う httpd-ssl.conf がコメントアウトされているので、コメントを外して有効にする。

# Secure (SSL/TLS) connections
Include etc/httpd/httpd-ssl.conf

http-ssl.conf で、サーバ証明書を SSLCertificate に、鍵を SSLCeritificateKeyFile に設定する。証明書の認証局が中間認証局であったりオレオレ認証局である場合には、認証局の証明書を SSLCertificateChainFile に設定する。

(略)
#   Server Certificate:
#   Point SSLCertificateFile at a PEM encoded certificate.  If
#   the certificate is encrypted, then you will be prompted for a
#   pass phrase.  Note that a kill -HUP will prompt again.  Keep
#   in mind that if you have both an RSA and a DSA certificate you
#   can configure both in parallel (to also allow the use of DSA
#   ciphers, etc.)
SSLCertificateFile "/usr/pkg/etc/httpd/server.crt"
#SSLCertificateFile "/usr/pkg/etc/httpd/server-dsa.crt"
#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile "/usr/pkg/etc/httpd/server.key"
#SSLCertificateKeyFile "/usr/pkg/etc/httpd/server-dsa.key"
#   Server Certificate Chain:
#   Point SSLCertificateChainFile at a file containing the
#   concatenation of PEM encoded CA certificates which form the
#   certificate chain for the server certificate. Alternatively
#   the referenced file can be the same as SSLCertificateFile
#   when the CA certificates are directly appended to the server
#   certificate for convinience.
SSLCertificateChainFile "/usr/pkg/etc/httpd/server-ca.crt"
(略)

設定が終わったら普通に再起動すると SSL が有効になる。以前と異なり startssl というものはない。

今回行った SSL 設定のディレクティブのまとめ。紛らわしいものに SSLCACertificateFile というものがある。こちらはクライアント認証を行うときに設定するもの。誤解して設定しても動くところがまた紛らわしい。

SSLCertificateFile
サーバ証明書のファイル名。
SSLCertificateKeyFile
サーバ秘密鍵のファイル名。
SSLCertificateChainFile
サーバ証明書を発行した中間認証局 (CA) の証明書のファイル名。
SSLCACertificateFile
クライアント認証を行う場合の、クライアント証明書を発行した CA の証明書のファイル名。誤解を恐れずにいえば、ブラウザにインストールされているルート証明書のようなもの。サーバ証明書を発行した中間認証局の証明書をここに置いても機能するが、中間証明書は SSLCertificateChainFile に置くのが正しい。Web で見られる事例も混同しているのが多いようだ。歴史的な経緯によるのかな?

自己 CA の証明書

自己 CA の証明書の形式に不具合があったので作りなおした。不具合とは、X509v3 Basic Constraints の値が CA:FALSE になっていたこと。この状態だと、自己 CA が認証局 (CA) として扱われない。Firefox などの証明書ビューアでは、Extensions – Certificate Basic Constraints の値が “Is a Certificate Authority” や ”Is not a Certificate Authority” などと表示される。キーチェインが正しく取り扱われるためには、もちろん “Is a Certificate Authority” である必要がある。

慌てて作業したので、CA の秘密鍵を上書きして消してしまった。バックアップから鍵を書き戻してやり直し。

まず、既存の鍵を指定して新しいリクエストを作成する。

$ openssl req -new -key private/cakey.pem -out careq.pem

次に、自分自身の鍵で署名する。

$ openssl req -x509 -key private/cakey.pem -in careq.pem -out cacert.pem -days 3650
(2010.6.10追記)

次のように -new と -x509 を同時に指定すれば、一回で自己署名した CA の証明書ができる。

$ openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 3650
(2010.6.10追記 ここまで)

ちなみに openssl ca -selfsign で作成した自己証明書では CA:TRUE にならなかった。openssl.cnf の中の全ての basicConstrains に CA:TRUE を指定してもダメ。うまくいった方が正しいのだろうけど、どう考えたらよいのか。

CA:TRUE であることを確認する。

$ openssl x509 -in cacert.pem -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
(略)
X509v3 extensions:
(略)
X509v3 Basic Constraints:
CA:TRUE
(略)

サーバにインストールしていた CA の証明書の部分を置き換えて完了。CA の秘密鍵は変更ないので、サーバ証明書は変更なし。

これで自己 CA の証明書が正しい形式になった。Firefox で「発行者の証明書が信頼されていないためこの証明書は信頼されません。」と正しい警告が表示される。

接続の安全性を確認できません

… に安全に接続するように求められましたが、接続の安全性が確認できませんでした。

安全に接続する場合は通常、あなたが適切な相手と通信することを確認できるように、信頼できる証明書を提供してきます。しかし、このサイトの証明書は信頼性を検証できません。

(略)

技術的詳細を表示

… は不正なセキュリティ証明書を使用しています。

発行者の証明書が信頼されていないためこの証明書は信頼されません。

(エラーコード: sec_error_untrusted_issuer)

(略)

SSL証明書の更新

いつものように Thunderbird でメールをチェックしようとしたら、SSL 証明書の有効期限が切れているとの警告が出た。メールサーバには imapd-uw を使って SSL 経由で接続している。自分で運用して自分でしか使っていないサーバなので、使っている証明書は、認証局 (CA) も自前の、いわゆるオレオレ証明書というものだ。

imapd で使う証明書を自己証明書にしても良いのだが、認証局の運用の仕組みを知りたかったので、自前サーバ上で OpenSSL による認証局を立ち上げ、imapd で使う証明書に署名をする形にしている。認証局の証明書は自己証明書で有効期限は10年とし、imapd の証明書の有効期限は 1 年としている。

自己認証局で、署名をする機会などそうそうあるものではなく、openssl を実行することは実際のところ、年に1度になっている。当然のように前にやったことなど忘れてしまっているので、今回もそうであるが、期限が切れてから慌てることになる。とはいえ、期限を短くすれば面倒なだけであるし、期限を3年とかにしたら、思い出すのが不可能になってしまうかもしれないので、1年に1度の混乱は我慢することにしている。

作業のメモは当然作るわけだが、理解しないまま作業した結果がたまたまうまくいったとか (しかも試行錯誤をしたうえで)、当時は普通だったけど今では時代遅れになっているとか、実行環境が変わって昔のやり方ではできないとか、以前はなかった要因が今回は増えているとかあって、作業の見直しはいつでも必要になる。

完全に理解した上で正しい記録を残すのが望ましいが、そうもいってられないので、せめて、後からの検証に耐えうるように、実際の作業の内容と結果、確認したことと、未確認なことが判別できるような記述を心がけたいと思う。

今回の証明書の更新では、有効期限が切れた証明書の失効手続きを行う、という作業が必要になった。更新は今回が初めてではないはずだが、1年前の作業を調べてみると、その時は CA を作り直している。何か思うところがあって、やり直したのだろうが、そこのところはメモしていなかった。我ながら困ったものである。たぶんそれまでの CA の運営方法が間違っていると判断したのだろう。今回は、CA はそのままで、imapd 用の証明書の更新のみを行うことにする。

はじめに証明書の失効手続きを行う。期限切れの証明書と、新たに更新する証明書は、特に理由がない限りその識別名 (DN) は同じにすると思う。私もそうする。ところが、 CA で署名する際に、DN が同じだと署名に失敗してしまう。有効な証明書は DN 1つに付き1つしか存在できないらしい。当然といえば当然かもしれない。ただ、期限切れの証明書と失効した証明書は別物というのは注意が必要なのかもしれない。また、OpenSSL の署名時のエラーメッセージも適切でないと思う。’failed to update database’ では失敗の原因を誤解するではないか。

証明書の失効手続きが初めての時は、crlnumber というファイルがおそらく存在しない。そのときは、あらかじめ次のように crlnumber というファイルを作成しておかなければならない。このファイル名は openssl.conf の crlnumber で定義されていて、サンプルでは $dir/crlnumber となっている。たぶん、ファイルの中身は失効した証明書の個数を表しているのだろう。

$ echo "00" > crlnumber

crlnumber ができたら、証明書の失効手続きをおこなう。失効手続きは CA.sh でサポートされていないようなので、openssl コマンドを直接実行しなければならない。また、失効させる証明書の現物が必要である。通常の環境であれば index.txt に CA が署名した DN とシリアル番号の一覧がある (行頭が V となっているのが現在有効な証明書) ので、ここで失効させたいシリアル番号を確認しておく。例えばシリアル番号 01 の証明書を失効させたい場合、newcerts/01.pem というように過去に署名した証明書の控えが保存されているはずなので、このファイルを指定して次のように失効手続きを行う。

$ openssl ca -revoke newcerts/01.pem
Using configuration from /etc/openssl/openssl.cnf
Enter pass phrase for /home/moriko/Config/CA/private/cakey.pem:
Revoking Certificate 01.
Data Base Updated

失効すると、index.txt の該当箇所には R (Revoked) の印がつけられる(他の情報も記録される)。crlnumber の中の数字がインクリメントされる。

また、次のようにして失効した証明書のリストを更新する。imap-uw で失効した証明書を調べてくれるのかどうかは知らない。

$ openssl ca -gencrl -out crl.pem

これで新しい証明書を作成する準備ができたので、CA.sh を使って新しいリクエストを作成する。この手順はよく知られている。ただし、CA.sh を使った場合、作成される鍵 (newkey.pem) にはパスフレーズが要求されてしまう。これが都合が悪い場合は後述するように、後からパスフレーズを不要にした鍵に変換すれば良い。CA.pl だと -newreq-nodes オプションで、はじめからパスフレーズ不要の鍵とすることができる、らしい。

$ ./CA.sh -newreq
Generating a 1024 bit RSA private key
(略)
writing new private key to 'newkey.pem'
Enter PEM pass phrase:(パスフレーズの入力)
Verifying - Enter PEM pass phrase:(パスフレーズの入力)
(略)