1. 通信の大きな流れ

  1. TCP 接続(3 ウェイハンドシェイク)
    • SYN → SYN/ACK → ACK でコネクション作成
    • HTTP でも HTTPS でも実行、SSL/TLS 以前の土台
  2. TLS ハンドシェイク
    • 暗号化の準備をする段階
    • サーバーの証明書を検証し、暗号化に使う鍵を決める
  3. 暗号化された通信の開始
    • HTTP リクエストを暗号化して送る

証明書の検証に失敗すると 2. で止まり、HTTP リクエストはサーバーに届きません。

2. 用語の整理

用語 意味
認証局(CA) 証明書を発行(署名)する組織・役割
サーバー証明書 サーバーの公開鍵・ドメイン名・有効期限・認証局名・認証局の署名
中間証明書 中間認証局の公開鍵・上位の認証局の署名
ルート証明書 一番上の認証局の証明書。自分自身で署名している(自己署名)
CA 一覧(CA バンドル) クライアントが最初から持っている、信頼するルート証明書のリスト
  • 「認証局」は組織、「〇〇証明書」はその認証局の身分証
  • 証明書は単なる公開鍵ではなく、「この公開鍵は誰のものか」に認証局の署名でお墨付きを与えたもの

3. サーバーが送ってくるもの

サーバーはハンドシェイクで、証明書の連鎖をまとめて送ってくる。

[0] example.com       ← サーバー証明書(中間 CA-1 が署名)
[1] 中間 CA-1         ← 中間証明書(中間 CA-2 が署名)
[2] 中間 CA-2         ← 中間証明書(ルート CA が署名)
    (ルート CA)     ← 送られてこない。クライアントの CA 一覧にある
  • 送る: サーバー証明書と中間証明書
    • クライアントは中間証明書を普通持っていないので、サーバーが送る必要がある
  • 送らない: ルート証明書
    • 送られてきても信頼の根拠にはならない

4. クライアントの検証手順

  1. サーバー証明書の署名を、中間証明書の公開鍵で確かめる
  2. 中間証明書の署名を、その上の証明書の公開鍵で確かめる(繰り返し)
  3. 連鎖の最後の証明書に書かれた発行者名で、CA 一覧からルート証明書を探す
  4. 見つかったルート証明書の公開鍵で、最後の証明書の署名を確かめる
  5. すべて正しければ検証成功

ルート証明書は「検証しない」

  • ルート証明書は自己署名なので、署名を確かめても正しさは証明できない
  • 「CA 一覧に入っているルートは信頼する」と最初から決めている(トラストアンカー)
  • 信頼の根拠は、サーバーから送られてきたものではなく、手元の CA 一覧

CA 一覧は誰が管理しているか

  • ブラウザや OS のベンダーが審査して管理している(Mozilla / Apple / Microsoft / Google など)
  • アップデートで追加や削除がある
  • アプリやライブラリが独自の CA 一覧ファイル(例: cacert.pem)を持っていることもある

5. クロス署名

新しいルート認証局は、まだ多くの CA 一覧に入っていない。 そこで、すでに広く信頼されている古いルートに署名してもらった証明書も用意する。

[2] 新ルート CA(クロス署名版)← 発行者: 旧ルート CA
    旧ルート CA                ← CA 一覧にある
  • CA 一覧に新ルートがある環境では、新ルートで検証が終わる
  • 旧ルートしかない環境では、旧ルートの公開鍵で新ルートの証明書を確かめて終わる
  • 名前に「Root」と付いていても、その連鎖での終点(真のルート)は、クライアントの CA 一覧によって変わる

6. よくあるエラー: unable to get local issuer certificate

意味は「発行者の証明書が手元にない」で、連鎖をたどりきれないときに出る。

原因 状況
クライアントの CA 一覧が古い 新しいルートが一覧に入っていない
サーバーが中間証明書を送っていない サーバーの設定ミス。ブラウザは中間証明書を自動で補うことがあるため、ブラウザでは見られるのに curl などでは失敗する

7. 実運用での注意点

  • ライブラリ独自の CA 一覧に注意
    • OS の CA 一覧を使わず、同梱の古い CA ファイルを使うライブラリがある
    • コードで CA ファイルを指定すると(curl の CURLOPT_CAINFO など)、php.ini などの設定より優先される
    • メンテナンスが止まったライブラリでは、CA 一覧が古いまま残る
  • コンテナの CA 一覧はイメージの中のもの
    • ECS / Fargate などのホスト側の CA 一覧は使われない
    • CA 一覧はイメージをビルドした時点のもので固定されるので、更新にはイメージの作り直しが必要
  • 確認コマンド ```bash

    サーバーが送ってくる証明書の連鎖を見る

    echo | openssl s_client -connect example.com:443 -servername example.com

    特定の CA ファイルで検証できるか試す

    curl –c