合同会社小村ソフト
第 6 章

openssl とブラウザで観察する

openssl s_client の出力と証明書ビューアの読み方を身につけ、証明書エラーを「3 チェックのどれが失敗したか」で切り分ける。

頭で追ったものを、実物で確かめる

第 5 章までで仕組みは一巡しました。この章では openssl とブラウザを使って、ここまで頭で追ってきたハンドシェイク・証明書・チェーンを実物で観察します。ゴールは 2 つ — 出力のどこを見ればよいかが分かること、そして証明書エラーを「第 4 章の 3 チェックのどれが失敗したか」に翻訳して切り分けられることです。

注意: 観察は自分が管理するサーバや公開サイトへの通常のアクセスの範囲で行ってください。以下のコマンドはすべて「1 回の TLS 接続をして結果を表示する」だけの、通常のアクセスと同じ操作です。

openssl s_client — ハンドシェイクをその場でやってみる

TLS 調査のいちばんの基本手です。実際にハンドシェイクを行い、受け取ったものを全部見せてくれます。

openssl s_client -connect example.com:443 -servername example.com < /dev/null

出力は長いですが、見る場所は決まっています。

Certificate chain(誰が誰に署名したか)
s:(subject = 証明書の主)と i:(issuer = 署名した CA)が段ごとに並ぶ。leaf の i: と次の段の s: が繋がっているかを目で追う — 第 4 章のチェーンがそのまま出力になっている
Verify return code(検証の結末)
0 (ok) なら 3 チェック通過。certificate has expiredunable to get local issuer certificate(チェーンが繋がらない)など、失敗理由がそのまま書かれる
Protocol / Cipher(何で話しているか)
TLSv1.3 / TLS_AES_128_GCM_SHA256 のように、合意されたバージョンと AEAD 暗号(第 5 章)が確認できる

-servername は第 5 章の SNI です。これを忘れるとサーバはどの証明書を出すべきか分からず、別のデフォルト証明書が返って誤診のもとになります。調査コマンドをブラウザと同じ条件にそろえる — 切り分けの前提です。

証明書の中身を 1 枚だけじっくり読みたいときは、x509 サブコマンドに渡します。

openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

notBefore / notAfter(有効期間)と SAN(名前の一覧)— 3 チェックのうち 2 つの材料が、この 1 行で手に入ります。ブラウザでも鍵マーク → 証明書ビューアで同じ情報を GUI で確認できます。どちらで見ても読む項目は同じです。

小問 6-1 — 出力を読む

openssl の出力と証明書の中身を、第 4 章の 3 チェックに対応づけて読みます。

Q1. openssl s_client の出力に verify error: certificate has expired と出ました。第 4 章の 3 つのチェックのうち、失敗しているのはどれですか。

Q2. 証明書を確認すると notAfter=Aug 11 23:59:59 2026 GMT とありました。今日を 2026 年 7 月 12 日とすると、有効期限まで残り約何日ですか。

Q3. openssl s_client -connect example.com:443 を実行するとき、-servername example.com(SNI の指定)を付け忘れると何が起きえますか。

証明書エラーを期限切れ・名前不一致・チェーン不備の 3 系統に切り分けるフローチャート

証明書エラーの切り分けは「3 チェックのどれが失敗したか」への翻訳から始まります。エラー文言は違っても、行き着く箱はこの 3 つ + 失効です。

3 大エラーの切り分け表

実務で出会う証明書エラーの大半は、次の 3 系統に落ちます。どれも第 4 章の 3 チェックと 1 対 1 に対応しています。

失敗したチェック典型的な文言よくある原因まず打つ手
有効期間certificate has expired更新忘れ・自動更新の失敗-dates で notAfter を確認し、更新。残り日数の監視を入れる
名前照合hostname mismatchSAN に載っていない名前でのアクセス、SNI の指定漏れSAN の一覧と、実際にアクセスしている名前・SNI を突き合わせる
署名チェーンunable to get local issuer certificate / self-signed certificate中間証明書の設定漏れ、自己署名、ルートストアにない社内 CAs_client でサーバが送るチェーンを確認。中間の欠落ならサーバ設定を修正

とくに中間証明書の設定漏れは、「ブラウザでは開けるのに、curl や API クライアントからだけ失敗する」という一見不可解な形で現れる定番です。ブラウザはキャッシュや補完取得で穴を埋めてしまうことがあるからで、サーバが実際に何を送っているかを s_client で見るのが直行ルートです。

「検証を切る」前に立ち止まる

切り分けを急ぐあまり、curl -k や「証明書エラーを無視する」設定に手が伸びることがあります。第 1 章の 3 つの問いで言えば、これは真正性の確認だけを自分で外す行為です。暗号化は残るので一見安全に見えますが、「偽物と秘密の会話をする」状態 — 第 4 章の中間者攻撃にそのまま無防備になります。

一方、社内ネットワークには正規の手続きで真ん中に入る仕組みもあります。TLS インスペクションを行うプロキシは、会社の自前 CA を各端末のルートストアに配布した上で、各サイトの証明書をその CA で発行し直します。検証の終点はルートストア(第 4 章)なので、これはエラーになりません。「社給 PC では出ないエラーが、持ち込み機や CI サーバでだけ出る」ときは、この構図を思い出してください — 足りないのはルートストアへの社内 CA の追加であって、検証を切ることではありません。

最後にもう 1 つ、ブラウザ側の防波堤として HSTS(HTTP Strict Transport Security)にも触れておきます。一度 HSTS ヘッダを受け取ったサイトには、ブラウザは以後 HTTPS でしか接続せず、証明書エラーの「無視して進む」ボタンも出しません。「エラー画面に進むボタンがない」のは故障ではなく、サイト側が指定した安全装置です。

小問 6-2 — 定番のケースを切り分ける

実務で繰り返し出会う 3 つの場面です。原因を 1 つに絞り込んでください。

Q4. ブラウザでは問題なく開けるサイトに、curl や自作プログラムからアクセスすると証明書検証エラーになります。まず疑うべき原因はどれですか。

Q5. 検証エラーの回避策として curl -k(--insecure)を恒久的に使うことの問題点はどれですか。

Q6. ある会社では、社内プロキシがセキュリティ検査のため TLS 通信をいったん復号しています(TLS インスペクション)。それでも社給 PC のブラウザに証明書エラーが出ないのはなぜですか。

この章で持ち帰ること

  • openssl s_client -connect ホスト:443 -servername ホスト が基本手。chain の s:/i:、Verify return code、Protocol/Cipher を読む
  • 証明書エラーは「3 チェックのどれが失敗したか」に翻訳してから対処する。文言の暗記ではなく対応づけ
  • 「ブラウザだけ通る」は中間証明書の欠落をまず疑う。「社給 PC だけ通る」はルートストアの社内 CA を疑う
  • 検証を切るのは解決ではない。原因のチェックを特定して直す

次章は総合演習です。ここまでの 6 章を横断するケース問題で、知識を「使える形」に仕上げます。