openssl でやっつけでクロスルート証明書を作って接続テストする

手元でクロスルート証明書を作って接続テストする手順のメモ。 openssl ca とか CA.sh だといろいろ面倒なので openssl x509 でやっつけです。

# CA1の秘密鍵と証明書(自己署名証明書)
openssl req -new -x509 -newkey rsa:2048 -nodes -sha256 -subj /CN=CA1/O=ore -days 365 -keyout ca1.key -out ca1.crt

# openssl x509 で署名時、素のままだとCA用の証明書にならないので
# X509拡張属性用のファイルを作成(中間証明書用)
#
# なお req で自己署名証明書を作るときは素のままでもCA用にx509拡張属性が付与される
# (そのように openssl.cnf で定義されている)
echo "basicConstraints=CA:true" > ca.ext

# 中間CAの秘密鍵とCSR
openssl req -new -newkey rsa:2048 -nodes -sha256 -subj /CN=inner/O=ore -keyout inner.key -out inner.csr

# 中間CA証明書をCA1で署名して発行
openssl x509 -req -days 365 -in inner.csr -out inner.crt -CA ca1.crt -CAkey ca1.key -CAcreateserial -extfile ca.ext

# サーバの秘密鍵とCSR
openssl req -new -newkey rsa:2048 -nodes -sha256 -subj /CN=localhost/O=ore -keyout sv.key -out sv.csr

# サーバ証明書を中間CAで署名して発行
openssl x509 -req -days 365 -in sv.csr -out sv.crt -CA inner.crt -CAkey inner.key -CAcreateserial

# CA1からサーバ証明書の検証
openssl verify -show_chain -CAfile ca1.crt -untrusted inner.crt sv.crt
#=> sv.crt: OK
#=> Chain:
#=> depth=0: CN = localhost, O = ore (untrusted)
#=> depth=1: CN = inner, O = ore (untrusted)
#=> depth=2: CN = CA1, O = ore

# CA2の秘密鍵と証明書(自己署名証明書)
openssl req -new -x509 -newkey rsa:2048 -nodes -sha256 -subj /CN=CA2/O=ore -days 365 -keyout ca2.key -out ca2.crt

# クロスルート用のCSR、秘密鍵にはCA1を指定する
openssl req -new -nodes -sha256 -subj /CN=CA1/O=ore -key ca1.key -out cross.csr

# クロスルート用の中間証明書をCA2で署名して発行
openssl x509 -req -days 365 -in cross.csr -out cross.crt -CA ca2.crt -CAkey ca2.key -CAcreateserial -extfile ca.ext

# CA2からサーバ証明書の検証
openssl verify -show_chain -CAfile ca2.crt -untrusted cross.crt -untrusted inner.crt sv.crt
#=> sv.crt: OK
#=> Chain:
#=> depth=0: CN = localhost, O = ore (untrusted)
#=> depth=1: CN = inner, O = ore (untrusted)
#=> depth=2: CN = CA1, O = ore (untrusted)
#=> depth=3: CN = CA2, O = ore

できました。openssl s_server でサーバを立てて curl でアクセスしてみます。 まずはクロスルート用中間証明書なしでサーバを実行した場合。

# クロスルート用中間証明書なしでサーバを実行
openssl s_server -accept 8443 -www -chainCAfile inner.crt -cert sv.crt -key sv.key

curl https://localhost:8443/ --cacert ca1.crt # OK
curl https://localhost:8443/ --cacert ca2.crt # ng

curl 側で cacert に CA1 を指定すれば OK ですが、CA2 だとクロスルート用中間証明書が無いのでダメです。

次にサーバでクロスルート用中間証明書ありでサーバを実行した場合。

# クロスルート用中間証明書ありでサーバを実行
openssl s_server -accept 8443 -www -chainCAfile <(cat cross.crt inner.crt) -cert sv.crt -key sv.key

curl https://localhost:8443/ --cacert ca1.crt # OK
curl https://localhost:8443/ --cacert ca2.crt # OK

curl 側で cacert に CA1 と CA2 のどちらの場合でも OK になりました。