Open125

『プロフェッショナルSSL/TLS』読書メモ

第1章 SSL/TLSと暗号技術

1.1 Transport Layer Security

p.1 セキュリティの効能

  • 正しいサーバとやりとりしている確認が持てる
  • 完全な状態で相手が情報を受け取れる

p.2 TLSの目標

  • 暗号学的なセキュリティ:二者間で安全な通信ができる(最優先)
  • 相互運用性:別のプログラム間で同じパラメータを使って暗号通信できる
  • 拡張性:新しい暗号アルゴリズムやハッシュ関数に対応しやすくする
  • 効率性:キャッシュにより他の三目標を妥当なパフォーマンスで達成する

第1章 SSL/TLSと暗号技術

1.2 ネットワークの階層

p.2 インターネットの根幹(IP+TCP)はセキュリティが考慮されていない、データを覗ける
p.2 DNSやBGPなど他のプロトコルも脆弱:意図しないコンピュータから返信を受け取りうる

※BGP

https://www.nic.ad.jp/ja/newsletter/No35/0800.html
  • パケットの経路制御のためのプロトコル
  • 経路制御プロトコル=EGP(Exterior Gateway Protocol)またはIGP(Interior Gateway Protocol)
  • EGP=インターネット上でやりとり、IGP=組織内でやりとり
  • BGPはEGPに分類される

p.2 トラフィックが正しい宛先に送られているか?=PKIで確認
p.3 OSIモデル
アプリケーション層:アプリデータ。 例)HTTP、SMTP、IMAP
プレゼンテーション層:データ表現、変換、暗号化。例)SSL/TLS
セッション層:複数のコネクションを管理
トランスポート層:パケット、ストリームの配送。例)TCP、UDP
ネットワーク層:経路制御、ノード間データグラム配送。例)IP、IPsec
データリンク層:LAN。例)Ethernet
物理層:ケーブル。例)CATS

※セッションより上は分類難。HTTP/2はセッション層にも踏み込んでいる。

p.3 HTTPはSSL/TLSなしでもTCPの上で動く。SSL/TLSはアプリケーション層の様々なプロトコルの暗号化に利用可能

1.3 プロトコルの歴史

p.3 SSLはNetscapeが開発、日の目を見ず
p.3 SSL2は1994リリース
p.3 SSL3.0は1995リリース
p.4 Microsoftが加わりTLS1.0として1999リリース
p.4 TLS1.1は2006リリース
p.4 TLS1.2は2008リリース

参考)TLS1.3は2018リリース

RFC 8996でTLS1.0とTLS1.1が廃止に

IETFで、TLS1.0とTLS1.1を正式に非推奨にする「RFC 8996 Deprecating TLS 1.0 and TLS 1.1」が公開されました。

新しいプロトコルへの以降期間は十分であるとし、TLS1.0, TLS1.1, DTLS1.0は廃止となり、TLS 1.2, TLS1.3, DTLS 1.2のみが使用できます。表現としても、MUST NOTで利用を禁止しています。

TLS 1.0 MUST NOT be used
TLS 1.1 MUST NOT be used
2015年に公開された、TLS利用時の推奨事項を定めたRFC7525がありますが、今回の禁止内容も含めて改定作業が開始されています。

1.4 暗号技術

p.4 数学を基盤とする暗号技術の解決する問題

  • 機密性(秘密が守られるか)
  • 真正性(本人である検証ができるか)
  • 完全性(データが改竄されないか)

1.4.1 要素技術

p.5 要素技術単体ではそれほど便利ではないが組み合わせることで強固なセキュリティを実現

■共通鍵暗号方式(対称暗号方式)
p.6 平文(plaintext)を暗号(cipher、アルゴリズムのこと)を利用して暗号文(ciphertext)にする
p.6 鍵のない置換暗号が数千年前から利用されてきた:安全ではない
p.6 Kerckhoffsの原則(ケルクホフスの原則):鍵以外の全てが攻撃者に掌握されても安全でなくてはならない

  • 暗号アルゴリズムは複数の相手と共有しなければ使えない
  • 他方で、たくさんの人の目にふれて精査されないと安全とは言えない

p.6 今日の暗号技術は計算量的安全性を根拠としている(↔︎情報理論的安全性もある)

p.7 暗号は大きく2種類、ストリーム暗号化とブロック暗号化

●ストリーム暗号化方式 例)RC4
p.7 1バイトずつ逐次暗号化/復号するような方式。排他的論理和を利用する。
p.7 ストリーム暗号は平文と暗号文が同じサイズになるため、HTTPリクエストなどリクエストメソッドやプロトコルバージョン、ヘッダー名などは位置が分かりやすいため、同じ鍵を使い回すと危険。通信のたびに一回限りの鍵を生成して利用する。

※RC4は鍵テーブルに統計的な偏りがあり平文の一部が回復可能なため脆弱であり、2015年にはRFC 7645でSSL/TLSでの利用禁止が提案された

※7.5節でRC4の弱点についてまとめられている(p.222-p.228)

●ブロック暗号化方式 例)AES
p.8 データをブロックごとにまとめて暗号化する。現在多くのブロックは128ビット(16バイト)。AESでは192ビット、256ビットも扱える。
p.8 入力が1ビット変わると出力が大きく変化する性質
p.8 欠点1:そのままでは任意の長さのデータを扱えない(ので後述のパディングを利用する)
p.8 欠点2:同じ入力・鍵については同じ結果となるので、様々な攻撃がありうる
p.8 上記の欠点については暗号化利用モードを利用し緩和

●パディング
p.8 ブロック長に満たないデータに余分なデータを追加する
p.8 TLSの場合、末尾にパディング長を示すバイトがあり、その直前に同じ個数だけ同じバイトを付加する

(1.4.1 要素技術)
■ハッシュ関数
p.9 任意の長さの入力を固定長の出力(ハッシュ値=フィンガープリント=(メッセージ)ダイジェスト)へ変換するアルゴリズム
p.9 メリット:大きなデータを手軽に比較できる
p.9 暗号学的ハッシュ関数に求められる3つの性質

  • 原像計算困難性 Preimage resistance
  • 第2原像計算困難性 Second preimage resistance
  • 衝突耐性 Collision resistance
    p.9 例)SHA2, SHA3 ※SHA1、MD5は弱いので利用すべきでない

(1.4.1 要素技術)
■MAC(メッセージ認証コード Message Authentication Code)
p.10 ハッシュ関数によるメッセージの完全性の検証にはハッシュ値の転送が必要だが、攻撃者により捏造されうる
p.10 MAC=鍵付きハッシュ(keyed-hash, keying-hash):ハッシュ関数を拡張して認証可能に。
p.10 暗号処理は機密性を、ハッシュ関数は完全性を与える
p.10 HMAC(Hash-based MAC)を使うとどんなハッシュ関数でもMACに使える

(1.4.1 要素技術)
■MAC(メッセージ認証コード Message Authentication Code)
p.10 ハッシュ関数によるメッセージの完全性の検証にはハッシュ値の転送が必要だが、攻撃者により捏造されうる
p.10 MAC=鍵付きハッシュ(keyed-hash, keying-hash):ハッシュ関数を拡張して認証可能に。
p.10 暗号処理は機密性を、ハッシュ関数は完全性を与える
p.10 HMAC(Hash-based MAC)を使うとどんなハッシュ関数でもMACに使える

(1.4.1 要素技術)
■暗号化利用モード
p.10 ブロック暗号化方式を拡張し、任意の長さのデータを暗号化できる。
p.10 ストリーム暗号化方式として使えるものもある。
p.10 ECB, CBC, CFB, OFB, CTR, GCMなどがある

GCM:認証つき暗号スイート。TLS1.2から利用可能
●ECBモード(Electronic Codebook最も単純な暗号化利用モード)
p.10 ブロック長の整数倍のデータにのみ対応=要パディング
p.10 ブロック暗号=決定論的(入力が同じなら結果も同じ)
p.11 さまざまな平文の暗号化を試すと暗号文から平文を推測できてしまう
p.11 TLSへのBEAST攻撃の原因

●CBCモード(Cipher Block Chaining)
p.11 ECBの決定論的性質への対処として、ランダムな初期化ベクター(IV, Initialization Vector)を導入:入力が同じでも出力が異なる
p.11 初期化ベクターと1つ目のブロックとの排他的論理和をとって暗号文ブロックとする
p.11 1つ目のブロックの暗号化の結果を次のブロックの初期化ベクターとして利用していく
p.11 初期化ベクターを受信側に送付することがポイント

(1.4.1 要素技術)
■公開鍵暗号化方式
p.11 共通鍵のメリット:大きなデータを高速に扱える、デメリット:個別に鍵を用意すると危殆化しやすい、多数必要、同じ鍵の他の暗号文も危険
p.12 公開鍵暗号(非対称暗号化方式)は鍵を2種類使う:公開鍵と秘密鍵
p.12 公開鍵で暗号化したら秘密鍵で復号
p.12 秘密鍵で暗号化したら公開鍵で復号(例:ディジタル署名)
p.12 公開鍵のメリット:公開鍵をPKIの仕組みで広く安全に共有し、大きな集団での安全な通信を実現できる
p.12 公開鍵のデメリット:計算に時間がかかり容量が大きなデータには不向き→共有鍵のネゴシエーションや、認証に利用
p.12 例:RSA(2048ビットの鍵が推奨、2016年時点)

(1.4.1 要素技術)
■ディジタル署名
p.12 電子的なメッセージの真正性(authenticity)を検証可能にするもの、例)MAC
p.13 MACの制約:事前にMAC鍵の共有が必要
p.13 公開鍵暗号方式を利用したディジタル署名:秘密鍵で署名して公開鍵で検証
p.13 RSA+ハッシュ関数のディジタル署名例

  1. 署名対象のハッシュ値を計算
  2. ハッシュ関数などのメタ情報を付加し符号化(エンコード)
  3. エンコードされたハッシュ値を秘密鍵で暗号化したものがディジタル署名。

p.13 署名検証手順は以下

  1. 同じハッシュ関数でハッシュ値を計算
  2. 公開鍵で署名から送り手の計算したハッシュ値を取得
  3. 1と2を比較

(1.4.1 要素技術)
■乱数生成器
p.13 秘密鍵=とても長い乱数;乱数生成器の品質が重要
p.13 予測可能な動作をするというコンピュータの特性が邪魔をする
p.14 無作為性(エントロピー)を集める:キー入力、マウスの動き、HDDの割り込み
p.14 上記をシード(種)として擬似乱数生成器(pseudo random number generator)を利用する
p.14 暗号学的PRNGには予測不可能性が必要:リバースエンジニアリングされないように

1.4.2 プロトコル
p.14 要素技術は機密性、完全性、真正性のいずれかを満たしてくれる:組み合わせてプロトコルを構成する
p.14 セキュリティプロトコルの最小構成の例

  • 機密性:AESを使ってメッセージを暗号化する
  • 完全性:当事者だけが知るハッシュ鍵でMACを計算し、メッセージと一緒に送る、連番つき、終了メッセージあり
  • 真正性:事前に公開鍵暗号化方式でお互いを認証(+データ交換のために必要な鍵を交換)
    p.15 ハンドシェイク:認証と鍵公開の一連のやりとり

1.4.3 暗号技術に対する攻撃

p.15 暗号技術は単純で用途特化:通常十分に問題点が解明されている <-> より複雑なスキーム、プロトコルの方が攻撃の余地が大きい
p.15 スキーム:要素技術の組み合わせ
p.15 プロトコルの実装への攻撃(ソフトウェアのバグ、脆弱性を悪用)もある
p.15 例)タイミング攻撃:処理時間を観察することで暗号を破られる
(参考:有名な例としてCPUの投機的実行に由来する2018年のMeltdown/Spectreがある)
(参考:Rebuild 200 34.37〜
p.15 暗号をバイパスする:サーバーに侵入して暗号鍵を入手すれば時間のかかる総当たり攻撃は不要
p.16 ポイント:自分でプロトコルやスキームを設計しない、暗号処理を実装しない、確立された暗号アルゴリズムを十分な鍵長で使う

1.4.4 暗号強度

p.16 暗号の強度=暗号アルゴリズムを破るのに必要な操作数で測定(ビット安全性)
p.16 128ビットの鍵=2^128の操作が必要:1ビット増やすと2倍強力になる
p.16 ENCRYPT2(2012)によれば、共通鍵暗号、楕円曲線暗号、ハッシュ値は256ビットでも長期間(30年)の攻撃に耐えうる:公開鍵暗号、DHは1776ビットでようやく短期間(10年)の攻撃に耐えられる

ディフィー・ヘルマン鍵共有(Wikipedia)
公開鍵暗号の一種。RSAより処理負荷高い。認証がなく中間者攻撃に脆弱、2015年には事前計算を利用したLogjam攻撃が明らかに。詳細は本書p.167(6.5. Logjam)。

p.16 現在のセキュリティだけでなく、長期間のセキュリティも考慮すべし:コンピュータが高速になり廉価になれば暗号の強度は変化する

※等価安全性について SSL/TLS暗号設定ガイドライン by IPA p.17

1.4.5 MITM攻撃(中間者攻撃、man-in-the-middle)

p.17 受動的ネットワーク攻撃:第三者が会話を聞いているだけ
p.18 能動的ネットワーク攻撃:通信内容を操作したり当事者間の会話に影響を与える

■アクセスの奪取
p.18 攻撃の前提条件:犠牲者、サーバ、通信インフラへの接近・接続
p.18 通信会社と結託した事例:おそらくアメリカ国家安全保障局(National Security Agency)とAT&T。脚注31のサイトはリンク切れだったのでNY Timesなどが参考になる)
p.18 通信機器を乗っ取った事例:光ファイバーケーブルを盗聴するイギリスの政府通信本部(GCHQ、Government Communications Headquarters)によるTEMPORAプログラム。

※NSAおよびCIAの元局員エドワード・スノーデンによるこれらの告発は2013年6月に行われた

  • ARPスプーフィング:MACアドレスとIPアドレスを関連づけるアドレス解決プロトコル(Address Resolution Protocol)を利用してLAN上で通信機器のなりすましを行う
  • WPADハイジャック:ブラウザのWebプロキシ自動発見(WPAD)を利用して、攻撃者がローカルでプロキシを起動してMITM攻撃を行う。2007年にIEの脆弱性があった
  • DNSハイジャック:ドメインの管理権限のない第三者が不正にドメインをのっとる
  • DNSキャッシュポイズニング:権威サーバーへのDNSメッセージの32ビットのIDベースでのリクエストに対する不正なレスポンスを送り込むことで、ドメイン名に対応する偽のIPをキャッシュさせる。DNSサーバーの脆弱性を悪用。カミンスキーアタックなどが知られる。対応策としてソースポートのランダム化がある。
  • BGP経路ハイジャック:ISPの相互接続などで利用するルーティングプロトコルであるBGPで、不正な経路を広告することで中間者攻撃を実現する。2018年に中国政府がアメリカの通信を傍受していた事例

■受動的攻撃
p.19 トラフィックが暗号化されていない場合に最も有効
p.19 RFC7258:「蔓延する監視は攻撃だ」(2014年5月)
p.19 暗号化されていても、暗号を破れるようになるまで保存することで受動的攻撃が成立しうる
p.20 前方秘匿性(perfect forward secrecy):長期的な鍵(long-term secrets、TLSでいうとサーバーの秘密鍵)からセッションキーを生成して通信を行うが、長期的な鍵が流出した場合でもセッションキーの安全性が保たれるという性質のこと。RSAをベースにしたTLSの鍵交換アルゴリズムではPFSを欠いており、RSA鍵を手に入れれば以前の通信が復号可能。2014年にはHeartbleed脆弱性により秘密鍵流出が問題に。(詳細は6.3, p.180)

■能動的な攻撃
p.20 有効なものとして受け取れる証明書を攻撃者が提示できる(詳細は第4章、Microsoft社を騙り証明書入手した事例など)
p.20 ブラウザの検証のバグをついて、有効に見える証明書を構成する(詳細は第6章、OSのAPIに問題がある場合も)
p.20 不正な証明書でも、エンドユーザーがブラウザの警告をうっかり無視することを期待して攻撃に利用するケースも。2011年シリアで電気通信省が行った?FacebookへのMITM攻撃の事例
p.20 ブラウザが能動的攻撃のターゲットとなることが多い
p.21 能動的攻撃は大規模には仕掛けにくい:主に重要人物に対して仕掛けられる
p.21 QuantumInsertプログラム:NSAとGCHQによる中間者攻撃の手法。本来のページより高速なレスポンスを返すサーバーを使い、不正なページにアクセスさせマルウェアをダウンロードさせる。LinkedInなどが狙われた。

第2章 プロトコル

p.23 TLSは接続指向のネットワーク通信を安全にするための暗号化プロトコル:上位層のプロトコルはなんでもよい

※接続指向:データを確実に相手に送信できる。TCP、SCTPなど。UDPは接続指向ではない。
SCTP:Stream Control Transmission Protocol(ストリーム制御伝送プロトコル)。電話網のプロトコルをIP上で転送するために作られた。LTEで利用。

NTTドコモ テクニカルレポート

2.1 Record プロトコル

p.24 TLSレコードがコネクション上でやりとりされる低レベルのメッセージ転送すべてを担う
p.24 TLSレコード=ヘッダ+メッセージデータ
ヘッダは以下の3つから成る。

  • コンテントタイプ:サブプロトコルのいずれかを示す以下の値。 20(Change Cipher Spec)、21(Alert)、22(Handshake)、23(Application Data)。Java実装
  • バージョン:majorバージョンとminorバージョン。それぞれuint8型(8 ビットの符号なし整数、0-255)。 TLS1.2の場合 { 3, 3 }(TLS1.0が{ 3, 1 }、TLS1.3は{ 3, 4 })。Java実装
  • レコード長:uint16型。最長で2^14バイト(16,384バイト)。
    p.24 上記のほか、64ビットのシーケンス番号が割り当てられ、通信両側がそれぞれ記録する。送受信されるデータには含まれない。リプレイ攻撃への防御として利用。Java実装

●メッセージの転送
p.25 書式が定まっていない(opaque)データのバッファを転送する
p.25 レコードは最長16,384バイト:それより長い場合、分割される。逆に単一のレコードにまとめられることもある。

●暗号化および完全性の検証
p.25 最初の接続におけるメッセージ群は保護されない(厳密にはTLS_NULL_WITH_NULL_NULL暗号スイートが利用される)
p.25 暗号スイートによっては暗号化を利用せず完全性の検証のみを行うものもある

●圧縮
p.25 TLSの圧縮機能は現在では利用されていない(2012年にCRIME攻撃に利用されたため(詳細は7.3))
p.25 HTTPレベルですでに圧縮されている

●拡張性
p.25 Recordプロトコルは暗号処理とデータ転送:他の機能はサブプロトコルで行う
p.25 サブプロトコルはネゴシエーションされたパラメータで自動的に暗号化され保護される
p.25 4つのサブプロトコル:Handshake, Change Cipher Spec, Application Data, Alert

2.2 Handshakeプロトコル

p.25 TLS接続で使うパラメータのネゴシエーションと認証を行うプロトコル
p.25 通信確立=ハンドシェイクには6〜10のメッセージが必要(利用機能に応じて異なる)
p.25 実用的には3つ

  • サーバ認証を伴うフルハンドシェイク
  • 前回のセッションを再開する場合の一部メッセージを省略したハンドシェイク
  • クライアントとサーバの認証を伴うハンドシェイク

p.26 Handshakeプロトコルのメッセージの先頭のヘッダ

  • メッセージの種類(HandshakeType):1バイト。Java実装
  • メッセージの長さ:3バイト(uint24)
enum {
  hello_request(0),
  client_hello(1),
  server_hello(2), 
  certificate(11),
  server_key_exchange (12), 
  certificate_request(13),
  server_hello_done(14), 
  certificate_verify(15),
  client_key_exchange(16), 
  finished(20),
  (255)
} HandshakeType;

2.2.1 フルハンドシェイク

p.26 TLS Sessionを確立するためにフルハンドシェイクを実行

  1. 接続で利用したいパラメータを双方が提示・合意
  2. 認証:証明書or他の方法
  3. セッション保護に利用するマスターシクレットを共有
  4. ハンドシェイクメッセージ群が第三者に書き換えられていないことの検証

p.26 上記の2と3は実際には1ステップで行う=鍵交換(key exchange)

p.27 フルハンドシェイクの10ステップ

  1. ClientHello (C->S):新規ハンドシェイクをクライアントが開始。暗号スイートや鍵交換方法のパラメータ群を送信。
  2. ServerHello (C<-S):サーバがパラメータを決定
  3. Certificate* (C<-S):サーバの証明書チェーンを送信(サーバ認証が必要な場合のみ)
  4. ServerKeyExchange* (C<-S):マスターシークレット生成に必要な情報がある場合これを送信
  5. ServerHelloDone (C<-S):サーバの番が終わったことを通知
  6. ClientKeyExchange (C->S):マスターシークレット生成に必要な情報を送信
  7. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  8. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  9. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  10. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)

p.27 何もエラーがなければこの後アプリケーションデータを送信する

2.2.1 フルハンドシェイク

■ClientHello
p.27 クライアントが希望するパラメータ群とその優先度を伝えるメッセージ
p.27 以下の3つの場合に送信

  • 新規にコネクションを開始するとき
  • 再ネゴシエーションをしたいとき
  • サーバからの再ネゴシエーション要求(HelloRequest)に応えるとき
    p.28 Versionフィールド:クライアントがサポートする最良のバージョンを表す(RFCの記載ではclient_versionフィールド)
    p.28 Randomフィールド
  • 32バイト=4バイトのクライアント時刻情報+28バイトのランダムな値。16進数表記になっている(4ビットで1文字)ので56文字。
  • クライアント時刻情報は1994年のNetscape Navigatorの脆弱性以降非推奨となり、ランダム値が送信されることもある。
  • この乱数が完全性検証における重要な役割をもつ(リプレイ攻撃も防止)
    p.29 Session IDフィールド:ランダムな32バイトが含まれる(意味はない)。初回接続時は空。再ネゴシエーション時は一意の識別子が含まれサーバがセッションをキャッシュするのに利用。
    p.29 Cipher Suitesフィールド:クライアントの対応可能な暗号スイートが適切な順番で格納される
    p.29 Compression methodsフィールド:クライアントの対応している圧縮方法。デフォルトはnullで圧縮しない(前述のCRIME攻撃の脆弱性のため(p.25))
    p.29 Extensionsフィールド:拡張情報が任意の数含まれる。server_nameやelliptic_curvesなど。詳細は後述。
enum { null(0), (255) } CompressionMethod;
      struct {
          ProtocolVersion client_version;
          Random random;
          SessionID session_id;
          CipherSuite cipher_suites<2..2^16-2>;
          CompressionMethod compression_methods<1..2^8-1>;
          select (extensions_present) {
              case false:
                  struct {};
              case true:
                  Extension extensions<0..2^16-1>;
          };
      } ClientHello;

■ServerHello

p.29 サーバが接続で使うパラメータを選択して返答する:構造はClientHelloと同じ
p.29 クライアントと同じ最新バージョンに対応している必要はなく、別の下位バージョンを提案することもある

