前回まで:
第1回: 今度こそopensslコマンドを理解して使いたい (1) ルートCAをスクリプトで作成する
第2回:. 今度こそopensslコマンドを理解して使いたい (2) 設定ファイル(openssl.cnf)を理解する
第1回で作成したルートCAを使ってサーバー/クライアント証明書を作成したいところですが、今回はその前に以下の準備を行います。
- ルートCAの作成方法と拡張設定を見直す
- 拡張設定を検証して詳しく調べる
ルートCA作成方法の見直し
前回調べた設定ファイルの内容を踏まえて、第1回で作成したルートCAの作り方を見直します。
設定ファイル(openssl.cnf)
第1回でルートCA証明書の自己署名に使用した拡張セクションは、ノーマルのopenssl.cnfの[ v3_ca ]です。
→ 「拡張セクションを指定する」
ノーマルのopenssl.cnfでは、拡張セクション[ v3_ca ]内の有効な行は以下の3行だけです。
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
前回調べたとおり、拡張セクションでは鍵の用途を明示的に設定することができます。
→ 「Key Usage(鍵の用途)」
今回はCA用の鍵の用途として、以下の1行を拡張セクション[ v3_ca ]に追加します。と言ってもコメントアウトされている既存の行をアンコメントするだけです。
keyUsage = cRLSign, keyCertSign
この行を追加したことによる効果は、後ほど検証します。
シリアル番号
第1回では、CA証明書のシリアル番号をreqコマンドの-set_serialオプションで指定していました。
→ 「証明書の自己署名を同時に行う」
しかしよく考えたらルートCAの証明書をCRL(失効リスト)で無効化することはあり得ないので、そもそもシリアル番号を管理する必要がありませんでした。そのため今回はシリアル番号の指定を省略して、自動的に大きな乱数が設定されるようにします。
スクリプトの変更
第1回で作成したスクリプトを以下のように変更しました。
作成するCAの情報を定義するファイルca-listから、シリアル番号の列を削除してコモンネームだけにします。
ca1.mydomain
ca2.mydomain
CAの秘密鍵に設定するパスフレーズは、第1回と同じくファイル.capassに記述します。
mycap@ss
スクリプトのreqコマンドから-set_serialオプションを削除します。前回と同じく設定ファイルを指定しないので、自動的に/etc/pki/tls/openssl.cnfが使用されます。
CATOP=$(dirname "${0}")
# 作成するCAのコモンネームをリストから1件ずつ読み込む
while read ca_name
do
# CAのディレクトリ、証明書、秘密鍵のパス
ca_dir="${CATOP}/${ca_name}"
ca_cert="${ca_dir}/cacert.pem"
ca_key="${ca_dir}/private/cakey.pem"
# すでに証明書と秘密鍵が作成済みの場合はスキップ
[[ -e "${ca_cert}" && -e "${ca_key}" ]] && continue
# CA用のディレクトリを作成する
mkdir -p "$(dirname "${ca_cert}")"
mkdir -p "$(dirname "${ca_key}")"
# 秘密鍵を生成して自己署名証明書を発行する
# -new 新しい証明書要求を生成する
# -keyout 指定のパスで秘密鍵を出力する
# -out 指定のパスに出力する(-x509オプションを指定した場合は自己署名証明書)
# -passout 出力する秘密鍵に設定するパスフレーズを指定する
# -subj 識別名を"/type0=value0/type1=value1/type2=..."の形式で指定する
# -x509 署名要求を出力する代わりに自己署名証明書を出力する
# -days 証明書の有効日数を指定する
# -extensions 設定ファイルの拡張セクション名を指定する
openssl req \
-new \
-keyout "${ca_key}" \
-out "${ca_cert}" \
-passout "file:${CATOP}/.capass" \
-subj "/C=JP/ST=Chiba/O=myorg/CN=${ca_name}" \
-x509 -days 1095 -extensions v3_ca
# 秘密鍵のパーミッションを設定する
chmod 0400 "${ca_key}"
done <"${CATOP}/ca-list"
スクリプトを実行すると、以下のようにCAごとのサブディレクトリに秘密鍵と証明書が出力されます。
.
├── ca1.mydomain
│ ├── cacert.pem
│ └── private
│ └── cakey.pem
├── ca2.mydomain
│ ├── cacert.pem
│ └── private
│ └── cakey.pem
証明書の内容を確認する
以下のようにx509コマンドを使って証明書の内容を確認します。
openssl x509 -in ca1.mydomain/cacert.pem -text
第1回で作成した証明書との違いとして、シリアル番号がランダムな数値になったことと、拡張設定keyUsageの追加がX509v3 Key Usage: Certificate Sign, CRL Signに反映されたことが確認できます。
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
90:e8:58:56:83:91:bc:1f
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=JP, ST=Chiba, O=myorg, CN=ca1.mydomain
Validity
Not Before: Aug 8 08:48:19 2019 GMT
Not After : Aug 7 08:48:19 2022 GMT
Subject: C=JP, ST=Chiba, O=myorg, CN=ca1.mydomain
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
(略)
X509v3 Basic Constraints:
CA:TRUE
X509v3 Key Usage:
Certificate Sign, CRL Sign
(略)
証明書の拡張設定を検証する
次に、拡張設定を追加した結果を検証します。
作成した証明書の用途をコマンドで検証する
今回作成した証明書の用途がどのように設定されたかは、以下のコマンドで検証することができます。
openssl x509 -in ca1.mydomain/cacert.pem -purpose -noout
Certificate purposes:
SSL client : No
SSL client CA : Yes
SSL server : No
SSL server CA : Yes
Netscape SSL server : No
Netscape SSL server CA : Yes
S/MIME signing : No
S/MIME signing CA : Yes
S/MIME encryption : No
S/MIME encryption CA : Yes
CRL signing : Yes
CRL signing CA : Yes
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : Yes
Time Stamp signing : No
Time Stamp signing CA : Yes
比較のために、第1回で作成したCA証明書の検証結果を以下に貼り付けます。
設定の違いは、拡張設定に鍵の用途keyUsage = cRLSign, keyCertSignがないことで、基本制約basicConstraints = CA:trueは同じです。
Certificate purposes:
SSL client : Yes
SSL client CA : Yes
SSL server : Yes
SSL server CA : Yes
Netscape SSL server : Yes
Netscape SSL server CA : Yes
S/MIME signing : Yes
S/MIME signing CA : Yes
S/MIME encryption : Yes
S/MIME encryption CA : Yes
CRL signing : Yes
CRL signing CA : Yes
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : Yes
Time Stamp signing : No
Time Stamp signing CA : Yes
どちらの証明書もSSLクライアント/サーバー用CA、各種の署名用CAとして使用できることが確認できますが、今回作成した証明書(上: keyUsageあり)はその他の用途では使用できないのに対して、第1回で作成した証明書(下: keyUsageなし)は他の用途でも使用できることが分かります。
つまりCA用として使えるようにするための拡張設定は基本制約basicConstraints = CA:trueで、鍵の用途keyUsage = cRLSign, keyCertSignを追加する意味は、他の用途で使えなくすることでした。
証明書の拡張設定をドキュメントで確認する
前回設定ファイルの公式ドキュメントを読んでも詳しい説明が見つからなかった部分がx509コマンドのドキュメントで見つかったので、以下に抜粋(+和訳)して引用します。
-
x509コマンド manpage: https://www.openssl.org/docs/man1.0.2/man1/x509.html
証明書の拡張設定
-purposeオプションは、証明書の拡張設定を確認して証明書の用途を判定する。実際に行われる確認はかなり複雑で、破損した証明書とソフトウェアを処理するためのさまざまなハックや回避策が含まれる。
同じコードが証明書チェーン内の信頼できない証明書の検証にも使用されるので、この節の内容は証明書チェーンが検証コードにリジェクトされた場合にも役立つ。
拡張設定
basicConstraints(基本制約)のCAフラグは、証明書がCAとして使用できるかを決定し、値がtrueであればCAであり、falseであればCAではない。すべてのCAはCAフラグがtrueでなければならない。
basicConstraintsがない証明書は「CAの可能性あり」とされ、意図された証明書の用途にしたがって他の拡張設定がチェックされる。そのような証明書は本当はCAと見なされるべきではないので警告が発せられるが、いくつかの壊れたソフトウェアでの動作のためにCAとして認められている。
参考: 前回の「Basic Constraints(基本制約)」
拡張設定
keyUsage(鍵の用途)を追加することで、証明書の用途を制限することができる。CA証明書に拡張設定keyUsageがある場合は、必ずkeyCertSignビットがセットされなければならない。
今回x509コマンドで調べた結果のとおり、拡張設定keyUsageは「証明書の用途を制限する」と明記されていました。
Extended Key Usage(鍵の用途の拡張)は、証明書の使用を制限する。この拡張機能が存在する場合(
criticalの有無を問わず)、鍵は指定された目的にしか使用できなくなる。
こちらも「証明書の使用を制限する」と書かれていますが、CA証明書以外ではこの設定がないと目的の用途に使用できない場合があるようです。
参考: 前回の「Extended Key Usage(鍵の用途の拡張)」
それぞれのテストの説明は下記のとおりで、上記の
basicConstraintsとkeyUsageに関するコメントはすべてのCA証明書に適用される。
SSL Client
Extended Key Usageは存在しないか、または "web client authentication" OIDが含まれること。
keyUsageは存在しないか、またはdigitalSignatureビットが設定されること。
Netscape証明書タイプは存在しないか、またはSSLクライアントのビットが設定されること。
SSL Client CA
Extended Key Usageは存在しないか、または "web client authentication" OIDが含まれること。
Netscape証明書タイプは存在しないか、またはSSL CAのビットが設定されること(basicConstraintsが存在しない場合の措置として使われる)。
SSL Server
Extended Key Usageは存在しないか、または "web server authentication"および/またはSGC OIDの1つが含まれること。
keyUsageは存在しないか、またはdigitalSignature、keyEnciphermentのセットまたは両方のビットが設定されること。
Netscape証明書タイプは存在しないか、またはSSLサーバーのビットが設定されること。
SSL Server CA
Extended Key Usageは存在しないか、または "web server authentication"および/またはSGC OIDの1つが含まれること。
Netscape証明書タイプは存在しないか、またはSSL CAのビットが設定されること(basicConstraintsが存在しない場合の措置として使われる)。
Netscape SSL Server
keyUsageがある場合は、SSLサーバーに接続するネットスケープSSLクライアントのためにはkeyEnciphermentビットが必要。
ただし一部の暗号スイートはデジタル署名に鍵を使用するため、これが常に有効とは限らない。それ以外は通常のSSLサーバーと同じ。
共通S/MIMEクライアントテスト
Extended Key Usageは存在しないか、または "email protection" OIDが含まれること。
Netscape証明書タイプは存在しないか、またはS/MIMEビットのセットが必要。Netscape証明書タイプにS/MIMEビットが設定されない場合、SSLクライアントのビットが代替として許容されるが、警告が表示される(一部のVerisign証明書がS/MIMEビットを設定しないため)。
S/MIME Signing
共通S/MIMEクライアントテストに加えて、keyUsageにdigitalSignatureビットが設定されること。
S/MIME Encryption
共通S/MIMEクライアントテストに加えて、keyUsageが存在する場合はkeyEnciphermentビットが設定されること。
S/MIME CA
Extended Key Usageは存在しないか、または "email protection" OIDが含まれること。
Netscape証明書タイプは存在しないか、またはS/MIME CAビットのセットが必要(basicConstraintsが存在しない場合の措置として使われる)。
CRL Signing
keyUsageは存在しないか、またはCRL署名のビットが設定されること。
CRL Signing CA
通常のCAテストが適用される。この場合を除き、basicConstraints拡張機能が必要。
以上の調査結果を元に、次回以降でサーバー/クライアント証明書を発行してOpenVPNでの動作を確認する予定です。
今後の予定
- サーバー/クライアント証明書を発行してOpenVPNでの動作を確認
- 証明書失効処理
記事一覧
今度こそopensslコマンドを理解して使いたい (1) ルートCAをスクリプトで作成する
今度こそopensslコマンドを理解して使いたい (2) 設定ファイル(openssl.cnf)を理解する
今度こそopensslコマンドを理解して使いたい (3) CA証明書の拡張設定を検証する
今度こそopensslコマンドを理解して使いたい (4) サーバー/クライアント証明書を一括生成する
今度こそopensslコマンドを理解して使いたい (5) CRL(証明書失効リスト)を作成してOpenVPNに配布する
今度こそopensslコマンドを理解して使いたい (補足1) サンプルスクリプトのまとめ