SSL 証明書の更新の際、誤って中間 CA 証明書に間違ったものを使用してしまい、ブラウザに警告が表示されたことがありました。今後このようなことを避けるために、Web サーバに適用する前に証明書のチェーンが正しいかどうか確認する方法をまとめました。
検証に使用した OS は Ubuntu20.04 です。
ルート証明書の確認
中間 CA 証明書の Issuer から、中間 CA 証明書の上位のルート証明書を確認します。GlobalSign の場合、中間 CA 証明書は ルート証明書/中間CA証明書 | GMOグローバルサイン サポート からダウンロードができます。
openssl x509 -in gsgccr3dvtlsca2020-x509.cer -issuer -noout
issuer= /OU=GlobalSign Root CA - R3/O=GlobalSign/CN=GlobalSign
上記コマンドで分かったルート証明書をサーバ上で探します。trust
コマンドが入っている場合は、証明書がインストールされているか確認ができます。たくさん表示されるのでgrep
コマンドで絞り込むと良いでしょう。
trust list | grep -i GlobalSign
label: GlobalSign ECC Root CA - R4
label: GlobalSign ECC Root CA - R5
label: GlobalSign Root CA
label: GlobalSign Root CA - R3
label: GlobalSign Root CA - R6
label: GlobalSign Root E46
label: GlobalSign Root R46
label: GlobalSign Secure Mail Root E45
label: GlobalSign Secure Mail Root R45
インストールが確認できたらルート証明書のファイルを探します。
Ubuntu20.04 の場合は /etc/ssl/certs/
にあります。詳しくは Installing a root CA certificate in the trust store | Ubuntu を参照。
Amazon Linux2 の場合は Red Hat 7 系の OS と同じく /etc/pki/tls/certs/ca-bundle.crt
にあります。詳しくは 4.14. 共有システムの証明書の使用 Red Hat Enterprise Linux 7 | Red Hat Customer Portal を参照。
openssl verify -CApath オプションの確認
証明書の検証は openssl verify
コマンドを使います。man verify
コマンドで使い方を確認します。
$ man verify
SYNOPSIS
openssl verify ... [-CApath directory] ... [certificates]
OPTIONS
...
-CApath directory
A directory of trusted certificates. The certificates should have names of the form: hash.0 or have symbolic links to them of this form ("hash" is the hashed
certificate subject name: see the -hash option of the x509 utility). Under Unix the c_rehash script will automatically create symbolic links to a directory of
certificates.
-CApath
オプションで指定するディレクトリにルート証明書と中間 CA 証明書を置いて、引数にサーバ証明書を指定すれば良いようです。ただし、オプションの説明を見ると以下のようにかかれています。
証明書は、hash.0という形式の名前、またはこの形式の証明書へのシンボリックリンクを持っている必要があります。("hash "はハッシュ化された証明書のサブジェクト名です:x509 ユーティリティの -hash オプションを参照してください。)
Unix では、c_rehash スクリプトは自動的に、証明書のディレクトリへのシンボリックリンクを作成します。
ルート証明書と中間証明書は hash.0
という形式の名前にするか、この形式にしたシンボリックリンクにする必要があるようです。そして、そのシンボリックリンクを作成してくれる c_rehash スクリプトが用意されているとのこと。
検証するために証明書のファイルを集める
サーバ証明書、中間 CA 証明書、ルート証明書を 1 箇所に集めます。certs
ディレクトリを作成し、ルート証明書と中間 CA 証明書を移動します。ディレクトリ構成はこんな感じ。
.
├── certs
│ ├── GlobalSign_Root_CA_-_R3.pem(ルート証明書)
│ └── gsgccr3dvtlsca2020-x509.cer(中間 CA 証明書)
└── server.pem(サーバ証明書)
ルート証明書と中間 CA 証明書にシンボリックリンクを作成する
ドキュメントにかかれていた c_rehash
スクリプトでシンボリックリンクを作成します。
openssl rehash certs/
certs
ディレクトリの中身を確認します。hash.0
形式のシンボリックリンクができていますね。
├── certs
│ ├── 062cdee6.0 -> GlobalSign_Root_CA_-_R3.pem
│ ├── 5d5277b9.0 -> gsgccr3dvtlsca2020-x509.cer
│ ├── GlobalSign_Root_CA_-_R3.pem
│ └── gsgccr3dvtlsca2020-x509.cer
└── server.pem
/etc/ssl/certs
ディレクトリも、よく見ると hash.0
形式のシンボリックリンクが置かれています。
$ ls -l /etc/ssl/certs/ | grep GlobalSign
062cdee6.0 -> GlobalSign_Root_CA_-_R3.pem
1d3472b9.0 -> GlobalSign_ECC_Root_CA_-_R5.pem
4a6481c9.0 -> GlobalSign_Root_CA_-_R2.pem
5ad8a5d6.0 -> GlobalSign_Root_CA.pem
GlobalSign_ECC_Root_CA_-_R4.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_ECC_Root_CA_-_R4.crt
GlobalSign_ECC_Root_CA_-_R5.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_ECC_Root_CA_-_R5.crt
GlobalSign_Root_CA.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_Root_CA.crt
GlobalSign_Root_CA_-_R2.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_Root_CA_-_R2.crt
GlobalSign_Root_CA_-_R3.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_Root_CA_-_R3.crt
GlobalSign_Root_CA_-_R6.pem -> /usr/share/ca-certificates/mozilla/GlobalSign_Root_CA_-_R6.crt
b0e59380.0 -> GlobalSign_ECC_Root_CA_-_R4.pem
dc4d6a89.0 -> GlobalSign_Root_CA_-_R6.pem
証明書を検証する
証明書を検証します。
openssl verify -CApath certs/ server.pem
正しい場合は以下のような出力になります。
server.pem: OK
階層構造がおかしい場合は以下のようなエラーになります。
error 20 at 0 depth lookup: unable to get local issuer certificate
error server.pem: verification failed