
opensslコマンドとは、SSL/TLS証明書や秘密鍵の中身を表示し、検証し、作成するためのOpenSSL付属のコマンドラインツールです。証明書の確認は「サーバーが実際に返している証明書」と「手元のファイル」の2系統に分かれ、使うサブコマンドも s_client と x509 に分かれます。まずこの区別を押さえると、コマンドを覚えやすくなります。
ここでは、有効期限・SAN(サブジェクト代替名)・発行者・チェーンの確認、SAN付きCSRの作成、秘密鍵との対応確認、PFXへの変換、期限の一括チェックまでを扱います。実行例はUbuntu 24.04のOpenSSL 3.0.13で、検証用に作った小さな認証局と、手元で起動したTLSサーバーを相手に取得したものです。
この記事でわかること
- サーバーの証明書を
s_clientで取り出し、有効期限・SAN・発行者を確認するコマンド - 「Verify return code」の20・21・62などが何を意味し、どこを直せばよいか
- SAN付きCSRの作り方と、秘密鍵・CSR・証明書が対応しているかの確かめ方
- PFX(PKCS#12)への変換と、OpenSSL 3で古いPFXが読めないときの対処
- 複数サーバーの期限をまとめて確認するスクリプトと、最長有効期間の短縮への備え
最初にファイルの形式を見分ける
証明書まわりのファイルは拡張子が当てにならず、.crt と .cer の中身がPEMのこともDERのこともあります。head -1 ファイル名 で先頭行を見るのが確実です。
| 形式 | 中身 | 見分け方 | 主な用途 |
|---|---|---|---|
| PEM(証明書) | 証明書1枚以上をBase64で表したテキスト | -----BEGIN CERTIFICATE----- | nginx、Apache、Linuxの多くのソフト |
| DER | 証明書1枚のバイナリ | テキストとして読めない | Windows、Java、一部のネットワーク機器 |
| 秘密鍵(PEM) | 鍵のテキスト | -----BEGIN PRIVATE KEY-----、EC PRIVATE KEY、RSA PRIVATE KEY | サーバーの設定。外に出さない |
| CSR | 証明書署名要求 | -----BEGIN CERTIFICATE REQUEST----- | 認証局への申請 |
| PKCS#12(PFX) | 証明書・中間証明書・秘密鍵をパスワード付きで1つにまとめたバイナリ | 拡張子 .pfx / .p12 | Windows(IIS)、Azure、証明書の受け渡し |
作業前に openssl version でバージョンも確かめます。この先のオプションはOpenSSL 3系を前提にしています。macOS標準の /usr/bin/openssl は実体がLibreSSLで、一部のオプションが無いことがあるため、Homebrewの openssl@3 を使うほうが迷いません。
サーバーの証明書を確認する:openssl s_client
s_client はTLSクライアントとしてサーバーに接続し、受け取った証明書と検証結果を表示します。出力が長いので、証明書部分だけを openssl x509 に渡して必要な項目を取り出すのが定番の使い方です。</dev/null を付けるのは、接続後に入力待ちで止まらず、すぐに切断させるためです。
# 公開サーバーの場合(ホスト名は自社のものに置き換える)
openssl s_client -connect www.example.jp:443 -servername www.example.jp </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -enddate -ext subjectAltName
# 検証環境での出力(手元のTLSサーバーに、検証用ルート証明書を指定して接続)
$ openssl s_client -connect 127.0.0.1:8443 -servername www.example.test -CAfile root.crt </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -enddate
subject=CN = www.example.test
issuer=CN = Example Test Intermediate CA
notAfter=Dec 22 23:53:50 2026 GMT-servername はSNI(接続先のホスト名をTLSの最初に伝える拡張)を送る指定です。1つのIPアドレスで複数のサイトを動かしているサーバーは、SNIを見て返す証明書を選びます。OpenSSL 1.1.1以降は -connect にホスト名を書けば自動でSNIを付けますが、ロードバランサーを飛ばしてオリジンのIPアドレスへ直接つなぐときは付かないので、-servername を明示しないと既定の別サイトの証明書が返ってきます。
接続の要点だけを見たいときは -brief、中間証明書まで含めてサーバーが何を送っているかを見たいときは -showcerts を使います。-showcerts の出力で 0 s:(サーバー証明書の主体)と i:(発行者)、1 s:(中間証明書)が並んでいれば、サーバーはチェーンを正しく送っています。
$ openssl s_client -connect 127.0.0.1:8443 -servername www.example.test -CAfile root.crt -brief </dev/null
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN = www.example.test
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits
DONE
$ openssl s_client -connect 127.0.0.1:8443 -servername www.example.test -CAfile root.crt -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'
0 s:CN = www.example.test
i:CN = Example Test Intermediate CA
1 s:CN = Example Test Intermediate CA
i:CN = Example Test Root CATLSのバージョンごとに受け付けるかを確かめるなら -tls1_2 や -tls1_3 を付けます。検証環境で -tls1_2 を付けると New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384 と表示され、TLS 1.2でも接続できることがわかりました。メールサーバーのようにSTARTTLSで暗号化を始めるサービスは、openssl s_client -connect mail.example.jp:587 -starttls smtp -servername mail.example.jp のようにプロトコルを指定します。
Verify return code の読み方
s_client の出力の最後にある Verify return code が、証明書チェーンの検証結果です。検証環境で意図的に壊した構成を用意し、実際に出た値を表にしました。
| コードと表示 | 再現した状況 | 主な原因 | 直す場所 |
|---|---|---|---|
| 0 (ok) | 中間証明書を送り、ルートを -CAfile で指定 | — | — |
| 20 (unable to get local issuer certificate) | -CAfile を付けずに社内CAの証明書へ接続 | クライアントが発行元のルートを信頼していない | クライアント側の信頼ストア(社内CAなら配布漏れ) |
| 21 (unable to verify the first certificate) | サーバーがサーバー証明書だけを送り、中間証明書を送らない | サーバー設定のチェーン不足 | サーバー側。中間証明書を連結したファイルを指定する |
| 18 (self-signed certificate) | 自己署名証明書のサーバーに接続 | 検証用の証明書のまま公開している | 正規の証明書に差し替える |
| 10 (certificate has expired) | 有効期限切れの証明書を検証 | 更新漏れ、または更新後の再読み込み漏れ | サーバー側で更新・リロード |
| 62 (hostname mismatch) | -verify_hostname に証明書にない名前を指定 | SANに接続先の名前が含まれていない | 証明書の再発行(SANの追加) |
注意したいのは62です。s_client は既定ではホスト名の一致を確かめないため、名前違いの証明書でも Verify return code: 0 (ok) になります。名前まで確かめるときは -verify_hostname www.example.jp を付けるか、-ext subjectAltName で目視します。スクリプトで使う場合は -verify_return_error を付けると、検証に失敗した時点で接続を打ち切って終了コード1を返すので、判定に使えます。
TLS 1.3で接続すると、サーバーから届くセッションチケットごとに接続情報が出力されるため、Verify return code の行が2〜3回表示されます。grep で拾うときは grep -m1 'Verify return code' で最初の1行に絞ってください。行数を数えて判定するスクリプトは、TLS 1.2のサーバーとで結果が変わってしまいます。
証明書ファイルの中身と有効期限を確認する
手元のファイルは openssl x509 で読みます。-noout で証明書本体の出力を止め、欲しい項目だけを並べます。全部を見たいときは -text ですが、100行を超えるので、普段は項目を指定したほうが速く読めます。
$ openssl x509 -in www.crt -noout -subject -issuer -dates -serial
subject=CN = www.example.test
issuer=CN = Example Test Intermediate CA
notBefore=Sep 23 23:53:50 2026 GMT
notAfter=Dec 22 23:53:50 2026 GMT
serial=7B98B88212D7C2947ADD173B3A2B046B41BD3194
$ openssl x509 -in www.crt -noout -ext subjectAltName,extendedKeyUsage
X509v3 Subject Alternative Name:
DNS:www.example.test, DNS:example.test
X509v3 Extended Key Usage:
TLS Web Server Authentication
# 日付をISO 8601形式で出す(スクリプトで比較しやすい)
$ openssl x509 -in www.crt -noout -enddate -dateopt iso_8601
notAfter=2026-12-22 23:53:50Z
# 30日(2,592,000秒)以内に切れるか。切れないなら終了コード0
$ openssl x509 -in www.crt -noout -checkend 2592000
Certificate will not expireチェーンの検証は openssl verify で行います。-CAfile に信頼するルート、-untrusted に中間証明書を渡します。中間証明書を渡し忘れると、サーバーが中間証明書を送らないときと同じ error 20 at 0 depth lookup: unable to get local issuer certificate になるので、サーバーへ入れる前のファイルの組み合わせを確かめるのに向いています。
$ openssl verify -CAfile root.crt -untrusted inter.crt www.crt
www.crt: OK
$ openssl verify -CAfile root.crt www.crt
CN = www.example.test
error 20 at 0 depth lookup: unable to get local issuer certificate
error www.crt: verification failedSAN付きのCSRを作る
CSR(証明書署名要求)は、公開鍵と「この名前で証明書が欲しい」という情報を秘密鍵で署名したものです。ブラウザーはChrome 58以降、証明書のCN(コモンネーム)ではなくSANだけでホスト名を照合するので、CSRにもSANを必ず入れます。-addext を使えば、OpenSSL 3ではコマンド1行で指定できます。
# RSA 2048ビットの鍵とCSRを同時に作る(-noenc は鍵を暗号化しない指定。旧 -nodes)
openssl req -new -newkey rsa:2048 -noenc \
-keyout www.example.jp.key -out www.example.jp.csr \
-subj "/CN=www.example.jp" \
-addext "subjectAltName=DNS:www.example.jp,DNS:example.jp"
chmod 600 www.example.jp.key
# 中身を確認する(署名が正しいか・名前・SAN)
openssl req -in www.example.jp.csr -noout -subject -verify
openssl req -in www.example.jp.csr -noout -text | grep -A1 'Subject Alternative Name'2つ目の確認コマンドは Certificate request self-signature verify OK と主体名を表示し、3つ目はSANの行を表示します。鍵の種類は、古い機器や一部のクライアントまで考えるならRSA 2048ビット、対応が確認できているならECDSA P-256(-newkey ec -pkeyopt ec_paramgen_curve:P-256)が選択肢です。DV証明書ならCN以外の主体情報は認証局がほぼ使わないので、組織名や所在地は認証局の申請画面の指示に従って入れます。秘密鍵は認証局にもベンダーにも送りません。送るのはCSRだけです。
秘密鍵・CSR・証明書の組み合わせを確かめる
サーバーの移設や更新で一番多い事故が、「別の秘密鍵と組み合わせてしまう」ことです。3つのファイルから公開鍵を取り出してハッシュを比べれば、一致するかどうかが一目でわかります。RSAでしか使えない -modulus の比較と違い、この方法はECDSAの鍵でもそのまま使えます。
$ openssl x509 -in www.crt -noout -pubkey | openssl sha256
SHA2-256(stdin)= 9a51e9c730d02a697d088336413b7f9836f7f3ca9c600a81a722b8bea677c2d7
$ openssl pkey -in www.key -pubout | openssl sha256
SHA2-256(stdin)= 9a51e9c730d02a697d088336413b7f9836f7f3ca9c600a81a722b8bea677c2d7
$ openssl req -in www.csr -noout -pubkey | openssl sha256
SHA2-256(stdin)= 9a51e9c730d02a697d088336413b7f9836f7f3ca9c600a81a722b8bea677c2d7
# 別の鍵(中間CAの鍵)では値が変わる
$ openssl pkey -in inter.key -pubout | openssl sha256
SHA2-256(stdin)= 2c6a7bcbf1ee186d1cb98ecfdff8df13c228edfbeb4c09239cf1bab037239408検証用の自己署名証明書と、小さな社内CA
動作確認だけなら自己署名証明書で足ります。-days を省略するとOpenSSL 3.0は30日の証明書を作りますが、後から見た人にも意図がわかるよう、検証用の短い期間を明示しておきます。
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout test.key -out test.crt -days 30 \
-subj "/CN=test.internal" -addext "subjectAltName=DNS:test.internal"社内の複数サーバーで使うなら、ルート証明書を1つ作って端末に配り、各サーバーの証明書をそこから発行するほうが管理しやすくなります。この記事の検証環境も、次の手順でルート→中間→サーバーの3段を作っています。ポイントは、CA用の証明書に CA:TRUE と keyCertSign、サーバー用に CA:FALSE と serverAuth を付けることと、-copy_extensions copy でCSRのSANを証明書へ引き継ぐことです。
# ルートCA(10年)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout root.key -out root.crt -days 3650 -subj "/CN=Example Test Root CA" \
-addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign,cRLSign"
# 中間CA(5年)
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout inter.key -out inter.csr -subj "/CN=Example Test Intermediate CA"
printf 'basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign\n' > inter.ext
openssl x509 -req -in inter.csr -CA root.crt -CAkey root.key -CAcreateserial -days 1825 -extfile inter.ext -out inter.crt
# サーバー証明書(90日)
openssl req -new -newkey rsa:2048 -noenc -keyout www.key -out www.csr \
-subj "/CN=www.example.test" -addext "subjectAltName=DNS:www.example.test,DNS:example.test"
printf 'basicConstraints=critical,CA:FALSE\nkeyUsage=critical,digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth\n' > www.ext
openssl x509 -req -in www.csr -CA inter.crt -CAkey inter.key -CAcreateserial -days 90 \
-extfile www.ext -copy_extensions copy -out www.crt
# サーバーに渡すチェーン(サーバー証明書→中間証明書の順)
cat www.crt inter.crt > fullchain.crtルート証明書は、Ubuntuなら /usr/local/share/ca-certificates/ に拡張子 .crt で置いて sudo update-ca-certificates、RHEL系なら /etc/pki/ca-trust/source/anchors/ に置いて sudo update-ca-trust で信頼ストアに入ります。検証環境で追加した後は、-CAfile なしの openssl verify でも OK になりました。Windowsの端末へはグループポリシーやIntuneで配るのが現実的です。ルートの秘密鍵 root.key は、中間CAを作り終えたらオフラインの媒体へ移し、日常の発行は中間CAで行います。
PFX(PKCS#12)への変換と、OpenSSL 3の注意
WindowsのIISやAzureに証明書を入れるときは、証明書・中間証明書・秘密鍵を1つにまとめたPFXを求められます。OpenSSL 3.0の既定では、中身をAES-256-CBCとPBKDF2で暗号化します。
# まとめる(エクスポート用のパスワードを2回聞かれる)
$ openssl pkcs12 -export -inkey www.key -in www.crt -certfile inter.crt -out www.pfx
Enter Export Password:
Verifying - Enter Export Password:
# 暗号方式を確認する(Certificate bag が2つ=サーバー証明書と中間証明書)
$ openssl pkcs12 -in www.pfx -info -noout
Enter Import Password:
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
Certificate bag
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
# 古いWindowsへ渡すなど、旧方式(3DES)で作る必要があるとき
openssl pkcs12 -export -inkey www.key -in www.crt -certfile inter.crt -out www-compat.pfx \
-keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1
# PFXから取り出す
openssl pkcs12 -in www.pfx -nokeys -out www-from-pfx.crt
openssl pkcs12 -in www.pfx -nocerts -noenc -out www-from-pfx.key
# PEMとDERの相互変換
openssl x509 -in www.crt -outform der -out www.cer
openssl x509 -in www.cer -inform der -out www-from-der.crtWindows Server 2016のような古いWindowsは、AES-256で暗号化したPFXを読み込めないことがあります。そのときだけ旧方式で作り直し、受け渡しが済んだPFXは削除します。逆に、他社のシステムから受け取った古いPFXをOpenSSL 3で開くと、RC2という古い暗号が既定で無効なため、次のエラーで止まります。
Error outputting keys and certificates
40071534C07F0000:error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported:../crypto/evp/evp_fetch.c:386:Global default library context, Algorithm (RC2-40-CBC : 0), Properties ()この場合は、読み込むコマンドに -legacy を追加すると開けます(例:openssl pkcs12 -in old.pfx -info -noout -legacy)。取り出したら、次に誰かへ渡すときは既定の方式で作り直してください。
PFXには秘密鍵が入っています。ファイルとパスワードを同じメールや同じチャットのスレッドで送ると、どちらか一方が漏れた時点で両方が漏れたのと同じになります。ファイルは共有ストレージ、パスワードは電話やパスワードマネージャーの共有機能というように経路を分け、受け渡しが済んだら送った側・受け取った側の両方でファイルを削除します。
有効期限をまとめてチェックする
証明書の最長有効期間は短くなり続けています。CA/Browser Forumの決定により、公開証明書の上限は2026年3月15日から200日、2027年3月15日から100日、2029年3月15日から47日へ段階的に短縮されます(執筆時点)。年1回の手作業での更新は成り立たなくなるので、ACMEによる自動更新と、それが本当に動いているかの監視を組み合わせます。監視側は、次のスクリプトを1日1回動かすだけでも始められます。
#!/bin/sh
# check-cert-expiry.sh — hosts.txt の「ホスト名:ポート」を順に調べ、期限が近いものを知らせる
DAYS=${DAYS:-30}
while read -r target; do
case "$target" in ''|'#'*) continue ;; esac
host=${target%:*}
pem=$(timeout 10 openssl s_client -connect "$target" -servername "$host" </dev/null 2>/dev/null | openssl x509 2>/dev/null)
if [ -z "$pem" ]; then
echo "NG $target 証明書を取得できない"
continue
fi
end=$(printf '%s\n' "$pem" | openssl x509 -noout -enddate -dateopt iso_8601 | cut -d= -f2)
if printf '%s\n' "$pem" | openssl x509 -noout -checkend $((DAYS * 86400)) >/dev/null; then
echo "OK $target $end"
else
echo "EXPIRE $target $end"
fi
done < "${1:-hosts.txt}"検証環境で、90日の証明書・10日の証明書・何も動いていないポートの3つを並べて実行すると、OK localhost:9443 2026-12-22 23:50:23Z、EXPIRE localhost:9444 2026-10-03 23:50:23Z、NG localhost:9445 証明書を取得できない の3行になりました。timeout 10 は応答しないホストで全体が止まらないようにするためです。NG を放置すると「監視していたつもりで見ていなかった」状態になるので、EXPIRE と同じ扱いで通知します。
Windowsでの確認方法
OpenSSLを入れていないWindowsでも、標準の certutil とPowerShellで同じ確認ができます。certutil -dump www.cer で中身を表示し、certutil -verify -urlfetch www.cer で中間証明書の取得と失効確認まで含めたチェーン検証を行います。サーバーに入っている証明書の期限は、PowerShellで Get-ChildItem Cert:\LocalMachine\My | Format-Table Subject, NotAfter, Thumbprint を実行すると一覧になります。
ブラウザーで確かめるなら、Chromeではアドレスバー左端のアイコンから「この接続は保護されています」→「証明書は有効です」と進むと、発行先・発行元・有効期間とチェーンが表示されます(表示名は執筆時点のもので、変わることがあります)。ただしブラウザーは足りない中間証明書を自分で補うことがあるため、コード21の問題はブラウザーでは見つからず、s_client でしか気づけないことがあります。
動作確認
本番に向ける前に、社内CAの手順で作ったファイルを使い、手元でTLSサーバーを起動して一連のコマンドを試せます。openssl s_server は検証用の簡易サーバーで、127.0.0.1にだけバインドしておけば外からは接続されません。
# チェーン付きで待ち受ける(別の端末で起動したままにする)
openssl s_server -accept 127.0.0.1:8443 -cert www.crt -key www.key -cert_chain inter.crt -www
# 確認する
openssl version
openssl s_client -connect 127.0.0.1:8443 -servername www.example.test -CAfile root.crt </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -enddate
openssl s_client -connect 127.0.0.1:8443 -servername www.example.test -CAfile root.crt -brief </dev/null
openssl verify -CAfile root.crt -untrusted inter.crt www.crt期待する結果は、1つ目で OpenSSL 3.0.13 などのバージョン、2つ目で主体・発行者・期限の3行、3つ目で Verification: OK、4つ目で www.crt: OK です。s_server を -cert_chain inter.crt なしで起動し直すと、3つ目の -brief の結果が Verification error: unable to verify the first certificate に変わり、接続自体は成立したままコード21の状態を再現できます。
つまずきポイント
s_clientが終わらずに止まる
</dev/null を付け忘れると、接続後にキーボード入力を待ち続けます。付けているのに止まる場合は、途中のファイアウォールで通信が捨てられています。スクリプトでは timeout 10 openssl s_client … のように上限を付け、手作業なら nc -vz ホスト名 443 で先に到達性を確かめます。
ブラウザーでは問題ないのに「Verify return code: 21」
サーバーが中間証明書を送っていません。ブラウザーは過去に見た中間証明書を使ったり取得し直したりして補うため気づきにくいのですが、curl、スマートフォンのアプリ、他社のシステム連携は失敗します。nginxなら ssl_certificate にサーバー証明書だけでなく、中間証明書を連結した fullchain.crt を指定します。
「key values mismatch」でWebサーバーが起動しない
証明書と秘密鍵が対になっていません。検証環境で別の鍵を指定して s_server を起動すると、error:05800074:x509 certificate routines:X509_check_private_key:key values mismatch で止まりました。nginxやApacheも同じOpenSSLの関数でこの確認をしています。前述の公開鍵ハッシュの比較で、正しい組み合わせの鍵を探します。
PFXを開くと「0308010C:digital envelope routines::unsupported」
OpenSSL 3で、RC2などの古い暗号で作られたPFXを読んだときのエラーです。-legacy を付けて開き、取り出した鍵と証明書は既定の方式で作り直します。Node.jsなどOpenSSL 3を内蔵したツールでも同じ番号のエラーが出ることがあり、原因は共通です。
よくある質問
SSL証明書の有効期限をコマンドで確認するには?
サーバーに入っている証明書なら openssl s_client で取得して openssl x509 -noout -enddate に渡し、ファイルなら直接 openssl x509 -in ファイル -noout -enddate を実行します。スクリプトで判定するなら、指定した秒数以内に切れるかどうかを終了コードで返す -checkend が便利で、30日前に知りたければ2592000秒を指定します。
証明書が正しくインストールされているか確認する方法は?
社外の端末から openssl s_client で接続し、Verify return codeが0であること、-showcerts で中間証明書まで送られていること、-verify_hostname で名前が一致することの3点を確かめます。ブラウザーだけの確認では、中間証明書の送り忘れを見逃すことがあります。
ChromeでSSL証明書を確認する方法は?
アドレスバー左端のアイコンをクリックし、「この接続は保護されています」から「証明書は有効です」を開くと、発行先・発行元・有効期間・チェーンが確認できます(執筆時点の表示名)。サーバー側の設定不備はブラウザーが補ってしまう場合があるので、公開前の確認にはコマンドでの検証を併用してください。
SSL化されているかをチェックする方法は?
443番で openssl s_client -brief を実行し、Verification: OK とTLSのバージョンが表示されればHTTPSで正しく応答しています。あわせて curl -sI http://ホスト名/ でHTTPからHTTPSへ転送されるかを確かめると、http://のままアクセスされる経路が残っていないかもわかります。
まとめ
サーバーの状態は s_client、ファイルの中身は x509、チェーンの組み合わせは verify、鍵の対応は公開鍵のハッシュ比較、と道具を使い分ければ、証明書まわりの確認はほぼ網羅できます。s_client は既定でホスト名を照合しないこと、コード21はブラウザーでは見えないことの2つを覚えておくと、切り分けで遠回りしません。有効期間の上限は今後も短くなるので、更新の自動化と期限監視のスクリプトを今のうちに用意しておいてください。