中間認証局(Intermediate CA)
概要
中間認証局(Intermediate CA) は、ルート認証局(Root CA)とサーバー証明書(End-Entity Certificate)の間に位置する認証局です。RFC 5280 の Section 6 で定義された証明書パス検証(Certification Path Validation)において、ルート CA が直接サーバー証明書に署名するのではなく、中間 CA を経由して署名する階層構造を取ります。
この階層構造にはセキュリティ上の明確な理由があります。ルート CA の秘密鍵は OS やブラウザーのトラストストアに組み込まれた信頼の起点であり、漏洩すればそのルート CA が署名したすべての証明書の信頼が崩壊します。ルート CA の秘密鍵はオフラインの HSM(Hardware Security Module)に厳重に保管し、日常的な証明書発行は中間 CA に委ねます。中間 CA が侵害された場合は、その中間証明書を失効させるだけでルート CA の信頼性を維持できます。
実際に 2011 年、オランダの認証局 DigiNotar が侵害を受け、Google や他の主要ドメインの不正証明書が発行されました。同年には Entrust の子会社 DigiCert Sdn. Bhd(マレーシア)が弱い鍵を持つ証明書 22 枚を発行し、Mozilla がこの中間 CA の信頼を取り消しています。これらの事例は、中間 CA の失効によってルート CA の信頼を守るという設計が実際に機能した事例です。
仕組み
中間 CA はルート CA の秘密鍵をオフラインに保ちつつ日常的な証明書発行を行い、侵害時には中間証明書の失効だけで影響を封じ込めます。
証明書チェーンにおける役割
証明書チェーンは通常 3 階層で構成されます。
[Root CA 証明書] ← OS/ブラウザーのトラストストアに格納
└── 署名
[中間 CA 証明書] ← サーバーが TLS ハンドシェイクで送出
└── 署名
[サーバー証明書] ← サーバーが TLS ハンドシェイクで送出
TLS ハンドシェイクでサーバーが送るのはサーバー証明書と中間証明書です。ルート証明書はクライアント側のトラストストアにあるため送信しません。ブラウザーはサーバー証明書の Issuer フィールドから中間証明書を辿り、中間証明書の Issuer からトラストストア内のルート証明書に到達することでチェーン全体を検証します。
Basic Constraints と pathLenConstraint
中間 CA の証明書には RFC 5280 で定義された Basic Constraints 拡張が必須です。この拡張は 2 つの情報を持ちます。
cA フラグは TRUE に設定され、この証明書が CA であること(つまり他の証明書に署名する権限があること)を示します。サーバー証明書ではこのフラグは FALSE です。
pathLenConstraint は、この CA の下に続けられる中間 CA の最大数を指定します。pathLenConstraint:0 と設定された中間 CA は、サーバー証明書にのみ署名でき、さらに別の中間 CA を作ることはできません。この制約により、万が一中間 CA が侵害されても、攻撃者が新たな中間 CA を作成して被害を拡大するリスクを防ぎます。
# 中間証明書の Basic Constraints を確認
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -text | grep -A2 "Basic Constraints"
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
ルート CA と中間 CA の運用上の違い
ルート CA と中間 CA は PKI における役割が明確に分かれています。
ルート CA の秘密鍵はオフラインの HSM に保管します。証明書の発行は数年に一度、新しい中間 CA を作成するときだけです。ルート証明書の有効期間は 20 - 30 年と長く、OS やブラウザーのアップデートを通じてトラストストアに配布されます。
中間 CA の秘密鍵はオンラインの HSM で運用され、日常的にサーバー証明書を発行します。中間証明書の有効期間は 5 - 10 年が一般的です。Let’s Encrypt の現行中間証明書(R10、R11)は 2027 年 3 月 12 日に期限を迎えます。
Let’s Encrypt の中間 CA 構成
Let’s Encrypt は 2024 年 3 月に新しい中間証明書 R10 - R14 を導入しました。すべて ISRG Root X1 から署名された RSA 2048-bit の中間証明書です。
ISRG Root X1(ルート証明書)
├── Let's Encrypt R10(中間証明書、RSA 2048、〜2027-03-12)
├── Let's Encrypt R11(中間証明書、RSA 2048、〜2027-03-12)
├── ...
└── Let's Encrypt R14
Let’s Encrypt は複数の中間 CA を同時に運用し、年単位でアクティブな中間 CA を切り替えます。certbot や acme.sh で取得した fullchain.pem にはサーバー証明書とその時点でアクティブな中間証明書が連結されています。どの中間 CA が使われたかは、証明書の Issuer フィールドで確認できます。
ECDSA 鍵を使う場合は、ISRG Root X2 から署名された E5 - E9 の中間 CA が使われます。
中間 CA の侵害と失効
中間 CA が侵害された場合、ルート CA がその中間証明書を CRL(Certificate Revocation List)に追加して失効させます。ルート CA 自体は影響を受けないため、別の中間 CA を使って証明書の発行を継続できます。
2017 年には Symantec が運営する中間 CA の管理不備が発覚し、Google と Mozilla が Symantec の PKI 全体の信頼を段階的に取り消しました。Symantec は DigiCert にインフラを移管し、2017 年 12 月 1 日以降は DigiCert のインフラから証明書を発行する形に移行しています。Chrome 70(2018 年 10 月)で Symantec の旧インフラから発行されたすべての証明書の信頼が完全に取り消されました。
この事例は、中間 CA の運用品質がルート CA の信頼にまで影響し得ることを示しています。CA/Browser Forum の Baseline Requirements では、中間 CA の監査要件や鍵管理基準が細かく規定されています。
設定例
サーバー証明書と中間証明書を正しい順序で結合し、Nginx や Apache の ssl_certificate に指定します。
商用 CA の場合
中間証明書を正しくサーバーに設定する方法です。商用 CA(DigiCert、GlobalSign、Sectigo など)から証明書を購入した場合、中間証明書は別ファイルとして提供されることがあります。
# サーバー証明書と中間証明書を結合(サーバー証明書が先)
cat server.crt intermediate.crt > fullchain.crt
# Nginx での設定
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/fullchain.crt;
ssl_certificate_key /etc/ssl/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
}
Let’s Encrypt の場合
Let’s Encrypt の場合、certbot が生成する fullchain.pem にサーバー証明書と中間証明書が含まれているため、手動で結合する必要はありません。
# Let's Encrypt の場合(fullchain.pem を指定するだけ)
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
Nginx で ssl_certificate に cert.pem(サーバー証明書のみ)を誤って指定すると、中間証明書が欠落します。
確認方法
openssl で中間証明書を確認するには次のコマンドを使います。
# チェーン全体を表示(-showcerts で中間証明書も出力)
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
出力の depth=1 に中間証明書、depth=0 にサーバー証明書が表示されます。depth=1 が表示されない場合、サーバーが中間証明書を送出していません。
中間証明書の発行者と有効期限を確認するには次のコマンドを使います。
# 中間証明書の詳細(Issuer、Subject、有効期限)を表示
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{if(++n==2) print}' | openssl x509 -noout -subject -issuer -dates
subject=CN = Let's Encrypt R10
issuer=CN = ISRG Root X1, O = Internet Security Research Group, C = US
notBefore=Mar 13 00:00:00 2024 GMT
notAfter=Mar 12 23:59:59 2027 GMT
subject が中間 CA の名称、issuer がルート CA です。notAfter は中間証明書の有効期限であり、サーバー証明書とは独立して管理されています。
外部の視点からも確認したい場合は、Labee Dev Toolbox の SSL Cert API を使うと、外部の視点から見た結果を取得できます。
curl "https://labee.dev/api/ssl-cert?hostname=example.com"
{
"success": true,
"data": {
"hostname": "example.com",
"port": 443,
"reachable": true,
"status": 200
},
"error": null,
"meta": { "responseTime": 123 }
}
data.reachable が true であれば HTTPS 接続が確立されています。中間証明書が欠落している場合、外部からの接続でも reachable: false が返ることがあります。手元の Chrome で問題なく表示されていても外部から false になる場合は、中間証明書の欠落を疑ってください。
よくある問題
中間証明書のトラブルは、設定漏れ・結合順序の誤り・有効期限切れが大半を占め、特定のブラウザーや端末でのみ症状が再現する厄介な特徴があります。
中間証明書の設定漏れ
最も多いトラブルです。ssl_certificate に中間証明書を含まないファイルを指定すると、Firefox と Android で SSL エラーが発生します。Chrome デスクトップは証明書の Authority Information Access(AIA)拡張フィールドに記載された URL から中間証明書をダウンロードする AIA fetching を実装しているため、問題なく表示されることがあります。
Firefox と Android の Chrome は AIA fetching を実装していません。そのため「Chrome デスクトップでは問題ないが Firefox や Android でエラーになる」という非対称な症状が発生します。openssl s_client -showcerts で depth=1 の証明書が出力されるか確認するのが確実です。
チェーンファイルの証明書の順序
チェーンファイル内でサーバー証明書を先頭に、中間証明書をその後に配置します。逆順にすると Nginx が起動に失敗するか、一部のクライアントで検証エラーが発生します。cat server.crt intermediate.crt > fullchain.crt の順序を間違えないようにしてください。
中間証明書の有効期限切れ
中間証明書にも有効期限があります。サーバー証明書の有効期限が切れていなくても、チェーン内の中間証明書が期限切れになると検証に失敗します。Let’s Encrypt の場合は certbot が fullchain.pem を自動更新するため通常は問題になりません。商用 CA から購入した証明書を使っている場合は、CA が中間証明書を更新した際にサーバー側のチェーンファイルも差し替える必要があります。
古い中間証明書のキャッシュ
CA が中間証明書を更新した後も、サーバーが古い中間証明書を返し続けるケースがあります。サーバー証明書を更新しても中間証明書のファイルを差し替えていない場合に起こります。新しいサーバー証明書の Issuer と古い中間証明書の Subject が一致しないと、チェーン検証に失敗します。証明書更新時には中間証明書も含めて確認してください。
複数階層の中間 CA
一部の CA は 2 階層の中間 CA(ルート → 中間 CA 1 → 中間 CA 2 → サーバー)を使います。この場合、サーバーは中間 CA 1 と中間 CA 2 の両方の証明書をチェーンに含める必要があります。チェーンが長くなるほど TLS ハンドシェイクの転送データが増え、初回接続の遅延が大きくなります。CA から提供されたすべての中間証明書を漏れなく結合してください。