※クライアントがサポートしていない場合、JavaだとSSLHandshakeExceptionが発生する

■Certificate

p.29 主に、サーバからクライアントにX.509証明書チェーンを運ぶ
p.29 証明書チェーン:ASN.1のDER(Distinguished Encoding Rules)を使用してエンコードされた証明書を順番に並べたもの(詳細は3.4を参照)

X.509:ITU-Tの公開鍵基盤 (PKI)の規格。公開鍵証明書の標準形式や証明書パス検証アルゴリズムなどを定めている。

https://www.ipa.go.jp/security/pki/033.html

ITU-T(International Telecommunication Union Telecommunication Standardization Sector):世界規模で電気通信を標準化することを目的として勧告Recommendationsを作成する国連機関。アルファベット1文字で○シリーズ勧告がある(Aシリーズ、Bシリーズなど)。Xシリーズ勧告は「データ網及びオープン・システム・コミュニケーション」に関する規定。ITU-Tで公開されているX.509標準の目次

DER:ITU-TのX.690標準で定められているASN.1符号化規則の一つ。X.690 は、基本符号化規則(BER、Basic Encoding Rules)と 2 つのサブセット、標準符号化規則(CER、Canonical Encoding Rules)と識別符号化規則(DER)を定義する。
CISCOの解説

例: DER では、20 ビット値 1010 1011 1100 1101 1110 が、次のように符号化されます。
タグ: 0x03(ビット列)
長さ: 0x04(バイト)
値: 0x04ABCDE0
DER 符号化全体: 0x030404ABCDE0

ASN.1:Abstract Syntax Notation One(抽象構文記法1)。ASN.1記法とASN.1符号化(エンコード)規則を組み合わせて使う。

p.30 サーバ証明書が先頭、中間証明書が続く。ルート証明書は省くべきとされている。
p.30 サーバには複数の証明書を設定できる:選択された暗号スイートによって、利用できる証明書の公開鍵アルゴリズムが変わるため
p.30 Certificateメッセージは必須ではない:証明書を必要としない認証方式、認証を利用しない暗号スイートもあるため(DH_anonなど)。
p.30 X.509でなくPGP鍵を用いる暗号スイートもある

RFCで定義されている構造体

      opaque ASN.1Cert<1..2^24-1>;
      struct {
          ASN.1Cert certificate_list<0..2^24-1>;
      } Certificate;

■ServerKeyExchange

p.30 目的:鍵交換に必要な付加的データを運ぶ
p.30 中身は暗号スイートによって異なる、送られない場合もある。

鍵交換手法のうち、以下の場合にServerKeyExchangeが送られる

  • DHE_DSS
  • DHE_RSA
  • DH_anon

下記の鍵交換手法の場合にはServerKeyExchangeが送られない

  • RSA
  • DH_DSS
  • DH_RSA

※鍵交換手法についてはRFC2246を参照

      enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
            /* 拡張される可能性がある。(例:ECDH について [TLSECC] 参照)*/
           } KeyExchangeAlgorithm;
      struct {
          opaque dh_p<1..2^16-1>;
          opaque dh_g<1..2^16-1>;
          opaque dh_Ys<1..2^16-1>;
      } ServerDHParams;     /* 超短期(Ephemeral)DH パラメータ */
      dh_p
         The prime modulus used for the Diffie-Hellman 処理。
      dh_g
         The generator used for the Diffie-Hellman 処理。
      dh_Ys
         サーバの Diffie-Hellman 公開値 (g^X mod p)。
      struct {
          select (KeyExchangeAlgorithm) {
              case dh_anon:
                  ServerDHParams params;
              case dhe_dss:
              case dhe_rsa:
                  ServerDHParams params;
                  digitally-signed struct {
                      opaque client_random[32];
                      opaque server_random[32];
                      ServerDHParams params;
                  } signed_params;
              case rsa:
              case dh_dss:
              case dh_rsa:
                  struct {} ;
                 /* メッセージは、rsa、dh_dss について省略される。*/
              /* そして、dh_rsa は、拡張される可能性がある。(例:ECDH について [TLSECC] 参照) */
          };
      } ServerKeyExchange;
      params
         そのサーバの鍵交換パラメータ。
      signed_params
         非匿名鍵交換用に、サーバの鍵交換パラメータ上の署名。

■ServerHelloDone

p.30 予定していたハンドシェイクメッセージをすべて送信したときにサーバから送る合図
p.30 サーバが待機状態に入る

※ServerHello および関連するメッセージの終りを示す。
※クライアントは、「そのサーバは、(要求される場合)有効な証明書を提供したか?」を検証する。

構造体

struct { } ServerHelloDone;

■ClientKeyExchange

p.30 鍵交換に必要な情報をクライアントから送信するための必須のメッセージ
p.30 中身は暗号スイートによって異なる。

構造体

struct {
    select (KeyExchangeAlgorithm) {
        case rsa:
            EncryptedPreMasterSecret;
        case dhe_dss:
        case dhe_rsa:
        case dh_dss:
        case dh_rsa:
        case dh_anon:
            ClientDiffieHellmanPublic;
        case ecdhe:
            ClientECDiffieHellmanPublic;
    } exchange_keys;
} ClientKeyExchange;

■ChangeCipherSpec

p.30 クライアント、サーバ両方が送信する
p.30 このメッセージの意味は以下の通り

  • 接続で使うパラメータを組み立てるのに十分な情報を手に入れたこと
  • 暗号鍵を生成したこと
  • これから暗号処理へ移行すること

p.30 サブプロトコルChangeCipherSpecのメッセージ。
p.30 これはハンドシェイクメッセージではない:完全性の検証対象外。ゆえにOpenSSLでは攻撃を受けやすい状態になっていた(2014年)。

※このメッセージは、値が 1 の 1byte から成る。

構造体

   struct {
       enum { change_cipher_spec(1), (255) } type;
   } ChangeCipherSpec;

■Finished

p.31 ハンドシェイクが完了したという合図:このメッセージ以前にApplication Dataプロトコルのメッセージを送信することは認められていない(攻撃を避けるため)

構造体

struct {
    opaque verify_data[verify_data_length];
} Finished;

verify_data
   PRF(master_secret, finished_label, Hash(handshake_messages))
      [0..verify_data_length-1];

p.31 verify_dataフィールド:受信した全ハンドシェイクメッセージをハッシュかしてマスターシークレットと合わせて計算した値
p.31 finished_label:クライアント側は「client finished」、サーバ側は「server finished」
p.31 このメッセージは暗号化されている:ネゴシエーション済みのMACで完全性保証[1]。=マスターシークレットとハンドシェイクメッセージのハッシュ値を知るのは非常に困難。
p.31 TLS1.2のFinishedメッセージ、つまりverify_dataのデフォルトの長さは12バイト(96ビット)。暗号スイートによって変わる[2][3]

RFC5246
ハンドシェイクメッセージとは?

  • HelloRequest以外のメッセージ、このFinishedメッセージまで(このメッセージ自身は含まない)のすべてのデータ
  • レコード層のヘッダは含まない
  • ※ChangeCipherSpecの節で見た通り、ChangeCipherSpecはハンドシェイクメッセージに含まれない。
    https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-5c5c5f435668d1
  • しかし、Finishedメッセージはハンドシェイクメッセージに含まれるので、後から送られるFinishedメッセージのハッシュには先に送られたFinishedメッセージが含まれる
脚注
  1. これってどういうこと? ↩︎

  2. SSL3.0では合計36バイト, TLS1.0TLS1.1では12バイトだった ↩︎

  3. 変わることは変わるらしいが、具体的にどの暗号スイートがいくつなのか不明。stackoverflowJava8の初期実装では12バイトとして扱われている。Java16ではTLS1.3のときに変更になりverifyDataLen = context.negotiatedCipherSuite.hashAlg.hashLength;とある。CipherSuiteのHashAlg定義によれば、SHA-256のとき32、SHA-384のとき48。 ↩︎

2.2.2 クライアント認証

p.31 クライアントとサーバの相互認証は必須ではない
p.32 サーバがクライアント認証を求めるときCertificateRequestメッセージを送る
p.32 クライアントはCertificateメッセージとCertificateVerifyメッセージを送る

p.32 相互認証フルハンドシェイクの13ステップ

  1. ClientHello (C->S):新規ハンドシェイクをクライアントが開始。暗号スイートや鍵交換方法のパラメータ群を送信。
  2. ServerHello (C<-S):サーバがパラメータを決定
  3. Certificate* (C<-S):サーバの証明書チェーンを送信(サーバ認証が必要な場合のみ)
  4. ServerKeyExchange* (C<-S):マスターシークレット生成に必要な情報がある場合これを送信
  5. CertificateRequest (C<-S):クライアントに認証を要求
  6. ServerHelloDone (C<-S):サーバの番が終わったことを通知
  7. Certificate (C->S):クライアントの証明書を送信
  8. ClientKeyExchange (C->S):マスターシークレット生成に必要な情報を送信
  9. CertificateVerify (C->S):秘密鍵でハンドシェイクメッセージに署名して送信
  10. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  11. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  12. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  13. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)

■CertificateRequest

構造体

      enum {
          rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
          rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
          fortezza_dms_RESERVED(20), (255)
      } ClientCertificateType;
      opaque DistinguishedName<1..2^16-1>;

      struct {
          ClientCertificateType certificate_types<1..2^8-1>;
          SignatureAndHashAlgorithm
            supported_signature_algorithms<2^16-1>;
          DistinguishedName certificate_authorities<0..2^16-1>;
      } CertificateRequest;

p.32 certificate_types:許容できる証明書(クライアントが提供してよい)の公開鍵を示す。

  • rsa_sign:RSA 鍵を含む証明書
  • dss_sign:DSA 鍵を含む証明書
  • rsa_fixed_dh:無期の(static)DH 鍵を含む証明書
  • dss_fixed_dh:無期の(static)DH 鍵を含む証明書

p.32 supported_signature_algorithms:サーバが検証できるハッシュ/署名アルゴリズムペアのリスト
p.32 certificate_authorities:許容できるCA(認証局)の識別名DistinguishedNameのリスト

■CertificateVerify

構造体

struct {
     digitally-signed struct {
         opaque handshake_messages[handshake_messages_length];
     }
} CertificateVerify;

p.33 これまでにやりとりした全ハンドシェイクメッセージの署名Signature

RFC5246より

  • 署名において使われるハッシュアルゴリズムおよび署名アルゴリズムは、CertificateRequest メッセージの supported_signature_algorithms フィールド中にあるもののひとつでなければならない
  • そのハッシュアルゴリズムおよび署名アルゴリズムは、クライアントのエンド主体証明書中の鍵と互換性がなければならない[1]
脚注
  1. RSAが署名に使われるなら、証明書の公開鍵もRSA、ECDSAで署名するなら証明書の鍵もECDSAということか?[1] ↩︎

2.2.3 セッションリザンプション

p.33 フルハンドシェイクはコストがかかる

  • アプリケーションデータ送信までにクライアント・サーバ間のやりとりが2往復必要
  • CPU負荷の高い暗号処理が何度も必要
  • 認証時の証明書検証はさらに負荷が高い

p.33 Session IDを利用してセッションを再開可能にする
p.33 以前共有したマスターシークレット(ClientKeyExchangeで共有したプリマスターシークレットから生死したもの)から、新たな暗号鍵を生成して通信に利用する

  1. ClientHello (C->S):以前のセッション再開リクエストをクライアントが送信
  2. ServerHello (C<-S):サーバが同一のSession IDを送信
  3. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  4. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  5. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  6. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)

p.34 HTTPクッキーに似たセッションチケットの仕組みもある:こちらはクライアントがすべての情報を保持する。サーバがセッション情報を管理しなくてもよい。チケットはサーバの公開鍵で暗号化されている。
TLS Session resumptionに関する英語のブログより

※TLS1.3ではPSK(Pre-Shared Keys、事前共有鍵)を用いてセッションリザンプションを実現する
TLS Session resumptionに関する英語のブログより

2.3 鍵交換

p.34 鍵交換の目的:プリマスターシークレットを生成し共有する
p.34 プリマスターシークレットからマスターシークレット(48バイト)を構成する
p.34 マスターシークレットがTLSセッションのセキュリティを支えている
p.34 よく利用される鍵交換アルゴリズム

鍵交換 説明
dh_anon 認証なしDHカギコウカン
dhe_rsa RSA認証を伴う一時的DH鍵交換
ecdh_anon 認証なしECDH鍵交換(RFC4492)[1]
ecdhe_rsa RSA認証を伴う一時的ECDH鍵交換(RFC4492)
ecdhe_ecdsa ECDSA認証を伴う一時的ECDH鍵交換(RFC4492)
krb5 Kerberos鍵交換(RFC2712)
rsa RSA鍵交換および認証
psk PSK(Pre-Shared Key)鍵交換および認証(RFC4279)
dhe_psk PSK認証を伴う一時的DH鍵交換(RFC4279)
rsa_psk PSK鍵交換およびRSA認証(RFC4279)
srp SRP鍵交換および認証(RFC5054)(Secure Remote Password)[2]

p.34 よく利用される4つ:RSA, DHE_RSA, ECDHE_RSA, ECDHE_ECDSA

脚注
  1. テキスト本文ではECDHE鍵交換となっているが誤記と思われる ↩︎

  2. SRP自体はRFC2945で定められている。Wikipediaによると、辞書攻撃に強く、信頼された第三者機関が必要ない。2021年現在のバージョンは6a。 ↩︎

●RSA鍵交換アルゴリズム

p.34 事実上の標準ともいえる
p.34 深刻な設計上の問題:サーバの秘密鍵が漏洩すると過去のやりとりもすべて復号可能(cf. Heartbleed)
p.35 従って、前方秘匿性のある他のアルゴリズムに置き換えが進んでいる
p.35 クライアントがプリマスターシークレットを生成、サーバの公開鍵で暗号化してClientKeyExchangeメッセージで送信
p.35 鍵転送のアルゴリズム

●DHE_RSA

p.35 一時的DH(Ephemeral Diffie-Hellman)の長所は前方秘匿性があること、短所は遅いこと
p.35 サーバとクライアント双方が処理に参加して共通の鍵を決定する鍵合意のアルゴリズム

●ECDHE_RSAおよびECDHE_ECDSA

p.35 一時的楕円曲線Diffie-Hellman(Ephemeral elliptic curve-):鍵合意アルゴリズム
p.35 処理が高速かつ前方秘匿性がある
p.35 現代的なクライアントでは広くサポートされている[1]

脚注
  1. ブラウザが対応するSSL/TLS CipherSuite一覧によると2010年時点でもそこそこサポートされている ↩︎

p.35 鍵交換はServerKeyExchangeメッセージから開始
p.35 rsa、dh_rsaの場合にはServerKeyExchangeメッセージは送られない=必要な情報は他で手に入る
p.35 鍵交換パラメータとともに署名も送られる(認証方法がanonでない場合のみ、サーバの証明書の秘密鍵で署名):クライアントはサーバの真正性を検証できる

p.35 ClientKeyExchangeメッセージは常に必須

2.3.1 RSA鍵交換

