証明書一枚を四つに分けて読む
目標
自前のCAでサーバー証明書を発行し、チェーン・有効期間・SAN・鍵の一致を、それぞれopensslで検証します。中間CAを立ててfullchainを組み立て、名前の検査結果を表にして残します。
なぜ重要なのか
証明書障害は、次の4つのうち1つです。チェーンが切れている、期限が切れている、名前が違う、鍵が組になっていない。直し方がすべて違うので、どれなのかをまず読み取る必要があります。このラボは、その4つをわざと作り、検証ツールが何と言うかを見ます。特に、OpenSSL 3.0のx509 -reqがCSRの拡張を既定で捨てるという事実は、発行が成功したように見える落とし穴なので、自分で体験しておくほうがよいです。
ステップ
- CAの秘密鍵(
/root/pki/ca.key)と自己署名証明書(/root/pki/ca.crt)を作成してください。サブジェクトはCN=Lab Root CAで、有効期間は30日です。 - サーバーの鍵(
/root/pki/server.key)とCSR(/root/pki/server.csr)を作成してください。サブジェクトはCN=www.lab.internal、SANはDNS:www.lab.internalとDNS:api.lab.internalの2つです。 - CAで署名して、サーバー証明書(
/root/pki/server.crt)を作成してください。有効期間は3日で、SANが証明書に残っている必要があります。 server.crtのシリアル番号・有効期限・SHA-256フィンガープリント・SANを保存してください(保存先:/root/pki/04-fields.txt)。- 比較用の鍵(
/root/pki/other.key)をもう1つ作成し、cert=・key=・other=の3行(それぞれ公開鍵PEMのsha256、64桁)とverdict=matchを書いてください(保存先:/root/pki/05-keymatch.txt)。 openssl x509 -enddateの出力行とrenew_within_7d=yes|noを書いてください(保存先:/root/pki/06-expiry.txt)。判定は、-checkend 604800の終了コードで行います。- 中間CA(
/root/pki/inter.key、/root/pki/inter.crt、CN=Lab Intermediate CA、CA:TRUE)をルートで署名して作成し、その中間CAでリーフ(/root/pki/api.crt、鍵は/root/pki/api.key、SANはDNS:api.lab.internal)を発行してください。リーフと中間CAをこの順に連結して、fullchainを作成してください(出力先:/root/pki/fullchain.pem)。 server.crtに対するwww.lab.internal・api.lab.internal・other.lab.internalの3つの名前の検証結果を、이름=OK|FAILの形式(プレースホルダーは名前です)で書いてください(保存先:/root/pki/08-hostname.txt)。
参考
- 鍵の生成:
openssl genrsa -out <파일> 2048(プレースホルダーはファイル名です)。自己署名:openssl req -x509 -new -key ... -days ... -subj ...。 - CSRにSANを入れる:
openssl req -new ... -addext "subjectAltName=DNS:a,DNS:b"。署名時に拡張を維持する:openssl x509 -req ... -copy_extensions copy。 - 中間CAには、
-extfileでbasicConstraints=critical,CA:TRUE,pathlen:0とkeyUsage=critical,keyCertSign,cRLSignを指定してください。 - 名前の検査:
openssl verify -CAfile ca.crt -verify_hostname <이름> server.crt(プレースホルダーは名前です)。 - よくある間違い: ステップ3で
-copy_extensions copyを忘れると、発行はできてもSANが消えます。ステップ7でリーフをルートで直接署名すると、チェーンになりません。
ルートCAを作る
/root/pki/ca.keyと自己署名の/root/pki/ca.crt(CN=Lab Root CA、30日)を作成してください。
reqに-x509を指定すると、CSRの代わりに自己署名証明書が出ます。発行者とサブジェクトが同じで、basicConstraintsがCA:TRUEになっているかを、openssl x509 -textで確認してください。
SANを含むCSR
/root/pki/server.keyと/root/pki/server.csr(CN=www.lab.internal、SAN 2つ)を作成してください。
-newkey rsa:2048 -nodes -keyoutで、鍵とCSRを一度に作れます。SANは-addextで入れ、openssl req -in server.csr -noout -textでSubject Alternative Nameを確認してください。
3日間のサーバー証明書の発行
CAで署名して、/root/pki/server.crt(3日、SAN維持)を作成してください。
x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3が骨組みです。発行後にopenssl x509 -in server.crt -noout -ext subjectAltNameが空なら、CSRの拡張が捨てられたということです。それを移すオプションがあります。
識別値を読む
server.crtのシリアル番号・有効期限・SHA-256フィンガープリント・SANを/root/pki/04-fields.txtに保存してください。
x509に-serial -enddate -fingerprint -sha256 -ext subjectAltNameを一度にまとめて指定できます。採点ツールは、同じ証明書から値を再計算して照合します。
鍵が組かどうかを判定する
/root/pki/other.keyを作成し、/root/pki/05-keymatch.txtにcert=・key=・other=(公開鍵PEMのsha256)とverdict=matchを書いてください。
証明書の公開鍵はx509 -pubkeyで、秘密鍵の公開鍵はpkey -puboutで、同じPEM形式になります。| sha256sum | cut -d' ' -f1で64桁だけを残してください。certとkeyが同じで、otherだけが異なる必要があります。
7日のウィンドウで期限を判定する
/root/pki/06-expiry.txtに-enddateの出力行とrenew_within_7d=yes|noを書いてください。
-checkend 604800は、7日(604800秒)以内に期限が切れると、0以外のコードで終了します。if文で受けて、yes/noを決めてください。3日間の証明書なら、答えは決まっています。
中間CAとfullchain
ルートが署名した中間CA(inter.key/inter.crt、CN=Lab Intermediate CA、CA:TRUE)を作成し、それでリーフのapi.crt(SAN api.lab.internal)を発行したあと、リーフ+中間の順で/root/pki/fullchain.pemを作成してください。
中間CAのCSRをルートで署名するときは、-extfileにbasicConstraints=critical,CA:TRUE,pathlen:0とkeyUsage=critical,keyCertSign,cRLSignを指定してください。リーフは-CA inter.crt -CAkey inter.keyで署名します。openssl verify -CAfile ca.crt api.crtは失敗し、-untrusted inter.crtを指定すると通るなら、本物のチェーンです。
名前検査の表
server.crtに対するwww・api・otherの3つの名前の-verify_hostnameの結果を、이름=OK|FAILの形式(プレースホルダーは名前です)で/root/pki/08-hostname.txtに書いてください。
名前の検査は、SANのdNSNameと照合します。CNにあっても、SANになければ失敗します。3つの名前をforで回しながら、終了コードでOK/FAILを決めてください。