サーバ証明書と中間証明書・ルート証明書のチェーン検証(正しい証明書のつながりかどうかの確認)をOpenSSLで行うには、実はコマンドを一発叩くだけでは上手くいかない「ひと手間」が必要です。
たまにしかやらない作業で毎回忘れかけるので、備忘録として手順と注意点をまとめました。
OpenSSLでチェーンを検証する基本コマンド
OpenSSLでチェーン検証を行うには、openssl verify コマンドを使用します。
openssl verify -CApath 【中間・ルート証明書のディレクトリ】 【サーバ証明書】
# 実行例
openssl verify -CApath ./CACerts server.cer-CApath オプションで中間証明書やルート証明書が入っているディレクトリを指定すればOK……と思いきや、ここで大きな罠があります。
OpenSSLでは、-CApath 内に配置する中間・ルート証明書のファイル名を、対象証明書の「ハッシュ値」にした名前に変更しなければ読み込んでくれません。
罠:ハッシュ値を使ったファイル名(.0)への変更
実際にやってみましょう。以下のように証明書を配置して、そのまま検証コマンドを叩くとエラーになります。
## server.cer:kaede.jpのサーバ証明書
## CACerts/ :中間証明書、ルート証明書を入れたフォルダ
$ ll CACerts/
total 8
-rw-r--r-- 1 forev 197609 1970 Jul 18 23:54 'ISRG RootX1.cer'
-rw-r--r-- 1 forev 197609 1856 Jul 18 23:54 R3.cer
# そのまま検証するとエラーになる
$ openssl verify -CApath ./CACerts server.cer
error server.cer: verification failed
CN = *.kaede.jp
error 20 at 0 depth lookup: unable to get local issuer certificateCApathで指定したフォルダ内の証明書は、**【ハッシュ値.0】**というファイル名にする必要があります。拡張子のように .0 を最後につけるのが重要です。
ハッシュ値の確認とリネーム(またはシンボリックリンク作成)
まずは対象の証明書(今回は中間証明書の R3.cer)のハッシュ値を確認します。
# ハッシュ値を確認するコマンド
$ openssl x509 -hash -noout -in ./CACerts/R3.cer
8d33f237ハッシュ値が 8d33f237 だと分かったので、これに .0 をつけた名前でシンボリックリンクを作成します。(mvコマンドでリネームしても良いですが、元のファイル名が分からなくなるのでシンボリックリンクがおすすめです)。
# シンボリックリンクを作成する
$ cd CACerts
$ ln -s R3.cer 8d33f237.0
# 再度検証を実行
$ cd ..
$ openssl verify -CApath ./CACerts server.cer
server.cer: OK無事に OK と表示されました! (※UNIX系の環境であれば、c_rehash というコマンドを使うと、指定したディレクトリ内の証明書のハッシュ値リンクを自動で一括作成してくれます)
便利なオプション:チェーン照会(-show_chain)
単にOKかどうかだけでなく、チェーンの階層構造(Depth)などの詳細情報を確認したい場合は、-show_chain オプションをつけると可視化できます。
$ openssl verify -CApath ./CACerts -show_chain ./server.cer
./server.cer: OK
Chain:
depth=0: CN = *.kaede.jp (untrusted)
depth=1: C = US, O = Let's Encrypt, CN = R3
depth=2: C = US, O = Internet Security Research Group, CN = ISRG Root X1補足:ルート証明書がすでにOSで信頼されている場合
ISRG Root X1 のように、実行している環境(OS等)にすでに信頼されたルート証明書としてインストールされている場合は、あえて -CApath を指定しなくても検証に成功することがあります。
$ openssl verify -show_chain ./R3.cer
./R3.cer: OK
Chain:
depth=0: C = US, O = Let's Encrypt, CN = R3 (untrusted)
depth=1: C = US, O = Internet Security Research Group, CN = ISRG Root X1よくあるエラーと対策
error 20 at 0 depth lookup: unable to get local issuer certificate
対象の証明書を発行した上位の証明書(中間やルート)が見つからない、または正しく紐付いていない場合に発生します。 -CApath の指定が間違っていないか、ディレクトリ内の証明書が正しく「ハッシュ化(.0)」されているかを確認してください。
error 10 at X depth lookup: certificate has expired
文字通り、検証しようとしている証明書、またはチェーンに含まれる中間・ルート証明書の**「有効期限が切れている」**場合に発生するエラーです。 (※署名がないなどのエラーではなく、純粋な期限切れエラーです。) 対象の証明書自体の期限が切れていないか、あるいは -CApath 内に古い(期限切れの)中間証明書が混ざっていないか、openssl x509 -dates -noout -in 【ファイル名】 で有効期限を確認してみてください。