p.36 クライアントが48バイトの乱数=プリマスターシークレットを生成、サーバの公開鍵で暗号化、ClientKeyExchangeメッセージで送信
p.36 TLSで利用されるRSA暗号化スキームはRSAES-PKCS1-v1_5(RFC3447 Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1[1]
p.36 前方秘匿性がない:簡単さゆえに、サーバの秘密鍵が漏洩するとプリマスターシークレットも漏洩し、セッションが乗っ取られる(リアルタイムでなくても通信を記録しておけばよい)

脚注
  1. 署名のためのスキームはRSASSA-PKCS1-v1_5など。RFC 8017 PKCS #1: RSA Cryptography Specifications Version 2.2で改訂されているが暗号スキームの方は変わってなさそう ↩︎

2.3.2 Diffie-Hellman鍵交換

p.37 安全でない通信路で共有の秘密鍵を確立するためのアルゴリズム:能動的攻撃(通信経路ののっとり)には脆弱なので認証と合わせて利用するのが一般的
p.37 逆方向の計算が非常に困難な数学の関数を利用:以下は簡易的な計算例[1]

dh_g 99
dh_p(素数) 13
dh_Ys 5
dh_Yc 6

S=dh_g^dh_Ys mod dh_p= 9509900499 mod 13=8
C=dh_g^dh_Yc mod dh_p=941480149401 mod 13 =12

C^dh_Ys mod dh_p = 248832 mod 13 =12
S^dh_Yc mod dh_p = 262144 mod 13 = 12

p.37 dh_g とdh_pをドメインパラメータ(またはDHパラメータ、グループパラメータ)と呼ぶ:サーバが選択し、ServerKeyExchangeメッセージで送信される
p.37 DHE(一時的DH、Ephemeral DH):前回のDH鍵交換で利用したパラメータを再利用しない
p.37 サーバおよびクライアント証明書に静的に埋め込まれたパラメータでDH鍵交換を行うこともできるが、同一鍵が使いまわされるため前方秘匿性がないため、TLSではまず使われない

DH鍵交換の問題点
p.38 DHパラメータのセキュリティ:サーバが選ぶパラメータの品質に依存する。弱いDHパラメータの場合、再ネゴシエーション時の脆弱性をつくトリプルハンドシェイク攻撃が可能(詳細は7.6節で後述)
p.38 DHパラメータ強度のネゴシエーションができない:DHパラメータがクライアントに受け入れられることを期待するしかない
p.38 不十分なDHパラメータ強度:2048ビット以上が強いが、かつては512ビットを利用しているサーバも珍しくなかった。2015年のLogjam攻撃は512ビットのDHパラメータをリアルタイムで破れることが判明。詳細は6.5節。

p.38 ネゴシエーションが可能になれば解消されるはず:テキスト脚注22のドラフトは2016年8月にRFC7919としてまとめられた[2]

脚注
  1. 実際にはもっと大きな値が利用される。参考:RFC3562 ↩︎

  2. Qiita TLSとDiffie-Hellmanグループパラメータ ↩︎

2.3.3 楕円曲線Diffie-Hellman鍵交換

p.39 ECDHE(一時的楕円曲線DH)の数学的基盤は楕円曲線[1]暗号[2]

p.39 理論上、一時的でない楕円曲線DHもあるが実際には利用されない
p.39 利用する楕円曲線を定義するのはサーバの役目(DHにおけるドメインパラメータと同じ役割):ServerKeyExchangeメッセージで送信(RFC8422で以下のように拡張されている)。

struct


      select (KeyExchangeAlgorithm) {
          ..(省略)..
          case ec_diffie_hellman:
              ServerECDHParams    params;
              Signature           signed_params;
      } ServerKeyExchange;


      enum { ecdsa } SignatureAlgorithm;  
      select (SignatureAlgorithm) {
          case ecdsa:
              digitally-signed struct {
                  opaque sha_hash[sha_size];
              };
      } Signature;
      ServerKeyExchange.signed_params.sha_hash
           SHA(ClientHello.random + ServerHello.random + ServerKeyExchange.params);

      struct {
           ECParameters    curve_params;
           ECPoint         public;
      } ServerECDHParams;

       struct {
           opaque point <1..2^8-1>;
       } ECPoint;

       struct {
           ECCurveType    curve_type;
           select (curve_type) {
               case named_curve:
                   NamedCurve namedcurve;
           };
       } ECParameters;

       enum {
           deprecated (1..2),
           named_curve (3),
           reserved(248..255)
       } ECCurveType;


       enum {
           deprecated(1..22),
           secp256r1 (23), secp384r1 (24), secp521r1 (25),
           x25519(29), x448(30),
           reserved (0xFE00..0xFEFF),
           deprecated(0xFF01..0xFF02),
           (0xFFFF)
       } NamedCurve;

楕円曲線

p.39 上記のようにサーバは名前つき曲線を指定する:これを受けてクライアントは以下のように公開パラメータを送信、その後それぞれがプリマスターシークレットを計算

       struct {
           select (KeyExchangeAlgorithm) {
               case ec_diffie_hellman: ClientECDiffieHellmanPublic;
           } exchange_keys;
       } ClientKeyExchange;

       struct {
           ECPoint ecdh_Yc;
       } ClientECDiffieHellmanPublic;

p.39 クライアントが対応する曲線をTLS拡張 elliptic_curvesで伝達する(ClientHelloメッセージ。RFC8422)詳細は2.12.3節。

脚注
  1. y^2=x^3+ax+bという方程式で定義される平面曲線としてあらわされる。Wikipedia ↩︎

  2. 楕円曲線上の離散対数問題 (EC-DLP) の困難性を安全性の根拠とする暗号。離散対数を計算する問題は整数の因数分解と以下の点が共通している:
    1.両方とも難しい(量子コンピュータ以外では効率的に解くアルゴリズムが得られていない)
    2.片方に対するアルゴリズムはしばしばもう片方にも利用できる
    3.問題の困難性が暗号系の構築に利用されている ↩︎

  3. https://asecuritysite.com/encryption/go_x448 ↩︎

2.4 認証

p.39 TLSでは認証と鍵交換が一体化:コストがかかる暗号処理の回数を減らすため
p.39 基本は証明書を利用した公開鍵暗号方式

RSAの場合
p.40 クライアントがランダム値を生成(=プリマスターシークレット):サーバの公開鍵で暗号化して送信(ClientKeyExchangeメッセージ)
p.40 秘密鍵をもつサーバだけがClientKeyExchangeメッセージを復号でき、マスターシークレットを生成して正しいFinishedメッセージを生成できる:暗黙的に認証完了

DHEおよびECDHEの場合
p.40 サーバの秘密鍵でパラメータに署名:クライアントは証明書から公開鍵を取得して、パラメータの出自を検証する
p.40 2.3.3 ECDHでみたように、パラメータ署名はClientHelloのRandomとServerHelloのRandomを利用する=ハンドシェイクごとに異なる。暗号化されずに署名が送られるが、再利用されることはない。ただし、弱い鍵の場合は事前計算によりLogjam攻撃が可能。

2.5 暗号化

p.40 多様な暗号化アルゴリズムでアプリケーションデータを暗号化:AES, 3DES, ARIA, CAMELLIA, RC4, SEEDなど

2.5.1 ストリーム暗号化方式

p.40 暗号化は2段階

  1. シーケンス番号+Recordヘッダ+平文を結合しMAC計算
  2. MACと平文を暗号化

p.40 RecordヘッダがMACに含まれる=暗号化されていないRecordヘッダが改竄されていないことを保障
p.40 シーケンス番号がMACに含まれる=リプレイ攻撃がないことを保障

2.5.2 ブロック暗号化方式

p.41 暗号化は5段階

  1. シーケンス番号、Recordヘッダ、平文データのMAC計算
  2. 暗号化前のデータに対しパディングを作る(通常16バイトの整数倍)
  3. 暗号化ブロックと同じ長さで初期化ベクター(IV)を生成(同じ平文でも違う暗号文を得るため)
  4. 平文データ、MAC、パディングをCBCモードで暗号化(Cipher Block Chaining、p.11
  5. IVと暗号文を一緒に送る

p.41 上記手順をMAC-then-encryptと呼ぶ:数多くの問題の元凶
p.41 TLS1.1以降ではレコードごとに明示的なIVが含まれる:TLS1.0以前は暗黙のIVを利用(前のTLSレコードを暗号化したブロックを次のIVとする)していたが、2011年に安全でないと判明(BEAST攻撃、7.2節参照)
p.41 パディングがMAC計算に含まれないため、パディングオラクル攻撃が可能(7.4節参照)
p.41 2014年9月、Encrypt-then-MACとよばれるTLS拡張が公開:平文データとパディングを暗号化し結果をMACに渡す

2.5.3 AEAD(認証付き暗号、Authenticated Encryption with Associated Data)

p.41 暗号化および完全性検証を1つのアルゴリズムにまとめた
p.41 ストリーム暗号化方式とブロック暗号化方式の折衷案

  1. 64ビットのナンス(nonce, 特別な乱数)を生成
  2. 平文を暗号化し、同時に完全性検証のためシーケンス番号とRecordヘッダも利用
  3. ナンスと暗号文を一緒に送る[1]

p.42 TLSで利用できる現在最良の暗号化利用モード:MAC-then-encryptの問題を回避できる
p.42 認証方式の選択肢としてGCMモード[2]およびCCMモード[3]が規程されているが、実際に利用可能なのはGCMのみ
p.42 AEADの新しい暗号スイートとしてChaCha20ストリーム暗号化方式に基づくものが標準化(RFC7905[4]

脚注
  1. ナンスの役割が分からん...... ↩︎

  2. Galois/Counter_Modeの略。暗号化利用モードのCTR(Counter)モードに認証としてGaloisモードを組み合わせたもの。並列計算が可能なため連鎖の必要なCBCモードより高速。2007年NISTが標準化。 ↩︎

  3. Counter with CBC-MACの略。CCMモードは128ビットブロック暗号に対してのみ定義されている。暗号のCTRモードと認証のCBC-MACモード。 ↩︎

  4. 2016年標準化。たとえばTLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256など。Poly1305は認証モード。 ↩︎

2.6 再ネゴシエーションrenegotiation

p.43 新しい接続のセキュリティパラメータの合意のため、改めてハンドシェイクを実行する。以下の場合に便利:

クライアント証明書

p.43 二要素認証の1つ。
p.43 全接続にクライアント証明書を要求すると不親切(クライアントがエラーを受け取れない)
p.43 トップページはクライアント証明書なしで許可する運用方法が好まれる
p.44 クライアント証明書が必要なページへのアクセスがあった場合に、サーバが再ネゴシエーションでクライアント証明書を要求する

情報の隠蔽

p.44 前述のように、二段階でクライアント証明書を有効にすると、2回目のハンドシェイクが暗号化される
p.44 つまり、クライアント証明書の盗聴、ネゴシエーションの監視といった受動的攻撃ができなくなる
p.44 Torの通信で利用されている方式[1]

暗号強度の変更

p.44 昔、Webサイトとの通信を暗号化するのが先進的だった時代は、暗号化強度を分割しているサイトがあった(前述のページによってクライアント証明書の要不要をきりかえるのと類似)

以下の2つの状況になる可能性は低い。

SGC: Server-Gated Crypto

p.44 1990年代に強い暗号技術を米国が輸出規制していた:アメリカだけが強い暗号を使えるようにする機能
p.44 デフォルトでは弱い暗号:限られたCAが発行するクライアント証明書をもつ場合のみ、再ネゴシエーションで強い暗号を利用できた
p.44 2000年の規制緩和でSGCは廃れた

TLSレコードのカウンタオーバーフロー

p.44 各レコードは64ビットのシーケンス番号が割り当てられる
p.44 オーバーフローしそうな場合は再ネゴシエーションするしかない(64ビットもあるのでほぼない)
p.45 クライアントが再ネゴシエーションしたい場合、ClientHelloを送る(Client-initiated Renegotiation)
p.45 サーバが再ネゴシエーションしたい場合、HelloRequestプロトコルメッセージを送る:クライアントはアプリケーションデータの送信を中止し、新しいハンドシェイクを開始

構造体

      struct { } HelloRequest;

p.45 もともと、再ネゴシエーションは能動的攻撃に悪用の恐れ:2009年に発見され(詳細は7.1節)[2]、renegotiation_info拡張の導入によって修正された[3]

脚注
  1. 諜報活動をオンラインで匿名で行うために米海軍が開発したネットワーク技術『The Onion Routing』をもとに、オープンソース・コミュニティーのプログラマーたちが海軍公認で開発を進めたもの。Torは主として接続経路を匿名化するものであり、通信内容の秘匿を保証するものではない。TCP通信は可能だが、UDP通信は現時点で不可能。参考:パソコン遠隔操作事件 ↩︎

  2. 中間者攻撃が可能になるらしい。 ↩︎

  3. とはいえ再ネゴシエーション周りは脆弱性が多そう。2021年でも、TLSらじお第2回でとりあげたOpenSSLの脆弱性がある。 ↩︎

2.7 Application Dataプロトコル

p.45 アプリケーションのデータを運ぶバッファ
p.45 セキュリティパラメータに従ってRecordプロトコルのレイヤでパッケージ化、細分化[1]、暗号化される

脚注
  1. p.25 レコードは最長16,384バイト(2^14):それより長い場合、分割される。逆に単一のレコードにまとめられることもある。https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-369ba9c2435126 ↩︎

2.8 Alertプロトコル

p.45 例外的な状況を伝える通知の仕組み
p.45 ほとんどはエラー:接続シャットダウンを通知するclose_notifyもある[1]

構造体(RFC5246)

      struct {
          AlertLevel level;
          AlertDescription description;
      } Alert;

      enum { warning(1), fatal(2), (255) } AlertLevel;

      enum {
          close_notify(0),
          unexpected_message(10),
          bad_record_mac(20),
          decryption_failed_RESERVED(21),
          record_overflow(22),
          decompression_failure(30),
          handshake_failure(40),
          no_certificate_RESERVED(41),
          bad_certificate(42),
          unsupported_certificate(43),
          certificate_revoked(44),
          certificate_expired(45),
          certificate_unknown(46),
          illegal_parameter(47),
          unknown_ca(48),
          access_denied(49),
          decode_error(50),
          decrypt_error(51),
          export_restriction_RESERVED(60),
          protocol_version(70),
          insufficient_security(71),
          internal_error(80),
          user_canceled(90),
          no_renegotiation(100),
          unsupported_extension(110),
          (255)
      } AlertDescription;

p.45 AlertDescriptionに任意の情報を入れる機能はない
p.45 深刻度がfatalの場合、現在の接続を即中断してセッションを無効化(同じセッションで進行中の接続は続く場合もあるが、再開はされない)
p.45 warningの場合、アラート送信側が接続を終えることはない(受信側はfatal扱いすることも)

脚注
  1. ネットワークファイアウォールなどで通信が遮断される場合、これがfatalで送信される ↩︎

2.9 接続を閉じる

p.45 接続を切断する場合close_notifyアラートを送る(SSL3.0で追加された、後述の強制切断攻撃対策)
p.45 受信側は書き込み中の内容を破棄し、自身もclose_nofityを送信:その後受け取ったメッセージは無視する
p.46 シャットダウンプロトコルが必要なのは、強制切断攻撃(truncation attack)への防御
p.46 強制切断攻撃に脆弱な実装は多数ある(6.7節によれば古いIEがそう)

2.10 暗号処理

2.10.1 疑似乱数生成器(Pseudorandom number generator / Pseudorandom function)

p.46 引数:シークレット、シード、一意なラベル
p.46 TLS1.2以降、暗号スイートでPRFを明示することが要求されている(TLS1.2(RFC5246)ではP_SHA256がデフォルト)[1]

p.46 TLS1.2のPRF:HMACとSHA256に基づく(暗号スイートに依らない)

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                             HMAC_hash(secret, A(2) + seed) +
                             HMAC_hash(secret, A(3) + seed) + ...

      A(0) = seed
      A(i) = HMAC_hash(secret, A(i-1))

p.46 シードとラベルが異なるので同じシークレットでもマスターシークレット生成時と鍵生成時で出力が異なる

2.10.2 マスターシークレット

p.47 鍵交換によってプリマスターシークレットを得る:さらにPRFで処理し、48バイト(384ビット)のマスターシークレットを生成する

      master_secret = PRF(pre_master_secret, "master secret",
                          ClientHello.random + ServerHello.random)

p.47 マスターシークレットは事実上ランダムで、ハンドシェイクに紐づいている
p.47 根拠となっているのが交換した乱数値のみなので、これらの値を観察して複製すると同じマスターシークレットを共有する複数のセッションを生成できる(トリプルハンドシェイク攻撃、詳細は7.6節)

2.10.3 鍵生成

p.47 アプリケーションデータの通信に必要な鍵素材は以下のように生成される

      key_block = PRF(SecurityParameters.master_secret,
                      "key expansion",
                      SecurityParameters.server_random +
                      SecurityParameters.client_random);

p.47 鍵ブロックはネゴシエーションしたパラメータによって長さが異なる
p.47 鍵ブロックは6つに分割される:MAC鍵2つ、暗号鍵2つ、IVが2つ[2][3][4]

      client_write_MAC_key[SecurityParameters.mac_key_length]
      server_write_MAC_key[SecurityParameters.mac_key_length]
      client_write_key[SecurityParameters.enc_key_length]
      server_write_key[SecurityParameters.enc_key_length]
      client_write_IV[SecurityParameters.fixed_iv_length]
      server_write_IV[SecurityParameters.fixed_iv_length]

p.47 セッション再開時に、鍵ブロック生成の際に利用するマスターシークレットは以前のセッションと同じものを利用する。しかし、新しいハンドシェイクから乱数を取得するので、結果として鍵は異なるものになる。

脚注
  1. TLS1.3ではPRFがHKDFに置き換えられている模様。https://datatracker.ietf.org/doc/html/rfc8447#page-8HMAC-based Key Derivation Function↩︎

  2. ストリーム暗号化方式(ChaCha20など)ではIVは利用されない。AEAD(GCM、ChaCha20)ではMAC鍵を使わない。 ↩︎

  3. RFC5246)ではIVが生成されるのはAEADの場合のみで、nonce値として利用される。 ↩︎

  4. AES_256_CBC_SHA256スイートの場合、32バイトの暗号キー2つと32バイトのMACキー2つで合計128バイトとなる(RFC5246↩︎

2.11 暗号スイート

p.48 TLSはセキュリティプロトコルを作り出すためのフレームワーク:柔軟な実装ができる
p.48 以前のバージョンではプロトコルにハードコードされている要素技術もあった[1]
p.48 暗号スイートを規定する属性の例

  • 認証の種類:RSA、ECDSAなど
  • 鍵交換の種類:RSA、ECDHEなど
  • 暗号化アルゴリズム:AES、3DESなど
  • 暗号鍵の長さ:128、256など
  • 暗号化利用モード:CBC、GCMなど
  • MACアルゴリズム:SHA(SHA1)、MD5など
  • PRF(TLS1.2以降):SHA256、SHA384など
  • Finishedメッセージのハッシュ関数(TLS1.2以降)
  • verify_data構造体の長さ(TLS1.2以降)

RFC5246 Appendix C TLS1.2のCipherSuites一覧

TLS_DH_anon_WITH_AES_128_CBC_SHA256
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 など

※GCM利用スイートはRFC5288で別途定義されている

      CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9C}
      CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9D}
      CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9E}
      CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9F} など

p.48 名前から類推できないパラメータはRFCで定義されている
p.48 本書執筆時点(2017年?)で300のスイート:一覧はIANAのページ参照[2]

脚注
  1. TLS1.2以前は暗号化利用モードとしてCBCしか利用できなかった....はず ↩︎

  2. tls-parameters-4.csvがダウンロードできた。442行あったが、ざっと目視で40行ほどunassignedまたはreservedのものがあったので2021年5月末時点での総数は400程度と思われる。 ↩︎

p.49 AEAD(認証付き暗号、GCMoyobi
ChaCha20-Poly1305)の導入に伴い、MAC不要のスイートも登場:その場合、スイート末尾のSHA256などはPRFを指す
p.49 CCM(Counter with CBC-MAC)の場合PRFは省略されている
p.49 TLS1.2以前のスイートは、TLSバージョンによってPRFが異なる
p.49 例:TLS_RSA_WITH_AES_128_CBC_SHA

  • TLS1.2: HMAC-SHA256
  • TLS1.0, TLS1.1: HMAC-MD5/HMAC-SHA1の組み合わせ[1]

p.49 SHA1は選択的プレフィクス衝突攻撃に弱いことが知られているがHMAC-SHA1に対する既知の重大な攻撃はない
p.49 使えるスイートはサーバの持つ鍵の種類などにより制限される:RSA鍵しか持たない場合、ECDSAを使うスイートは対応できない
p.49 認証の強度は証明書・鍵の長さと署名アルゴリズムによって決まる:サーバ側で設定されるが、利用者に公開していないサーバもある

脚注
  1. TLS1.1のRFCによると PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) と排他的論理和を利用している ↩︎

2.12 TLS拡張Extensions

p.50 RFC3546(2003年)で定義[1]:TLS1.1で仕様に追加
p.50 拡張ブロックがClientHello/ServerHello Messageのあとに配置

RFC3546より

      struct {
          ProtocolVersion client_version;
          Random random;
          SessionID session_id;
          CipherSuite cipher_suites<2..2^16-1>;
          CompressionMethod compression_methods<1..2^8-1>;
          Extension client_hello_extension_list<0..2^16-1>;
      } ClientHello;

      struct {
          ProtocolVersion server_version;
          Random random;
          SessionID session_id;
          CipherSuite cipher_suite;
          CompressionMethod compression_method;
          Extension server_hello_extension_list<0..2^16-1>;
      } ServerHello;


      struct {
          ExtensionType extension_type;
          opaque extension_data<0..2^16-1>;
      } Extension;

      enum {
          server_name(0), max_fragment_length(1),
          client_certificate_url(2), trusted_ca_keys(3),
          truncated_hmac(4), status_request(5), (65535)
      } ExtensionType; // 2バイト

      enum {
          hello_request(0), client_hello(1), server_hello(2),
          certificate(11), server_key_exchange (12),
          certificate_request(13), server_hello_done(14),
          certificate_verify(15), client_key_exchange(16), finished(20),
          certificate_url(21), certificate_status(22), // 追加部分
          (255)
      } HandshakeType;

p.50 新しい機能に対応していることの表明+必要なデータを運搬する役割
p.50 プロトコルの進化を牽引
p.50 拡張の一覧はIANAのページ

脚注
  1. TLS1.0のリリースが1999年、TLS1.1が2006年、TLS1.2が2008年。 ↩︎

2.12.1 ALPN(Application-Layer Protocol Negotiation)

p.50 ポート443でデフォルトはHTTP1.1、ネゴシエーションしてSPDYやHTTP/2などが可能
p.50 application_layer_protocol_negotiation(0x10):クライアントが対応するプロトコル一覧を送る、レスポンスも同じ拡張
p.50 以前からあるNext Protocol Negotiation拡張と同様:NPNは暗号化されているが、ALPNは平文(ネットワーク機器が経路制御できるように)

RFC7301で定義されている。
ハンドシェイク中にネゴシエーションが完了するため、通信のラウンドトリップを削減できる。

2.12.2 CT(Certificate Transparency:証明書の透明性)

p.51 公開のログサーバにCA(認証局)が自身の証明書を登録する
p.51 ログサーバはSCT(Signed Certificate Timestamp)を登録証明としてCAに返送する
p.51 末端の利用者のツール上でSCTをチェック
p.51 SCTの転送方法の1つがsinged_certificate_timestamp拡張

RFC6962で定義されている

  • ExtensionTypeは18(0x12)
  • ClientHelloでextension_dataが空で送られる
  • ServerHelloで以下のデータがextension_dataにセットされる
        opaque SerializedSCT<1..2^16-1>;

        struct {
            SerializedSCT sct_list <1..2^16-1>;
        } SignedCertificateTimestampList;
  • セッションリザンプションでセッションが再開された場合、ClientHelloは通常時と同じだが、SeverHelloにはこの拡張は含まれない

2.12.3 楕円曲線の利用可能性

p.51 RFC4492 Elliptic Curve Cryptography (ECC) Cipher Suites for TLS
p.51 以下の2つの拡張が定義されている

     enum { elliptic_curves(10), ec_point_formats(11) } ExtensionType;

p.51 elliptic_curves:対応する名前付き曲線の名前のリストをClientHelloで送信[1][2]
p.52 ec_point_formats:楕円曲線上の点を圧縮するオプションをネゴシエーションできる(帯域の節約のため:とはいえ256ビットの曲線で64バイト程度の節約のため、圧縮されることは実際にはほとんどない)

p.52 RFC4492のNIST選定の楕円曲線はパラメータ選定基準が不明で、Dual_EC_DRBGにはバックドアがあることが判明している。
p.52 置き換えを目指してCurve25519、Curve448が標準化された(2018年、RFC8422)

脚注
  1. 楕円曲線DH鍵交換で見た通りhttps://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-46c09a05248899 ↩︎

  2. 名前付き楕円曲線は最適化されており処理が早いという利点がある。 ↩︎

