Linux で証明書チェーンからルート CA と下位 CA を抽出するにはどうすればよいでしょうか?

Linux で証明書チェーンからルート CA と下位 CA を抽出するにはどうすればよいでしょうか?

中間証明書とルート証明書を持つエンド エンティティ/サーバー証明書があります。catエンド エンティティ証明書を開くと、単一のタグのみが表示されますBEGINENDこれは唯一のエンド エンティティ証明書です。

BEGIN中間証明書とルート証明書の内容を表示する方法はありますか。必要なのは、とタグの内容だけですEND

Windows では、「証明パス」から完全な証明書チェーンを確認できます。以下は Stack Exchange の証明書の例です。

ここに画像の説明を入力してください

そこから私はビューの証明書エクスポートします。Windows ではルートと中間の両方でこれを行うことができます。Linux でも同じ方法を探しています。

ここに画像の説明を入力してください

答え1

Web サイトからは、次の操作を実行できます。

openssl s_client -showcerts -verify 5 -connect stackexchange.com:443 < /dev/null

これにより、証明書チェーンとサーバーが提示したすべての証明書が表示されます。

さて、これら 2 つの証明書をファイルに保存すると、次を使用できますopenssl verify

$ openssl verify -show_chain -untrusted dc-sha2.crt se.crt 
se.crt: OK
Chain:
depth=0: C = US, ST = NY, L = New York, O = "Stack Exchange, Inc.", CN = *.stackexchange.com (untrusted)
depth=1: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 High Assurance Server CA (untrusted)
depth=2: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA

この-untrustedオプションは中間証明書を指定するために使用されます。これse.crtは検証する証明書です。depth=2 の結果は、システムの信頼された CA ストアから取得されました。

中間証明書がない場合、検証は実行できません。これが X.509 の仕組みです。

証明書によっては、中間証明書を取得するための URI が含まれている場合があります。例として、次のものopenssl x509 -in se.crt -noout -textが含まれます。

        Authority Information Access: 
            OCSP - URI:http://ocsp.digicert.com
            CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2HighAssuranceServerCA.crt

この「CA Issuers」URI は中間証明書を指します (DER 形式なので、openssl x509 -inform der -in DigiCertSHA2HighAssuranceServerCA.crt -out DigiCertSHA2HighAssuranceServerCA.pemOpenSSL でさらに使用できるように変換する必要があります)。

を実行するとopenssl x509 -in /tmp/DigiCertSHA2HighAssuranceServerCA.pem -noout -issuer_hashが取得され244b5494、これは のシステム ルート CA ストアで検索できます/etc/ssl/certs/244b5494.0(.0名前に追加するだけです)。

これらすべてを実行する、便利で簡単な OpenSSL コマンドは存在しないと思います。

答え2

tl;dr - チェーン内のすべての証明書をダンプするワンライナーの bash マジック

openssl s_client -showcerts -verify 5 -connect wikipedia.org:443 < /dev/null |
   awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN CERTIFICATE/){a++}; out="cert"a".pem"; print >out}'
for cert in *.pem; do 
        newname=$(openssl x509 -noout -subject -in $cert | sed -nE 's/.*CN ?= ?(.*)/\1/; s/[ ,.*]/_/g; s/__/_/g; s/_-_/-/; s/^_//g;p' | tr '[:upper:]' '[:lower:]').pem
        echo "${newname}"; mv "${cert}" "${newname}" 
done

2ステップで説明

チェーン内のすべての証明書を現在のディレクトリにダンプするには、次のようにしますcert${chain_number}.pem

openssl s_client -showcerts -verify 5 -connect your_host:443 < /dev/null |
 awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN CERTIFICATE/){a++}; out="cert"a".pem"; print >out}' 

一般的な名前に変更するためのボーナストラック:

for cert in *.pem; do 
   newname=$(openssl x509 -noout -subject -in $cert | sed -nE 's/.*CN ?= ?(.*)/\1/; s/[ ,.*]/_/g; s/__/_/g; s/_-_/-/; s/^_//g;p' | tr '[:upper:]' '[:lower:]').pem
   mv $cert $newname 
done

答え3

-verify 5オプションを使用すると、openssl はチェーンの奥深くまで移動し、証明書の展開に含まれていないものも含め、すべての証明書を表示することがわかりました。

証明書にどのチェーンが提供されているかを本当に理解したい場合は、次のコマンドを実行する必要があります。

openssl s_client -showcerts -partial_chain -connect YOUR_ENDPOINT:443 < /dev/null |less

答え4

上記の方法は、Lets Encrypt の無料ワイルドカード証明書を使用していたときには機能しませんでした。

具体的には、
*.mydomain.dev の Lets Encrypt の無料ワイルドカード証明書を使用して構成された Kubernetes クラスター + Ingress コントローラーがあり、次の 2 つのドメイン名をホストしています。

  • grafana.mydomain.dev
  • prometheus.mydomain.dev

このサイトに従って、次の -servername フラグを追加する必要がありました。https://community.letsencrypt.org/t/where-can-i-download-the-trusted-root-ca-certificates-for-lets-encrypt/33241/2

export DOMAIN=grafana.mydomain.dev
openssl s_client -showcerts -verify 5 -connect $DOMAIN:443 -servername $DOMAIN < /dev/null 2> /dev/null | awk '/BEGIN/,/END/{ if(/BEGIN/){a++}; print}'

また、チェーンを微調整して、完全な証明書 + 中間証明書 + ルート証明書を標準出力に提供し、stderr ノイズを非表示にしました。

実は... テストしてみると、これでは CA が得られないことがわかりました... openssl s_client -showcerts -verify 5 -connect letsencrypt.org:443 < /dev/null 2> /dev/null | awk '/BEGIN/,/END/{ if(/BEGIN/){a++}; print}'

curl https://letsencrypt.org/certs/isrgrootx1.pem 異なる値を与えます (いくつかのものをテストする場合、これが機能する値です)。

関連情報