OpenSSL の使い方練習 - Qiita の説明が大げさすぎたので、もっと簡単に証明書チェーンを作る方法です。
ここでは、openssl でできるだけ単純な証明書チェーンを作ります。目標
- root.crt: ルート証明書
- middle.crt: 中間証明書
- leaf.crt: 下っ端の証明書。S/MIME だけに使える。
ルート証明書を作る
まず、できるだけ簡単にオレオレルート証明書 (root.crt) と秘密鍵 (root.key) を作ります。
openssl req -x509 -days 36500 -subj "/CN=Tama Root CA" -keyout root.key > root.crt
- openssl req: 本来証明書要求 (CSR) を作成するコマンドですが、-x509 オプションを付けて一気にオレオレ証明書まで作っています。
- -x509: オレオレ証明書を作るオプションです。
- -days: -x509 と一緒に指定して有効期限を決められます。遊びなので 100 年にしてみました。
- -subj: Subject name を指定します。キーバリューペアで持ち主の情報を指定するもので、X.520 で規定されているそうです。CN だけ指定すれば見分けは付きます。
- -keyout: ついでに秘密鍵も作成します。
ルート証明書の中を確認します。
openssl x509 -text -noout -purpose < root.crt
-purpose オプションでこの証明書の利用目的を確認出来ます。ほぼ Yes なので、これだけで簡単な実験には十分と思います。
中間証明書を作る
次に中間証明書用を作ります。試しに今度は設定ファイルを使ってみます。以下のような middle.conf を作ります。ファイルの説明は openssl-req(1) CONFIGURATION-FILE-FORMAT にあります。
[req] # req コマンドではこのセクションを読む
prompt = no # 対話的に設定したくないなら no
distinguished_name = dn # prompt = no の時に subject として参照するセクション。この場合 [dn]
[dn] # ここに持ち主の情報を書きます。属性は X.520 で決まっているそうです。
C = AQ # 国名
L = Penguin Villege # 町名
O = Penguin Police # 組織名
CN = Penguin Middle CA # 名前や URL など
今度は真面目に証明書要求 (middle.csr) と秘密鍵 (middle.key) を作ります。
openssl req -new -config middle.conf -keyout middle.key -nodes > middle.csr
- -new: 証明書要求を作るオプションです。
- -config: コマンドラインにあれこれ書くより設定ファイルを指定出来ます。指定したファイルの
[req]
セクションが使われます。 - -nodes: パスフレーズ無しで秘密鍵を生成したい時に使います。
証明書要求の中を確認します。
openssl req -text -noout < middle.csr
実は、今回もう一つ設定ファイルが必要です。ルート証明書は openssl req -x509 で作ってしまったので自動生成されましたが、他の証明書を検証するには CA として有効になるように basicConstraints=CA:TRUE
という制約設定が必要です。このように証明書の細かい機能を指定する物を x509 V3 extension といいます(/docs/man1.1.1/man5/x509v3_config.html)。次のようなファイル middle-ext.conf を作ります。
basicConstraints=critical,CA:TRUE, pathlen:0
ちなにみ、この設定は後に証明書を検証する時にだけ使われます。CA:FALSE でも証明書の署名はできてしまうので注意。
証明書要求 (middle.csr) をルート証明書で署名して、中間証明書 (middle.crt) を作ります。extension の設定を -extfile middle-ext.conf
で与えます。副産物としてシリアル番号ファイル (root.srl) が出来ます。
openssl x509 -req -days 36500 -CA root.crt -CAkey root.key -CAcreateserial -extfile middle-ext.conf < middle.csr > middle.crt
- openssl x509: ルート証明書では省略しましたが、本来署名は openssl x509 コマンドで行います。
- -req: 入力として証明書要求を受け取ります。これがないと証明書を受け取るらしいです。
- -CAcreateserial: シリアル番号を記録するファイルを自動的に作ります。ルート証明書に .csr がついた名前になります。
- -CA: 署名する証明書です。
- -CAkey: 署名する証明書の秘密鍵です。
下っ端証明書を作る
最後に下っ端証明書を作ります。同じように証明書要求 (leaf.csr) と秘密鍵 (leaf.key) を作ります。今度は再び -subj で Subject name を指定してみます。
openssl req -new -subj "/L=Musashi/CN=kodaira.example.com" -keyout leaf.key -nodes > leaf.csr
S/MIME 専用の証明書にするには、やはり x509 V3 extension を使います。leaf-ext.conf を作ります。
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = emailProtection
ここが一番難しく、この記述の組み合わせで証明書の用途を制限します。例えば S/MIME のためには x509(1) の S/MIME Signing, Encryption の条件を満たす必要があります。歴史的事情ですかね。
- S/MIME Signing には Common S/MIME client tests が有効で keyUsage の digitalSignature が必要。
- S/MIME Encryption には Common S/MIME client tests が有効で keyUsage の keyEncipherment が必要。
- Common S/MIME client test には extendedKeyUsage の emailProtection が必要。
いよいよ下っ端証明書要求 (leaf.csr) を中間証明書で署名して、下っ端証明書 (leaf.crt) を作ります。S/MIME 専用にするために extension を -extfile leaf-ext.conf
で与えます。副産物としてシリアル番号ファイル (middle.srl) が出来ます。
openssl x509 -req -days 36500 -CA middle.crt -CAkey middle.key -CAcreateserial -extfile leaf-ext.conf < leaf.csr > leaf.crt
下っ端証明書の中を確認します。-purpose
で S/MIME に使えるか確認します。
openssl x509 -text -noout -purpose < leaf.crt
...
S/MIME signing : Yes
確認する。
中間証明書の検証には openssl verify コマンドを使います。
$ openssl verify -show_chain -x509_strict -CAfile root.crt middle.crt
middle.crt: OK
Chain:
depth=0: C = AQ, L = Penguin Villege, O = Penguin Police, CN = Penguin Middle CA (untrusted)
depth=1: CN = Tama Root CA
最後に下っ端証明書の検証をしたいのですが、どうやら openssh verify コマンドで証明局を指定する -CAfile オプションが一つしか指定出来ないらしく、middle.crt と root.crt を同時に指定出来ません。そのため -CApath オプションを使う必要があるのですが、このオプションを使うには証明書のファイル名を c_rehash で特殊な形式に変換(シンボリックリンク)する必要があります。
$ c_rehash .
$ ls -l *.0
lrwxrwxrwx 1 tyamamiya tyamamiya 10 Dec 22 11:44 13c5cc8a.0 -> middle.crt
lrwxrwxrwx 1 tyamamiya tyamamiya 8 Dec 22 11:44 253caadf.0 -> root.crt
lrwxrwxrwx 1 tyamamiya tyamamiya 8 Dec 22 11:44 63d9aef2.0 -> root.crt
lrwxrwxrwx 1 tyamamiya tyamamiya 8 Dec 22 11:44 68c2b9ae.0 -> leaf.crt
lrwxrwxrwx 1 tyamamiya tyamamiya 10 Dec 22 11:44 d349d568.0 -> middle.crt
lrwxrwxrwx 1 tyamamiya tyamamiya 8 Dec 22 11:44 f97b0df8.0 -> leaf.crt
$ openssl verify -show_chain -CApath . leaf.crt
leaf.crt: OK
Chain:
depth=0: L = Musashi, CN = kodaira.example.com (untrusted)
depth=1: C = AQ, L = Penguin Villege, O = Penguin Police, CN = Penguin Middle CA
depth=2: CN = Tama Root CA
ここで invalid CA certificate
のような意味不明のエラーが出たら https://www.openssl.org/docs/man1.1.1/man1/verify.html#DIAGNOSTICS を読むと良いです。