2.12.4 Heartbeat(RFC6520

p.53 TLS/DTLS[1]向けのキープアライブ(死活確認)およびパスMTU探索[2]機能のプロトコル拡張
p.53 TCPにはキープアライブ機能があるので、これは主にUDPベースのDTLS向け
p.53 長さゼロのTLSレコードをキープアライブに使う案もある(プロトコルで許可されている、らしいがRFCのどの部分かはっきりせず...):PMTU探索ではペイロードを変化させる必要があるため両立不可

   enum {
      peer_allowed_to_send(1),
      peer_not_allowed_to_send(2),
      (255)
   } HeartbeatMode;

   struct {
      HeartbeatMode mode;
   } HeartbeatExtension;

   enum {
      heartbeat_request(1),
      heartbeat_response(2),
      (255)
   } HeartbeatMessageType;

   struct {
      HeartbeatMessageType type;
      uint16 payload_length;
      opaque payload[HeartbeatMessage.payload_length];
      opaque padding[padding_length];
   } HeartbeatMessage;

p.53 HeartbeatはTLSのサブプロトコル:他のプロトコルメッセージやアプリケーションデータと同時にやりとり可能
p.53 RFCはハンドシェイク完了時点でHeartbeatメッセージ許可:実際のところ、OpenSSLではTLS拡張やりとり直後から許可
p.53 2014年4月までは実際に使われているか不明だったが、Heartbleed攻撃が発覚(サーバのメモリ上にあるデータが抜き出される、詳細は6.3節)

脚注
  1. Datagram Transport Layer Security ↩︎

  2. Path Maximum Transmission Unit:1回の転送で送信できるデータ長の最大値。パケットがホップする場合、有効な値を探索する必要がある。イーサネットでは1500バイトだが、ユーザー認証などのためPPPoEを使うとカプセル化で8バイト使うため、1492バイトとなる。Wikipediaより ↩︎

2.12.5 Next Protocol Negotiation

p.54 GoogleがSPDYプロトコルを広める際に必要となり追加された拡張、ChromeだけでなくFirefox、OpenSSLが対応していた。
p.54 標準化を目指していたが、最終的には前述のALPNが採用された(2014年)

  • 新しいハンドシェイクメッセージの導入により通常のハンドシェイクフローに変更が必要となり、破壊的で混乱を招くとされたため。
  • 経路上のネットワーク機器がネゴシエーションされるプロトコルが把握できないことによる問題も懸念された(ので平文のALPNが採用された)

p.54 NPNはバージョン違いの仕様がある:2010年の012011年の022012年の032012年の04
p.54 実際に使われているのは2011年の古いバージョン

ハンドシェイク

p.54 SPDYが有効なクライアントは空のnext_protocol_negotiation拡張と接続したいホストを示すserver_name拡張をClientHelloで送る
p.54 ServerHelloには対応しているプロトコル一覧がnext_protocol_negotiation拡張で返る
p.54 NextProtocolハンドシェイクメッセージは以下の構造体で、接続に使いたいプロトコルを示す

struct {
  opaque selected_protocol<0..255>;
  opaque padding<0..255>;
} NextProtocol;

p.54 クライアントを受動的攻撃から守るためNextProtocolは暗号化して送られる:ChangeCipherSpecのあと、Finishedの前
p.54 パディングを使って選択したプロトコルを推測されないようにしている

2.12.6 安全な再ネゴシエーション(RFC5764、2010年

p.55 過去にハンドシェイクを確立した二者間の再ネゴシエーションを検証するための拡張

p.55 最初のハンドシェイクでデータなしでrenegotiation_info (extension type 0xff01 [65281])を送信し合う
p.55 SSL3.0では非対応: TLS_EMPTY_RENEGOTIATION_INFO_SCSV[1]という特別な暗号スイート[2]をクライアントが利用(これもRFC5764で定義。ClientHelloのcipher_suitesにTLS_EMPTY_RENEGOTIATION_INFO_SCSVを追加してメッセージを送信するだけ)

      struct {
          opaque renegotiated_connection<0..255>;
      } RenegotiationInfo;

p.55 再ネゴシエーションのハンドシェイクでは、以前のハンドシェイクのFinishhedメッセージのverify_dataを送る
p.55 クライアントは自身が送信したverify_dataを送る[3](暗号化されているため攻撃者は取得できない)
p.55 サーバはクライアントのverify_dataと自信が送信したverify_dataを送る[4]

脚注
  1. Signaling Cipher Suite Value。 ↩︎

  2. IANAのリストにも載っている。 ↩︎

  3. TLS1.2では12バイト。SSL3.0の場合は36バイトとなる。 ↩︎

  4. TLS1.2では合計24バイト。SSL3.0の場合は72バイト。この拡張の256バイト制限を考慮すると、verify_dataの長さは暗号スイートによっては128バイトまで利用可能、ということだろうか? ↩︎

2.12.7 SNI(Server Name Indication)

p.55 2003年のRFC3546で提案され2006年にTLS1.1からTLSに追加(初期のTLS拡張の一つ)
p.55 server_name拡張:ClientHelloに含まれる
p.55 同じネットワークアドレスで複数の仮想サーバに安全に接続できるようになる:サーバに該当の証明書を見つけさせる

extension_dataはServerNameList

      struct {
          NameType name_type;
          select (name_type) {
              case host_name: HostName;
          } name;
      } ServerName;

      enum {
          host_name(0), (255)
      } NameType;

      opaque HostName<1..2^16-1>;

      struct {
          ServerName server_name_list<1..2^16-1>
      } ServerNameList;

p.55 SNI未対応の製品:Windows XP、Androidの初期バージョンなど[1][2]

脚注
  1. 2011年2月リリースのAndroid 3.0の標準ブラウザは対応している。https://knowledge.sakura.ad.jp/1706/ ↩︎

  2. Javaの場合、2011年7月リリースのJava 7から対応している。https://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html ↩︎

2.12.8 セッションチケット(2008年のRFC5077

p.55 サーバ側でセッション情報を保持せずセッション再開可能にする拡張:暗号化したチケットとチケット鍵をクライアントに送る
p.55 Webサーバ間でセッションの同期が不要になるので、クラスタの大規模化が容易になるかも
p.56 チケット鍵の強度が重要:実装によっては接続のための暗号より弱い場合もある。
p.56 OpenSSLは128ビットのAES鍵を利用し、同一チケット鍵が複数セッションで再利用される:チケット鍵を周期的に交換しなければならない
p.56 session_ticket拡張:クライアントは最初、空の拡張を送信。2回目はチケットを送信。
p.56 対応しているサーバはServerHelloに空の拡張を送信。Finishedメッセージのあとに、チケットをNewSessionTicketハンドシェイクメッセージ(新規追加された)に格納して送信。

     struct {
          HandshakeType msg_type;
          uint24 length;
          select (HandshakeType) {
              case hello_request:       HelloRequest;
              case client_hello:        ClientHello;
              case server_hello:        ServerHello;
              case certificate:         Certificate;
              case server_key_exchange: ServerKeyExchange;
              case certificate_request: CertificateRequest;
              case server_hello_done:   ServerHelloDone;
              case certificate_verify:  CertificateVerify;
              case client_key_exchange: ClientKeyExchange;
              case finished:            Finished;
              case session_ticket:      NewSessionTicket; /* NEW */
          } body;
      } Handshake;

      struct {
          uint32 ticket_lifetime_hint;
          opaque ticket<0..2^16-1>;
      } NewSessionTicket;

      struct {
          opaque key_name[16];
          opaque iv[16];
          opaque encrypted_state<0..2^16-1>;
          opaque mac[32];
      } ticket;

     /* encrypted_stateの暗号化前 */
      struct {
          ProtocolVersion protocol_version;
          CipherSuite cipher_suite;
          CompressionMethod compression_method;
          opaque master_secret[48];
          ClientIdentity client_identity;
          uint32 timestamp;
      } StatePlaintext;

      enum {
         anonymous(0),
         certificate_based(1),
         psk(2)
     } ClientAuthenticationType;

      struct {
          ClientAuthenticationType client_authentication_type;
          select (ClientAuthenticationType) {
              case anonymous: struct {};
              case certificate_based:
                  ASN.1Cert certificate_list<0..2^24-1>;
              case psk:
                  opaque psk_identity<0..2^16-1>;   /* from [RFC4279] */
          };
       } ClientIdentity;

p.56 サーバがセッションチケットでセッション再開する場合、ServerHelloのSession IDフィールドを空で送る:クライアントがセッションIDを生成してもよく、その場合サーバが同じIDで応答する。

2.12.9 署名アルゴリズム(RFC5246=TLS1.2

p.56 signature_algorithms拡張:対応している署名アルゴリズムとハッシュ関数をクライアントが伝える。
p.56 署名アルゴリズム:RSA、DSA、ECDSA
p.56 ハッシュ関数:MD5、SHA1、SHA224、SHA256、SHHA384、SHA512
p.56 拡張なので必須ではない:サーバは暗号スイートを元に署名アルゴリズムを推察する

  • 鍵交換アルゴリズムがRSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA:SHA1またはRSA
  • 鍵交換アルゴリズムがDHE_DSS, DH_DSS:SHA1またはDSA
  • 鍵交換アルゴリズムがECDH_ECDSA, ECDHE_ECDSA:SHA1またはECDSA

RFC5246 7.4.1.4.1. Signature Algorithms

      enum {
          signature_algorithms(13), (65535)
      } ExtensionType;

      /* extension_dataはsupported_signature_algorithms */

      enum {
          none(0), // 将来のハッシュ化不要な署名アルゴリズム用
          md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
          sha512(6), (255)
      } HashAlgorithm;

      enum { anonymous(0), // この拡張で使ってはいけない(DH_anonとか用)
       rsa(1), dsa(2), ecdsa(3), (255) }
        SignatureAlgorithm;

      struct {
            HashAlgorithm hash;
            SignatureAlgorithm signature;
      } SignatureAndHashAlgorithm;

      SignatureAndHashAlgorithm
        supported_signature_algorithms<2..2^16-2>;

セッションリザンプションの際にClientHelloに含まれていた場合は無視される(すでに合意済みのため)

2.12.10 OCSPステープル(RFC4366、およびRFC6066

p.56 status_request拡張(0x05):クライアントがOCSPステープリングに対応していることを示す
p.56 OCSPステープル:サーバからクライアントに証明書の失効情報を送る(失効については5.11節)

ClientHello"extension_data"は"CertificateStatusRequest"

      struct {
          CertificateStatusType status_type;
          select (status_type) {
              case ocsp: OCSPStatusRequest;
          } request;
      } CertificateStatusRequest;

      enum { ocsp(1), (255) } CertificateStatusType;

      struct {
          ResponderID responder_id_list<0..2^16-1>;
          Extensions  request_extensions;
      } OCSPStatusRequest;

      opaque ResponderID<1..2^16-1>;
      opaque Extensions<0..2^16-1>;

p.56 (RFC4366/6066で追加された)CertificateStatusハンドシェイクメッセージでOCSPレスポンス(DER形式)[1]を提示(1つしか送れない)

      struct {
          CertificateStatusType status_type;
          select (status_type) {
              case ocsp: OCSPResponse;
          } response;
      } CertificateStatus;

      opaque OCSPResponse<1..2^24-1>;

p.57 status_request_v2拡張(RFC6961):複数のOCSPレスポンスに対応(2016/7年あたりではクライアント、サーバともにあまりサポートされていない)

     struct {
       CertificateStatusType status_type;
       uint16 request_length; /* Length of request field in bytes */
       select (status_type) {
         case ocsp: OCSPStatusRequest;
         case ocsp_multi: OCSPStatusRequest; // 追加された複数対応
       } request;
     } CertificateStatusRequestItemV2;

     enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;

     struct {
       ResponderID responder_id_list<0..2^16-1>;
       Extensions request_extensions;
     } OCSPStatusRequest;

     opaque ResponderID<1..2^16-1>;
     opaque Extensions<0..2^16-1>;

     struct {
       CertificateStatusRequestItemV2
                        certificate_status_req_list<1..2^16-1>;
     } CertificateStatusRequestListV2;
     struct {
       CertificateStatusType status_type;
       select (status_type) {
         case ocsp: OCSPResponse;
         case ocsp_multi: OCSPResponseList;
       } response;
     } CertificateStatus;

     opaque OCSPResponse<0..2^24-1>;

     struct {
       OCSPResponse ocsp_response_list<1..2^24-1>;
     } OCSPResponseList;
脚注
  1. RFC2560Rubyのリファレンス ↩︎

2.13 プロトコルの限界

p.57 TLSには意図しない弱点や、OSIレイヤや設計方針に由来する制限がある
p.57 TCPは平文なので送信元と宛先のIPアドレスは判別可能
WiresharkでIPアドレスを確認できる

p.57 TLSでも多くの情報は平文(特に最初のハンドシェイク):回避策はあるが採用されていない

  • クライアントのブラウザーフィンガープリント
  • SNI情報
  • ホスト/クライアントの証明書

p.57 暗号化が有効でも観察できる情報:サブプロトコルや各メッセージの長さ
例)リクエストとレスポンスからHTTPでどのリソースにアクセスしているか推測可能[1]

脚注
  1. 2009年くらいの研究を見つけた:George Danezis, Traffic Analysis of the HTTP Protocol over TLSによれば、暗号化されたリクエストからリソースを絞り込むことはできるし、Referrerヘッダーなども参照してユーザーの興味関心を知ることができる。サーバーからのレスポンスも、公開されているサイトならば攻撃者は事前に知ることができるので、ユーザーがどこにアクセスしているか推測可能。 ↩︎

2.14 プロトコルのバージョンによる相違

p.57 SSL3.0(1995年):以降プロトコルの中核はそれほど変更なし
p.57 TLS1.0(1999年):名前の修正のみ
p.57 TLS1.1(2006年):セキュリティ上の問題修正
p.57 TLS1.2(2008年):AEADの導入、ハッシュ関数の一掃、ハードコードされたプリミティブの除去

2.14.1 SSL3.0

p.58 スクラッチから開発された
p.58 詳細な変更はAnalysis of the SSL 3.0 protocol, 1997

2.14.2 TLS1.0

p.58 HMACによってPRFが規定される(HMAC-MD5とHMAC-SHA1の排他的論理和)[1]
p.58 マスターシークレットがPRFによって生成されるようになった
p.58 Finishedメッセージのverify_dataの値がPRFによって生成されるようになった
p.58 MACにおいて標準化されたHMACを利用(SSL3.0は古いバージョンを利用)
p.58 パディングのフォーマットが強固に(SSL3.0のパディングは2014年のPOODLE攻撃の対象)
p.58 暗号スイートからFORTEZZA[2]が除外

p.58 TLS1.0はFIPS認証取得:アメリカ政府機関で利用可能に
p.58 プロトコル設計方針については『マスタリングTCP/IP SSL/TLS編』が詳しい

2.14.3 TLS1.1

p.58 CBC暗号化利用モードで明示的なIVを利用(のちのBEAST攻撃で悪用される問題への対処)[3]
p.58 パティング攻撃への防御:bad_record_macアラート(20)[4]
p.58 TLS拡張の参照(RFCではClientHelloのstructに含まれず)

2.14.4 TLS1.2

p.59 AEADのサポート
p.59 HMAC-SHA256暗号スイートのサポート
p.59 IDEAおよびDES暗号スイートの除外
p.59 主要なTLS拡張が組み込まれた(RFCでもClientHelloのstructにExtensionが追加された)
p.59 signature_algorithms拡張でクライアントの希望アルゴリズムを伝達可能
p.59 PRF、ディジタル署名がMD5+SHA1からSHA256に。暗号スイートが独自のハッシュ関数を指定することも可能。
p.59 Finishedメッセージのverify_dataの長さを暗号スイートで明示的に指定可能

脚注
  1. 2.11 暗号スイート https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-c1840870a17ff2 ↩︎

  2. アメリカ政府が利用していたPCカードを利用したハードウェアベースの暗号標準。暗号化アルゴリズムにSKIPJACKというブロック暗号を利用していたが、機密扱いで詳細が公表されなかったため、IETFが標準化を拒んだためTLSで除外された。『マスタリングTCP/IP SSL/TLS編』pp.118-119 ↩︎

  3. 2.5 暗号化 https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-6e19c7679b29ce ↩︎

  4. 2.8 アラートプロトコル https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-d84dd400d77a97 ↩︎

第3章 公開鍵基盤

p.61 Public Key Infrastructure(PKI)

  • 会ったことがない相手と安全に通信する
  • 公開鍵を保管・失効する
  • 世界規模で使える:数百万のサーバ、数十億のデバイス

3.1 インターネットPKI

p.61 もともとはインターネット用ではなかったPKI[1]
p.61 Web PKI:ブラウザにおける証明書利用・検証に主眼
p.61 現在のPKI:信頼のおける第三者機関であるCA(Certificate Authority、認証局)[2]が発行する証明書を無条件に信頼するモデル

p.62 証明書所有者(Subscriber):エンドエンティティ(End-Entity)ともよぶ
p.62 登録局(RA, Registration Authority):本人性の検証が仕事。実際にはCAがRAを兼ねる。
p.62 認証局(CA, Certificate Authority):証明書所有者の本人性を保証する証明書を発行する。証明書の失効情報をオンラインで提供する。
p.62 証明書利用者(Relying party):厳密には、証明書を検証するのはWebブラウザなどのプログラムやOS。プログラムやOSは、トラストアンカー(デフォルトのルート証明書)を含むルートトラストストアを利用する。

脚注
  1. Wikipediaによると1970年台前半にイギリスのGCHQで開発されたが、1990年代まで公開されなかった。 ↩︎

  2. GlobalSignDigiCertなどがある ↩︎

p.63 信頼(trust):証明書がトラストストアに含まれるCAのルート証明書によって検証し得る、という意味
p.63 本人性(identity):正しいサーバである、というだけ。オフラインの本人性はEV証明書でないと得られない[1]

脚注
  1. EV(Extended Validation)証明書。SSL証明書にはDV(Domain Validation)、OV(Organization Validation)、EVの3種類があり、その中で最も厳格な審査方式を採用しているのがEV。EV証明書の企業名表示は、2018年9月にリリースされたChrome 77よりアドレスバーに表示されないよう仕様変更された。 ↩︎

3.2 証明書の標準

p.63 X.509:公開鍵基盤の国際標準(詳細はCertificateハンドシェイクメッセージの項を参照)、元々は電子ディレクトリサービス向け。
p.63 RFC5280:X.509をベースにPKIXワーキンググループがインターネットでの利用に適した仕組みにしたもの。主に以下を規定。

  • 証明書のフォーマット
  • 信頼パス(trust path)
  • 証明書失効リスト(CRL、Certificate Revocation List)

p.64 CA/Browser Forum (CAB Forum):証明書の発行および処理の標準を確立、徹底することに関心を持つCAやブラウザベンダーを中心とした団体。2007年〜。
p.64 Baseline Requirements:正式名称はBaseline Requirements for the Issuance and Management of Publicly-Trusted Certificates。2012年発表、以後定期的にアップデートされている[1][2]
p.64 CABフォーラムには2021年6月現在で、51のCAが参加している[3]
p.64 Baseline Requirementsは事実上すべてのCAに適用される:BRがCA向け監査プログラムであるWebTrustに組み込まれており、ルートトラストストアの運営元(Mozillaなど)が明示的にBRを要求するため。

脚注
  1. 2021年6月3日にバージョン1.7.6が公開された。 ↩︎

  2. これに関連して、先日GlobalSign社からSSLサーバ証明書のドメイン認証情報の再利用期間短縮のお知らせが発表された。再利用期間を825日から397日に短縮するというもの。これはBaselime Requirements 1.7.5での変更による。おそらく、2020年9月より証明書の有効期限を398日間以上にすることを禁じたことと関連すると思われる。 ↩︎

  3. Androidには100以上のCAのルート証明書が登録されているらしい。Wikipediaより ↩︎

3.3 証明書

p.64 証明書には、公開鍵、公開鍵に紐づけられた主体に関する情報、証明書発行主体のディジタル署名が含まれる
p.64 証明書はPKIの基本的な構成要素

p.64 ASN.1(Abstract Syntax Notation 1、抽象構文記法1):複雑なデータ構造やオブジェクトの定義、転送、交換のためのルール集。様々なプラットフォーム間でのネットワーク通信の手段として、実装に依存しない形で設計された。1998年に規定、2008年に更新。
p.64 ASN.1のエンコード方法はBERなどの標準がある。
p.64 BER(Basic Encoding Rules)のサブセットのDER(Distinguished Encoding Rules)がX.509では利用される
p.64 DERをBase64でエンコードするとPEM(Privacy-Enhanced Mail)になる
p.65 証明書はPEM形式がほとんどだが、一部DER形式のものも。

Amazonのルート証明書(Amazon Root CA 1)をASN.1デコーダーでデコードした結果。

3.3.1 証明書のフィールド

Googleの証明書

p.65 Version(バージョン):バージョン1(0)、バージョン2(1)、バージョン3(2)がある。

  • バージョン1:基本的なフィールドのみ[1]
  • バージョン2:一意の識別子が加わる[2]
  • バージョン3:拡張が利用可能となった

p.65 Serial Number(シリアル番号):あるCAの発行した証明書を一意に区別する番号。かつては連番の正の整数が利用されたが、選択プレフィクス衝突攻撃の防止のため、現在は予測不能な値を利用する。
p.65 Signature Algorithm(署名アルゴリズム):署名によって保護できるよう証明書内部に格納。
p.65 Issuer(発行者):主体の識別名(DN, Distinguished Name)。国(Country)、組織(Organization)、部門(Organizational-Unit)の3つから成る。
p.65 Validity(有効性):開始日と終了日の2つの日付で表される。
p.65 Subject(主体者):公開鍵にひもづく団体の識別名が格納される。自己署名証明書の場合、Issuerと同じ。かつてはCommonNameがサーバのホスト名として使われたが、複数ホストの場合に問題があるため現在では代わりにSAN拡張(Subject Alternative Name)が利用される
p.66 Public Key(公開鍵):Subject Public-Key Info構造体で示される(アルゴリズムの識別子+公開鍵)

※バージョン2で追加された一意の識別子は利用されず、バージョン3ではAuthority Key Identifierおよび
Subject Key Identifier拡張が利用される。

脚注
  1. RFC1422によれば、次の7つ:version, serial number, signature (algorithm ID and parameters), issuer name, validity period, subject name, subject public key (and associated algorithm ID)。 ↩︎

  2. Wikipediaによれば、issuer unique identifier / subject unique identifierが追加された。 ↩︎

3.3.2 証明書の拡張

p.66 バージョン3で導入:フォーマットに柔軟性を持たせるため
p.66 拡張=識別子(OID、Object Identifier)+重要度(critical)+値(ASN.1構造体)

Extension  ::=  SEQUENCE  {
        extnID      OBJECT IDENTIFIER,
        critical    BOOLEAN DEFAULT FALSE,
        extnValue   OCTET STRING
                    -- contains the DER encoding of an ASN.1 value
                    -- corresponding to the extension type identified
                    -- by extnID
        }

p.66 criticalな拡張は正しく処理できない場合、証明書ごと破棄することになっている

p.66 Subject Alternative Name(主体者の別名):単一のホスト名しか指定できない基本のSubject(主体者)フィールドにかわって、DNS名やIPアドレスやURIによって示される複数の主体を公開鍵に紐づけられる。

   id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }

   SubjectAltName ::= GeneralNames

   GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

   GeneralName ::= CHOICE {
        otherName                       [0]     OtherName,
        rfc822Name                      [1]     IA5String,
        dNSName                         [2]     IA5String,
        x400Address                     [3]     ORAddress,
        directoryName                   [4]     Name,
        ediPartyName                    [5]     EDIPartyName,
        uniformResourceIdentifier       [6]     IA5String,
        iPAddress                       [7]     OCTET STRING,
        registeredID                    [8]     OBJECT IDENTIFIER }

   OtherName ::= SEQUENCE {
        type-id    OBJECT IDENTIFIER,
        value      [0] EXPLICIT ANY DEFINED BY type-id }

   EDIPartyName ::= SEQUENCE {
        nameAssigner            [0]     DirectoryString OPTIONAL,
        partyName               [1]     DirectoryString }

p.66 Name Constraints(名前制約):CAが証明書を発行できる主体を制限するのに利用。たとえば、下位のCAを設置して自社ドメインに対してのみ証明書を発行できるようにする、など。RFC5280ではName Constraintsをcriticalな拡張としているが、実際にはcriticalに設定せずに利用されることもある。

p.67 Basic Constraints(基本制約):CA証明書かどうかを示す。同時に、下位CAの証明書パスの深さを制御する。すべてのCA証明書はこれを含まなければならないが、2016/17年当時はまだバージョン1で拡張のないルート証明書もあった[1]

   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }

   BasicConstraints ::= SEQUENCE {
        cA                      BOOLEAN DEFAULT FALSE,
        pathLenConstraint       INTEGER (0..MAX) OPTIONAL }



脚注
  1. 手元のmacOS Catalina 10.15.7のキーチェーンアクセスをざっと確認したところ、バージョン1の証明書は見つからなかった(シリアル番号が1のものはいくつか見つかった) ↩︎

p.67 Key Usage(鍵用途):この証明書に含まれる鍵の用途を示す。

id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }

KeyUsage ::= BIT STRING {
     digitalSignature        (0), // ディジタル署名
     nonRepudiation          (1),  // 否認防止
     keyEncipherment         (2), // 鍵暗号
     dataEncipherment        (3), // データ暗号
     keyAgreement            (4), // 鍵交換
     keyCertSign             (5), // 電子証明書の検証
     cRLSign                 (6), // CRLの署名検証
     encipherOnly            (7), // 鍵交換時のデータ暗号用
     decipherOnly            (8) } // 鍵交換時のデータ復号用

p.67 Extended Key Usage(鍵拡張用途):任意の用途をOIDを利用して追加で指定できる。

   id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }

   ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

   KeyPurposeId ::= OBJECT IDENTIFIER

-- extended key purpose OIDs

id-kp-serverAuth             OBJECT IDENTIFIER ::= { id-kp 1 }
id-kp-clientAuth             OBJECT IDENTIFIER ::= { id-kp 2 }
id-kp-codeSigning            OBJECT IDENTIFIER ::= { id-kp 3 }
id-kp-emailProtection        OBJECT IDENTIFIER ::= { id-kp 4 }
id-kp-timeStamping           OBJECT IDENTIFIER ::= { id-kp 8 }
id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }

p.67 RFC5280ではエンドエンティティ用証明書に対してのみEKU拡張を利用すべきとされているが、実際には中間CAの証明書の用途制限にも利用[1]


脚注
  1. つまりどういうこと? ↩︎

p.67 Certificate Policy(証明書ポリシー):1つまたは複数のポリシーを示すOIDと、オプションでポリシー全文を示すURL。

   id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }

   anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }

   certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation

   PolicyInformation ::= SEQUENCE {
        policyIdentifier   CertPolicyId,
        policyQualifiers   SEQUENCE SIZE (1..MAX) OF
                                PolicyQualifierInfo OPTIONAL }

   CertPolicyId ::= OBJECT IDENTIFIER

   PolicyQualifierInfo ::= SEQUENCE {
        policyQualifierId  PolicyQualifierId,
        qualifier          ANY DEFINED BY policyQualifierId }

p.67 Baseline Requirementsではエンドエンティティ用証明書にはポリシーを最低1つ含め、BR準拠であることを示すべしとしている。
p.67 この拡張を用いて証明書の検証の種類を指定できる[1]

脚注
  1. RFCをざっくり読んだがどこの話かよくわからず... ↩︎

p.67 CRL Distribution Points(CRL配布点):証明書失効リスト(CRL)の場所を示す。通常、LDAPやHTTPのURIで示される。
p.67 Baseline RequirementsではCRLかOCSPいずれかで失効情報を示すこととなっている

   id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::=  { id-ce 31 }

   CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint

   DistributionPoint ::= SEQUENCE {
        distributionPoint       [0]     DistributionPointName OPTIONAL,
        reasons                 [1]     ReasonFlags OPTIONAL,
        cRLIssuer               [2]     GeneralNames OPTIONAL }

   DistributionPointName ::= CHOICE {
        fullName                [0]     GeneralNames,
        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }

このURLにアクセスするとバイナリが返ってくるためcurlで直接表示はできない。以下のようにopensslを利用する。

$ curl http://crls.pki.goog/gts1d4/E0jY99efK8g.crl | openssl crl -inform der -text
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 77323  100 77323    0     0  2288k      0 --:--:-- --:--:-- --:--:-- 2359k
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: /C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
        Last Update: Jul  4 07:22:28 2021 GMT
        Next Update: Jul 14 06:22:27 2021 GMT
        CRL extensions:
            X509v3 Authority Key Identifier: 
                keyid:25:E2:18:0E:B2:57:91:94:2A:E5:D4:5D:86:90:83:DE:53:B3:B8:92

            X509v3 CRL Number: 
                772
            X509v3 Issuing Distribution Point: critical
                Full Name:
                  URI:http://crls.pki.goog/gts1d4/E0jY99efK8g.crl
                Only User Certificates

