このページの目次
証明書とPKI
TLSの安全な基盤——X.509証明書チェーン、ACMEによる自動発行、OCSP/CRLによる失効確認、Certificate Transparency(CT)による公開監査。PKIは完全ではない(任意のCAが任意のドメインの証明書を発行できる可能性がある)。CTとキーピンニングは、この信頼モデルに対するパッチである。
概要
TLSの信頼の基盤は、X.509証明書とPKI(Public Key Infrastructure)です。ブラウザやOSには約150個のルートCA証明書がプリインストールされており、これらのCAは任意のドメインの証明書を発行できるため、HTTPSの信頼体系における単一障害点となっています。Let's Encrypt(2016年)は、ACMEプロトコルを通じて証明書の発行を自動化し、完全に無料を提供することで、HTTPSの導入率を40%から90%以上に引き上げました。Certificate Transparency(2013年)は、すべての証明書を公開ログに記録することを義務付け、不正な発行を検出可能にしています。OCSP Staplingは、プライバシーを保護しながら失効確認を実現します。
X.509証明書
Certificate:
tbsCertificate (to-be-signed):
Version: v3 (2)
Serial Number: 乱数 (CAによる重複防止)
Signature Algorithm: sha256WithRSAEncryption または ecdsa-with-SHA256
Issuer: C=US, O=Let's Encrypt, CN=R3 ← 誰が発行したか
Validity:
Not Before: 2024-01-01T00:00:00Z
Not After: 2024-03-31T23:59:59Z (LEの場合、最大90日)
Subject: CN=grafana.liz6.com ← 証明書の所有者
Subject Public Key Info:
Algorithm: id-ecPublicKey (または rsaEncryption)
Public Key: (256ビットのECポイント または 2048ビットのRSA法数)
Extensions:
SAN (Subject Alternative Name): grafana.liz6.com, *.liz6.com ← 重要!
Basic Constraints: CA=FALSE ← CAではない (サブ証明書の発行不可)
Key Usage: Digital Signature, Key Encipherment
Extended Key Usage: TLS Web Server Authentication
CRL Distribution Points: http://r3.i.lencr.org/
Authority Information Access:
OCSP: http://r3.o.lencr.org/
CA Issuers: http://r3.i.lencr.org/
Certificate Policies
CT Precertificate SCTs (Signed Certificate Timestamps)
Signature Algorithm
Signature Value
SANの重要性
ブラウザはCN(Common Name)を完全に無視しています。すべてのドメイン検証はSANに基づいて行われます。証明書にアクセスするドメインが含まれていない場合、ブラウザはエラー ERR_CERT_COMMON_NAME_INVALID を表示します:
SAN: DNS:grafana.liz6.com, DNS:*.liz6.com
→ grafana.liz6.com にマッチ ✓, chat.liz6.com にマッチ ✓, grafana.liz6.com:8443 にマッチ ✗ (SANにはポートが含まれていない)
→ ワイルドカード: *.liz6.com は1レベルのサブドメイン (chat.liz6.com) にはマッチするが、複数レベル (sub.chat.liz6.com) にはマッチしない
信頼の連鎖 (Chain of Trust)
Root CA (ISRG Root X1):
Subject = Issuer = 自身 (自己署名)
Basic Constraints: CA=TRUE
→ OS/ブラウザの信頼ストア /etc/ssl/certs/ にプリインストールされている
Intermediate CA (R3):
Subject: R3, Issuer: ISRG Root X1 → ルートによって発行
Basic Constraints: CA=TRUE, pathLenConstraint=0 (これ以上CAを発行できない)
Leaf (grafana.liz6.com):
Subject: grafana.liz6.com, Issuer: R3 → インターメディアによって発行
Basic Constraints: CA=FALSE
検証: 下から上へ: leaf → R3 → Root → 信頼アンカー (trust store内)
ACME
クライアント (certbot/acme.sh) は ACME v2 プロトコルを通じて証明書を自動取得する:
1. アカウントの作成: POST /acme/new-acct → アカウントURL
2. オーダーの送信: POST /acme/new-order { identifiers: [grafana, *.liz6.com] }
→ オーダーオブジェクト + 承認情報 + チャレンジ
3. チャレンジの完了:
HTTP-01: http://domain/.well-known/acme-challenge/<token>
→ CAは GET のレスポンスが key authorization = token + "." + thumbprint であることを検証
DNS-01: TXT _acme-challenge.domain = key authorization を設置
→ CAはDNSを検証 (ワイルドカードの発行も可能!)
TLS-ALPN-01: ALPN内で key authorization を返す
4. 検証の待機 → CAがチャレンジを検証
5. Finalize: POST CSR → CAが証明書を発行
6. ダウンロード: 証明書チェーン (PEM形式、約3-5KB)
OCSPと失効
OCSP (Online Certificate Status Protocol):
クライアント: CAに「このシリアル番号の証明書の状態は?」と問い合わせる
CA: "good" / "revoked" / "unknown"
問題: CAはどのサイトを訪問しているかがわかる → プライバシーの懸念 + 遅延 (追加のTLS接続が必要)
OCSP Stapling (RFC 6066, TLS Certificate Status Request拡張):
サーバー: CAから定期的にOCSPレスポンス(署名済み)を取得 → ローカルにキャッシュ
TLSハンドシェイク: CertificateStatusメッセージにOCSPレスポンスを添付
クライアント: OCSPレスポンスの署名を検証 → 個別にOCSPを要求する必要がない
→ プライバシー保護 + 遅延の最適化
CRL (Certificate Revocation List):
定期的に公開される失効証明書の一覧 (CA全体で失効されたすべての証明書)
欠点: 巨大 (MB単位になる場合も)、更新が不十分 (通常24時間)
OCSPはよりリアルタイム (ただしプライバシー保護にはstaplingが必要)
Certificate Transparency
問題: 悪意のあるCA(または侵害されたCA)が認可されていない証明書を発行 → 中間者攻撃
CT (RFC 6962):
すべての証明書を公開されたCTログに提出:
→ SCT (Signed Certificate Timestamp): 証明書に対するログの「領収書」
→ ブラウザの検証: 証明書には少なくとも2つのSCT(異なるログオペレーター由来)が含まれている必要がある
→ モニター: 誰でもCTログを監視でき → 認可されていない発行を発見可能
あなたの証明書: crt.sh/?domain=liz6.com → liz6.comのすべての証明書の履歴を表示
参考
- RFC: 5280, 8555, 6960, 6962, 7633 (コード署名用のCT)
- ツール:
openssl x509 -text -in cert.pem,crt.sh,certbot certificates
キーワード: X.509, SAN, 信頼の連鎖, ACME, Let's Encrypt, DNS-01, OCSP Stapling, CRL, SCT, CTログ