Revoked Certificates:
    Serial Number: 02470B5B0FC19F5A09000000005DD138
        Revocation Date: Mar 29 09:04:14 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
    Serial Number: FB9AA96CC279D675090000000076FACD
        Revocation Date: Jun 26 11:56:32 2021 GMT
    Serial Number: 55DA994202A25FB50A00000000EA2A6D
        Revocation Date: Jun 26 11:17:45 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
    Serial Number: 0EFD60DB5C7C8635090000000076F9BD
        Revocation Date: Jun 26 19:19:55 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
...(以下大量に表示されたので省略)

p.68 Authority Information Access(認証機関アクセス情報):証明書を発行したCAの付加的な情報やサービスへのアクセス情報を示す。下記のように、リアルタイムで失効情報を確認するためのOCSPレスポンダのURLなど。他に、発行者の証明書を発見できるURLも(不完全な証明書チェーンの再構築に役立つ)。

   id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }

   AuthorityInfoAccessSyntax  ::=
           SEQUENCE SIZE (1..MAX) OF AccessDescription

   AccessDescription  ::=  SEQUENCE {
           accessMethod          OBJECT IDENTIFIER,
           accessLocation        GeneralName  }

   id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }

   id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }

   id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }

p.68 Subject Key Identifier(主体者鍵識別子):特定の公開鍵を含む証明書を区別するための識別子。公開鍵のハッシュ値などが識別子として推奨される。CA証明書はすべてこの拡張を含まねばならないし、この値が発行済み証明書のAuthority Key Identifier(機関鍵識別子)と同じでなくてはならない。

id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }

SubjectKeyIdentifier ::= KeyIdentifier

p.68 Authority Key Identifier(機関鍵識別子):証明書に対する署名鍵を一意に特定する。証明書パスを構築するために使われる。

   id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }

   AuthorityKeyIdentifier ::= SEQUENCE {
      keyIdentifier             [0] KeyIdentifier           OPTIONAL,
      authorityCertIssuer       [1] GeneralNames            OPTIONAL,
      authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }

   KeyIdentifier ::= OCTET STRING



p.68 その他のRFC 5280拡張(あまり使われない)

  • Delta CRL Distribution Point(Freshest CRLとも)
  • Inhibit anyPolicy
  • Issuer Alternative Name
  • Policy Constraints
  • Policy Mappings
  • Subject Directory Attributes
  • Subject Information Access

3.4 証明書チェーン

p.68 証明書の検証にはエンドエンティティの証明書だけでは不十分:信頼の起点となるルート証明書へのチェーンが必要

【ルートを安全に保つ】
p.69 ルートCAの鍵はPKIのエコシステム全体にとってとても重要:ルートトラストストアの多くは更新されず、古くからの鍵は事実上替えが効かない
p.69 Baseline Requirementsでは、ルート鍵を使う場合手作業が要求される(自動化しない)
p.69 いくつかのCAはルート証明書を直接使ってエンドエンティティの証明書を発行しているが、そうしたやり方は認められていない

【相互認証証明書(Cross-certification)】
p.69 新しくCAの運用を開始する場合の唯一の方法:相互認証
p.69 新しいCAのルート鍵が広範囲に配布されるのには時間がかかるので、他のルート鍵で署名してもらう(古いデバイス向け)[1]

【区画化(Compartmentalization)】
p.69 下位CA(非ルートCA)は証明書発行を自動化、オンライン化
p.69 CAのリスク回避として、下位CAを複数に分割する:例)証明書のクラス、ビジネス部門などで分割[2]

【委譲(Delegation)】
p.69 CAが自分たちと関連のない別組織を下位CAにすることもある:大企業がプライベートCAを運営したくない場合など
p.69 下位CAの証明書を親CAがコントロールすることもあれば、自由に発行できる場合もある(その場合は、発行可能な名前空間に制約がつく、Name Constraints拡張を参照)

p.69 証明書チェーンは一つだが、信頼パスは多様:相互認証の場合、メインのCAだけではなく、他方のルートCAに連なるパスもある
p.70 パスの構築は実装が貧弱で、様々な問題を引き起こす:サーバー側の問題(ヒューマンエラーや証明書設定のユーザビリティ)も、クライアント側の問題(信頼パスの構築と検証にまつわるセキュリティ問題、詳細は6.1節)もある。

脚注
  1. StarfieldのリポジトリにはMicrosoftからの相互認証証明書が記載されている。 ↩︎

  2. StarfieldはEV証明書やコード署名証明書などで中間証明書を分けている。 ↩︎

3.5 証明書利用者

p.70 証明書検証のために信頼できるルートCA証明書の一覧が必要:OSの提供するルートトラストストア
p.70 例外:Mozillaは独自のトラストストアを用意

(画像はFirefoxの証明書ストアとMacBookのキーチェーン)

【Apple】
p.70 Apple Root Certificate Programを運用:監査を通過しないと追加してもらえない

【Chrome】
p.70 ChromeはホストOSのトラストストアを利用するが、Linux上ではMozillaのものを利用
p.70 OSの提供するものだけでは不十分として、独自の機能レイヤを持つ

  • 証明書のブラックリスト機能[1]
  • EV証明書を発行できるCAのリスト
  • 一部もしくは全部の証明書へのCTへの追加対応への要求[2]

【Microsoft】
p.70 Microsoft Root Certificate Programを運用:一年間の監査を通過しないと追加してもらえない

【Mozilla】
p.71 Mozilla CA Certificate Policy(2021年現在はMozilla Root Store Policy)にもとづき運用
p.71 様々なLinuxディストリビューションのルートトラストストアのベースとして利用される

p.71 いずれのプログラムも、CAが独立した監査を受けることを要求:DV、OVであれば以下。

  • WebTrust for CA[3][4]:EV証明書の発行についての監査のみ?(GlobalSignのページを見るとそうでもなさそう)
  • ETSI TS 101 456[5] Electronic Signatures and Infrastructures (ESI); Policy requirements for certification authorities issuing public key certificates
  • ETSI TS 102 042 Electronic Signatures and Infrastructures (ESI); Policy requirements for certification authorities issuing public key certificates
  • ISO 21188:2006 Public key infrastructure for financial services
脚注
  1. Digicertの資料によれば、2011年のComodo/Diginotar事件で登録局がハッキングされ、Gmailなどの証明書が偽造された際に、Comodoなどの証明書をブラックリストに追加してブラウザベンダが配布した、とされている。 ↩︎

  2. 2.12.2節 CTを参照。CT:Certificate Transparency(証明書の透明性)はSSL/TLSの信頼性を高めるための技術で、Google社により提唱され、2013年にRFC6962としてまとめられた。認証局が証明書を発行する都度、全ての証明書発行の証跡を、第三者の監査ログに記載し、Signed Certificate Timestamp(SCT)と呼ばれるデータが返される。Webサーバはこれを証明書とともにブラウザに提示し、ブラウザが検証する。 ↩︎

  3. https://jp.globalsign.com/webtrust/ によれば、AICPA(米国公認会計士協会)とカナダ勅許会計士協会によって共同開発された国際的な電子商取引認証局監査プログラム ↩︎

  4. 正確には、WebTrust
    Principles and Criteria for Certification Authoritiesのことか。 ↩︎

  5. European Telecommunications Standards InstituteのTechnical Specification。 ↩︎

3.6 CA

p.71 パブリックCAになるために必要なこと

  1. 競争力のあるCAを構築する
  2. 各国の法律を遵守する(ライセンス取得が必要な場合も)[1]
  3. ルートCA証明書プログラムで要求される監査をパスする
  4. 自分のルートCA証明書をさまざまなルートCA証明書プログラムに配置する
  5. ルート証明書の相互認証を行って運用を開始する

p.71 競争力のあるCAを構築する、とは...

  • PKIおよびCAの運用に深い知識をもつ
  • ルートCA証明書と下位CAの証明書鍵を防御しつつ、強固で安全な区画化されたネットワークを設計する
  • 証明書のライフサイクルに対応する
  • Baseline Requirementsに従う
  • EV SSL Certificate Guidlinesに従う[2]
  • グローバルなCRL、OCSP基盤を用意する

p.71 初期はDV証明書販売は割の良い仕事だった:2015年にLet's Encryptという無償CAが登場し、価格急落[3]
p.71 EV証明書関連は利益率が高くなるはず[4]

脚注
  1. 日本の場合、電子署名法にもとづきJIPDEC(一般財団法人日本情報経済社会推進協会)が認定している。参考:認証局の種別と関連制度 ↩︎

  2. こちらもCAB Forumのだしているガイドライン。 ↩︎

  3. 最近ではZeroSSLというサービスもあるらしい。参考:無料の SSL 証明書が得られる ZeroSSL を使ってみた ↩︎

  4. 参考:GlobalSignだとEV証明書は¥140,800、マルチドメインEV証明書は¥222,200。 ↩︎

3.7 証明書のライフサイクル

p.72 証明書所有者がCSR(Certificate Signing Request)を用意、CAに送信
p.72 CSR:公開鍵を格納すること、対応する秘密鍵で署名し秘密鍵の所有を明らかにする
p.72 CSRにはメタデータを格納できるが一部しか使われない:CAが他から手に入れた情報で上書きすることもある[1]

【DV証明書(Domain Validation)】
p.72 証明書所有者がメールアドレス宛に送られてきたメールに記載のリンクをクリックして承認すると、証明書が発行される
p.72 完全に自動化されており迅速に発行される
p.72 メール以外にも電話や郵送による確認もある

【OV証明書(Organization Validation)】
p.72 サイトを運営する組織が実在するか、本物の組織化を確認する
p.72 Baseline Requirements登場までOV証明書発行手続きは標準化されておらず、現在でも一貫していない部分がある

【EV証明書(Extended Validation)】
p.72 非常に厳格が本人性の検証が行われる。証明書の審査過程が業界統一の規格になった。[2]
p.72 証明書の入手には数日から数週間かかることもある。

p.73 上記検証が完了後、CAが証明書を発行する
p.73 証明書の再発行という言葉があるがそのような手続きはない:失効した場合は、単に新しい証明書を発行するだけ

脚注
  1. Nginx+opensslの場合のCSR作成手順。Country, Name, State or Province Name, Locality Name, Organization Name, Organization Unit Name, Common Name(ウェブサーバのFQDN。例:ssl.globalsign.com), Email Addressなどのメタデータがある。 ↩︎

  2. CA/B Forumの定めるGuidelines for the Issuance and Management of Extended Validation Certificates、通称EV SSL Certificate Guidelines。対面での本人確認には写真つきの免許証、パスポートなどを用いるべし、などと書かれている。 ↩︎

3.8 失効

p.73 証明書の秘密鍵が危殆化した場合、証明書が必要なくなった場合に失効される:2つの標準

【CRL(Certificate Revocation List)】[1]
p.73 期限切れになっていない、失効した証明書のシリアル番号一覧[2]
p.73 証明書のCRL Distribution Points拡張を利用してURLが格納されている
p.73 肥大化するためリアルタイム検索が遅い

【OCSP(Onlince Certificate Status Protocol)】
p.73 単一の証明書の失効状態を取得できる仕組み。OCSPのサーバをOCSPレスポンダという。
p.73 Authority Information Access拡張を利用してOSCPレスポンダの場所を示す。
p.73 リアルタイム検索ができるが、パフォーマンスとプライバシの問題がある[3]
p.73 こうした問題を解決する技術:OSCPステープリング(WebサーバがOSCPレスポンダと通信し、TLSハンドシェイクにOSCPレスポンスを埋め込む)[4]

脚注
  1. Digicertのホワイトペーパーに詳しい ↩︎

  2. 現物はhttps://zenn.dev/link/comments/ec15e852430d54 ↩︎

  3. Wikipediaの記事によれば、Google Chromeは待ち時間やプライバシーの問題を理由に、2012年に OCSP チェックをデフォルトでは無効にした。同記事の注にあるWebサイトによると、OSCPリクエストを受け取るCAがOSCPリクエスト送信元のIPと失効チェック対象の証明書から、どこからどのサイトが見られているか分かるのを問題視した模様。また、同サイトによれば、OSCPのレスポンスの中央値は300ms程度で、平均値は1秒程度とのこと。確かに遅い。 ↩︎

  4. RFC6066 Transport Layer Security (TLS) Extensions: Extension Definitionsで定義されている。本書2.12.10 OCSPステープルを参照。 ↩︎

3.9 弱点

p.73 1995年ごろ、インターネットはまだ重要性が低かった:Eコマースの発展とともに暗号化が必要に
p.74 Eコマースにとって十分なセキュリティが実現された:商業的セキュリティ
p.74 CAとブラウザベンダが制御
p.74 CAの立場の難しさ:何百ものCAがとても低いエラー率で証明書を発行し全体が動作しているのに、無償かつ完璧なセキュリティを求める人々がいる
p.74 インターネットPKIのさまざまな欠点

証明書の発行に際してドメイン所有者の許可が求められない

p.74 全てのCAが許可なくどんなドメイン名の証明書でも発行できる
p.74 数百あるCAの質も様々:監査を受けていても安全ではない ex.2011年のComodo/DigiNotar社の事件
p.74 CAがセキュリティより商業的利益を優先するケースも:2011年Trustwave社が証明書のでっちあげを認めた[1][2]
p.75 政府がCAのシステムを悪用している可能性も

信頼を迅速に回復できない

p.75 Trust agilityが欠如している:証明書に問題がある場合、ルートトラストストアからCAの証明書を除去すればいいが、大手は除外しづらい
p.75 ブラウザが、発行済み証明書を信頼するが新規の証明書を信頼しない、としたこともある(2017年、WoSignおよびStartCom)[3]

弱いドメインの検証

p.75 DV証明書は安全ではないWHOISプロトコルで取得できるドメイン所有者情報をもとに発行される
p.75 ドメインをのっとったり、電子メールやCAネットワークへの不正アクセスで偽のDV証明書を取得できる[4]

失効がうまくいかない

p.75 2011年にいくつかのCAで問題発生:ブラウザが自前のブラックリストなどで確実に失効させる必要があった
p.75 理由1:失効情報が各システムへ波及するまでの遅延(Baseline RequirementsではCRL/OCSPについて10 日間、中間証明書については12ヶ月までの有効にすることを認めている[5]
p.75 理由2:ブラウザのソフトフェイル・ポリシーにより、失効情報が取得できなくても接続が遮断されない
p.76 これらの理由から、ブラウザベンダーは失効確認を放棄[6]
p.76 失効については5.11節でさらに説明がある

証明書の警告がセキュリティの意図を台無しにする

p.76 証明書の検証が手ぬるい[7]:検証を完全に端折っているアプリやライブラリが多数、ブラウザの警告も迂回可能[8]
p.76 HSTS(HTTP Strict Transport Security)と呼ばれる新しい標準:ブラウザに証明書警告をエラーに置き換え、迂回をできなくさせる[9]

脚注
  1. ある記事によれば、ある会社が社内ネットワーク上でTLS接続を盗み見るために中間者攻撃を可能にする下位のルート証明書をTrustwaveが発行した。これを受けてMozillaがルート証明書プログラムからの除外を検討したとされているが、2021年7月現在のFirefoxのストアにはTrustwaveの証明書が確認できるので、結果としては除外されなかった? ↩︎

  2. 2011年のこれらの事件を受けて翌2012年にBaseline Requirementsが発表された。 ↩︎

  3. Wikipediaの記事によれば、日付を偽装して証明書を発行していたため、MozillaがWoSignをブロックした。WoSignはStartComを買収していた。別のサイトによれば、ルート証明書もその後Mozillaのストアから削除され、Googleも同様の対応をとった模様。 ↩︎

  4. CAへの不正アクセスについては、 ↩︎

  5. 最新のBaseline Requirementsを確認すると、中間証明書は失効から24時間以内にOCSPを更新すること、とされている。通常の証明書については最低8時間最大10日間OCSP情報を有効にしておくことを認めている。 ↩︎

  6. 最近のChromeはそうでもなさそう?Chromeのヘルプでは「Chrome が失効のステータス情報を取得できない場合、証明書は失効したものとして扱われます。」と書かれていた。 ↩︎

  7. このサイトによれば、iOS4.Xの証明書検証はBasicConstraints拡張を完全に無視しており、なりすましが可能であった。 ↩︎

  8. 本書1.4.5節 中間者攻撃のシリアの事例。 ↩︎

  9. RFC6797で規定。HTTPでの接続時にHTTPSを強制するのが主な機能。 ↩︎

3.10 ルートCA証明書の鍵の危殆化

p.76 PKIへの最も確実な攻撃=ルートCA証明書を狙う:政府機関の要求、100万ドルで新規にCAを設置
p.76 エンドエンティティ証明書を発行した形跡のないCAもいる
p.76 こうした状況への対策:公開鍵ピンニング(HPKP)[1]、HTTPS Everywhere拡張[2]
p.76 最も手間がかからない攻撃=既存のルートCA証明書、中間CA証明書を狙う:偽の証明書を発行しても発行元が同じなので見分けるのは困難
p.77 2003年のShamir/Tromerの発表:1024ビットの鍵は1000万ドルのマシンで約1年で破れる
p.77 2013年のTromerの見積もり:1024ビットの鍵は100万ドルでいける
p.77 => 政府機関にとっては容易に破りうるレベル
p.77 Googleは2013年に1024ビットの証明書から移行[3]
p.77 Mozillaは2013年末までに弱いルートCA証明書削除を予定していたが、2015年後半にようやく完了した[4]

脚注
  1. HPKP、HTTP Public Key PinningRFC7496で2015年4月に規定されたが、非推奨となり、Google Chromeは2019年のv72でサポートを廃止した。Firefoxは2015年1月リリースのv35からこれをサポートし続けている。これを置き換えられるものとして、Certificate Transparencyがある。 ↩︎

  2. Firefox版Chrome版などがある。すべてのWebサイトに接続する際にHTTPSで接続するようになる。TorプロジェクトとEFF(Electronic Frontier Foundation)が作成。 ↩︎

  3. Googleの発表によると、2013年7月に2048ビットの鍵へ移行中。2〜3ヶ月かかる見込み。 ↩︎

  4. この記事によれば、Firefox 32(2014年)でEntrustやGoDaddyなどいくつかの弱いルート証明書が削除されている。 ↩︎

3.11 エコシステムの観測

p.77 2010年以降PKIエコシステムの活発なスキャニング・モニタリングが実施:それ以前のことはあまりわからない
p.77 2010年7月の筆者Ivan Ristićの調査:12億ドメインの証明書、TLSセキュリティ分析
p.77 その数日後にEEFのSSL Observatory調査:全IPv4アドレス空間の同様の調査
p,77 2011年Holzらの同様の研究
p.77 2012年EEFがHTTPS Everywhereを利用したDistributed SSL Observatoryを発表:結果は未公開
p.78 2012年、筆者Ivan RistićのSSL Labsの一環としてSSL Pulseプロジェクト:毎月15万サイトをスキャン
p.78 2012年、ISC Certificate Notaryプロジェクト(2018年以降はあまり更新されていなそう)
p.78 2013年のDurumericらによる調査が最も包括的:ZMapというOSSツール、スキャン結果を公開
p.78 2014年、IE11によるテレメトリ収集対象に証明書を含める

p.78 いずれも、深刻な問題を明らかにしたわけではないが、重要な問題に光を当てた
p.78 例)CAがプライベートIPアドレス向けの証明書や完全修飾でないドメインへの証明書を定期的に発行

p.78 2014年、CA/B Forumのガイドライン遵守状況の評価結果が公開:Baseline Requirements導入後改善が見られた

p.79 CAの正確な数ははっきりしていない:通常のルートCAは100ちょっと、上位10のルートCAが市場の90%を占める
p.79 2015年Comodo社がcrt.shという証明書検索エンジンを立ち上げ:CTのログが情報源
p.79 2015年ミシガン大学がCensysというネットワークセキュリティ検索エンジンを立ち上げ:セキュリティ研究者向け

3.12 改善

p.79 2011年複数のCAのセキュリティが破られ、改善の動き
p.79 失敗したものも多い:残ったのはCT、公開鍵ピンニング、DANE、CAA(詳細は10章)

【Perspectives】
p.79 TLS認証を補助する公証人の概念を最初に導入:クライアントが公証人に相談して証明書を認証
p.79 2008年立ち上げ、2021年現在も活動している[1]

脚注
  1. 元はカーネギーメロン大学のプロジェクトだった。Perspectivesプロジェクトのサイトによると、2021年現在、AWS in Educationなどの助成を受けて、8つの公証人サーバを運用している。35万サイトを1日2回チェックしている。公証人にアクセスするにはFirefox拡張などを利用することができる。 ↩︎

【Convergence】
p.79 Perspectivesからフォークして改良した:2011年ローンチ、2013年以降活動なし、短命
p.80 プライバシー改善のため公証人へのリクエストに複数プロキシを介在
p.80 パフォーマンス改善のためサイト証明書を一定期間キャッシュ

【公開鍵ピンニング(Public key pinning)】
p.80 信頼できるCAをサイト所有者がピン留め:CAがどんなドメインの証明書も許可なく発行できる問題を解決する
p.80 2つの標準:HTTP Public Key Pinningと動的ピンニング(dynamic pinning)(詳細は10.3節)[1]
p.80 Chromeの独自の仕組み、静的ピンニング(static pinning)(詳細は10.3節)

【DANE】
p.80 DNSSECとTLSの橋渡しをする
p.80 DNSSEC(Domain Name System Security Extensions):DNSの拡張、安全性の検証を可能にする。
p.80 DANEは公開鍵ピンニングにも利用できる
p.80 DANEでパブリックCAを迂回し、DNSをTLSの認証に使えるようにもなる

【ソブリン鍵(Sovereign Keys)】
p.80 公的に検証可能なログに記録される鍵(ソブリン鍵)でドメイン名を主張する
p.80 CAやDNSSECなど既存のセキュリティ基盤を拡張する提案
p.80 2011年に公表されたが、鍵を失った場合の回復手段がなく、まだアイデアの段階(参考:EEFのプロジェクトページ

【MECAI(Mutually Endorsing CA Infrastructure)】
p.80 公証人の一種で、その基盤をCAが運用するというもの
p.80 煩雑な作業を全てサーバで行う:プライバシーとパフォーマンス改善が期待できる
p.80 CAが証明書の鮮度を保証するバウチャーを発行するVA(Voucher Authorities)を兼ねる(参考
p.80 2011年発表、まだアイデアの段階

脚注
  1. 証明書のハッシュや証明書そのものをアプリに組み込むピンニングの場合、証明書期限切れ時にアプリのアップデートができなくなる問題があった:dynamic pinningの場合ハッシュを外部からダウンロードすることでこれを解決する。参考 ↩︎

【CT(Certificate Transparency)】
p.81 パブリックな証明書の監査とモニタリングのためのフレームワーク
p.81 RFC6962として2013年に策定、Googleが推進[1][2]
p.81 2015年、Chromeは新規発行されるEV証明書がCT対応することを要求:最終的に2018年4月までにすべてのパブリックな証明書がCT対応することを要求[3]

【TACK(Trust Assurances for Certificate Keys)】
p.81 2012年に登場したピンニングの一種。サーバが提供した署名鍵をピン留めする。
p.81 長期的な署名鍵を利用すればCAに依存しなくて済むようになる(その分処理が大変)
p.81 他の提案と違い、HTTP以外でもTLSで保護される全てのプロトコルで動作
p.81 本書執筆時点でサポートしているクライアントはない[4]

【CAA (Certification Authority Authorization)】
p.81 ドメインに対する証明書を発行できるCAをドメイン名所有者が指定できるようにする提案
p.81 2013年RFC6844 DNS CAA Resource Recordとして提案
p.81 CA/B Forumが2017年3月にCAA利用を義務付けている

p.81 多くのアイデアは特別な状況でうまくいかず、実装されなかった
p.81 公証人をベースにした提案は注意すべき点が多すぎる:公証人の意見が一致しない場合、複数の証明書を同じ名前でデプロイしているときの誤検出、など
p.82 公開鍵ピンニングはかなり見込みがある:2011年にGoogleがデプロイしたおかげでDigiNotarによるセキュリティ侵害が発覚した(他の障害もいくつか見つかった)
p.82 DANEは優れた解決策ではあるが、DNSが中央集権的で政府の影響を避けられないことが課題:ブラウザベンダーは2021年現在も乗り気ではなさそう(参考:caniuse.com

p.82 2つの方向性:既存システムの改善路線とサイト毎にセキュリティを選べる路線
p.82 改善路線:Mozillaの働きかけによる2012年のCA/B ForumとBaseline Requirements発表や、GoogleによるCT推進、2010年以降のモニタリング活動
p.82 そこそこのセキュリティを可能にする新しい技術:公開鍵ピンニング、HSTS(HTTP Strict Transport Security)、CSP(Content Security Policy)、強制的なOCSPステープリング

脚注
  1. Googleのサイトによれば、2021年7月25日時点でGoogleのCTログに追加された証明書は 14,128,739,375 件。同サイトではCTログを閲覧することもできる。 ↩︎

  2. Let's EncryptのCTログは https://oak.ct.letsencrypt.org/2021/ct/v1/get-roots にアクセスするとみることができる。参考 ↩︎

  3. このメールによれば、Chrome 68(2018年7月リリース)以降、2018年4月30日よりあとに発行された証明書について、CT対応が必須となっている模様。 ↩︎

  4. 2021年現在でも、Googleで1年以内の記事を検索して関連する記事が出てこないため、状況は変わってなさそう。 ↩︎

第4章 PKIに対する攻撃

4.1 VeriSign社のMicrosoft社に対するコード署名証明書

p.83 2001年1月、身元を詐称した何者かにVeriSignがMicrosoftのコード署名証明書2通を発行
p.83 同年3月にMicrosoftが対応策を実施したあとに公になった

https://internet.watch.impress.co.jp/www/article/2001/0323/verims.htm

p.84 VeriSignは間違いに気づき証明書を失効したが、CRL配布ポイントが指定されておらず不十分な対策
p.84 Miscrosoftはこの証明書をブラックリストに入れるOSアップデートを公開

4.2 Thawte社とlogin.live.com

p.84 2008年夏、セキュリティ研究者がThawteの証明書検証処理をだまして証明書を取得
p.84 Thawteのドメイン認証に電子メールを利用している+Microsoftが@live.comのアドレスを誰でも利用できた
p.84 この問題はDEFCON17で発表された[1]
p.84 同様の問題がMicrosoftのlive.fiドメインで2015年にも発生

脚注
  1. DEFENSE CONDITION 29が2021/08/05-08開催される ↩︎

4.3 StartCom社のセキュリティ侵害(2008年)

p.85 セキュリティ研究者がStartComのドメイン名検証Webサイトの欠陥を悪用して迂回
p.85 StartComが目立つWebサイトドメインをブラックリストとして管理していたため発覚:paypal.comとverisign.com
p.85 数分ですべて失効された

4.4 CertStar(Comodo社)のMozilla証明書

p.85 StartComのCTOが同社への攻撃のあと他のCAでの同様の問題を発見
p.85 ComodoのパートナーのCertStarがドメイン名を全く検証せずに証明書を発行していた
p.85 mozilla.dev.tech.cryptoメーリングリストで大きな議論に
p.85 Comodoが検証し、証明書を失効させた

4.5 偽造RapidSSL

p.85 2008年SotirovとStevensを中心とする研究グループがRapidSSLを利用して偽造CA証明書を取得:任意のドメインの証明書発行可能
p.86 MD5の衝突を利用した攻撃で偽造CA証明書を取得

MD5とPKIに対する攻撃年史

  • 1991年:MD4を置き換えるものとしてMD5が設計される
  • 〜1996年:MD5が一般化、弱点を示す兆候が見られ、別のハッシュが推奨される
  • 2004年:MD5の完全な衝突の実例が示される:攻撃自体はまだ現実的ではない
  • 2005年:異なる2通の証明書が同じMD5ハッシュ値(同じ署名)を持つ現実的な衝突の実例が示される(RSA鍵空間が異なるのみで、証明書の本人性は同一であった)
  • 2006年:選択プレフィクス衝突攻撃(当初はターゲット衝突と呼ばれた)で、本人性が異なる証明書を衝突させることに成功:実質的にMD5は完全に破られた
  • 2008年:MD5による署名での証明書発行が止まらず:SotirovとStevensを中心とする研究グループによる攻撃の事例
  • 2012年:Flameとよばれるマルウェアが中東のネットワークで感染拡大:Windows Updateのコード認証の仕組みを攻撃するため、Microsoft社のCA証明書にMD5の衝突を利用していた。2-5年程度、政府の後ろ盾を受け活動していたとみられる。

4.5.1 選択プレフィクス衝突攻撃

p.87 ディジタル署名:データのハッシュ値に対して署名をするため、同じハッシュ値をもつ証明書が作れれば、一方に対する署名は他方についても有効となる
p.87 攻撃者にとっての制約:CAに証明書を送っても署名してもらえず、公開鍵やドメイン名などの情報を送ってCAが証明書を生成する。(乗り越えることは可能)
p.87 異なるデータのハッシュ値を一致させるために必要な条件

  • オリジナルの文書(潔白な文書)の先頭部分(プレフィクス)を事前に知っていること
  • オリジナルの文書(潔白な文書)の途中に衝突ブロックを配置できること

p.87 ファイルの末尾は同一にする必要がある

4.5.2 衝突する証明書の構成方法

p.87 ディジタル署名の作成における制約

  1. 証明書は攻撃者が作成したCSRの情報を使って、CAが作成する
  2. 証明書の構造はX509v3仕様で決まる:攻撃者は構造を予測することが容易
  3. CSRから証明書にコピーされる部分は攻撃者が制御可能:特に、公開鍵はそのままコピーされる。ランダムに見える衝突ブロックを作りやすい
  4. CAが追加する情報の一部に攻撃者が影響を及ぼすことが可能:例、証明書の失効時刻などは予測しやすい

p.88 以上より、プレフィクス=公開鍵よりも前にある全てのフィールド、衝突ブロック=公開鍵
p.88 プレフィクスの大半は、同じCAから発行された別の証明書とCSRに記載の情報から入手可能
p.88 CAが制御できるプレフィクス(シリアル番号と期限切れとなる日付):これも予測は不可能ではない(後述)
p.88 攻撃のプロセスは以下のようになる

  1. CAで生成される証明書のプレフィクスを確認し、CSRのフィールドを決める
  2. 不正な証明書に必要となるプレフィクスを構成する
  3. 証明書のサフィックスを決める
  4. 1-3のデータで衝突ブロックを構成する
  5. CSRを組みてててCAに送り本物の証明書を入手する
  6. 偽造プレフィクス、2つ目の衝突ブロック、サフィックス、本物の証明書から取り出した署名から、不正な証明書を組み立てる

p.88 RapidSSLへの攻撃では、証明書の利用に支障がないように、衝突ブロックにComment拡張(処理の際に無視される)が利用された

4.5.3 プレフィクスの予測方法

p.89 シリアル番号と期限切れ日時をどのように予測したか?:運とCAからの手助け

  1. RapidSSLでは完全自動化された証明書発行処理が6秒で完了[1]:期限切れ日時を秒単位で予測しやすい
  2. RapidSSLではシリアル番号に乱数を使わず単純なカウンタを利用:2つの証明書を連続して取得すると2つ目のシリアル番号が予測できる

p.89 MD5署名の証明書を発行するCAは2008年当時6つ存在[2]
p.89 研究チームは200台のPlayStation 3クラスタで1日かけて衝突を生み出した
p.89 CAの処理が最も空いている日曜夕方に攻撃を実行:4週間かけて成功

4.5.4 後日談

p.89 被害を最小限にする対策

  1. 不正な証明書は期限が過去の日時となるように生成
  2. トラストストアを管理する団体(MSやMozilla)に発表前にブラックリストへの追加を依頼
  3. RapidSSLにも事前に警告:攻撃の発表から数時間でSHA1へ移行

p.91 各種対策を経て安全であると判断してから選択プレフィクス衝突技法が完全に公開された
p.91 攻撃費用:たった657ドル(PS3クラスタを除く。RapidSSLでは1通新規69ドル、更新45ドルだが、無料で20回まで証明書を再発行できた)
p.91 Amazon EC2だと2万ドル近くかかる。改良すれば2000ドル。

p.90 真正な証明書と衝突した証明書の構成(研究報告スライドより)

研究報告サイトより

脚注
  1. 研究報告スライドによれば、Acceptボタンを押してから6秒後に完了するとのこと。 ↩︎

  2. 研究報告スライドによれば、他にFreeSSL、TrustCenter、RSA Data Security、Thawte、verisign.co.jpがMD5で証明書を発行していた。 ↩︎

4.6 Comodo社のリセラーのセキュリティ侵害

p.91 2011年の一連の事件のうち、最初のもの。
p.91 3/15:ComodoのRAの一つがセキュリティを侵害され7つのサイトの証明書が発行された(addons.mozilla.org、google.com、login.live.comなど)が、数時間で全て失効された
p.91 このときOCSPレスポンダへのアクセスはlogin.yahoo.comの証明書について2回だけだった(が、MITM攻撃によりOCSPへのトラフィックが抑圧されていた可能性もあるので全容は不明)
p.91 3/16:Comodoから関連団体へ通知、パッチを当てる処理が開始(例:FirefoxなどMozillaのコアモジュールで証明書を明示的にブロックChromeもFirefoxとやや異なる証明書をブラックリストに追加
p.91 3/22:3/15に攻撃があったことが、Comodo、Mozilla、Microsoftなどにより公開された
p.92 3/26:Comodoがさらに2社のリセラーでセキュリティ侵害があったことを公表、不正な証明書は発行されず
p.92 3/26:ComodoHackerを名乗る攻撃者が、数ヶ月に及ぶ大規模な攻撃であると発表(このあと他の攻撃にも関与)

p.92 2008年のCertStar事件以降、証明書発行を自由に行えるパートナーは9%となっていたが、本件以後は0%となった
p.92 本件で判明した重大な問題:Comodo社が実態に即した脅威モデル(RAそのものを攻撃対象として侵害する)を検討していなかった

4.7 StartCom社のセキュリティ侵害(2011年)

p.92 6/15:おそらくComodoHackerによってStartComが狙われた
p.92 これをうけて、StartComは証明書発行を1週間停止:不正な証明書の発行やルート鍵の危殆化はなし
p.93 StartComからの詳細報告はなく、2011/9/9のEddy NiggのStartComのサイト上のブログ記事が詳しい[1]

4.8 DigiNotar社

p.93 オランダのCA、DigiNotar:オランダ政府の電子政府プログラムのPKI部分を担当
p.93 7/19:ComodoHackerによるMITM攻撃を受け、531通の不正証明書を発行[2]
p.93 8/29:問題が公になる
p.93 9/5:ComodoHackerが声明を発表
p.93 9/19:DigiNotarは廃業し、自己破産

4.8.1 発見の経緯

p.93 8/27:イランのGmailユーザーが日常的なサービスダウンを報告、背景にMITM攻撃があったことが判明
p.93 Chromeの公開鍵ピンニングの仕組みがMITMを検出し防いだ
p.93 その後、約30万のIPアドレス(イランの全IPアドレスに相当)が影響を受ける大規模なものであることが判明

4.8.2 CAの信用失墜

p.93 オランダ政府は外部セキュリティコンサルタントFox-IT社を投入
p.94 1週間後の9/5にFox-ITの報告

  • CAサーバがネットワーク越しにアクセス可能
  • 全CAサーバが単一のWindowsドメインに所属、パスワードルールがあまり強くない
  • パッチが当たっていないソフトウェアがインストールされていた
  • サーバにアンチウイルス対策がない
  • IPS(侵入防止システム)は導入されていたが攻撃をブロックできず
  • ネットワークの中央ロギングシステムはなし
    p.94 1年後の2012年8月全容のレポート
  • 2011/6/17:Webサーバ上のコンテンツ管理アプリが破られる
  • 2011/7/1:ルート鍵の素材が保存される最重要ネットワークセグメントへ侵入
  • 2011/7/10:128通の不正な証明書を手に入れるプログラムを実行、最終的に53組織531通に(ログの改竄もあり、正確な数は不明)
  • 2011/7/19:DigiNotarが侵入に気づき、外部コンサルタントと協力してシステムをクリーンアップ、何通かの証明書を失効させたが、外部へは報告せず

p.94 証明書に利用された名前:有名Webサイト、CA、政府機関など

  • CA:comodo, digicert, globalsign, thawte
  • 有名サイト:google, mozilla, microsoft, skype, twitter, wordpress, facebook
  • 政府機関:cia[3], mossad[4], sis[5]
    p.94 Webサイトを騙る目的ではなく、メッセージが目的の証明書も(どんな暗号でも解ける、Torも破る、名もなき兵士、など)

4.8.3 MITM攻撃

p.95 不正な証明書にはDigiNotarのOCSP情報が埋め込まれており、OCSPレスポンダのログにより証明書の追跡が可能(MITM攻撃でOCSPサーバへのトラフィックが妨害されていない場合)
p.96 2011/8/4:大規模な運用の兆候が見られた
p.96 2011/8/29:各ブラウザでDigiNotarのルート証明書が失効され、不正な証明書が一掃された
p.96 この間、恒常的に攻撃があったわけではなく局所的だった(DNSキャッシュポイズニングが利用された?)
p.96 攻撃者の目的はGmailのパスワード収集
p.96 Google社を騙る証明書のOCSPリクエストの95%はイラン国内から、残りは世界各地のTor出口ノード、プロキシ、VPN

4.8.4 ComodoHackerの犯行声明

p.96 2011/9/5:Pastebinで声明、問題の証明書で署名したバイナリファイルや、攻撃の詳細の一部(後の公式報告と一致)が含まれた
p.97 イランにおける攻撃への関与は不明:MITMについてはあまり触れず

脚注
  1. startcomのブログは現在は消えているが、Internet Archiveで閲覧できる。このとき狙われた証明書はGoogle、Twitter、Yahooのものとのこと。 ↩︎

  2. 詳細はWikipediaに詳しい ↩︎

  3. Central Intelligence Agency、中央情報局 ↩︎

  4. イスラエル諜報特務庁 ↩︎

  5. Secret Intelligence Service(秘密情報部、通称MI6) ↩︎

4.9 DigiCert Sdn. Bhd.

p.98 2011年11月:Entrustと契約するマレーシアの中間CA、DigiCert Sdn. Bhd.[1]が危険な弱い証明書22通を発行していると判明[2]

  • 512ビットの鍵:総当たりで因数分解可能(一般数体ふるい法(GNSF:General Number Field Sieve Method)を使えば、総当たり不要[3]
  • EKU拡張による用途制限がない:契約上、Webサイト証明書しか発行できなかったが、制限がないためコード署名などにも利用可能
  • 失効情報がない

p.98 総当たりで破られた公開鍵がマルウェアへの署名として利用されて問題が発覚
p.98 Entrustが中間CA証明書を失効させブラウザベンダーに通達
p.98 米国DigiCert社は本件と無関係であるプレスリリースを出した

脚注
  1. Sdn. Bhd.はSendirian Berhad(スンディリアン・ブルハド)の略で、非公開株式有限責任会社の意味。参考ページ ↩︎

  2. Bugzillaのチケットによると、マレーシアの政府機関や中央銀行などもこのCAを利用していたらしい。 ↩︎

  3. GNSFをサクッと説明してくれる資料は見つからなかったorz。「近年の素因数分解について」(2008)によると、1990年に提唱された方法で、1999年時点で512ビット(155桁)、2005年時点で663ビット(200桁)、2010年のNTTの発表によると768ビット(232桁)、Qiitaの記事によると2020年に829ビットの素因数分解に成功している。 ↩︎

4.10 Flame

p.99 Flame:Flamer、Skywiperとも。2012年5月に研究者による分析開始(攻撃は数年前に開始したとみられる)
p.99 当時最も高度なマルウェア:Lua+SQLiteで、ネットワークアナライザ、マイク有効化、ファイル検索などの20の攻撃モジュールからなる。
p.99 イラン、イスラエル、パレスチナ、スーダン、シリア、レバノン、サウジアラビア、エジプトなど中東の1000のシステムで発見された
p.99 発見後、作成者が全インスタンスを消去する自動消滅コマンドを発行:いくつかは捕捉され分析された

4.10.1 Windows Updateに対するFlameの攻撃

p.100 Windows Updateを攻撃し、ローカルネットワーク上のWindowsに拡大:過去に知られていない暗号技術を利用した攻撃
p.100 IEがWPAD(Web Proxy Auto-Discovery)を利用しており、FlameはプロキシとしてHTTPトラフィックを乗っ取り、Windows Updateサーバとして悪意あるコードをインストールさせた
p.100 Windows Updateは平文を使っていたが、コード署名で防御していた:FlameはMD5衝突を利用して、この署名を偽造

4.10.2 Windowsターミナルサービスに対するFlameの攻撃

p.100 Windowsターミナルサービス、現在の呼び名はリモートデスクトップサービス。
p.100 問題の1つは、証明書の入手が用意であったこと

  • サービスのCA証明書がWindows UpdateのCAと同じルート証明書を利用:サービスのCA証明書から、顧客ごとの下位CA証明書を発行
  • サービスのCAを、ライセンス処理以外に、なぜかコード署名に利用できた
  • 下位CA証明書には使用方法の制限がない=親の制限が継承される(コード署名に利用できる)

p.100 上記をまとめると、リモートデスクトップサーバの顧客ごとに無制限の下位CA証明書が与えられ、これを利用してコード署名が可能だった
p.100 ただし、下位CA証明書にはHydraというcriticalな独自拡張があり、Windows Vista(2007年リリース)以降では動作せず:Windows XPでのみ動作した(XPではcriticalな拡張を無視するため)

4.10.3 MD5を悪用するFlame

p.101 もう1つの問題:証明書の署名がMD5
p.101 ターミナルサービスの設計時点でMD5は安全でないことが知られていたにもかかわらず、ルート証明書の署名に利用された
p.101 RapidSSLへの選択プレフィクス衝突攻撃が利用された
p.101 RapidSSLのときとの違いは、シリアルナンバーが連番ではないものの、起動時からの経過時間(ミリ秒
)に固定の2バイトと連番が続く形式だった。
p.101 ミリ秒単位の正確さが要求されるので、強力なクラスタが必要だったはず
p.102 研究者Marc Stevensによれば、新しい差分パス構築アルゴリズムが使われたとされる

暗号解析への対策

p.102 MD5は言うまでもなく、SHA1も弱いことがわかっている(まだしばらくは使われそう)[1]
p.102 Marc Stevensが発明した対策:耐暗号分析(counter-cryptanalysis)[2][3]

  • 暗号分析による攻撃(例:選択プレフィクス攻撃)により不可避的に生じる異常を検出できる
  • (なので)MD5/SHA1によるハッシュ値が偽造でないことを検証できる
脚注
  1. 2017年のGoogleの記事によれば、SHA-1が初めて衝突した。この記事の著者はMarc Stevensら。Stevens自身はGoogleではなくアムステルダムにあるオランダ国立数学情報科学研究所に所属。Googleと同研究所が2年間かけて共同研究した。この記事によると、MD5はスマホで30秒で破れるらしい。SHA1は110台のGPUで1年かかるとのこと。なお、この発表の翌日、FirefoxはSHA1による証明書を無効化すると発表した(参考)。 ↩︎

  2. 論文の要約によれば、Stevensはこの技術を利用して、Flameが選択プレフィクス衝突攻撃を利用していることをつきとめたらしい。 ↩︎

  3. こちらのブログで日本語で解説されていたがよくわからなかったorz。このブログで、Marc StevensによるC++製OSS暗号分析ツールHashclashが紹介されている。 ↩︎

4.11 TURKTRUST社

p.102 2012年10月:Google Chromeの公開鍵ピンニングが問題を発見、ユーザーが問題の証明書チェーンをGoogleに送付、Googleが調査
p.102 証明書の出所はトルコのTURKTRUST社[1]:数日で証明書は失効
p.103 2011年8月のシステム移行時にSSL証明書ではなく、誤って中間CA証明書を発行していた:そのうちの1つEGO社で MITM機能を持つファイアウォールを導入し誤ってGoogle社の証明書のクローンが作成された
p.103 GoogleとOperaではTURKTRUST社のEV証明書を無効化[2]

脚注
  1. Googleのブログによると、*.google.comドメインの証明書が、中間CA証明書によって発行された。この中間証明書のルート証明書がTURKTRUSTのもの。 ↩︎

  2. Googleのブログによると、HTTPS接続はできるがEV証明書としての表示を無効化したということのよう。 ↩︎

4.12 ANSSI

p.103 ANSSI:Agence nationale de la sécurité des systèmes d’information(フランスの国家機関)
p.103 2013年12月同機関から発行された下位CA証明書をChromeのルートストアから削除、親CAについてはフランス国内のドメインの証明書のみとする制限を課した
p.103 同機関のネットワーク上でMITM機能が動作し、Googleに属する証明書が利用されていた:これもやはりChromeの公開鍵ピンニングで検出
p.103 ANSSIは人為的ミスであったと説明
p.103 MozillaとMicrosoftも問題があるCA証明書を無効化

p.104 ANSSIの問題点が明らかに

  • 多くの証明書に失効情報がない
  • 空だったCRLに数千の証明書が一気に登場
  • Baseline Requirements非対応:早くて2015年12月[1]
脚注
  1. その後の対応状況を調べてみたがよくわからず。FirefoxのトラストストアやmacOSのキーチェーンには含まれていない様子。2021年8月22日現在のANSSIのサイトはCertignaというフランスのCAの発行した証明書を利用していた。2021年8月9日時点でオランダのPKIoverheidが「EU最後の政府運用CA」と言われているので、フランスも2013年から2021年の間にCAをやめたのだろうか。 ↩︎

4.13 インド情報工学センター

p.104 NIC:National Informatics Centre of India
p.104 2014年7月、Google所有のドメインへの証明書が同センターの中間CAから発行された
p.104 発行元はインド政府の認証管理局(CCA:Controller of Certifying Authorities):のちに、NICのCAがセキュリティ侵害を受けたことを暴露
p.104 証明書は失効され、NICのCAは証明書発行を停止
p.104 ChromeはCCA発行の証明書についてインドのドメイン(.in)の7つのサブドメインに限定[1]

脚注
  1. Googleのブログによれば、もともとWindowsのルートトラストストアにCCAのルート証明書が含まれており、Windows上のChrome(とInternet Explorer)が影響を受けた。Firefoxは独自のトラストストアを利用するため影響をうけず、また、Windows以外のOS上で動作するChromeも影響をうけなかった。 ↩︎

4.14 広範囲に及ぶTLSの傍受

p.104 ローカルにインストールされたソフトや、ネットワークプロバイダによるTLSの傍受は日常的(2017年のDurumericらの研究)

4.14.1 Gogo社

p.104 Gogo社:航空機内インターネット接続サービスを手がける
p.104 2015年1月、ChromeのセキュリティチームのAdrienne Porter Feltにより、同社が暗号化されたトラフィックを傍受し不正な証明書を利用していることを指摘
p.105 不正な証明書に関する警告が出る状態
p.105 同社は機内の帯域制御に必要と釈明するも、後日傍受を完全停止

4.14.2 Superfishとその仲間

p.105 2015年2月、AdrienneがLenovo社のSuperfishプリインストール問題を指摘
p.105 Superfish:利用者の全トラフィックを傍受
p.105 OSのルート証明書ストアに不正なルート証明書を追加し、プロキシ経由でこれを利用しMITM
p.105 全てのユーザーで同じルート証明書を利用していたことが問題(ユーザーごとに異なる証明書なら良い):秘密鍵を抜き出したユーザーは他のユーザーを攻撃できてしまうため
p.105 SuperfishのプロキシはTLS1.1しかサポートしていなかった(当時の最新はすでにTLS1.2)
p.106 MITMにより、どんなサイトに接続しても証明書の警告がでない状態だった
p.106 Facebookの調査では、カザフスタンからのFacebookへの接続の4.5%がSuperfish経由
p.106 MicrosoftとLenovoが協力して、Superfishを25万台から数日で削除
p.106 その後、SuperfishでのKomodiaが開発したTLS傍受用SDK利用が判明:類似の製品としてComodo社のPrivDogなど、同様のものはたくさんある

4.15 CNNIC

p.107 CNNIC:China Internet Network Information Center(中国ネットワークインフォーメーションセンター)
p.107 2015年3月、MCS(Mideast Communication Systems)社がCNNICから試験的中間CA証明書を受領
p.107 誤ってGoogle社を騙る証明書が発行される
p.107 Google・MozillaはCNNICのルート証明書を失効:中間CA証明書を、杜撰な組織に発行した責任を問う形
p.107 失効以前の有効な証明書についてはホワイトリストを利用して許可し続けた

4.16 Symantec社によるテスト用証明書

p.107 2015年9月、Symantecがgoogle.comに対するEV証明書を権限なしに発行したとするGoogleのブログが公開
p.107 Symantecは2人の社員のミスを主張し彼らを解雇
p.107 EV証明書に必須であったCTのログを精査したところ、総数2645の証明書が誤発行されていたことが判明
p.108 GoogleはSymantecのインシデント報告の遅れを理由に、2016年6月以降同社の証明書全てをCTに登録することを要求

4.17 WoSign社とStartCom社の問題

p.108 2011年のDigiNotarが最初の信用失墜したCA:2016年のWoSignとStartComがそれに続く
p.108 WoSign:中国の大手CA、無料証明書発行でシェア拡大。イスラエルのStartComを買収
p.108 WoSignの運用について問題があるとしてMozillaが調査:2015年1月からルート証明書の不適切利用が明らかに[1]
p.108 決定的であったのはStartCom買収に伴う所有権移転を公表しなかったこと:Mozilla Root Store Policy
の8. CA Operational Changes
に違反
p.108 信頼に値しないとしてMozilla、Apple、Googleがルートストアから排除
p.108 StartComは2008年2011年にも問題をおこしていたが、WoSignとインフラの大部分を共有し、組織的上下関係があったことで同じく排除された
p.109 排除の手法:ある日以降に発行される証明書を拒否(Google、Mozillaは2016年10月21日に設定)
p.109 WoSign/StartComのその後:他のCAの再販業者として操業継続

脚注
  1. MozillaのWikiによると、シリアルナンバーの重複や、多数のBaseline Requirements違反があった。その中には、Baseline Requirementsで認められていない暗号アルゴリズムである中国のSM2を利用した証明書発行もあった。 ↩︎

4.18 Various Validation Incidents

StartEncryptでの検証失敗

p.109 2016年6月、StartCom社が新しいプロトコルStartEncryptを発表:Let's Encryptと同社のACMEプロトコルへの対抗策
p.109 Let's Encryptが非対応だったOV証明書EV証明書に対応
p.109 1ヶ月で致命的な欠陥が見つかる

  • 詐称した証明書が取得可能
  • リダイレクトが許可されたWebサイトの証明書を取得可能だった

p.109 StartComはStartEncryptを破棄してACMEの利用を発表

Comodo社のトップレベルドメイン証明書の誤発行

p.109 2016年9月、sbとwww.sbの両方に有効な証明書を発行:ホストの所有者が異なる
p.110 この前にもtbドメインで同じ問題があったが、こちらは所有者が同じだった

Comodo社が検証の過程でOCR利用

p.110 2016年10月、研究者がComodoの検証プロセスの問題を発見:OCRに脆弱性(1とl)
p.110 WHOISがスパム対策として画像でメールアドレスを提示するためOCRを利用
p.110 のちにComodoはOCR利用を中止

GoDaddy社が404レスポンスで所有権を認めた問題

p.110 2017年1月、GoDaddyが問題を公表:権限なしに8850の証明書が発行された
p.110 ドメイン検証の際に、GoDaddyが乱数を送付、ドメイン所有者がWebサイトに同じ乱数を出力していた
p.110 もともとHTTP(S)でリクエストを送ってサイトをチェックしていたが、検証のバグにより、404ステータスの際にも(URLに乱数が含まれたため)検証が通過するようになってしまった[1]
p.110 この検証方法はCAB Forumで問題視され、Ballot 169[2]で投票の結果、Baseline Requirementsが改善された。

脚注
  1. 詳細はmozillaのメーリングリストに。 ↩︎

  2. Ballotは投票の意味。 ↩︎

4.19 SHA1の終焉

p.111 2017年2月SHA1が破られた:以前見た通り]
p.111 SHA1の署名が同一となる2つのPDFが公開された:このPDFをSubversion/Gitに投入しようとするとVCS自体が壊れてしまった
p.111 発表者の1人、Marc Stevensは選択的プレフィクス攻撃の検出機能のあるSHA1ライブラリを公開

4.19.1 同一プレフィクス攻撃(identical-prefix attack)

p.112 研究者チームが使用した手法:Marc Stevensがこの数年前に理論上の手法として提示していた
p.112 SHA1:任意の長さの入力から、160ビットの出力を生成するハッシュ関数。内部的に512ビットのブロックに分割される
p.112 関数の内部状態を操作するために、近衝突ブロック(near-collision block)2つを生成する:2つ目で完全に衝突させる

第5章 HTTPおよびブラウザの問題

p.113 ブラウザベンダーが旧来のWebサイトの扱いに苦慮した結果多くの問題が発生

5.1 サイドジャッキング

p.113 セッションハイジャックの一種:暗号化されてないトラフィックからセッションIDを抜き出す攻撃
p.113 無線LANやローカルネットワーク上で簡単に実行できる
p.113 暗号化をしていてもつけ込まれる可能性
p.113 1. 設計上のセッション漏れ:パスワード認証時のみ暗号化しているケース
p.113 2. ミスによるセッション漏れ:HTTPのコンテンツが混在するケース(クッキーから漏洩:混在コンテンツについては本章後半で)
p.114 クッキー以外にも、リクエストパスやパラメータとしてセッションIDが埋め込まれる
p.114 2007年8月Robert GrahamとDavid MaynorがFerretとGamsterという攻撃を自動化するツールをリリースし、本攻撃が知られるようになった
p.114 2010年Eric ButlerがFirefoxアドオンFiresheepを公開:簡単にサイドジャッキングを実行可能[1]、有名なサイトの完全な暗号化を促進
p.114 対策・警告ツールとしてBlackSheep[2]、FireShepherd[3]、Idiocy[4]、CookieCadgerなどが登場

脚注
  1. この記事によると、「ローカルWiFiネットワークをスキャンして、Facebook、Twitter、Google、Amazon、(中略)といった、数多あるWebサービスにログインしているユーザーを洗い出し、そのユーザーに成りすますことをいとも容易く可能に」するとのこと。 ↩︎

  2. この記事によると「Blacksheepはこのクッキーを横取りし、Firesheepには偽のログイン・クッキーを渡すと同時に、ユーザーにFiresheepの存在を警告し、攻撃者が使用しているデバイスのIPアドレスを表示する」。 ↩︎

  3. 配布サイトの説明によると、これは小さなコンソールプログラムで、近くのワイヤレスネットワークにFireSheep停止のためのパケットを大量に送り込み、FireSheepを0.5秒ごとに停止させるらしい。一歩間違えると大惨事なような...と思ったらこちらの記事では使わない方がいいと書かれている。やはり。 ↩︎

  4. こちらの記事によると、「HTTPセッションハイジャックを実施してTwitterアカウントを取得し、そのユーザになりすまして自動的に警告文章をつぶやくツール」らしい。実際のツイートはたぶんこれ。IdiocyはPythonで実装されている。 ↩︎

5.2 クッキー窃取

p.115 Webサイトの完全TLS化だけではサイドジャッキングは防げない:クッキーの暗号化も必要
p.115 WebサイトのTLS化時:クッキーにSecure属性を設定すべき[1]
p.115 Secure属性がない場合のMITM攻撃

  • 犠牲者が平文のHTTPリクエストを送るのを待つ
  • リクエストに、標的のWebサイトのポート80へリダイレクトさせる
  • Webサイトからクッキーが発行される
  • クッキーからセッションIDを取得

p.115 ポート80を開いていなくても、「http://www.example.com:443」にリダイレクトさせ、そのリクエストで暗号化されずに送信されるクッキーを取得できる
p.116 この問題はMike Perryが提唱:DEFCONで発表しCookieMonsterという概念実証ツールを発表

脚注
  1. MDNの説明を引用:HTTPS プロトコル上の暗号化されたリクエストでのみサーバーに送信され、安全でない HTTP では決して送信されないため、中間者攻撃者が簡単にアクセスすることはできません。(中略)ただし、Secure によってクッキー内の機密情報へのアクセスをすべて防げると思ってはいけません。例えば、クライアントのハードディスクへアクセスすることで読み取られる可能性があります。 ↩︎

5.3 クッキーを書き換える攻撃

p.116 Secure属性がついて読み取れないクッキーは書き換えれば攻撃できる

5.3.1 HTTPクッキーの基礎

p.116 HTTPの拡張:小さなデータをブラウザで保持する
p.116 Set-Cookieレスポンスヘッダで指定:名前と値、存続期間などのメタデータ

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None

// 以下の例のように、複数のディレクティブも利用することができます。
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

参考:MDN

p.116 ブラウザはクッキージャーにクッキーを格納:HTTPリクエストのたびに適用するクッキーを全てCookieリクエストヘッダで送信

Cookie: name=value
Cookie: name=value; name2=value2; name3=value3

p.117 クッキーの仕様はとても貧弱で悪用可能:2011年にようやくRFC6265
p.117 セキュリティの観点から大きく2つの問題:セキュリティを弱める振る舞いを許す、Same-Origin Policyと矛盾する

●ホスト名のスコープがゆるい

p.117 クッキーはプロトコル、ポートをまたいで共有され、サブドメインでもすべて有効になる
p.117 Domain属性を指定していない場合、親ドメインへも拡大可能[1]
p.117 つまり、悪質なサーバが同じドメイン名で別ホスト名を利用しているサイトにクッキーを注入可能
p.117 Same-Origin Policy(同一生成元ポリシー)はプロトコルとホスト名とポートが完全一致している文脈でセキュリティを規定するため、相容れない

●サーバがメタデータを見られない

p.117 クッキーの出所がわからない:自分が発行していないクッキーも拒否できない

●安全なクッキーにおける同一性の欠如

p.117 Secure属性があってもなくても同じドメイン名で格納され、同一視される
p.117 クッキーの名前、ドメイン、パスがマッチすると、Secure属性がないクッキーでSecure属性ありクッキーを上書きできる

p.117 以上のように、HTTPクッキーは完全性が保証されていないという問題がある

5.3.2 クッキー書き換え攻撃

p.118 クッキー書き換え=削除orクッキー注入(インジェクション)
p.118 インジェクション以外にも、クロスサイトクッキー、クッキー固定化Fixation、クッキー強制、クッキートスtossingなどと呼ばれる

■クッキー排除攻撃Cookie Eviction

p.118 ブラウザのクッキージャーへの攻撃:クッキージャーは個々のクッキーサイズ(通常4kb)やドメイン毎のクッキー数(通常数十個)、クッキーの総サイズが制限されている
p.118 攻撃者はダミーの巨大なクッキーを送信することで本物のクッキーを消し、攻撃に必要なものを残す

■クッキーを直接注入する攻撃

p.118 暗号化されていると読めないが、Secure属性の有無によらず名前空間が同じなので上書きは可能
p.119 リダイレクトなどでHTTPリクエストを犠牲者に強制し、レスポンスでクッキーを改竄する
p.119 これにはクッキーのメタデータの情報が必要:例)TomcatならPathが常にルート(/)など

■親戚関係にあるサブドメインからのクッキー注入

p.119 blog.example.comにXSS脆弱性があるとwww.example.comのクッキーも書き換え可能

document.cookie = 'JSESSIONID=FORCE_ID; domain=example.com';

p.119 このように別部門・組織がそれぞれサイトを運用する状況は危険

●先頭のクッキーになる

p.120 本物のクッキーと偽物のクッキーがある場合、以下のように送信される

Cookie: JSESSION_ID=REAL_ID; JSESSION_ID=FORCED_ID

p.120 とりうる攻撃は2つ:クッキージャーをあふれさせるorメタデータをごまかす
p.120 ブラウザはより特定的なクッキーを先頭におくので、以下のようにPath属性を使う

document.cookie = 'JSESSIONID=SECOND_FORCE_ID; domain=example.com; path=/admin';
↓
Cookie:  JSESSION_ID=SECOND_FORCED_ID; JSESSION_ID=REAL_ID; JSESSION_ID=FORCED_ID
●親戚関係にあるサブドメインを使ってクッキーを上書きする

p.120 ドメインが明示されていないクッキーはホストオンリーとなる
p.120 ホストオンリーのクッキーとドメインが明示されたクッキーは一致しないため、攻撃できない
p.121 blog.example.comからwww.blog.example.comやexample.comへのクッキーは発行できるが、兄弟レベルのサブドメイン(例:www.example.com)にはクッキーを発行できない
p.121 つまり、クッキーのドメインをわざわざルート(example.com)にしていると上書きされてしまう
p.121 IE11では暗黙のドメイン設定と明示的なドメイン設定が区別されないので上書きされうる

●親戚関係にあるサブドメインを捏造してクッキーを上書きする

p.121 MITM攻撃により、www.blog.example.comにリクエストを強制し、blog.example.comへのクッキーを発行できる

5.3.3 影響

p.121 XSS脆弱性、CSRF対策の回避、アプリの操作、セッション固定化[2]といった影響がある

5.3.4 緩和策

p.121 攻撃者に偽装させず、受け取ったクッキーの真正性を確認するための対策をとればよ

●サブドメインを網羅したHSTSを採用する

p.122 HSTS:HTTP Strict Transport Security、ホスト名に対し暗号化を強制する[3]
p.122 MITMによるクッキーインジェクションができなくなる
p.122 問題点1:まれにブラウザがサポートしていない[4]
p.122 問題点2:親戚関係のサブドメインが侵害されたり、信用できない組織が運用している場合は対処不可

●クッキーの名前にプレフィクスをつける

p.122 クッキープレフィクス:より安全なクッキーの階層。本書執筆時点では標準化されていないがFF, Chromeで利用可能[5]
p.122 例:__Secure-でSecure属性を強制、__Host-でホストオンリーを強制

●クッキーの完全性検証

p.122 クライアントから受け取ったクッキーが自サイトで発行したものか確認することが最大の防御
p.123 HMAC[6]や暗号化(JavaScriptで使わない場合)が有効
p.123 ユーザーごとに検証できるようにしないと、攻撃者が取得したクッキーを注入できてしまう
p.123 XSSでクッキーが盗まれる場合、HMACや暗号化では防げない:トークンバインディング(同一のブラウザでしかクッキーを使えないようにする)[7]などが必要

脚注
  1. これはおそらくIEなど特定のブラウザの話かと思われる。徳丸さんのブログ参照。 ↩︎

  2. IPAのサイトの解説がわかりやすかった。 ↩︎

  3. MDNの解説:includeSubDomainsを指定すると、サブドメインにもHTTPSを強制できる ↩︎

  4. MDNの解説:Android用のOperaがサポートしていないっぽい? ↩︎

  5. 2021年現在もまだドラフトの模様。https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis ↩︎

  6. 署名つきCookieについてはGoogleのCloud CDNのサイトが詳しい。https://cloud.google.com/cdn/docs/using-signed-cookies?hl=ja ↩︎

  7. こちらのブログが詳しい。簡単に言うと、ブラウザ側で鍵ペアを接続先ごとに生成し、接続先に公開鍵を送り、クッキーの送信時に秘密鍵で署名する、というイメージ。しかし、こちらのQiita記事によると、Financial-grade API(OAuth 2.0とOpenID Connectを基盤とした、金融業界向けのより高いセキュリティーのための技術要求事項)では、このようなProof-of-possession Tokenとしてはクライアント証明書によるmTLSのみが認められ、Token Bindingは最終版にて削除されたとのこと。 ↩︎

5.4 HTTPSストリッピング

p.123 URLのプロトコル部分を省略して入力するとブラウザは平文でまずアクセスする:これを悪用するとHTTPSストリッピング攻撃が可能
p.123 MITMをしかけると、HTTP通信を外部から読み取って、機微情報の観測や通信の書き換えも可能
p.124 攻撃の手口:標的サイトとよく似たアドレスを使う

p.124 sslstripというツールが公開されている

5.5 MITM証明書

p.125 中間者攻撃の方法3つ

●検証フローの裏をかく

p.125 TLSの検証フローにバグがあれば裏をかける

●不正な証明書

p.125 2008年のRapidSSLのように不正な証明書を偽造して入手する
p.125 1024ビットの弱い鍵を使う証明書を総当たりで破る、など
p.125 犠牲者のネットワークが制御下にある場合、不正な証明書を見破ることは事実上不可能:OCSP+MITMという攻撃もある、多くのブラウザがOCSP失敗を無視する

●自己署名証明書

p.125 ユーザーが警告を無視するのに期待する攻撃者

p.125 sslsniff:https://github.com/moxie0/sslsniff
p.125 SSLsplit:https://github.com/droe/sslsplit[1]

脚注
  1. まだTLS1.3はサポートしていなさそう。部分的なサポートのPRが出ている程度。 ↩︎

5.6 証明書の警告

p.125 TLSの認証は主に証明書による:接続先のホスト名を保証する証明書が返ってくることを期待する
p.125 不正な証明書を受け取ったら、接続を中止すべき
p.126 しかし、ブラウザは接続中止してくれない:証明書の警告を出し、ユーザーに問題を押し付ける

5.6.1

p.126 不正な証明書が使われる原因はいくつかある

●仮想ホストの設定ミス

p.126 同じIPで、平文のサイトと暗号化されたサイトを運用するミス:平文のサイトにhttpsでアクセスしようとすると異なる証明書
p.126 原因の一部:サイトから暗号化に対応しているかどうか表明する仕組みがない
p.126 平文のサイトをホストするIPアドレスのポート443を閉じるのがよい
p.126 2010年の筆者の調査:1億1900万ドメイン対象、2265万のサイトがHTTPS、72万のサイトのみが正しい証明書を持っていた
p.126 名前が一致する証明書を持っているものの、他の理由で信用できないサイトが3割(20万)

●名前が全て網羅されていない

p.126 証明書にホスト名が不足:www.example.comの他にexample.comも証明書に必要

●自己署名証明書とプライベートCA

p.126 これらはMITM攻撃で使われる証明書と区別がつけづらい
p.127 それでも利用される理由

  • 証明書の購入、設定、更新作業が大変
  • 2010年台前半まで証明書が高価だった
  • 証明書が無料であるべきと考えて購入を拒否する人がいる
●アプライアンス製品で使われている証明書

p.127 Webベースの管理インターフェースには安全な通信が必要:しかし、出荷時には利用するホストやIPアドレスは不明
p.127 エンドユーザーが証明書をインストールする必要があるが、利用頻度やUI不足で設定されない

●期限切れの証明書

p.127 筆者の調査では不正な証明書の57%が期限切れ:所有者の更新忘れ

●設定ミス

p.127 サーバは完全に有効なチェーンを用意する必要がある[1]
p.127 ブラウザは不完全なチェーンの再構成を試みるが、他のユーザーエージェントは実行しない

p.127 2013年の研究:39億のHTTPS接続を調査、1.54%で証明書の警告
p.127 イントラネットや社内アプリなどはもっと酷いはず

5.6.2 証明書の警告の効果

p.127 2008年に筆者がMozillaに提案:不正な証明書を迂回できなくしてはどうか→拒否された
p.128 MITM攻撃の最大の問題:ユーザーが気付かない、証明書の警告が「よくあること」になっている
p.128 今日の主要なブラウザは介在型interstitial/割り込み型interruptiveでブラウザウインドウ全体で警告を出す[2]
p.128 Firefoxのテレメトリによると、不正な証明書のサイトへ進んだユーザーはわずか33%
p.128 Chromeの場合ユーザーの70%が警告をやりすごしている:警告のデザイン変更(Firefoxの真似)により、56%まで定価

5.6.3 やりすごせる警告ではなく例外を挙げる

p.129 Firefoxは証明書の例外設定をさせているから成功している?[3]
p.129 自己署名証明書は必ずしも悪くない:自宅のサーバなど、個人利用や理解ある技術者の小規模な集団なら利用可
p.129 TOFU(Trust On First Use)=鍵継続管理(key continuity management):誰かが攻撃して証明書を入れ替えたら、例外に設定されていない証明書なので再び警告が表示されるようになる

5.6.4 緩和策

p.129 エコシステム全体についてはできることはほとんどない
p.129 HSTS(HTTP Strict Transport Security)に対応する:ブラウザに証明書の警告を抑制する機能もある[4]

脚注
  1. SSL PulseのMonthly Scan: August 04, 2021の結果によると、13万以上のサイトを調査したところ、1.6%にあたる2238サイトが不完全な証明書チェーンを提示した。 ↩︎

  2. 本書ではSafariがダイアログで警告を出すのみ、とされているが、2021年現在のバージョン14.1.2ではウインドウ全体で警告を出す方式になっていた。確認に利用したのは https://badssl.com/ ↩︎

  3. MacのFirefox92.0で確認したところ、Chromeの動作とさほどかわらず2クリックで問題のあるサイトを開くことができた...どこかのバージョンで動作が変わったのだろうか ↩︎

  4. RFC6797でHSTSが定められており、8.4で証明書に問題がある場合ユーザーエージェントは接続を終了すべし(MUST)とされている。 ↩︎

5.7 セキュリティインジケーター

p.129 ウェブページのセキュリティに関する付加的情報を提供するUI

  • このページは暗号化されている
  • このWebサイトを運営している法人が判明している[1]
  • このページでは不正な証明書が使われている
  • このページの暗号化に何らかの問題がある

p.130 ユーザーの大部分が無視しているとの調査結果
p.130 モバイルプラットフォームでは画面が小さいことから、セキュリティインジケーターも省略されがち:フィッシングに対して脆弱
p.132 インジケーターは無用ではない:2014-16のSHA256証明書への移行に有効な役割を果たした

脚注
  1. EV証明書はChromeでは2019年9月、Firefoxでは2019年10月以降もはや専用表示がなくなった。参考:https://ssl.sakura.ad.jp/column/ev-ssl2/ ↩︎

5.8 混在コンテンツ

p.132 TLS:単一の接続を保護し、ネットワークレベルでデータを安全にたもつ
p.132 FTPやHTTP:複数の接続が違いに関係する、安全かどうかはユーザーエージェントの実装にかかっている
p.132 HTTPS:HTML、画像、スタイルシート、JavaScriptなどが複数の接続で取得される、混在コンテンツと呼ばれる問題が発生する
p.132 混在コンテンツ:同一ページだけでなく、Webサイト全体でも起こる(平文のページと安全なページの混在 → HTTPSストリッピング攻撃、機微情報の未暗号化などの問題につながる)

5.8.1 根本的な原因

p.132 Webの猛烈な進化スピードに起因

●パフォーマンス

p.132 初期SSLの劣悪なパフォーマンス:平文が好まれていた
p.133 かつての解決策は高価なハードウェアアクセラレータのみ
p.133 現在の懸念は主にネットワークの遅延(パフォーマンスの詳細は9章で後述)

●マッシュアップ

p.133 自分のところだけで全てのコンテンツを提供するわけではない
p.133 特殊な例:Google Analyticsなどサードパーティのコードを利用
p.133 コストは劇的に下がるが、セキュリティにとっては悪夢:サイトの制御がほぼ完全にサードパーティの手に渡る
p.133 Webサイトのユーザーも、自分のデータがどこに格納されるかわかりにくくなる
p.133 サードパーティが暗号化されていないことも:Google AdSenseがHTTPSに対応したのが2013年9月[1]

●インフラのコスト

p.133 CDNの流行:1箇所からWebサイトを配信してもパフォーマンスが悪く競争力を維持できない
p.134 暗号化の負担:CPU、RAM、キャッシュ、証明書、鍵管理など
p.134 IPアドレスの問題:HTTPSを利用する仮想ホスティング(1つのIPで複数サイト)[2]は未対応のクライアントが一定数ある[3]ため、サイトごとにIPが必要だが、IPv4アドレスの欠乏問題もある。

p.134 上記の背景により、ブラウザが混在コンテンツの問題を許容してきた

5.8.2 影響

p.134 2種類のリソース:受動的混在コンテンツ(画像など:混在表示mixed displayとも)と能動的混在コンテンツ(HTMLやJS:混在スクリプティングmixed scriptingとも)
p.134 能動的混在コンテンツがより危険:HTML、CSS、Flash[4]、Java[5]など
p.134 受動的混在コンテンツもページの完全性を損ねる:偽の画像によるフィッシングや、ブラウザの脆弱性を利用してスクリプトとして処理させる(古いIEにおけるコンテンツスニッフィングの悪用)
p.135 同一ホストでの混在コンテンツの場合、受動的攻撃者はクッキーにもアクセス可能

5.8.3 ブラウザでの対処

p.135 当初のブラウザベンダー:サイトの開発者が正しく実装すると考えていた
p.135 2010年代になって、混在コンテンツを制限するようになったが妥協的:受動的混在コンテンツを許可し、能動的混在コンテンツは許可しない

  • Internet Explorer:95年のIE5から混在コンテンツを検出し警告、IE9で能動的混在コンテンツをブロック(2011年)
  • Firefox:混在コンテンツの検出と警告は可能だった、能動的混在コンテンツのブロックはバージョン23から(2013年)
  • Chrome:バージョン38から能動的混在コンテンツをブロック(2014年)
  • Safari:バージョン9から混在コンテンツをブロック(2015年)

p.136 ブラウザのプラグインは特に危険:好きなリクエストをなんでも発行できる
p.136 W3Cで混在コンテンツの扱いを標準化する動き:2021年現在まだドラフト版

5.8.4 混在コンテンツの広がり

p.136 2011年の筆者の調査:Alexa[6]上位100万サイト中、22.41%に安全でないコンテンツが利用されていた
p.136 2013年の研究:Alexa上位10万サイト中の約2万サイト中、43%が混在コンテンツを含む

5.8.5 緩和策

p.137 サイトを正しく実装することで対処できる
p.137 Webサーバーの設定による緩和策2つ:HSTSとCSP

HSTS(HTTP Strict Transport Security)

p.137 強制的に安全なリソースを取得させる仕組み
p.137 ユーザーのミス(ポート80でアクセス)やページの実装ミス(リンクがhttp)にも対応可能
p.137 リソースが自分の管理下にあるホストにある場合のみ有効

CSP(Content Security Policy)

p.137 安全でないリソースをブロックできるセキュリティポリシー
p.137 ブロック以外にも検出を報告する機能もある(report-onlyモード)
p.137 安全でないリンクを暗号化が有効なリンクに書き換えることもできる((upgrade-insecure-requests ディレクティブ)[https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests])

脚注
  1. WikipediaによればGoogle AdSenseのリリースは2003年。https://en.wikipedia.org/wiki/Google_AdSense ↩︎

  2. Server Name Indicationのこと。 ↩︎

  3. 例えば、JavaがSNIに対応したのはJava 7(2011年7月リリース)。 ↩︎

  4. 2019年のChromeをはじめとして、順次各ブラウザでFlashのサポートが打ち切られている。参考:https://www.itmedia.co.jp/pcuser/articles/2012/01/news043.html ↩︎

  5. Wikipediaによると、JavaアプレットについてはChromeが2015年、Firefoxが2017年にサポートを打ち切り、2017年にリリースされたJava 9では非推奨となった。 ↩︎

  6. Alexaはアマゾンの子会社でウェブサイトを順位づけするシステム。https://www.alexa.com/ ↩︎

5.9 Webの完全な暗号化を目指して

p.138 Webの暗号化は部分的、個々のサイト管理者が責任を持つ
p.138 大手ブラウザベンダーを中心にWebの完全な暗号化を目指す過渡期
p.138 2017年のGoogleとMozillaの報告:全体の50%がHTTPS
p.138 ブラウザベンダー:暗号化が有効な場合だけブラウザの先進的機能を提供し、サイト管理者に暗号化を促す

●セキュリティ警告のスコープを拡大

p.138 セキュリティインジケータの範囲拡大:HTTPが安全でないという警告
p.138 2017年1月、Chrome56とFirefox51からHTTPでパスワードやクレジットカード番号入力するページに警告表示
p.138 Googleは2017年中にHTTPでフォーム送信するページに対象拡大を宣言[1][2]

●暗号化だけで利用可能な強力な機能

p.139 利用者の地理データのような情報をHTTPで使えなくする[3]

脚注
  1. このサイトによると、2017年10月のChrome 62で対応が完了した模様。 ↩︎

  2. Googleのブログによると、2020年9月にはChrome 86で混在フォーム(HTTPSページ上のHTTPフォーム)についても同様の警告が表示されるようになった。この機能については問題があったらしく、直後のバージョンで無効化され、そのつぎのバージョンで再度有効化されたと言われている。参考サイト ↩︎

  3. 註に挙げられていたページによると、地理データ以外には、デバイスの向き、AppCache、通知、カメラやマイクの利用、Encrypted Media Extensions (EME:HTMLで動画などのコンテンツを保護するためのAPI標準化仕様)が挙げられている。 ↩︎

5.10 EV証明書

p.139 SSLの黎明期にはすべての証明書発行時に厳格な検証が要求された
p.139 現在そのような検証はEV証明書についてのみ必要:2007年にCA/B Forumが規定
p.139 EV証明書の利点

  • ドメイン所有者の本人性が厳密に確認されて、その識別子が証明書にエンコードされている
  • 検証手順が手動であり、証明書の捏造が困難[1]

p.139 これらの利点は現実的な恩恵となるかは疑問:セキュリティインジケータは気付かれていない

参考:最近のChromeだとグリーンのインジケータはなくなり、EV証明書を表示する前に法人名が表示される

p.140 問題点:ページ単位で検出されるので、スクリプトなどのリソースでもEV証明書が利用されているとは限らない(コストを理由に、サブドメインではDV証明書が使われるケースも多い)
p.140 これを利用した攻撃手法がある(詳細はこちらのスライド

  • 他のドメイン名のサイトからリソースを持ち込む:詐称したDV証明書でマルウェアを仕込む
  • クッキー泥棒:既存のクッキーを盗む、新しいクッキーを設定する
  • 永続的マルウェア注入:キャッシュの利用を強要し、マルウェアを稼働させ続ける
脚注
  1. 厳密には捏造ではないが、別の州に同名の会社を設立して証明書を取得する手法が紹介されていた。参考サイト ↩︎

5.11 証明書の失効

p.140 理想的には証明書の失効確認すべきだが、とても難しい問題

5.11.1 クライアントの対応が不十分

p.140 ブラウザがなにをどのタイミングで実行しているか理解するのは困難
p.140 メーリングリストやバグ報告、ソースコードを掘り起こす必要がある
p.140 OCSPステープリングのような新しい機能はなかなかブラウザに搭載されない[1]
p.141 コマンドラインツールでは失効はもちろん証明書検証もままならない:デフォルトでは失効確認をしない[2]
p.141 失効確認は設計どおりには機能していない:2011年の一連の事件で、確実な手段はブラックリストだった

5.11.2 失効確認の標準化に伴う主な問題

p.141 CRLとOCSPの設計上の欠陥3つ

●証明書と問い合わせの分断

p.141 CRLもOCSPもCAが割り当てたシリアル番号で問い合わせる=手元の証明書とCAが参照している証明書が同一か完全には確認できない

●ホワイトリストではなくブラックリスト

p.141 CRLはブラックリストそのもの。初期のOCSPはCRLから情報を取得していた。
p.141 OCSPレスポンスでは問い合わせられたシリアル番号について何も知らなくてもgood(not revoked)扱いにしていた:2013年8月以降CA/B Forumで禁止された[3]
p.141 2011年のDigiNotar事件で現実の問題に:OCSPレスポンダが全てを失効扱い+ルート証明書をブラウザから削除して対応

●プライバシー

p.142 自分がどんなWebサイトを閲覧しているか、という情報がCAに知られてしまう
p.142 CRLには大量の証明書が含まれるので侵害度合いはやや低め
p.142 OCSPレスポンダへのトラフィックモニタリングでWebサイト閲覧同行を監視できる
p.142 この問題への対策がOCSPステープリング

5.11.3 CRL

p.142 当初の失効確認の唯一の仕組み:スケールしづらいためOCSPが作られた

■CRLの長さに伴う問題

p.142 GoDaddy社によると、同社の失効情報は2007年に158Kバイト、2013年に41Mバイト。
p.142 近年は、複数のCRLを利用することでサイズを抑えている。
p.143 大量データのダウンロードはモバイルで問題:帯域やCPU
p.142 差分CRL(delta CRL):Windowsでサポートされているがあまり使われていない

■CRLの新鮮さ

p.143 Netcraftの調査によると、McAfeeのサイトの中間証明書が失効に気づかれないまま放置された
p.143 このときOCSPの情報はなく、CRLには失効情報があったが無視されていた
p.143 Baseline Requirementsの記述

  • CAは12ヶ月に一度CRLを再発行しなければならない
  • CAは下位CA証明書の失効から24時間以内にCRLを再発行しなければならない
  • nextUpdateフィールドの値をthisUpdateから12ヶ月より後にしてはいけない

参考:RFC5280

   CertificateList  ::=  SEQUENCE  {
        tbsCertList          TBSCertList,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

   TBSCertList  ::=  SEQUENCE  {
        version                 Version OPTIONAL,
                                     -- if present, MUST be v2
        signature               AlgorithmIdentifier,
        issuer                  Name,
        thisUpdate              Time,
        nextUpdate              Time OPTIONAL,
        revokedCertificates     SEQUENCE OF SEQUENCE  {
             userCertificate         CertificateSerialNumber,
             revocationDate          Time,
             crlEntryExtensions      Extensions OPTIONAL
                                      -- if present, version MUST be v2
                                  }  OPTIONAL,
        crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
                                      -- if present, version MUST be v2
                                  }

p.143 中間証明書のCRLは12ヶ月間新鮮とみなされる

  • 数百万サイトで利用されるので、長期間(12ヶ月)保持したい
  • CRLはオフライン保管のルート証明書の鍵で署名されるので、頻繁には利用できない

p.143 サーバー証明書のCRLの場合は、10日以内とされている

5.11.4 OCSP

■OCSPリプレイ攻撃

p.144 OCSPオリジナル設計はリプレイ攻撃に強い:ナンスが含まれる
p.144 オリジナル設計はスケールせず、軽量版OCSPプロファイルでバッチ処理とキャッシュが導入:キャッシュのため、リプレイ攻撃耐性は断念
p.144 現在、クライアントはナンスを使わないし、サーバーも無視する
p.144 唯一の防御は有効期限のみ(nextUpdate):数時間から数日、DV証明書の方が長くEV証明書が短い
p.144 Baseline Requirementsの規定では10日間(中間証明書は12ヶ月)

■OCSPレスポンスの隠蔽

p.144 OCSPレスポンスの失敗はブラウザでは無視される
p.144 これを利用して、全てのレスポンスを失敗させて失効確認を隠蔽できる
p.145 OCSPレスポンスは通常電子署名が付与されるが、失敗の場合署名がつかない:これを利用して攻撃が可能[4]

■クライアントにおけるOCSP対応

p.145 古いプラットフォームやブラウザはデフォルトではOCSPを利用しない:Windows XP、10.7以前のOS X
p.145 iOSはOCSPと(おそらくCRL)をEV証明書にしか使わない
p.145 Chromeは2012年にOCSPを打ち切り、CRLSetsと呼ばれる軽量な仕組みを採用(CA証明書ばかりなので、セキュリティ的には劣る)
p.145 MozillaはCRLSetsを参考にOneCRLを導入

■レスポンダの可用性とパフォーマンス

p.146 OCSPは初期の問題から、ブラウザ側でソフトフェイル(失敗しても無視)扱い
p.146 Netcraftのレポートでパフォーマンスがわかる:https://uptime.netcraft.com/perf/reports/performance/CRL

●可用性

p.146 ハードフェイルの場合にはレスポンダがダウンすると自サイトもダウン
p.146 ソフトフェイルの場合も、ネットワークパフォーマンスに影響
p.146 認証が必要なWiFIネットワーク(キャプティブポータル)でOCSPレスポンダに到達できないことが多い

●パフォーマンス

p.146 そもそもOCSPはパフォーマンスが悪い:OCSPが終わらないと本来のWebサイトへ進めない
p.147 OCSPレスポンダのパフォーマンスがCAの最大の差別化要因

●正確性

p.147 あるCAでは証明書の生成からOCSPレスポンダの更新まで40分かかる場合も(その間リクエストが失敗する)

■強制OCSPステープリング

p.147 パフォーマンスと可用性を満たすかもしれないOCSP Must-Staple
p.148 ステープリングを強制できれば、証明書の盗用(攻撃)にOCSPレスポンスも必要となる
p.148 2016年のFirefox 45から強制OCSPステープリングが利用可能[5]

■サーバ側でのOCSP対応

p.148 主要OSSでOCSPステープリングがデフォルト有効なWebサーバはない[6]
p.148 対照的に、MicrosoftのIISではデフォルトで有効になっている
p.148 実装が貧弱:レスポンスの取得が遅い
p.148 OCSPレスポンスが得られない場合にHTTPリクエストへの応答を停止するサーバーも。

脚注
  1. Wikipediaによると、OCSPステープリングにはIEが2012年、Firefoxが2013年、Chromeが2014年に対応した。 ↩︎

  2. curlの場合、OCSPステープリングの機能はデフォルトではオフになっている。参考サイト。この機能には2017年に脆弱性が見つかっている↩︎

  3. Baseline Requirements 1.8.0, 2021.08.25の57ページに該当の記述あり。同じページには、セキュリティ対応のため、そのようなシリアル番号についてのリクエストを監視すべしとの規定も。 ↩︎

  4. RFC6960によると、malformedRequest、internalError、tryLater、sigRequired、unauthorizedのステータス。 ↩︎

  5. メーリングリストのやりとりで、Chromeについては2016年時点では対応予定なしとされている。その後2019年にもやはり対応されていない様子。 ↩︎

  6. 参考:ApacheのOCSPステープリング設定方法 ↩︎

第6章 実装の問題

p.149 ソフトウェアは必然的に安全でない

  • 言語とライブラリがセキュリティを考慮して書かれていない
  • コストの問題:時間的にも金銭的にも最小コストが要求されセキュリティがないがしろにされがち

p.149 「暗号は破られるのではなく迂回される」

6.1 証明書の検証における欠陥

p.149 証明書に関して確認すべき2つの事項

  • 証明書が意図したホスト名に対して発行されているか
  • 証明書が有効で信頼できるか

p.150 証明書を確認するコードを開発する際、実在の証明書チェーンだけで開発すると重要な検証機能を作り損ねる
p.150 検証の細部に悪魔が潜んでいる

  1. サーバ証明書が意図したホスト名に対して有効か
  2. 証明書チェーンの全てが、期限切れになっておらず、かつ、署名が有効である
  3. 中間CA証明書は場合によって以下の要求を満たす必要がある
  • 他の証明書に対する署名に使えること
  • 他のCA証明書に対する署名に使えること[1]
  • 末端の証明書におけるホスト名の署名に使えること

参考:RFC5280


      id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
      KeyUsage ::= BIT STRING {
           digitalSignature        (0),
           nonRepudiation          (1), -- recent editions of X.509 have
                                -- renamed this bit to contentCommitment
           keyEncipherment         (2),
           dataEncipherment        (3),
           keyAgreement            (4),
           keyCertSign             (5), // 他の証明書に対する署名に使えるかどうかのビット
           cRLSign                 (6),
           encipherOnly            (7),
           decipherOnly            (8) }

   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
   BasicConstraints ::= SEQUENCE {
        cA                      BOOLEAN DEFAULT FALSE, // 上記5が立っている場合、TRUE=本証明書はCA証明書
        pathLenConstraint       INTEGER (0..MAX) OPTIONAL } // 0の場合、他のCA証明書には署名できない

p.150 他にも、鍵が協力か、弱い署名アルゴリズム(MD5やSHA1)が利用されていないか、なども確認必要

脚注
  1. 註に、エンドエンティティ証明書を発行するCA証明書は下位CA証明書を発行できてはいけない、とされている。しかし、RFCを掲載しているIETFのサイトの中間証明書「Starfield Secure Certificate Authority - G2」はpathLenConstraintの値が設定されていない=CA証明書を発行できる、ように見える。これって良いのか?CA/B Forumの使ってるGo Daddyの中間証明書も同様にpathLenConstraintの値がない。Baseline Requirementsでは「MAY be present」だからいいのか? ↩︎

6.1.1 ライブラリとプラットフォームにおける検証の不備

p.150 ライブラリの証明書検証の欠陥は決して珍しくはない

・Microsoft社のCryptoAPIにおけるBasic Constraints確認に欠陥があった事例(2002年

p.150 ルート証明書が信頼できればどんな証明書でも信頼してしまうバグ:中間者攻撃が可能になる
p.150 Windows以外にも影響(Mac上のOfficeやIEにも影響:参考、KDEのデフォルトブラウザKonquerorにも影響(どうして?))
p.151 2002年にMoxie Marlinspikeが発見、同氏はsslsniffというMITMツールを公開

・GnuTLSにおける証明書チェーン検証の欠陥(2008年)

p.151 チェーンの末尾にルート証明書を追記すると不正な証明書が信頼されてしまうバグ:中間者攻撃ができる
p.151 本来はチェーンの一部でないので無効

・OpenSSLにおけるDSAおよびECDSA署名検証の欠陥(2009年)

p.151 Googleのセキュリティチームが発見
p.151 DSAとECDSA署名検証時の境界値チェックが不十分で、MITM攻撃の可能性あり

・iOSにおけるBasic Constraintsの確認に欠陥があった事例(2011年)

p.151 iOS4の一部のバージョンで、証明書を下位CA証明書として利用してよいかをチェックしていなかった:エンドエンティティ証明書で証明書が発行できてしまっていた

・iOSおよびOS Xにおける接続検証の欠陥(2014年)

p.151 iOS6とiOS7、OS X 10.9のTLS接続認証のバグ:DHEおよびECDHEの接続がMITMで乗っ取られる
p.151 この記事によれば、goto文が連続で出現する行があったため、以降の行がデッドコードとなったことが問題:同記事によれば、TLS1.2の場合は別の関数を利用するため影響なし
p.152 TLSハンドシェイク中の問題のため、脆弱性のあるクライアントだけに標的を絞ることが可能
p.152 独自のライブラリを利用するChromeやFirefoxなどのクロスプラットフォームなアプリは影響を受けず

・GnuTLSにおける証明書チェーン検証の欠陥(2014年)

p.152 2つの脆弱性が発見された
p.152 1つは、X509バージョン1(既に廃止されたバージョン)の証明書が任意の中間CA証明書として扱われるバグ
p.152 もう1つは、先のApple同様のバグ:参考例外が発生すると間違ったエラーコードが返るが、証明書検証が成功してしまう

・OpenSSLのChangeCipherSpecインジェクション攻撃(2014年)

p.152 能動的な攻撃者がChangeCipherSpecメッセージ(値が1だけのメッセージ)をインジェクションして、予測可能なマスターシークレットのネゴシエーションを強制できる
p.152 ChangeCipherSpecはハンドシェイクプロトコルの一部でないため認証されないのが原因(=他のハンドシェイクメッセージのように、ハッシュ化して擬似乱数生成関数にかけてverify_dataとして扱われない)
p.153 攻撃にはクライアントとサーバーがOpenSSLである必要があるが、クライアントとしてはあまり利用されていないので影響は限定的:例、Android 4.4
p.153 SSL Pulseによれば、影響のあったサーバーは全体の14%

・OpenSSLにおける証明書チェーン検証の欠陥(2015年)

p.153 ネットワーク上の攻撃者が末端の証明書を中間CA証明書として利用可能だった
p.153 Metasploit:Metasploit Frameworkは、ペネトレーションテストを行うためのフレームワーク。

フランケン証明書によるテスト

p.153 研究者らが特殊加工した「フランケン証明書」でライブラリをテスト:元の証明書にランダムにフィールドや拡張を追加・変更したもの
p.153 それほど使われていないライブラリ(GnuTLSなど)で深刻な問題が見つかる

ログインするとコメントできます