Network Working Group T. Dierks Request for Comments: 2246 Certicom Category: Standards Track C. Allen Certicom January 1999 TLSプロトコル バージョン1.0 このメモの位置付け このドキュメントは、インターネット・コミュニティに対し、インターネット 標準化プロトコルを規定し、その改善のための議論と提案を求めるものである。 このプロトコルの標準化状態と位置付けは、"Internet Official Protocol Standards"(STD 1)の最新版を参照のこと。このメモの配布は無制限である。 著作権 Copyright (C) The Internet Society (1999). All Rights Reserved. 要旨 本ドキュメントでは、Transport Layer Security(TLS)プロトコルのバージョン 1.0を規定する。TLSプロトコルは、インターネット上で通信プライバシーを 提供する。本プロトコルを使用することにより、クライアント/サーバアプリ ケーションは、盗聴、改竄、またはメッセージ偽造を防ぐように設計された 方法を使用して通信を行うことが出来る。 目次 1. はじめに 3 2. 目的 4 3. このドキュメントの目的 5 4. 表記言語 5 4.1. 基本ブロックサイズ 6 4.2. その他 6 4.3. ベクトル 6 4.4. 数値 7 4.5. 列挙 7 4.6. 構造体 8 4.6.1. バリエーション 9 4.7. 暗号属性 10 4.8. 定数 11 5. HMACと擬似乱数関数 11 6. TLSレコードプロトコル 13 6.1. コネクションステータス 14 6.2. レコード層 16 6.2.1. フラグメンテーション 16 6.2.2. 圧縮と展開 17 6.2.3. レコード送受信中の保護 18 6.2.3.1. Nullまたは標準ストリーム暗号 19 6.2.3.2. CBCブロック暗号 19 6.3. 鍵計算 21 6.3.1. 輸出可能な暗号の鍵生成例 22 7. TLSハンドシェイクプロトコル 23 7.1. ChangeCipherSpecプロトコル 24 7.2. Alertプロトコル 24 7.2.1. 終了アラート 25 7.2.2. エラーアラート 26 7.3. ハンドシェイクプロトコル概要 29 7.4. ハンドシェイクプロトコル 32 7.4.1. Helloメッセージ 33 7.4.1.1. HelloRequestメッセージ 33 7.4.1.2. ClientHelloメッセージ 34 7.4.1.3. ServerHelloメッセージ 36 7.4.2. ServerCertificateメッセージ 37 7.4.3. ServerKeyExchangeメッセージ 39 7.4.4. CertificateRequestメッセージ 41 7.4.5. ServerHelloDoneメッセージ 42 7.4.6. ClientCertificateメッセージ 43 7.4.7. ClientKeyExchangeメッセージ 43 7.4.7.1. RSAを使用したEncryptedPreMasterSecretメッセージ 44 7.4.7.2. ClientDiffieHellmanPublic値 45 7.4.8. CertificateVerifyメッセージ 45 7.4.9. Finishedメッセージ 46 8. 暗号計算 47 8.1. master_secretの計算 47 8.1.1. RSA 48 8.1.2. Diffie-Hellman 48 9. 不可欠な暗号スイート 48 10. アプリケーションデータプロトコル 48 A. プロトコル定数値 49 A.1. レコード層 49 A.2. ChangeCipherSpecメッセージ 50 A.3. Alertメッセージ 50 A.4. ハンドシェイクプロトコル 51 A.4.1. 各種Helloメッセージ 51 A.4.2. サーバ認証と各種鍵交換メッセージ 52 A.4.3. クライアント認証と各種鍵交換メッセージ 53 A.4.4. Finishedメッセージ 54 A.5. 暗号スイート 54 A.6. セキュリティパラメータ 56 B. 用語集 57 C. 暗号スイートの定義 61 D. 実装上の注意 64 D.1. 一時的RSA鍵 64 D.2. 乱数生成とその種 64 D.3. 証明書と認証 65 D.4. 暗号スイート 65 E. SSLの下位互換 66 E.1. バージョン2のClientHello 67 E.2. なりすましによるバージョンロールバック攻撃の回避 68 F. セキュリティ解析 69 F.1. ハンドシェイクプロトコル 69 F.1.1. 認証と鍵交換 69 F.1.1.1. 匿名鍵交換 69 F.1.1.2. RSA鍵交換と認証 70 F.1.1.3. 認証を伴うDiffie-Hellman鍵交換 71 F.1.2. バージョンロールバック攻撃 71 F.1.3. ハンドシェイクプロトコルに対する攻撃の検出 72 F.1.4. セションの再利用 72 F.1.5. MD5とSHA 72 F.2. アプリケーションデータの保護 72 F.3. 最終注記 73 G. 特許声明 74 セキュリティに関する考察 75 参考文献 75 あとがき 77 コメント 78 著作権表示 80 1. はじめに TLSプロトコルの主な目的は、通信を行う2つのアプリケーション間に、通信プラ イバシーとデータ保全機能を提供することである。プロトコルは2つの層から構成 されている。それはTLSレコードプロトコルとTLSハンドシェイクプロトコルで ある。信頼のおける伝送プロトコル(例えば、TCP [TCP])のすぐ上、最も低い レベルに位置するのがTLSレコードプロトコルである。TLSレコードプロトコル により、次の2つの基本的特性をもつコネクションセキュリティが提供される。 - コネクションはプライベートである。 対称暗号がデータ暗号化に使用され る(例えば、DES [DES]、RC4 [RC4]など)。この対称暗号に使用される鍵は 各コネクションごとに生成されるもので、他のプロトコル(例えばTLSハンド シェイクプロトコルなど)によってネゴシエーションされるシークレット に基づいている。レコードプロトコルはまた、暗号化なしで使用すること もできる。 - コネクションは信頼できる。メッセージ送受信が行われる際には、鍵付き MACを使用したメッセージの保全チェックが行われる。MACを計算するため に、安全なハッシュ関数(例えば SHA、MD5など)が使用される。レコード プロトコルは、MACなしでも処理を行うことができるが、一般にはこの保全 チェックモードのみが使用される。他のプロトコルは、このレコードプロ トコルを、セキュリティパラメータをネゴシエーションするための通信 手段として使用する。 TLSレコードプロトコルは、より上位に位置するさまざまなプロトコルのカプセル 化を行う。カプセル化されるプロトコルの1つであるTLSハンドシェイクプロト コルでは、アプリケーションプロトコルの最初のデータを送信または受信する 前に、サーバとクライアントの相互認証、暗号化アルゴリズムと暗号鍵の ネゴシエーションを行うことができる。TLSハンドシェイクプロトコルにより、 次の3つの基本的特性をもつコネクションセキュリティが提供される。 - コネクションの両端のアイデンティティは、非対称すなわち公開鍵暗号 (例えば、RSA [RSA]、DSS [DSS]など) を使用して認証することができる。 この認証は任意とすることができるが、一般には、少なくともひとつの コネクション端においては必要とされる。 - 共有されるシークレットのネゴシエーションは安全である。ネゴシエー ションされたシークレットは、盗聴者には利用できない。また認証された コネクションにおいては、コネクションの間に攻撃者が位置していたとして も、シークレットを得ることはできない。 - ネゴシエーションは信頼できる。通信をしているパーティーによって検出 されることなく、攻撃者がネゴシエーションコミュニケーションを変更 することはできない。 TLSの利点の1つは、アプリケーションプロトコルから独立していることである。 TLSプロトコルを透過的なものとした、より上位のプロトコル層を形成すること ができる。 しかしTLS規格では、より上位のプロトコルにおいて、どのように TLSを使用したセキュリティを追加するか、については規定しない。どのように TLSハンドシェイクに着手し、交換された認証証明書をどのように解釈するかに 関しては、TLS上を動作するプロトコルの設計者と実装者の判断に任せられる。 2. 目的 TLSプロトコルの目的を、重要な順に示す。 1. 暗号セキュリティ: TLSは、2つのパーティー間で安全なコネクションを 確立するのに使用される。 2. 共同利用性: それぞれのプログラマは、互いのコードに関する知識を必要 とすることなく、暗号パラメータを問題なく交換することができるTLSアプ リケーションを、個別に開発することができる。 3. 拡張性: TLSは、新しい公開鍵暗号方式と大量暗号方式を、必要なときに組み 込むことのできるフレームワークの提供を行っている。また、これにより さらに次の2つの目標を達成することが出来る。それは新しいプロトコルの 作成(そして、新しい弱点を招くという危険)を防ぐこと、そして完全に新しい セキュリティライブラリを実装する必要性を避けることである。 4. 相対的な効率: 暗号化処理、特に公開鍵暗号処理は、CPU負荷が高いと いう傾向がある。そのため、TLSプロトコルではオプショナルで、ゼロから 確立する必要のあるコネクションの数を減少させるために、セションの キャッシングを行うという手法を導入した。さらに、ネットワーク通信量 を減少させるための配慮も行っている。 3. このドキュメントの目的 このドキュメントとTLSプロトコル自体は、Netscape社によって発行されたSSL 3.0プロトコル仕様書に基づいている。TLS1.0とSSL3.0の差異はそれほど劇的 なものではないが、その違いはTLS1.0とSSL3.0が相互運用できないほど(TLS 1.0では、実装においてSSL3.0にバージョンダウンできるようなメカニズムを 組み込んでいるけれども)重大である。このドキュメントは主として、プロト コルを実装しようとしている人と、その暗号分析を行おうとする人を対象とし て書かれている。この規格書はこれを念頭に書かれており、またそれらの2つの グループの必要性を反映するように意図されている。これらの理由から、アル ゴリズムに依存する多くのデータ構造と多くの規則を、(付録だけでなく)本文に も含めており、より簡単に参照することができるようになっている。 このドキュメントでは、サービスの定義や、インターフェースの定義に関する 詳細については述べていない。しかし、ポリシーに関する分野の一部をカバー している。それは堅固なセキュリティを維持するのに必要であるからである。 4. 表記言語 このドキュメントでは、データフォーマットを、コンピュータの内部表現に 依存しない、一般的な表現で扱う。以下に示されるような、非常に基本的で、 かつ幾分カジュアルに定義されたプレゼンテーション構文を使用する。構文には その元になっている構造がいくつか存在する。構文は、プログラミング言語"C" の構文と、XDR [XDR]の構文とその目的に類似しているが、あまりに多くを類似 させるのは危険である。このプレゼンテーション言語の目的は、TLSのみを説明 することであり、その目的を超えた適用を行うことではない。 4.1. 基本ブロックサイズ すべてのデータ項目は、明確に定義される。基本的なデータブロックサイズは 1バイト(すなわち 8ビット)である。多重バイトで構成されるデータ項目は、 バイトを連鎖させたもので、左から右、先端から下部へバイトデータを連鎖させる。 バイトストリームから多重バイト項目(例えば1つの数値)を形成するには、(C記法 を使用して)次のように行われる。 value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) | ... | byte[n-1]; この多重バイトにおけるバイト順序は、通常のネットワークバイト順序、すな わちビックエンディアン形式である。 4.2. その他 コメントは"/*"で始まり、"*/"で終わる。 オプショナルコメントは、"[[ ]]"の、2重括弧でくくられる。 解析の行われないデータを含む1バイトのエンティティを、opaque型とする。 4.3. ベクトル ベクトル(1次元配列)は、単一データ要素のストリームである。ベクトルのサイズは、 本ドキュメントで指定されるものもあれば、実行時まで不定な状態であるものもある。 どちらの場合でも、宣言される長さはそのベクトルのバイト数であり、要素数では ない。T型の固定長ベクトルを持つ新しい T' 型を指定するための構文は、以下の ようなものである。 T T'[n]; ここでT'は、データストリーム上でnバイトを占有する。nはTのサイズの整数倍 である。エンコードされたストリームには、ベクトル長データは含まれない。 以下の例では、Datumは、連続した3バイトで定義されるもので、このプロトコル では解析が行われない。一方Dataは、3つの連続したDatumで定義されるもので、 合計9バイトを使用する。 opaque Datum[3]; /* 解析の行われない3バイトベクトル */ Datum Data[9]; /* 3つの連続した3バイトのベクトル */ 可変長ベクトルは、表記を使用して、規定上の範囲を指定する ことにより定義される。これをエンコードしたときには、その長さを示すデータが、 ベクトルのコンテンツの前に付加される。このときには、ベクトルにおいて 指定された最大(ceiling)の長さを保持するために必要なバイト長が確保される。 実際の長さがゼロである可変長ベクトルを、空ベクトルと呼ぶ。 T T'; 以下の例では、mandatoryは、opaque型をもつ300-400バイトのベクトルである。 空にはならない。ベクトルの実際の長さを格納するフィールドは2バイトすなわち uint16を使用する。これは値400を格納するのに十分である(第4.4章を参照)。 一方longerは、最大800バイトまでのデータ、またはuint16型をもつ最大400個の データを表す。これは空ベクトルになってもよい。そのエンコードにおいては、 ベクトルの前に、実際の長さを表す2バイトのフィールドが含まれる。エンコード されたベクトルの長さは、単一要素の長さの整数倍でなければならない(例えば、 uint16型をもつ17バイトのベクトル、というのは文法違反である)。 opaque mandatory<300..400>; /* データ長を格納するフィールドは2バイトである。空であって はならない */ uint16 longer<0..800>; /* ゼロから400までの、16ビット符号なし整数 */ 4.4. 数値 基本的な数値データ型は、符号なしバイト(uint8)である。それより大きい数値 データ型はすべて、第4.1章で示されるように、固定長バイトを連鎖させること により形成される。それらにもまた符号はない。 以下の数値型がすでに定義 されている。 uint8 uint16[2]; uint8 uint24[3]; uint8 uint32[4]; uint8 uint64[8]; この仕様書を通じて使用されているすべての値は、「ネットワーク」順序、すな わち「ビックエンディアン」順序として記憶される。16進法で 01 02 03 04と して表されるuint32は、10進法における値16909060に等しい。 4.5. 列挙 列挙と呼ばれる、断続的な値をもつデータ型が使用される。列挙型のフィールド には、その定義内において宣言された値のみが割り当てられる。それぞれの定義 同士は、異なる型をもつ。同じ型をもつ列挙同士のみが代入、比較される。 列挙におけるすべての要素には、以下の例で示されるように値が割り当てられな ければならない。列挙におけるそれぞれの要素の順番は問われないため、どの ような値をどのような順序で割り当てても構わない。 enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te; 列挙においては、定義されている序数の最大値を表すのに必要なメモリ量を バイトストリームとして占有する。以下の定義では、Color型フィールドとして 1バイトが使用される。 enum { red(3), blue(5), white(7) } Color; ある値をタグなしで指定することにより、型サイズの定義を強制することが できる。以下の例では、Tasteはデータストリームとして2バイトを使用するが、 割り当てられている値は1、2または4だけである。 enum { sweet(1), sour(2), bitter(4), (32000) } Taste; 列挙における各要素の名前は、定義された型の中のみで有効である。最初の 例では、列挙の2番目の要素に対する正確な参照方法は、Color.blueである。 ただし代入される値のターゲットが明白であれば、必ずしもこのように指定 する必要はない。 Color color = Color.blue; /* 十分な指定。文法的に正確 */ Color color = blue; /* これは正しい。型が明白。 */ 内部でのみ使用され、一般的な表記に変換されることのない列挙に関しては、 数値情報を省略してもよい。 enum { low, medium, high } Amount; 4.6. 構造体 構造体は、基本的なデータ型から構成される。それぞれの定義では、新しく、 そして唯一の型を宣言する。定義構文はC言語に似たものである。 struct { T1 f1; T2 f2; ... Tn fn; } [[T]]; 構造体内のフィールドは、列挙において利用可能な構文に似た構文を使用し、 型名を使用することで指定することが出来る。例えばT.f2は、先の宣言における 2番目のフィールドを参照する。構造体の定義はネストしてもよい。 4.6.1. バリエーション 構造体では、その環境で利用できる情報に基づいたバリエーションを持つことが 出来る。このときのセレクタは、その構造体で定義しているバリエーションを 定義するための列挙型でなければならない。selectで宣言されている列挙型に 含まれるすべての要素に対して、case文による処理が表記されていなければなら ない。構造体のバリエーション部分には、参照のためにラベルを付与してもよい。 どのバリエーションが実行時に選択されるかのメカニズムについては、ここで 使用している言語では規定されない。 struct { T1 f1; T2 f2; .... Tn fn; select (E) { case e1: Te1; case e2: Te2; .... case en: Ten; } [[fv]]; } [[Tv]]; 例: enum { apple, orange } VariantTag; struct { uint16 number; opaque string<0..10>; /* 可変長 */ } V1; struct { uint32 number; opaque string[10]; /* 固定長 */ } V2; struct { select (VariantTag) { /* セレクタの値が含まれる */ case apple: V1; /* バリエーションの型, tag = apple */ case orange: V2; /* バリエーションの型, tag = orange */ } variant_body; /* バリエーションのラベル(オプショナル)*/ } VariantRecord; 構造体のバリエーションは、型の前にセレクタのための値を指定することに よって、定義(固定)することが出来る。例えば、 orange VariantRecord は、V2型のバリエーションを持つ、VariantRecordの宣言となる。 4.7. 暗号属性 4つの暗号処理、すなわちデジタル署名、ストリーム暗号、ブロック暗号、公開鍵 暗号ではそれぞれ、データをデジタル的に署名し、ストリーム的に暗号化し、 ブロックごとに暗号化し、公開鍵で暗号化する。あるフィールドに対する暗号処理 は、そのフィールドの型宣言の前に、適切なキーワードを付与することによって 指定される。暗号化鍵は、カレントのセションステータスによって決定される (第6.1章を参照のこと)。 デジタル署名においては、署名アルゴリズムへの入力として、一方向ハッシュ 関数の出力を使用する。デジタル的に署名された要素は、opaqueベクトル <0..2^16-1>としてエンコードされる。その長さは、署名アルゴリズムと鍵に よって特定される。 RSA署名においては、2つのハッシュ値(1つはSHA、もう1つはMD5)をもつ、 36バイトの構造体に署名する(私有鍵により暗号化される)。これは、[PKCS1] に示されている、PKCS #1ブロック型 0 または 1 によりエンコードされる。 DSSにおいては、SHAによりハッシュされた20バイトのデータが、さらにハッシュ 処理されることなく、デジタル署名アルゴリズム(DSA)に直接渡される。 これにより2つの値、rとsが生成される。DSS署名は、上記のようにopaque ベクトルであり、その内容をDERエンコードで示すと、以下のようになる。 Dss-Sig-Value ::= SEQUENCE { r INTEGER, s INTEGER } ストリーム暗号では、平文は、暗号的に安全な鍵付き擬似乱数発生器により 生成された、平文と同じ量の出力と、排他的OR処理される。 ブロック暗号では、それぞれの平文ブロックは、1つの暗号文ブロックに暗号化 される。すべてのブロック暗号は、CBC (Cipher Block Chaining)モードで 処理される。ブロック暗号処理されたすべてのブロックは、暗号ブロック長と 同じ長さを持つ。 公開鍵暗号では、公開鍵アルゴリズムを使用してデータを暗号化するため、 その公開鍵に対する私有鍵を使用してのみ、データを復号することができる。 公開鍵暗号で暗号化された要素は、opaque型のベクトル<0..2^16-1>として エンコードされる。ここで、要素の長さは、署名アルゴリズムと鍵により特定 される。RSA暗号値は、[PKCS1]で示されている、PKCS #1ブロック型 2 でエン コードされる。 例えば次の例では、 stream-ciphered struct { uint8 field1; uint8 field2; digitally-signed opaque hash[20]; } UserType; hashの内容が、そのまま署名アルゴリズムへ入力される。そして、構造体全体 がストリーム暗号で暗号化される。この構造体の長さは、バイト単位で、 field1とfield2のための2バイト、署名の長さのための2バイト、および署名アル ゴリズムの出力長である。署名アルゴリズムの長さは既知である。それは、署名 に使用されるアルゴリズムと鍵は、この構造体をエンコードまたはデコードする 前に、既知であるためである。 4.8. 定数 必要な型を宣言し値をそれに割当てることにより、型をもつ定数を定義すること ができる。特定の型(opaque、可変長ベクトル、およびopaqueを含む構造体)に 値を割り当てることはできない。複数の要素を持つ構造体またはベクトルでは、 フィールドを省略することはできない。 例: struct { uint8 f1; uint8 f2; } Example1; Example1 ex1 = {1, 4}; /* f1 = 1, f2 = 4 の割り当て */ 5. HMACと擬似乱数関数 TLSレコード層とハンドシェイク層における多くの処理において、鍵付きMACが 必要である。鍵付きMACとは、secretによって保護された、あるデータの安全な ダイジェストのことである。このsecretの知識なしに、MACを偽造することは 不可能である。この鍵付きMAC処理において使用される構造は、HMACとして知ら れているものである[HMAC]。 HMACは、さまざまなハッシュアルゴリズムと組み合わせることができる。TLSでは、 ハンドシェイクにおいて2つのアルゴリズム、すなわちMD5とSHA-1、を使用し、 これらをHMAC_MD5(secret, data)とHMAC_SHA(secret, data)と表記する。暗号 スイートを使用してさらなるハッシュアルゴリズムを定義し、そのアルゴリズム を使用してレコードデータを保護することができるが、プロトコルの本バージョン においては、MD5とSHA-1を、ハンドシェイク処理の説明において直に記述する。 さらに、鍵生成または鍵検証のために、secretを拡張してデータブロックとする ための構造が必要である。これを行う擬似乱数関数(pseudo-random function:PRF) では、secret、seed、および識別を行うためのlabelを入力として取り、任意長の データを出力する。 PRFをできるだけ安全にするために、PRFでは2つのハッシュアルゴリズムを使用 する。そしてどちらかのアルゴリズムが安全なままであれば、そのセキュリティ が保証される、という方法で使用する。 ここではまず、データ拡張関数であるP_hash(secret, data)を定義する。これは 1つのハッシュ関数を使用し、secretとseedを拡張して、任意長のデータを出力 する。 P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ... ここで、 + は連鎖を意味する。 A()は次のように定義される。 A(0) = seed A(i) = HMAC_hash(secret, A(i-1)) P_hashでは、必要な長さのデータを生成するまで計算を繰り返すことができる。 例えば、P_SHA-1を使用して64バイトのデータを作成する場合、ハッシュを4回 (A(4)まで)繰り返し、80バイトの出力データを得た後、最後の繰り返し計算に おける出力の最後の16バイトのデータを切り捨て、残りの64バイトを出力 データとする。 TLSにおけるPRFでは、secretを2つに分割し、その1つをP_MD5を使用した データ生成に使用し、もう1つをP_SHA-1を使用したデータ生成に使用する。 そしてそれらの2つの拡張関数の出力に対して排他的OR処理を行う。 S1とS2は、secretを2つに分割したものであり、それぞれは同じ長さを持つ。 S1はsecretの前半、S2は後半である。それらのバイト数は、secret全体の長さ を2で割った値を繰り上げることによって作成される。したがって、もし元の secretのバイト数が奇数ならば、S1の最後のバイトはS2の最初のバイトと同じ ものになる。 L_S = secretのバイト長 L_S1 = L_S2 = ceil(L_S / 2); secretは、上記のように2つに分割され(ここでは1つの共有バイトがある可能性 がある)、S1が前半のL_S1バイト部分、S2は後半のL_S2バイト部分とされる。 PRFは、2つの擬似乱数ストリームを排他的ORすることによりミックスした結果 として定義される。 PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed); ここで、labelはASCII文字列である。labelは、そのバイト長を示すデータや、 最後のNULL文字のない正確な形で処理される。例えば、label "slithy toves"は、 以下のバイト列をハッシュすることによって処理される。 73 6C 69 74 68 79 20 74 6F 76 65 73 MD5は16バイトの出力、SHA-1は20バイトの出力を行うため、それらの内部的な 繰り返し処理回数は一致しないことに注意する必要がある。80バイトの出力を 生成するためには、P_MD5ではA(5)まで繰り返し、P_SHA-1ではA(4)まで繰り返 しを行う。 6. TLSレコードプロトコル TLSレコードプロトコルは、複数の層から構成されている。各層のメッセージは、 データ長フィールド、メッセージ情報フィールド、そしてコンテンツから構成 されている。レコードプロトコルは、上位層から渡されたメッセージを受け取り、 データを処理しやすいブロックへ分解し、任意でデータを圧縮し、MACを適用し、 暗号化し、結果を下位レベル層に渡す。また下位レベル層から受け取ったデータ を復号し、検証し、展開し、組み立て直して、上位レベルのクライアントに渡す。 4つのレコードプロトコルクライアントが本ドキュメントで記述されている。 それはハンドシェイクプロトコル、Alertプロトコル、ChangeCipherSpecプロト コル、およびアプリケーションデータプロトコルである。 TLSプロトコルを拡張 するために、レコードプロトコルに対して新規のレコードタイプを追加すること ができるようになっている。新規のレコードタイプは、ここで記述された4つのレ コードタイプのすぐ後から、ContentTypeにおけるレコードタイプ値を割り当て ていくべきである(付録 A.2を参照)。TLS実装においては、理解のできないレコード タイプを受信したならば、単純にそれを無視するべきである。TLSを使用する ように設計されるプロトコルは、可能性のあるすべての攻撃に対応できるように 入念に設計されなければならない。レコードタイプとデータ長の情報は、暗号化 による保護は行われないので、これらのトラフィック分析値を最小にするため の注意を払うべきである。 6.1. コネクションステータス TLSコネクションステータスは、TLSレコードプロトコルの動作環境である。ステー タスでは、圧縮アルゴリズム、暗号化アルゴリズム、およびMACアルゴリズムが 指定される。さらに、これらのアルゴリズムのパラメータ、すなわち、読み込み、 書き出し方向のコネクションにおけるMACシークレット、大量暗号化鍵、 IVも求められている。論理的には、常に4つのコネクションステータスが存在する。 それは、カレントの読み込み、書き出しステータス、未定状態の読み込み、書き 出しステータスである。すべてのデータは、カレントの読み込み、書き出しス テータスの下で処理される。未定ステータスのセキュリティパラメータは、TLS ハンドシェイクプロトコルによって設定することが出来る。そしてハンドシェイク プロトコルはまた、2つの未定ステータスをカレントステータスに変更することが できる。この場合、該当するカレントステータスは処分され、未定ステータスで 置きかえられる。そして未定ステータスは、空の状態に再初期化される。セキュ リティパラメータで初期化されていないステータスをカレントステータスにするの は違反である。カレントステータスの初期状態では、どのような暗号化、圧縮、 またはMACも使用されない、という指定が行われる。 TLSコネクションの読み込み、書き出しステータスにおけるセキュリティパラ メータは、以下の値を提供することによって設定される。 コネクション端 このエンティティは、コネクションにおける「クライアント」であるか 「サーバ」であるか。 大量暗号化アルゴリズム 大量のデータの暗号化に使用されるアルゴリズム。設定には、このアルゴ リズムの鍵サイズ、有効鍵長、暗号はブロック型であるかストリーム型 であるか、(該当する場合)暗号のブロックサイズ、「輸出」可能な暗号 であるか否かを含む。 MACアルゴリズム メッセージ認証に使用されるアルゴリズム。設定には、MACアルゴリズム によって返されるハッシュサイズを含む。 圧縮アルゴリズム データ圧縮に使用されるアルゴリズム。設定には、アルゴリズムが圧縮を 実行するのに必要とするすべての情報が含まれていなければならない。 マスターシークレット コネクションの両端で共有される48バイトのシークレット。 クライアント乱数 クライアントによって提供される32バイト値。 サーバ乱数 サーバによって提供される32バイト値。 これらのパラメータは、ここで使用する言語を使用して、次のように定義される。 enum { server, client } ConnectionEnd; enum { null, rc4, rc2, des, 3des, des40 } BulkCipherAlgorithm; enum { stream, block } CipherType; enum { true, false } IsExportable; enum { null, md5, sha } MACAlgorithm; enum { null(0), (255) } CompressionMethod; /* CompressionMethod, BulkCipherAlgorithm, そしてMACAlgorithm で指定されるアルゴリズムは、追加が可能である。*/ struct { ConnectionEnd entity; BulkCipherAlgorithm bulk_cipher_algorithm; CipherType cipher_type; uint8 key_size; uint8 key_material_length; IsExportable is_exportable; MACAlgorithm mac_algorithm; uint8 hash_size; CompressionMethod compression_algorithm; opaque master_secret[48]; opaque client_random[32]; opaque server_random[32]; } SecurityParameters; レコード層では、セキュリティパラメータを使用して、以下の6つを生成する。 クライアント書き出しMACシークレット サーバ書き出しMACシークレット クライアント書き出し鍵 サーバ書き出し鍵 クライアント書き出しIV (ブロック暗号のみ) サーバ書き出しIV (ブロック暗号のみ) クライアント書き出しパラメータは、サーバにおいては、レコードを受信し処理 するときに使用する。逆もまた同様である。セキュリティパラメータからこれ らを生成するのに使用されるアルゴリズムは、第6.3章で述べる。いったんセキュ リティパラメータが設定され鍵が生成されると、そのコネクションステータスを カレントステータスにすることにより、有効にすることができる。これらのカレ ントステータスは、処理される各レコードごとにアップデートされなければなら ない。それぞれのコネクションステータスは以下の要素を含む。 圧縮ステータス 圧縮アルゴリズムの、カレントステータス。 暗号ステータス 暗号化アルゴリズムのカレントステータス。これはそのコネクションにスケ ジュールされた鍵から構成される。さらに、CBCモード(TLSで指定される 唯一のモード)で動作するブロック暗号においては、最初はそのコネク ションステータスのIVが含まれている。IVはレコードが処理されるに従い、 暗号化または復号された最新の暗号ブロックにアップデートされる。 ストリーム暗号においては、ここにはデータを暗号化または復号するため に必要な、何かしらのステータス情報が含まれる。 MACシークレット 上記のように生成された、このコネクションにおけるMACシークレット。 シーケンス番号 それぞれのコネクションステータスには、シーケンス番号が含まれる。 読み込み、書き出し用の番号はそれぞれ別々に維持される。コネクション ステータスがアクティブになったときには、シーケンス番号は0にセット されなければならない。シーケンス番号は、uint64型であり、2^64-1を 超えない。シーケンス番号は、各レコードごとに増加される。明らかなこと であるが、ある特定のコネクションステータスの下で転送される最初の レコードは、シーケンス番号0を使用するべきである。 6.2. レコード層 TLSレコード層は、 上位レベルの層から、任意サイズの空でないブロックデータを 受け取る。このデータは解析されない。 6.2.1. フラグメンテーション レコード層では、情報ブロックを、2^14バイト以下のチャンクとして、 TLSPlaintextレコードデータにフラグメントする。クライアントメッセージの 境界はレコード層では保持されない(すなわち、同じContentTypeを持つ複数の クライアントメッセージは、1つのTLSPlaintextレコードとして結合されるかも しれない。もしくは、1つのメッセージがいくつかのレコードに渡ってフラグ メントされるかもしれない)。 struct { uint8 major, minor; } ProtocolVersion; enum { change_cipher_spec(20), alert(21), handshake(22), application_data(23), (255) } ContentType; struct { ContentType type; ProtocolVersion version; uint16 length; opaque fragment[TLSPlaintext.length]; } TLSPlaintext; type フラグメントされたデータを処理する上位のプロトコルタイプ。 version 使用されるプロトコルのバージョン。 このドキュメントではTLSバー ジョン1.0を記述しているが、その場合バージョン{3、1}を使用する。 バージョン値である 3.1 は歴史的な理由による。TLSバージョン1.0は SSL3.0プロトコルをマイナーチェンジしたものである。SSL3.0では、 バージョン値は3.0である(付録 A.1を参照)。 length 次のTLSPlaintext.fragmentの長さ(単位バイト)。長さは 2^14を超えない。 fragment アプリケーションデータ。 このデータは透過で、typeフィールドで 指定されている上位プロトコルによって処理されるよう、独立した ブロックとして処理される。 注: 異なるTLS レコード層コンテンツタイプを持つデータが割り込んでいても よい。アプリケーションデータは一般に、転送に際しては他のコンテンツ タイプよりも優先度が低い。 6.2.2. 圧縮と展開 すべてのレコードは、カレントのセションステータスで定義されている圧縮アルゴ リズムを使用して圧縮される。常に、アクティブ状態の圧縮アルゴリズムが存在 する。しかし、初期化時にはCompressionMethod.nullとして定義される。圧縮 アルゴリズムにより、TLSPlaintext構造体はTLSCompressed構造体に変換される。 圧縮関数はコネクションステータスがアクティブになったときには、デフォルト のステータス情報により初期化される。圧縮においては、ロスがあってはならず、 その長さは1024バイト以上増加してはならない。展開関数において TLSCompressed.fragmentを展開したとき、その長さが2^14バイトを超えた場合 は、fatalレベルの decompression failureエラーで応答しなければならない。 struct { ContentType type; /* TLSPlaintext.type に同じ */ ProtocolVersion version;/* TLSPlaintext.version に同じ */ uint16 length; opaque fragment[TLSCompressed.length]; } TLSCompressed; length 次のTLSCompressed.fragmentの長さ(単位バイト)。 長さは、2^14 + 1024を超えない。 fragment TLSPlaintext.fragmentを圧縮したもの。 注: CompressionMethod.null 演算が、唯一の演算である。他に代わるものは ない。 実装上の注意: 展開を行う関数は、メッセージ処理により内部バッファのオーバー フローを起こすことがないことを保証する責任がある。 6.2.3. レコード送受信中の保護 暗号化とMAC関数により、TLSCompressed構造体はTLSCiphertext構造体へ変換 される。復号関数では、逆の処理を行う。レコードのMACはまた、シーケンス 番号を含んでいるため、紛失、超過、繰り返しメッセージを検出することが できる。 struct { ContentType type; ProtocolVersion version; uint16 length; select (CipherSpec.cipher_type) { case stream: GenericStreamCipher; case block: GenericBlockCipher; } fragment; } TLSCiphertext; type typeフィールドは、TLSCompressed.typeと同じ。 version versionフィールドは、TLSCompressed.versionと同じ。 length 次のTLSCiphertext.fragmentの長さ(単位バイト)。長さは、2^14 + 2048 を超えない。 fragment TLSCompressed.fragmentを、MAC付きで暗号化したもの。 6.2.3.1. Nullまたは標準ストリーム暗号 ストリーム暗号(BulkCipherAlgorithm.nullを含む。付録A.6を参照)は、 TLSCompressed.fragment構造体からTLSCiphertext.fragment構造体への変換、 またはその逆変換を行う。 stream-ciphered struct { opaque content[TLSCompressed.length]; opaque MAC[CipherSpec.hash_size]; } GenericStreamCipher; MACは次のように生成される。 HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment)); ここで、"+"は連鎖を意味する。 seq_num このレコードのシーケンス番号。 hash SecurityParameters.mac_algorithmで指定されるハッシュアルゴリズム。 MACは、暗号化の前に計算されることに注意。ストリーム暗号では、MACを含む 全体のブロックを暗号化する。(RC4などの)同期ベクトルを使用しないストリーム 暗号では、ある1つのレコードの最後におけるストリーム暗号ステータスはその まま、その後のパケット処理に使用される。もしCipherSuiteが TLS_NULL_WITH_NULL_NULLであるならば、暗号化処理は、恒等処理として行われる (すなわち、データは暗号化されず、MACが使用されないのでMACサイズはゼロで ある)。TLSCiphertext.lengthはTLSCompressed.lengthとCipherSpec.hash_size の和である。 6.2.3.2. CBCブロック暗号 (RC2やDESなどの)ブロック暗号の処理では、暗号化関数とMAC関数により、 TLSCompressed.fragment構造体はTLSCiphertext.fragment構造体へ、 TLSCiphertext.fragment構造体はTLSCompressed.fragment構造体へ変換される。 block-ciphered struct { opaque content[TLSCompressed.length]; opaque MAC[CipherSpec.hash_size]; uint8 padding[GenericBlockCipher.padding_length]; uint8 padding_length; } GenericBlockCipher; MACは第6.2.3.1節で記述されるように生成される。 padding paddingは、平文の長さがブロック暗号のブロック長の整数倍になるように するために、データに追加されるものである。 TLSCiphertext.length がブロック長の整数倍になる限り、パディング長は255バイトまでのどんな 長さでもよい。必要とするよりも長くパディングすることは、交換された メッセージの長さを分析することに基づくプロトコル攻撃を無力化するため、 望ましいことかもしれない。パディングデータベクトルにおけるそれぞれの uint8は、パディング長の値で埋められなければならない。 padding_length パディング長は、GenericBlockCipher構造体の全サイズが、その暗号に おけるブロック長の整数倍になるようにすべきである。規定上の値は、 ゼロから255までの間で変化する。padding_lengthはパディングフィールド の長さを指定するもので、padding_lengthフィールド自体の長さを含まない。 暗号化されたデータの長さ(TLSCiphertext.length)は、TLSCompressed.length、 CipherSpec.hash_size、およびpadding_lengthの合計よりさらに1バイト大きい 値である。 例: ブロック長が8バイト、コンテンツ長(TLSCompressed.length)が61バイト、 MACの長さが20バイトであるならば、パディングをする前の長さは82バイト である。したがって、8を法としたときのパディング長は、全ブロック長が 8バイト(ブロック長)の整数倍になるように、6でなければならない。パディ ング長は、6、14、22から、254までの値が可能である。 もしパディング 長が、必要最小限である6であったとき、それぞれには6の値が含まれる。 したがって、ブロック暗号化前のGenericBlockCipherにおける最後の8オク テットは、xx 06 06 06 06 06 06 06 となる。ただし、xxはMACの最後の オクテットである。 注: CBC(Cipher Block Chaining)モードにおけるブロック暗号では、最初の レコードのための初期ベクトル(IV)は、セキュリティパラメータが設定 されるときに、他の鍵やシークレットと同時に生成される。それに続く レコードのIVは、前のレコードの最後の暗号ブロックである。 6.3. 鍵計算 レコードプロトコルでは、ハンドシェイクプロトコルによって提供されるセキュ リティパラメータから鍵、IV、およびMACシークレットを生成するためのアルゴリ ズムが必要である。 マスターシークレットは、安全なバイト列にハッシュされる。これはカレントの コネクションステータスにおいて必要とされるMACシークレット、鍵、輸出の できない暗号におけるIVに割り当てられる(付録 A.6を参照)。CipherSpecでは、 クライアント書き出しMACシークレット、サーバ書き出しMACシークレット、 クライアント書き出し鍵、サーバ書き出し鍵、クライアント書き出しIV、そして サーバ書き出しIVを必要とする。これらはこの順序で、マスターシークレット から生成される。使用しない値は空である。 鍵とMACシークレットを生成するときには、マスターシークレットをエントロピー ソースとして使用する。そして乱数を使用して、輸出可能な暗号のための、暗号化 されないソルトとIVが作成される。 鍵マテリアルを生成するには、次を計算する。 key_block = PRF(SecurityParameters.master_secret, "key expansion", SecurityParameters.server_random + SecurityParameters.client_random); これを十分な出力が得られるまで行う。次に、key_blockは以下の通りに仕切 られる。 client_write_MAC_secret[SecurityParameters.hash_size] server_write_MAC_secret[SecurityParameters.hash_size] client_write_key[SecurityParameters.key_material_length] server_write_key[SecurityParameters.key_material_length] client_write_IV[SecurityParameters.IV_size] server_write_IV[SecurityParameters.IV_size] client_write_IVとserver_write_IVは、輸出のできないブロック暗号のために のみ生成される。輸出可能なブロック暗号においては、初期ベクトルは後に、 以下で記述されるように生成される。余分なkey_blockマテリアルは捨てられる。 実装上の注意: このドキュメントにおいて定義されている暗号スペックの中で、最も長い マテリアルを必要とするものは、3DES_EDE_CBC_SHAである。これは2 x 24 バイトの鍵、2 x 20バイトのMACシークレット、2 x 8バイトのIV、合計104 バイトの鍵マテリアルを必要とする。 輸出可能な暗号化アルゴリズム(CipherSpec.is_exportableがtrue)では、 最終的な書き出し鍵を得るために、以下のような追加処理が必要となる。 final_client_write_key = PRF(SecurityParameters.client_write_key, "client write key", SecurityParameters.client_random + SecurityParameters.server_random); final_server_write_key = PRF(SecurityParameters.server_write_key, "server write key", SecurityParameters.client_random + SecurityParameters.server_random); 輸出可能な暗号化アルゴリズムでは、そのIVはHelloメッセージにおける乱数 から作成される。 iv_block = PRF("", "IV block", SecurityParameters.client_random + SecurityParameters.server_random); このiv_blockは、上記のkey_blockのときと同じように、2つの初期ベクトルに 分割される。 client_write_IV[SecurityParameters.IV_size] server_write_IV[SecurityParameters.IV_size] PRFはこの場合、シークレットなしで使用されることに注意。これは、シーク レットはゼロバイトの長さを持ち、PRFのハッシュに何も寄与しないことを 意味する。 6.3.1. 輸出可能な暗号の鍵生成例 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5では、2つの暗号化鍵に対しそれぞれ5バイト の乱数と、MAC鍵としてそれぞれ16バイト、合計42バイトの鍵マテリアルを必要と する。 PRFの出力は、key_blockに格納される。key_blockはさらに分割され、 輸出可能な暗号化アルゴリズムであるために、書き出し鍵はソルト処理される。 key_block = PRF(master_secret, "key expansion", server_random + client_random)[0..41] client_write_MAC_secret = key_block[0..15] server_write_MAC_secret = key_block[16..31] client_write_key = key_block[32..36] server_write_key = key_block[37..41] final_client_write_key = PRF(client_write_key, "client write key", client_random + server_random)[0..15] final_server_write_key = PRF(server_write_key, "server write key", client_random + server_random)[0..15] iv_block = PRF("", "IV block", client_random + server_random)[0..15] client_write_IV = iv_block[0..7] server_write_IV = iv_block[8..15] 7. TLSハンドシェイクプロトコル TLSハンドシェイクプロトコルは、3つのサブプロトコルから構成されている。 双方のピアの間で、レコード層で使用するセキュリティパラメータの合意、 相互認証、ネゴシエーションされたセキュリティパラメータのインスタンス生成、 そしてエラーレポートを行うために、これらのプロトコルが使用される。 ハンドシェイクプロトコルは、セションに関するネゴシエーションを行う。 1つのセションは以下の項目から構成されている。 セション識別子 アクティブセションステータスもしくは再利用可能セションステータスを 識別するために、サーバによって選択される任意のバイト列。 ピア証明書 ピアのX509v3 [X509]証明書。ステータスにおけるこの要素は空でもよい。 圧縮方式 データを圧縮するためのアルゴリズム。暗号化の前に適用される。 暗号スペック 大量暗号化アルゴリズム(例えばnull、DESなど)と、MACアルゴリズム (例えばMD5やSHAなど)を特定するもの。また、hash_sizeなどの 暗号属性の定義も行う。(正式な定義に関しては付録 A.6を参照。) マスターシークレット クライアントとサーバの間で共有される48バイトのシークレット。 再利用可能性 新しいコネクションを開始するのに、そのセションを利用することができる かどうかを示すフラグ。 これらの項目は、セキュリティパラメータを生成するのに使用される。生成した パラメータは、アプリケーションデータを保護する際にレコード層により使用 される。TLSハンドシェイクプロトコルの再利用性により、1つのセションを使用 して、複数のコネクションのインスタンスを生成することができる。 7.1. ChangeCipherSpecプロトコル ChangeCipherSpecプロトコルは、ネゴシエーション時において通知を行うための ものである。プロトコルは、ただ一つのメッセージから構成されている。この メッセージは、カレントの(未定ではない)コネクションステータスのもとで 暗号化、圧縮が行われる。メッセージは値1をもつ1バイトから構成されている。 struct { enum { change_cipher_spec(1), (255) } type; } ChangeCipherSpec; ChangeCipherSpecメッセージは、クライアントとサーバの両方によって送信され るもので、メッセージを受信したパーティーに対し、この後に続くデータは、 新たにネゴシエーションされたCipherSpecと鍵のもとに保護されていることを 通知する。このメッセージを受信することにより、受信した側ではレコード層に 対し、読み込み未定ステータスを、読み込みカレントステータスにすぐにコピー するように命令する。このメッセージを送信した直後に、送信した側ではレコード 層に対し、書き出し未定ステータスを書き出しカレントステータスに変更する よう命令する(第6.1章を参照)。ChangeCipherSpecメッセージは、ハンドシェイク の間、セキュリティパラメータが合意された後、Finishedメッセージが送信される 前に送信される(第7.4.9章を参照)。 7.2. Alertプロトコル TLSレコード層によってサポートされているコンテンツタイプのひとつに、Alert (警告)タイプがある。Alertメッセージは、アラートの重大度とその内容を相手に 通知するものである。fatal(致命的)レベルを持つAlertメッセージでは、コネ クションは即座に切断される。この場合、そのセションにおける他のコネクション は継続してもよいが、セション識別子は無効化される。これは失敗したセション を使用して新しいコネクションを確立するのを防ぐためである。他のメッセージ 同様、Alertメッセージはカレントのコネクションステータスのもとで暗号化と 圧縮が行われる。 enum { warning(1), fatal(2), (255) } AlertLevel; enum { close_notify(0), unexpected_message(10), bad_record_mac(20), decryption_failed(21), record_overflow(22), decompression_failure(30), handshake_failure(40), 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(60), protocol_version(70), insufficient_security(71), internal_error(80), user_canceled(90), no_renegotiation(100), (255) } AlertDescription; struct { AlertLevel level; AlertDescription description; } Alert; 7.2.1. 終了アラート クライアントとサーバは、トランケーション攻撃を避けるために、コネクション を終了しようとしているという情報を共有しなければならない。どちらのパー ティーから終了メッセージの交換を始めてもよい。 close_notify このメッセージは、メッセージの送信者がその受信者に対し、このコネク ションではこれ以上メッセージを送信しないことを通知するために使用さ れる。warning(警告)レベルをもつ適切なclose_notifyメッセージなしに コネクションが終了したときには、そのセションは再利用不可となる。 どちらのパーティからでも、close_notifyを送信することによるコネクションの 終了を始めてもよい。終了アラートを受信した後に受信したデータは無視される。 どちらのパーティーも、コネクションの書き出し側を閉じる前には、close_notify を送信する必要がある。他方のパーティーは、自分自身のclose_notifyで応答し、 すぐにコネクションを閉じ、書き出していないデータを破棄する必要がある。 最初にコネクションの終了を始めた側は、close_notifyの応答を待ってから読み 出し側を閉じる必要はない。 TLSを使用したアプリケーションプロトコルが、TLSコネクションが閉じた後にも データの送受信を認めている場合には、TLS実装では、アプリケーション層に対して TLSコネクションが終了したことを通知する前に、close_notifyを受信しなければ ならない。もしアプリケーションプロトコルが、さらなるデータ送受信を行わず、 カレントのコネクションを閉じるだけであれば、TLS実装では、応答される close_notifyを待たずに送信を終了してもよい。データ転送時のTLSの制御方法を そのアプリケーションプロトコルにおいて規定するときには、コネクションの 開始または終了方法を含め、本規格におけるどのような部分もそのプロトコル 規定に転載すべきではない。 注:コネクションの終了処理では、その通信を終了する前に、未送信データが 転送処理されるものと仮定している。 7.2.2. エラーアラート TLSハンドシェイクプロトコルにおけるエラー処理は非常に簡単である。エラー が検出されたとき、それを検出したパーティーは、もう片方のパーティーにメッ セージを送信する。fatalレベルのAlertメッセージの送信または受信があると、 双方のパーティーはすぐにコネクションを閉じる。サーバとクライアントは、 失敗したコネクションに関するすべてのセション識別子、鍵、およびシーク レットを忘れなければならない。 以下のエラーアラートが定義されている。 unexpected_message 不適当なメッセージを受信した。このアラートは常にfatalである。 適切な実装間での通信においては使用されることはない。 bad_record_mac このアラートは、不正確なMACをもつデータを受信したときに返される。 このメッセージは常にfatalである。 decryption_failed 無効な方法によりTLSCiphertext構造体が復号された。これは、データが ブロック長の整数倍ではない場合、またはパディング値をチェックした際に、 それが正しくない場合のどちらかである。このメッセージは常にfatal である。 record_overflow TLSCiphertext構造体データが、2^14+2048バイトより長かった、または TLSCompressed構造体へ復号されたデータが、2^14+1024バイトより 長かった。このメッセージは常にfatalである。 decompression_failure データの展開を行う関数が不適当な入力(例えば、長さの超過したデータ) を受け取った。このメッセージは常にfatalである。 handshake_failure handshake_failureメッセージを受信したときは、メッセージの送信者は、 与えられた利用可能なオプションでは、受理可能なセキュリティパラメータ のネゴシエーションができなかったことを示している。これはfatal エラーである。 bad_certificate 証明書が不正であった。これには、正しく確かめられなかった署名が 含まれていた、などが挙げられる。 unsupported_certificate 証明書は、サポートされていないタイプのものであった。 certificate_revoked 証明書はその署名者によって無効化されていた。 certificate_expired 証明書はすでに有効期限が切れている、もしくは現在、有効ではない。 certificate_unknown 証明書処理において、その他の(特定されていない)問題が発生し、受理 できなかった。 illegal_parameter ハンドシェイクにおけるフィールドが、その値の範囲を超えていた、 または他のフィールドと矛盾していた。これは常にfatalである。 unknown_ca 有効な証明書チェーンまたは部分的チェーンを受信したが、信用のおける CAの証明書を見つけることができなかった、すなわち既知の、信用のおける CAと一致しなかったため、証明書が受理されなかった。このメッセージは 常にfatalである。 access_denied 有効な証明書を受信したが、アクセスコントロールが適用されたため、 送信者が、これ以上ネゴシエーションを続けないと決定した。この メッセージは常にfatalである。 decode_error あるフィールドが、指定された範囲から脱していた、またはメッセージの 長さが不正確だったので、メッセージをデコードすることができなかった。 このメッセージは常にfatalである。 decrypt_error ハンドシェイク暗号処理に失敗した。これには、署名の検証が正しく出来 なかった、交換された鍵の復号に失敗した、またはFinishedメッセージの 有効性を正しく確かめることができなかった、などが含まれる。 export_restriction 輸出制限に従っていないネゴシエーションが検出された。例えば、 RSA_EXPORTハンドシェイクにおいて、1024ビットの一時的RSA鍵を 転送しようとした。このメッセージは常にfatalである。 protocol_version クライアントがネゴシエーションしようとしたプロトコルバージョンは 認識したが、それはサポートされていない。(例えば、セキュリティ的な 理由により、古いプロトコルバージョンを避けたい場合。)このメッセー ジは常にfatalである。 insufficient_security クライアントがサポートしている暗号よりも、より安全な暗号をサーバが 要求しているためネゴシエーションに失敗したときに、handshake_failure を返す代わりにこれを返す。このメッセージは常にfatalである。 internal_error ピアとは関係のない、またはプロトコルの正確さには関係のない内部的 なエラーにより、処理を続けることが出来ない(例えばメモリ確保エラー など)。このメッセージは常にfatalである。 user_canceled プロトコルのエラーとは関係のない理由により、ハンドシェイクがキャン セルされた。もしユーザが、ハンドシェイクが終わった後に処理をキャン セルするときには、close_notifyを送信してコネクションを単純に閉じる のがより適切である。このアラートの後には、close_notifyが続くべきで ある。このメッセージは一般にwarningである。 no_renegotiation HelloRequestメッセージに対するクライアントのレスポンス、または最初の ハンドシェイク後に受信したClientHelloに対するサーバのレスポンスで送信 される。これらの場合は通常、その後に再ネゴシエーションを行うが、それ が適切でない場合に受信者はこのアラートを返す。このとき、最初にリクエスト を送信した側は、コネクションを継続するか否かを決定することが出来る。 これが適切とされる一例として、サーバが、リクエストを処理するために プロセスを生成する場合が挙げられる。そのプロセスは、生成時にセキュリ ティパラメータ(鍵長、認証など)を受けとるが、その後にパラメータを変更 することが難しい場合である。このメッセージは常にwarningである。 アラートレベルが示されていないエラーにおいては、送信者の裁量で、そのレベルが fatalであるか否かを決定することが出来る。もしwarningレベルのアラートを受信 したとき、それを受信したパーティーは自身の裁量で、これをfatalエラーと 同様に処理するか否かを決定することが出来る。しかし、fatalレベルで送信 されるすべてのメッセージは、fatalメッセージとして扱われなければならない。 7.3. ハンドシェイクプロトコル概要 セションステータスの暗号パラメータは、TLS ハンドシェイクプロトコルによって 生成される。TLSハンドシェイクプロトコルは、TLS レコード層の上位で処理 されるプロトコルである。TLSクライアントとサーバが最初に通信し始めるとき には、プロトコルバージョン、暗号アルゴリズム選択、そして任意で相互認証、 共有するシークレットを生成するための公開鍵暗号方式、について合意が 行われる。 TLSハンドシェイクプロトコルには、以下のステップがある。 - Helloメッセージを交換し、アルゴリズムの合意や、乱数の交換、そして セション再利用についてチェックする。 - 必要な暗号パラメータを交換することにより、クライアントとサーバが プレマスターシークレットを共有する。 - 証明書と暗号情報を交換することにより、クライアントとサーバの相互 認証を行う。 - プレマスターシークレットと交換した乱数値から、マスターシークレット を生成する。 - レコード層に、セキュリティパラメータを提供する。 - クライアントとサーバが、同じセキュリティパラメータを計算している こと、そしてハンドシェイクが攻撃者によって変更されていないこと を確認する。 TLSハンドシェイクプロトコルよりも上位の層においては、TLSでは常に、クライ アントとサーバの両者の間で最も強力なコネクションをネゴシエーションして いる、ということを当てにしてはならない。なりすました攻撃者が、クライ アントとサーバがサポートしている最も非力なセキュリティ方式を選択するよう にさせるための方法は、たくさんある。本プロトコルは、このリスクを最小限に するよう設計しているが、それでも攻撃が可能な状態にある。例えば、攻撃者は セキュアサービスを実行しているポートへのアクセスをブロックすることが出来 る。もしくは、クライアントとサーバが、認証を行わないコネクションを確立 するようにさせることができる。基本的なルールとしては、上位の層においては、 セキュリティとして何が必要とされるのか、そして必要とされるものより低い セキュリティでは情報を送受信しないこと、を認識しなければならない。TLS プロトコルは安全である。それぞれの暗号スイートでは、それぞれのレベルでの セキュリティを提供する。もし1024ビットのRSA鍵の証明書をもつホストとの間で、 トリプルDESをネゴシエーションしたならば、それは安全であると期待できる。 しかし、40ビットの暗号セキュリティにおいては、その暗号を破るための努力を する程の価値はないと思われるデータでない限り、データを送信すべきではない。 これらの目的は、ハンドシェイクプロトコルによって実現される。簡単に述べる と、次のようになる。クライアントはClientHelloメッセージを送信する。サーバ はServerHelloメッセージで応答するか、fatalエラーによりコネクション確立 に失敗する。ClientHelloとServerHelloを使用することにより、クライアントと サーバ間での、セキュリティ処理能力を決定する。そしてプロトコルバージョン、 セションID、暗号スイート、圧縮アルゴリズムの各属性を確立する。さらに、 2つの乱数が生成され、交換される。これは、ClientHello.random と ServerHello.randomである。 実際の鍵交換においては、4つのメッセージを使用する。それは、 ServerCertificate、ServerKeyExchange、ClientCertificate、そして ClientKeyExchangeである。これらのメッセージに対してフォーマットを指定 し、クライアントとサーバ間でシークレットを共有するためのメッセージの 使用法を定義することにより、新しい鍵交換方式を複数作成することが出来る。 このシークレットは十分に長いものであるべきである。現在定義されている 鍵交換方式では、48から128バイトの間の長さのシークレットを交換する。 Helloメッセージに続き、サーバは自身の証明書を送信する。これは、認証処理 が行われる場合である。さらに、ServerKeyExchangeメッセージを送信する。 これは送信が必要な場合(すなわち、サーバに証明書がない、または証明書が 署名のみ可能なものである場合)である。サーバが認証されるならば、サーバは クライアントへ証明書を要求してもよい。これは選択された暗号スイートに おいて適切な場合である。そしてサーバはServerHelloDoneメッセージを送信する。 これにより、ハンドシェイクにおけるHelloメッセージフェーズが終了したことを 示す。サーバはその後、クライアントからのレスポンスを待つ。サーバが CertificateRequestメッセージを送信しているならば、クライアントはCertificate メッセージを送信しなければならない。そしてClientKeyExchangeメッセージが 送信されるが、その内容はClientHelloとServerHelloの間で選択された公開鍵 アルゴリズムに依存する。もしクライアントが署名能力をもつ証明書を送信して いるならば、デジタル的に署名されたCertificateVerifyメッセージを送信し、 証明書の検証を行う。 ここで、ChangeCipherSpecメッセージがクライアントから送信される。そして クライアントは、未定状態の暗号スペックを、カレントの暗号スペックにコピー する。クライアントはすぐに、新しいアルゴリズム、鍵、そしてシークレットの もとでFinishedメッセージを送信する。それに応じ、サーバは自身の ChangeCipherSpecメッセージを送信し、未定状態の暗号スペックをカレントに 移行し、新しい暗号スペックのもとでFinishedメッセージを送信する。ここで ハンドシェイクが完了し、クライアントとサーバはアプリケーション層のデータ の交換を開始する(下記のフローチャートを参照)。 クライアント サーバ ClientHello --------> ServerHello Certificate* ServerKeyExchange* CertificateRequest* <-------- ServerHelloDone Certificate* ClientKeyExchange CertificateVerify* [ChangeCipherSpec] Finished --------> [ChangeCipherSpec] <-------- Finished Application Data <-------> Application Data 図1. 完全なハンドシェイク処理におけるメッセージフロー * は、オプショナルなもの、または常に送信されるわけではない、状況 依存のメッセージ。 注: パイプラインの停止を避けるために、ChangeCipherSpecは、独立したTLS プロトコルコンテンツタイプであり、実質的にはTLSハンドシェイクメッ セージではない。 クライアントとサーバが以前のセションを再利用する、または(新しいセキュ リティパラメータをネゴシエーションする代わりに)カレントのセションを複製 するときには、メッセージフローは以下のようになる。 クライアントは、再利用するセションのセションIDを使用してClientHelloを 送信する。サーバはセションキャッシュをチェックする。もし同じものが見つ かり、指定されたセションステータスのもとでコネクションを再確立しようと する場合には、サーバは同じセションID値を含めたServerHelloメッセージを 送信する。ここで、クライアントとサーバの双方は、ChangeCipherSpecメッ セージを送信し、すぐにFinishedメッセージへ移行しなければならない。再確立 が完了すると、クライアントとサーバは、アプリケーション層のデータ交換を 開始する(下記のフローチャートを参照)。もしセションIDに一致したものが 見つからない場合には、サーバは新しいセションIDを生成し、TLSクライアント との間で完全なハンドシェイクを実行する。 クライアント サーバ ClientHello --------> ServerHello [ChangeCipherSpec] <-------- Finished [ChangeCipherSpec] Finished --------> Application Data <-------> Application Data 図2. 簡略化されたハンドシェイク処理におけるメッセージフロー それぞれのメッセージの内容と意味は、以下の章で詳細に示される。 7.4. ハンドシェイクプロトコル TLSハンドシェイクプロトコルは、TLSレコードプロトコルの上位クライアント として定義されたものの中のひとつである。このプロトコルは、セションの セキュリティ属性をネゴシエーションするのに使用される。ハンドシェイク メッセージはTLSレコード層に渡され、そこで1つ以上のTLSPlaintext構造体に カプセル化され、カレントのアクティブセションステータスで指定されている パラメータにより処理され、送信される。 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; 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; } body; } Handshake; 以下では、ハンドシェイクプロトコルメッセージを、送信される順番で説明して いく。予期されない順番でハンドシェイクメッセージが送信されると、fatal エラーとされる。不要なハンドシェイクメッセージは省略することができる。 ただし説明の順番に関しては1つだけ例外がある。Certificateメッセージは ハンドシェイクにおいて2度使用される(サーバからクライアントへの場合と、 クライアントからサーバへの場合である)が、ここでは最初の場合のみ説明する。 この順番に関係のない唯一のメッセージが、HelloRequestメッセージである。 これはいつでも送信することができるが、ハンドシェイクの最中にクライアント がこれを受信したときには無視される。 7.4.1. Helloメッセージ Helloフェーズのメッセージは、クライアントとサーバの間で、それぞれが可能な セキュリティ処理能力に関する情報を交換するのに使用される。新しいセション を開始するときには、レコード層のコネクションステータスにおける暗号化、 ハッシュ、および圧縮アルゴリズムはnullに初期化される。カレントのコネク ションステータスは再ネゴシエーションメッセージに適用される。 7.4.1.1. HelloRequestメッセージ メッセージが送信されるとき: HelloRequestメッセージは、サーバがいつでも送信することが出来る。 メッセージの意味: HelloRequestは単純な通知である。クライアントは都合のよいときにClientHello メッセージを送信することにより、新たなネゴシエーションプロセスを開始する べきであることを通知する。クライアントがセションのネゴシエーション中で あるときには、このメッセージはクライアントによって無視される。セション の再ネゴシエーションを望まない場合には、クライアントはそれを無視するか、 もしくはno_renegotiation アラートで応答する。ハンドシェイクメッセージは、 アプリケーションデータよりも優先されて送信されるため、クライアントから アプリケーションデータを受信する前にそのネゴシエーションが開始される ことが期待されている。サーバがHelloRequestを送信したにもかかわらず、 レスポンスとしてClientHelloを受信しなかった場合には、fatalレベルの アラートによりコネクションを終了してもよい。 HelloRequestを送信した後は、サーバはその後のハンドシェイクネゴシエー ションが完了するまで、リクエストを繰り返すべきでない。 メッセージの構造: struct { } HelloRequest; 注:このメッセージは、ハンドシェイクを通じて維持され、Finishedメッセージ、 CertificateVerifyメッセージで使用されるメッセージハッシュに含めて はならない。 7.4.1.2. ClientHelloメッセージ メッセージが送信されるとき: クライアントが最初にサーバに接続するときには、その最初のメッセージと してClientHelloメッセージを送信することが必要である。クライアントはまた、 HelloRequestのレスポンスとしてClientHelloを送信することができる。また 現存するコネクションにおけるセキュリティパラメータの再ネゴシエーション を行うために、クライアントから送信することも出来る。 メッセージの構造: ClientHelloメッセージには、Random構造体が含まれる。これはプロトコル 処理の後の方で使用される。 struct { uint32 gmt_unix_time; opaque random_bytes[28]; } Random; gmt_unix_time 送信者の内部クロックにおける標準UNIX32ビットフォーマットの 現在時間と日付(グリニッジ標準時1970年1月1日の真夜中からの秒数)。 基本的なTLSプロトコルにおいては、クロックは正しく設定されている 必要はない。ただし、より上位の層またはより上位のアプリケーション プロトコルにより、追加条件を定義してもよい。 random_bytes 安全な乱数生成器により生成された28バイトの乱数。 ClientHelloメッセージには、可変長のセション識別子が含まれる。これが 空でないとき、その値は、クライアントが再利用しようとするセキュリティ パラメータの含まれている、以前と同じクライアントとサーバの間でのセション を識別する。セション識別子は、以前のコネクション、そのコネクション、 または他のアクティブなコネクションからのものであってもよい。そのコネク ションのセション識別子を含める場合には、コネクションのRandom構造体と その派生値をアップデートすることができるため、これはクライアントがそれ のみを望んでいるときに有用である。また他のアクティブなコネクションを 含めることにより、完全なハンドシェイクプロトコルを繰り返さずに、複数の 独立したせキュリティコネクションを確立することができる。これらの独立 したコネクションは連続して、または同時に発生する可能性がある。SessionID は、ハンドシェイクネゴシエーションがFinishedメッセージを交換して完了 したときに有効になり、セションに関するコネクションの時間切れまたは fatalエラーが発生するまで継続する。SessionIDの実際の内容はサーバに よって定義される。 opaque SessionID<0..32>; 警告:SessionIDは、暗号化もMACによる保護もなく送信されるため、サーバは セション識別子に秘密情報を含めてはならない。さもないと、偽の セション識別子を含むコンテンツにより、セキュリティが侵害される ことになる。(SessionIDを含むすべてのハンドシェイクのコンテンツは、 ハンドシェイクの最後に交換されるFinishedメッセージによって保護 される。) CipherSuiteリストは、ClientHelloメッセージにおいてクライアントから サーバへ送信されるもので、クライアントがサポートしている暗号アルゴ リズムを組合わせたものである。これはクライアントの好みの順で(好みの ものが最初)に指定されている。それぞれのCipherSuiteには、鍵交換アルゴ リズム、大量暗号化アルゴリズム(セキュリティ鍵長を含む)と、MACアル ゴリズムが定義されている。サーバは暗号スイートを選択するが、もし選択 できるものが提示されていない場合、サーバはhandshake_failure アラートを 返してコネクションを終了する。 uint8 CipherSuite[2]; /* 暗号スイートの選択肢 */ ClientHelloには、クライアントによってサポートされている圧縮アルゴリズム のリストが含まれる。これは、クライアントの好みの順番で指定されている。 enum { null(0), (255) } CompressionMethod; struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-1>; CompressionMethod compression_methods<1..2^8-1>; } ClientHello; client_version クライアントがこのセションで通信しようとするTLSのバージョン。 これはクライアントがサポートする最新のもの(最高のもの)である べきである。本仕様書の本バージョンでは、バージョンは3.1になる。 (下位互換性についての詳細は付録Eを参照。) random クライアントが生成したRandom構造体。 session_id クライアントがこのコネクションで使用しようとしているセションID。 session_idが利用可能でない場合、またはクライアントが新しいセキュ リティパラメータを生成しようとする場合には、このフィールドは空で ある。 cipher_suites クライアントによってサポートされている暗号オプションのリスト。 これはクライアントの好みの順で並べられる。もしsession_idフィールド が空でないならば(すなわちセション再利用リクエストを意味する場合)、 このベクトルには少なくとも、そのセションのcipher_suiteが含まれて いなければならない。この値は付録A.5で定義される。 compression_methods クライアントによってサポートされている圧縮アルゴリズムのリスト。 これはクライアントの好みの順で並べられる。もしsession_idフィールド が空でないならば(すなわちセション再利用リクエストを意味する場合)、 そのセションのcompression_methodを含まなければならない。このベクトル には、CompressionMethod.nullを含まなければならず、またすべての 実装においてこれをサポートしなければならない。そのため、クライ アントとサーバは、圧縮方式に関しては常に合意を行うことが出来る。 ClientHelloメッセージを送信した後、クライアントはServerHelloメッセージの 受信を待つ。HelloRequestメッセージを除く、他のハンドシェイクメッセージが サーバから返されたときには、fatalエラーとして処理される。 上位互換性: 上位互換性のために、ClientHelloメッセージの圧縮アルゴリズムの後に 拡張データを含めることができる。このデータはハンドシェイクのハッシュ に含まれなければならないが、その他の場合では無視されなければならない。 このようなことは、ハンドシェイクメッセージの中では唯一ClientHello のみに認められている。他のすべてのメッセージでは、メッセージのデータ 量は、正確にメッセージの規定量に一致していなければならない。 7.4.1.3. ServerHelloメッセージ メッセージが送信されるとき: サーバは、ClientHelloメッセージの応答としてこのメッセージを送信する。 これは、受理可能な一連のアルゴリズムが存在した場合である。もしそのような ものが存在しなかった場合には、handshake_failure アラートで応答する。 メッセージの構造: struct { ProtocolVersion server_version; Random random; SessionID session_id; CipherSuite cipher_suite; CompressionMethod compression_method; } ServerHello; server_version このフィールドは、ClientHelloによりクライアントから提供されている もの以下で、かつサーバでサポートしている最大のものとなる。本仕様の 本バージョンでは、バージョンは3.1である(下位互換性の詳細に関しては、 付録Eを参照)。 random これはサーバにより生成され、ClientHello.randomとは異なる(そして独立 である)必要がある。 session_id このコネクションに関するセション識別子。もしClientHello.session_id が空でなければ、サーバは、一致するIDをキャッシュから探す。もし一致 するIDが見つかり、指定されたセションステータスを使用して新規コネク ションを確立しようとするときには、サーバは、クライアントから送信され てきたIDと同じ値で応答する。これはセションを再利用することを意味し、 両者は直ちにFinishedメッセージへ進まなければならない。そうでない場合 には、このフィールドには別の値を入れ、新規セションであることを示す。 サーバはまた、このフィールドを空で返すことも出来る。これは、セションは キャッシュされず、それゆえ再利用できないことを示す。もしセションが 再利用されたならば、最初にネゴシエーションしたものと同じ暗号スイート を利用しなければならない。 cipher_suite ClientHello.cipher_suitesのリストから、サーバによって選択された 1つの暗号スイート。セションの再利用においては、このフィールドは 再利用されたセションステータスから取得された値が格納される。 compression_method ClientHello.compression_methodsのリストから、サーバによって選択 された1つの圧縮アルゴリズム。セションの再利用においては、この フィールドは再利用されたセションステータスから取得された値が格納 される。 7.4.2. ServerCertificateメッセージ メッセージが送信されるとき: サーバは、クライアントとの間で合意された鍵交換方式が匿名方式でないとき には、サーバ証明書を送信しなければならない。このメッセージは常に、 ServerHelloメッセージの直後に送信される。 メッセージの意味: 送信される証明書は、選択された暗号スイートにおける鍵交換アルゴリズムに 対して、適切なものでなければならない。証明書としては一般に、X.509v3 証明書が使用される。証明書には、以下に示す鍵交換方式に適用される鍵が含ま れていなければならない。特に指定されない限り、証明書で使用されている 署名アルゴリズムは、証明書の鍵として使用されるアルゴリズムと同じでな ければならない。特に指定されない限り、公開鍵はどのような長さでもよい。 鍵交換アルゴリズム 証明書鍵タイプ RSA RSA公開鍵。証明書では、その鍵が暗号化処理に 使用できるようになっていなければならない。 RSA_EXPORT 512ビットより長い鍵長をもつ署名用のRSA 公開鍵、もしくは暗号化と署名処理に使用 できる512ビット以下の鍵長をもつRSA公開鍵。 DHE_DSS DSS公開鍵。 DHE_DSS_EXPORT DSS公開鍵。 DHE_RSA 署名用のRSA公開鍵。 DHE_RSA_EXPORT 署名用のRSA公開鍵。 DH_DSS Diffie-Hellman鍵。証明書に署名するための アルゴリズムはDSSでなければならない。 DH_RSA Diffie-Hellman鍵。証明書に署名するための アルゴリズムはRSAでなければならない。 すべての証明書プロファイル、鍵そして暗号フォーマットは、IETF PKIXワーキ ンググループ [PKIX] によって定義される。鍵用途エクステンションが存在する 場合には、上記のように、署名可能な鍵として使用できるようdigitalSignature ビットが設定されなければならず、また上記のように、暗号化に使用できるよう keyEnciphermentビットが存在しなければならない。 Diffie-Hellman証明書に おいては、keyAgreementビットが設定されていなければならない。 新しい鍵交換方式を指定するCipherSuiteをTLSプロトコルに追加する場合には、 対応する証明書フォーマットと、必要とされる、エンコードされた鍵情報を 指定する。 メッセージの構造: opaque ASN.1Cert<1..2^24-1>; struct { ASN.1Cert certificate_list<0..2^24-1>; } Certificate; certificate_list X.509v3証明書のシーケンス(チェイン)。送信者の証明書がリストの最初 になければならない。それに続く証明書は、前の証明書を直接に証明して いなければならない。証明書の検証を行うには、ルートCAの鍵が別途配布 されている必要があるため、ルートCAを示す自己署名証明書は、この チェインから省略してもよい。これは、通信の他端ではどのような場合 においても証明書の確認ができるよう、ルートCAの証明書をすでに保有し ていることを仮定している。 CertificateRequestメッセージに対応するクライアントからのレスポンスに おいても、同じメッセージタイプと構造が使用される。クライアントは、 サーバの認証リクエストに対するレスポンスを送信する際、適切な証明書を 持っていなければ、証明書を送信しなくても良いことに注意。 注:証明書ベクトルでは、PKCS #7 [PKCS7]フォーマットを使用しない。これは PKCS #6 [PKCS6] 拡張証明書が使用されないからである。またPKCS #7では SEQUENCEではなくSETで定義されているため、リストの解析処理が難しい。 7.4.3. ServerKeyExchangeメッセージ メッセージが送信されるとき: このメッセージは、ServerCertificateメッセージの直後(匿名ネゴシエー ションのときにはServerHelloメッセージの直後)に送信される。 ServerKeyExchangeメッセージは、ServerCertificateメッセージ(これはもし 送信された場合である)に、クライアントとのpremaster_secretの交換に必要な データが含まれていない場合にのみ、サーバから送信される。以下の鍵交換 方式で使用される。 RSA_EXPORT (サーバ証明書の公開鍵が512ビットより長いとき) DHE_DSS DHE_DSS_EXPORT DHE_RSA DHE_RSA_EXPORT DH_anon 以下の鍵交換方式においてServerKeyExchangeメッセージを送信するのは違反 である。 RSA RSA_EXPORT (サーバ証明書の公開鍵が512ビット以下のとき) DH_DSS DH_RSA メッセージの意味: このメッセージは、クライアントがpremaster_secretを送信するのに必要と なる暗号情報を送信する。これはpremaster_secretを暗号化するためのRSA 公開鍵、またはクライアントが鍵交換処理(処理結果がpremaster_secretと なる)を行うことのできるDiffie-Hellman公開鍵のどちらでもよい。 新しい鍵交換アルゴリズムを含むCipherSuiteがTLS用に追加定義されたとき には、ServerKeyExchangeメッセージは、その鍵交換アルゴリズムに関連する 証明書が、クライアントに対してpremaster_secretを交換するのに十分な 情報を提供していない場合のみに送信される。 注 : 現在の米国輸出法では、米国から輸出したソフトウェアにおいては、512 ビットより長いRSAのモジュラスを鍵交換において使用してはならない ことになっている。このメッセージを送信した場合、証明書内に含まれ ている512ビットより長いRSA鍵は、RSA_EXPORT鍵交換方式用の、512ビット 以下の長さを持つ一時的RSA鍵に署名するのに使用される。 メッセージの構造: enum { rsa, diffie_hellman } KeyExchangeAlgorithm; struct { opaque rsa_modulus<1..2^16-1>; opaque rsa_exponent<1..2^16-1>; } ServerRSAParams; rsa_modulus サーバの一時的RSA鍵のモジュラス。 rsa_exponent サーバの一時的RSA鍵の公開指数。 struct { opaque dh_p<1..2^16-1>; opaque dh_g<1..2^16-1>; opaque dh_Ys<1..2^16-1>; } ServerDHParams; /* 一時的 DH パラメータ */ dh_p Diffie-Hellman演算に使用される素数モジュラス。 dh_g Diffie-Hellman演算に使用されるgenerator。 dh_Ys サーバのDiffie-Hellman公開値(g^X mod p)。 struct { select (KeyExchangeAlgorithm) { case diffie_hellman: ServerDHParams params; Signature signed_params; case rsa: ServerRSAParams params; Signature signed_params; }; } ServerKeyExchange; params サーバの鍵交換パラメータ。 signed_params 匿名ではない鍵交換においては、関連するparams値のハッシュ に対して適用された適切な署名。 md5_hash MD5(ClientHello.random + ServerHello.random + ServerParams); sha_hash SHA(ClientHello.random + ServerHello.random + ServerParams); enum { anonymous, rsa, dsa } SignatureAlgorithm; select (SignatureAlgorithm) { case anonymous: struct { }; case rsa: digitally-signed struct { opaque md5_hash[16]; opaque sha_hash[20]; }; case dsa: digitally-signed struct { opaque sha_hash[20]; }; } Signature; 7.4.4. CertificateRequestメッセージ メッセージが送信されるとき: 匿名ではないサーバは、選択された暗号スイートにおいて適切であるならば、 任意でクライアントに対し証明書を要求することができる。 このメッセージ が送信される場合には、ServerKeyExchangeメッセージの直後(または、 ServerCertificateメッセージの直後)に送信される。 メッセージの構造: enum { rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), (255) } ClientCertificateType; opaque DistinguishedName<1..2^16-1>; struct { ClientCertificateType certificate_types<1..2^8-1>; DistinguishedName certificate_authorities<3..2^16-1>; } CertificateRequest; certificate_types 要求される証明書種別のリスト。これはサーバの好みの順に指定 される。 certificate_authorities 受理することのできる認証局のDistinguishedNameのリスト。これらの DistinguishedNameには、必要とされるルートCAや、その下位のCAの DistinguishedNameを指定してもよい。それゆえこのメッセージは、 既知のルートと必要な認証空間を示すのに使用することが出来る。 注:DistinguishedName は [X509]から導入されている。 注:匿名サーバがクライアント証明書を要求した場合には、fatalレベルの handshake_failure アラートとなる。 7.4.5. ServerHelloDoneメッセージ メッセージが送信されるとき: ServerHelloDoneメッセージはサーバから送信されるもので、ServerHello と、それに関連するメッセージの終了を示す。このメッセージを送信した後、 サーバはクライアントからのレスポンスを待つ。 メッセージの意味: このメッセージは、鍵交換をサポートするためのメッセージの送信を、サーバ が完了したことを意味する。そしてクライアント側で、鍵交換フェーズを続行 していくことができる。 ServerHelloDoneメッセージを受信したならば、クライアントは、もしサーバ 認証の必要があるならば、サーバが有効な証明書を提供しているかどうかを検証 するべきである。また、ServerHelloパラメータが受理できるか否かをチェック すべきである。 メッセージの構造: struct { } ServerHelloDone; 7.4.6. ClientCertificateメッセージ メッセージが送信されるとき: これは、ServerHelloDoneメッセージを受信した後に、クライアントが送信 することのできる最初のメッセージである。このメッセージは、サーバが 証明書を要求している場合にのみ送信される。もし適切な証明書がないならば、 クライアントは、証明書を含んでいないClientCertificateメッセージを送信 するべきである。もし、ハンドシェイクを続けるためにはクライアント認証 が必要であるとサーバにより判断されているならば、fatalなhandshake_failure アラートがサーバから返信される。ClientCertificateの送信には、第7.4.2節に 定義されるCertificate構造体を使用する。 注:固定Diffie-Hellmanに基づいた鍵交換方式(DH_DSSまたはDH_RSA)の場合 には、もしクライアント認証が要求されており、またクライアントの パラメータが鍵交換に使用されるときには、クライアント証明書に記載 されているDiffie-Hellman groupとgeneratorは、サーバが指定した Diffie-Hellmanパラメータに合致していなければならない。 7.4.7. ClientKeyExchangeメッセージ メッセージが送信されるとき: このメッセージは、必ずクライアントから送信される。もしClientCertificate メッセージが送信されているならば、このメッセージはそのすぐ後に送信 される。そうでない場合には、クライアントがServerHelloDoneメッセージを 受信した後、最初に送信するメッセージとなる。 メッセージの意味: このメッセージにより、premaster_secretが設定される。これは、RSAにより 暗号化されたsecretを直接送信することにより、または双方が同じ premaster_secretを共有することのできるDiffie-Hellmanパラメータを送信 することにより設定される。鍵交換方式としてDH_RSAまたはDH_DSSを使用した 場合、クライアント証明書が要求されており、またクライアントは、サーバ 証明書に記載されているDiffie-Hellman公開鍵パラメータ(groupと generator)と同じパラメータを持つ証明書を送信することができるならば、 このメッセージには何もデータが含まれない。 メッセージの構造: メッセージは、どの鍵交換方式を選択するかに依存する。第7.4.3節の KeyExchangeAlgorithmの定義を参照のこと。 struct { select (KeyExchangeAlgorithm) { case rsa: EncryptedPreMasterSecret; case diffie_hellman: ClientDiffieHellmanPublic; } exchange_keys; } ClientKeyExchange; 7.4.7.1. RSAを使用したEncryptedPreMasterSecretメッセージ メッセージの意味: 鍵交換と認証方式としてRSAが使用されているならば、クライアントは48 バイトのpremaster_secretを生成し、サーバ証明書から取得した公開鍵、 またはServerKeyExchangeメッセージにて提供される一時的RSA鍵を使用して 暗号化する。その結果をEncryptedPreMasterSecretメッセージに含め送信 する。この構造はClientKeyExchangeメッセージの一種であり、これ自体は 独立したメッセージというわけではない。 メッセージの構造: struct { ProtocolVersion client_version; opaque random[46]; } PreMasterSecret; client_version クライアントがサポートしている、最新のバージョン。これは、 バージョンロールバック攻撃を検出するのに使用される。この premaster_secretを受信すると、サーバは、この値がClientHello メッセージで受信した値と同じであるかをチェックすべきである。 random 安全に生成された46バイトの乱数。 struct { public-key-encrypted PreMasterSecret pre_master_secret; } EncryptedPreMasterSecret; 注:Daniel Bleichenbacher によって発見された攻撃法 [BLEI] では、PKCS #1 でエンコードされたRSAを使用しているTLSサーバへの攻撃が可能である。 その攻撃は、ある特別なメッセージを復号したとき、さまざまな原因で処理 が失敗することにより、メッセージが適切にPKCS #1 フォーマットに従って いるかどうかを、TLSサーバに強制的に明示させることができる、ということ を利用している。 この攻撃に関する弱みを避ける最も良い方法は、正しくフォーマットされた RSAブロックと、不適切にフォーマットされたメッセージを、区別なく扱う ことである。それゆえ、不適切にフォーマットされたRSAブロックを受信 したときには、サーバは48バイトの乱数を生成し、それをpremaster_secret として使用し、処理を続行すべきである。これにより、受信したRSAブロック が正しくエンコードされているか否かに関係なく、サーバは同じ動作を行う ことになる。 pre_master_secret この乱数値はクライアントによって生成され、master_secretを 生成するのに使用される。これは第8.1節で定義される。 7.4.7.2. ClientDiffieHellmanPublic値 メッセージの意味: これは、クライアントのDiffie-Hellman公開値(Yc)が、クライアントの証明書 に含まれていなかった場合に、それを送信するものである。Ycに使用される エンコード方式は、列挙型のPublicValueEncodingによって決定される。 この 構造は独立したメッセージではなく、ClientKeyExchangeメッセージの一種で ある。 メッセージの構造: enum { implicit, explicit } PublicValueEncoding; implicit クライアント証明書に、既に適切なDiffie-Hellman鍵が記載されている ならば、Ycはimplicit(内在)であり、再送する必要はない。この場合、 ClientKeyExchangeメッセージ自体は送信されるものの、中身は空である。 explicit Ycを送信する必要がある。 struct { select (PublicValueEncoding) { case implicit: struct { }; case explicit: opaque dh_Yc<1..2^16-1>; } dh_public; } ClientDiffieHellmanPublic; dh_Yc クライアントのDiffie-Hellman公開値(Yc)。 7.4.8. CertificateVerifyメッセージ メッセージが送信されるとき: このメッセージは、クライアント証明書の検証を行うのに使用される。この メッセージは、署名可能なクライアント証明書(すなわち、固定Diffie-Hellman パラメータを含んた証明書以外のすべての証明書)が送信された後にのみ送信 される。送信される場合には、ClientKeyExchangeメッセージの直後に送信 される。 メッセージの構造: struct { Signature signature; } CertificateVerify; Signature型は第7.4.3節で定義されている。 CertificateVerify.signature.md5_hash MD5(handshake_messages); Certificate.signature.sha_hash SHA(handshake_messages); ここでhandshake_messagesは、ClientHelloメッセージから現在までの、この メッセージを除く、送信または受信したすべてのハンドシェイクメッセージ を表す。各メッセージは、ハンドシェイクメッセージのmsg_typeやlength フィールドを含むものである。そしてこれは、これまでに交換された、 第7.4節で定義されるすべてのハンドシェイク構造体を連鎖させたものである。 7.4.9. Finishedメッセージ メッセージが送信されるとき: Finishedメッセージは、常にChangeCipherSpecメッセージの直後に送信され、 鍵交換と認証処理が成功したことを確認する。他のハンドシェイクメッセージ とFinishedメッセージの間に、ChangeCipherSpecメッセージを受信すること が必要である。 メッセージの意味: Finishedメッセージは、これまでにネゴシエーションされたアルゴリズム、鍵 およびシークレットで保護される最初のメッセージである。Finishedメッセー ジの受信者は、その内容が正しいことを確認しなければならない。一方の側が Finishedメッセージを送信し、またFinishedメッセージを相手から受信して、 そのメッセージを確認すると、そのコネクションを使用したアプリケーション データの送受信が始まる。 struct { opaque verify_data[12]; } Finished; verify_data PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11] finished_label クライアントによって送信されるFinishedメッセージでは、文字列 として"client finished"が使用される。サーバによって送信される Finishedメッセージでは、その文字列は"server finished"である。 handshake_messages このメッセージ以外の、ここまでのすべてのハンドシェイクメッセージ のすべてのデータである。このデータは、ハンドシェイク層のみで見る ことのできるデータのみであり、レコード層のヘッダデータは含まれな い。これまでに交換された、第7.4節で定義されるハンドシェイク構 造体のすべてを連鎖させたものである。 もし、ハンドシェイクの適切な時点において、Finishedメッセージが ChangeCipherSpecメッセージよりも先であったならば、それはfatalエラー である。 サーバによって送信されるFinishedメッセージに含まれるハッシュには、 Sender.serverを組み込む。また、クライアントによって送信されるものには Sender.clientを組み込む。ここでhandshake_messagesは、ClientHelloメッ セージから始まり、このFinishedメッセージを除く、すべてのハンドシェイク メッセージが含まれる。これは、(送信された場合には)CertificateVerify メッセージも含むため、第7.4.8節のhandshake_messagesとは異なるものと なる。また、クライアントから送信されるFinishedメッセージにおける handshake_messagesは、サーバによって送信されるFinishedメッセージの ものとは異なる。それは、後に送信される方は、前に送信されたメッセージを 含むからである。 注:ChangeCipherSpecメッセージ、Alert、そしてその他のレコード型はハンド シェイクメッセージではない。そのためハッシュ計算においてはそれらを 含めない。また、HelloRequestメッセージも、ハッシュ計算には含めない。 8. 暗号計算 コネクションの保護を開始するために、TLSレコードプロトコルでは、一連のアルゴ リズム、マスターシークレット、クライアントおよびサーバ乱数値を必要とする。 認証、暗号化、MACアルゴリズムは、サーバによって選択された暗号スイートに よって決定され、ServerHelloメッセージにおいて確立する。圧縮アルゴリズム は、Helloメッセージにおいてネゴシエーションされる。また乱数値はHello メッセージにおいて交換される。最後は、master_secretを計算することである。 8.1. master_secretの計算 すべての鍵交換方式において、pre_master_secretをmaster_secretへ変換するの に、同一のアルゴリズムが使用される。master_secretが計算されると、 pre_master_secretはメモリ上から削除されるべきである。 master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) [0..47]; master_secretの長さは、常に48バイトである。pre_master_secretの長さは、 鍵交換方式によって異なる。 8.1.1. RSA RSAがサーバ認証と鍵交換に使用されるとき、48バイトのpre_master_secretが クライアントによって生成され、サーバの公開鍵で暗号化されて、サーバに 送信される。サーバは、自身の私有鍵を使用してpre_master_secretを復号する。 そして両方のパーティーは、上記のような方法により、pre_master_secretを master_secretに変換する。 RSAデジタル署名は、PKCS #1 [PKCS1]ブロック型1を使用して実行される。 RSA公開鍵暗号処理は、PKCS #1ブロック型2を使用して実行される。 8.1.2. Diffie-Hellman 従来のDiffie-Hellman計算が実行される。ネゴシエーションされた鍵(Z) はpre_master_secretとして使用され、上記のような方法でmaster_secretに 変換される。 注: Diffie-Hellmanパラメータはサーバによって指定される。そのパラメータ は一時的(ephemeral)なもの、もしくはサーバ証明書に含まれるものの どちらでもよい。 9. 不可欠な暗号スイート 特に指定されない限り、アプリケーションプロフィール標準が存在しない場合 には、TLSに準拠しているアプリケーションでは、暗号スイート TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHAを実装しなければならない(MUST)。 10. アプリケーションデータプロトコル アプリケーションデータメッセージは、カレントのコネクションステータスに 基づいて分割され、圧縮され、暗号化されて、レコード層によって送信される。 メッセージは、レコード層では透過データとして扱われる。 A. プロトコル定数値 この章では、プロトコルの型と定数について示す。 A.1. レコード層 struct { uint8 major, minor; } ProtocolVersion; ProtocolVersion version = { 3, 1 }; /* TLS v1.0 */ enum { change_cipher_spec(20), alert(21), handshake(22), application_data(23), (255) } ContentType; struct { ContentType type; ProtocolVersion version; uint16 length; opaque fragment[TLSPlaintext.length]; } TLSPlaintext; struct { ContentType type; ProtocolVersion version; uint16 length; opaque fragment[TLSCompressed.length]; } TLSCompressed; struct { ContentType type; ProtocolVersion version; uint16 length; select (CipherSpec.cipher_type) { case stream: GenericStreamCipher; case block: GenericBlockCipher; } fragment; } TLSCiphertext; stream-ciphered struct { opaque content[TLSCompressed.length]; opaque MAC[CipherSpec.hash_size]; } GenericStreamCipher; block-ciphered struct { opaque content[TLSCompressed.length]; opaque MAC[CipherSpec.hash_size]; uint8 padding[GenericBlockCipher.padding_length]; uint8 padding_length; } GenericBlockCipher; A.2. ChangeCipherSpecメッセージ struct { enum { change_cipher_spec(1), (255) } type; } ChangeCipherSpec; A.3. Alertメッセージ enum { warning(1), fatal(2), (255) } AlertLevel; enum { close_notify(0), unexpected_message(10), bad_record_mac(20), decryption_failed(21), record_overflow(22), decompression_failure(30), handshake_failure(40), 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(60), protocol_version(70), insufficient_security(71), internal_error(80), user_canceled(90), no_renegotiation(100), (255) } AlertDescription; struct { AlertLevel level; AlertDescription description; } Alert; A.4. ハンドシェイクプロトコル 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; 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; } body; } Handshake; A.4.1. 各種Helloメッセージ struct { } HelloRequest; struct { uint32 gmt_unix_time; opaque random_bytes[28]; } Random; opaque SessionID<0..32>; uint8 CipherSuite[2]; enum { null(0), (255) } CompressionMethod; struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-1>; CompressionMethod compression_methods<1..2^8-1>; } ClientHello; struct { ProtocolVersion server_version; Random random; SessionID session_id; CipherSuite cipher_suite; CompressionMethod compression_method; } ServerHello; A.4.2. サーバ認証と各種鍵交換メッセージ opaque ASN.1Cert<2^24-1>; struct { ASN.1Cert certificate_list<1..2^24-1>; } Certificate; enum { rsa, diffie_hellman } KeyExchangeAlgorithm; struct { opaque RSA_modulus<1..2^16-1>; opaque RSA_exponent<1..2^16-1>; } ServerRSAParams; struct { opaque DH_p<1..2^16-1>; opaque DH_g<1..2^16-1>; opaque DH_Ys<1..2^16-1>; } ServerDHParams; struct { select (KeyExchangeAlgorithm) { case diffie_hellman: ServerDHParams params; Signature signed_params; case rsa: ServerRSAParams params; Signature signed_params; }; } ServerKeyExchange; enum { anonymous, rsa, dsa } SignatureAlgorithm; select (SignatureAlgorithm) { case anonymous: struct { }; case rsa: digitally-signed struct { opaque md5_hash[16]; opaque sha_hash[20]; }; case dsa: digitally-signed struct { opaque sha_hash[20]; }; } Signature; enum { rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), (255) } ClientCertificateType; opaque DistinguishedName<1..2^16-1>; struct { ClientCertificateType certificate_types<1..2^8-1>; DistinguishedName certificate_authorities<3..2^16-1>; } CertificateRequest; struct { } ServerHelloDone; A.4.3. クライアント認証と各種鍵交換メッセージ struct { select (KeyExchangeAlgorithm) { case rsa: EncryptedPreMasterSecret; case diffie_hellman: DiffieHellmanClientPublicValue; } exchange_keys; } ClientKeyExchange; struct { ProtocolVersion client_version; opaque random[46]; } PreMasterSecret; struct { public-key-encrypted PreMasterSecret pre_master_secret; } EncryptedPreMasterSecret; enum { implicit, explicit } PublicValueEncoding; struct { select (PublicValueEncoding) { case implicit: struct {}; case explicit: opaque DH_Yc<1..2^16-1>; } dh_public; } ClientDiffieHellmanPublic; struct { Signature signature; } CertificateVerify; A.4.4. Finishedメッセージ struct { opaque verify_data[12]; } Finished; A.5. 暗号スイート 以下では、ClientHelloとServerHelloメッセージで使用されるCipherSuite コードを定義する。 またそれぞれのCipherSuiteは、TLSバージョン1.0でサポートされる暗号仕様を 定義する。 TLS_NULL_WITH_NULL_NULLが定義され、またこれはTLSコネクションの最初の ハンドシェイクにおける初期状態とされるが、ネゴシエーションにおいてこれを 選択してはならない。なぜならば、これはコネクションを保護しないからである。 CipherSuite TLS_NULL_WITH_NULL_NULL = { 0x00,0x00 }; 以下のCipherSuite定義では、鍵交換に使用することのできるRSA証明書をサーバが 提供する必要がある。 サーバは、CertificateRequestメッセージにおいて、 RSAまたはDSSのどちらかの、署名可能な証明書を要求することができる。 CipherSuite TLS_RSA_WITH_NULL_MD5 = { 0x00,0x01 }; CipherSuite TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 }; CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x03 }; CipherSuite TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 }; CipherSuite TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 }; CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x06 }; CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00,0x07 }; CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x08 }; CipherSuite TLS_RSA_WITH_DES_CBC_SHA = { 0x00,0x09 }; CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0A }; 以下のCipherSuite定義は、サーバにより認証された(または任意で、クライ アントにより認証された)Diffie-Hellmanに使用される。DHは、認証局(CA)に よって署名されたサーバ証明書に含まれているDiffie-Hellmanパラメータを 使用した暗号スイートを示すものである。DHEは、CAによって署名されたDSS またはRSA証明書により署名されたDiffie-Hellmanパラメータを使用した一時的 Diffie-Hellmanを示すものである。使用される署名アルゴリズムは、DHまたは DHEパラメータの後に指定される。サーバは、クライアント認証を行うために、 クライアントに対してRSAまたはDSSの署名可能な証明書、またはDiffie-Hellman 証明書を要求することができる。クライアントによってDiffie-Hellman証明書が 提供された場合には、サーバによって指定されたパラメータ(groupとgenerator) を使用しなければならない。 CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0B }; CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00,0x0C }; CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D }; CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0E }; CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00,0x0F }; CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 }; CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 }; CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00,0x12 }; CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 }; CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 }; CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00,0x15 }; CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 }; 以下の暗号スイートは、どちら側のパーティーも認証されることのない、完全に 匿名なDiffie-Hellman通信に使用される。このモードは、なりすまし攻撃を受け やすいため、推奨されないことに注意。 CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x17 }; CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 }; CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 }; CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00,0x1A }; CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1B }; 注:最初のバイトが0xFFであるすべての暗号スイートは、プライベートなものと されており、ローカルまたは実験的アルゴリズムを定義するのに使用する ことができる。そのような暗号スイートの共同利用は、そのローカルにお ける問題である。 注:暗号スイートを指定したRFCを発行することにより、暗号スイートを追加登録 することができる。そのRFCには、必要なTLSプロトコル情報、すなわちメッ セージエンコード、プレマスターシークレット生成方法、対称暗号とMAC計算、 およびそのアルゴリズムにおいて適切な参照情報を記述する。RFCを編集する オフィスでは、その暗号スイートが技術的に有用で、また完全に仕様が決定 されていることがわかれば、(例えば機密扱いのアルゴリズムなどの)完全に は仕様が公開されない暗号スイートに対する仕様書の発行の可否を、オフィス の裁量により選択することができる。 注:暗号化スイート値 {0x00、0x1C} と {0x00、0x1D} は、SSL 3 における Fortezza ベースの暗号化スイートとの衝突を避けるために予約されている。 A.6. セキュリティパラメータ これらのセキュリティパラメータは、TLSハンドシェイクプロトコルで決定され、 コネクションステータスを初期化するためのパラメータとして、TLSレコード層 へ渡される。SecurityParametersには、以下のものが含まれる。 enum { null(0), (255) } CompressionMethod; enum { server, client } ConnectionEnd; enum { null, rc4, rc2, des, 3des, des40, idea } BulkCipherAlgorithm; enum { stream, block } CipherType; enum { true, false } IsExportable; enum { null, md5, sha } MACAlgorithm; /* CompressionMethod、BulkCipherAlgorithmとMACAlgorithm で指定されるアルゴリズムは追加が可能である。*/ struct { ConnectionEnd entity; BulkCipherAlgorithm bulk_cipher_algorithm; CipherType cipher_type; uint8 key_size; uint8 key_material_length; IsExportable is_exportable; MACAlgorithm mac_algorithm; uint8 hash_size; CompressionMethod compression_algorithm; opaque master_secret[48]; opaque client_random[32]; opaque server_random[32]; } SecurityParameters; B. 用語集 アプリケーションプロトコル アプリケーションプロトコルは通常、トランスポート層(例えば、TCP/IP) のすぐ上位の層にあるプロトコルである。 例えば、HTTP、TELNET、FTP、 SMTPなどが挙げられる。 非対称暗号 公開鍵暗号の項を参照。 認証 認証とは、あるエンティティが、他のエンティティのアイデンティティを 決定する能力である。 ブロック暗号 ブロック暗号は、平文に対し、ブロックと呼ばれるビットのグループ単位で 処理を行うアルゴリズムである。ブロックサイズは通常64ビットである。 大量暗号 大量のデータを暗号化するのに使用される対称暗号アルゴリズム。 暗号ブロックチェーン(cipher block chaining: CBC) CBCとは、ブロック暗号で暗号化されるすべての平文ブロックが、1つ前の 暗号文ブロック(最初のブロックの場合は初期ベクトル)と、排他的OR 処理されるモードのことである。 復号処理においては、すべてのブロック はまず復号された後、1つ前の暗号文ブロック(または初期ベクトル)と 排他的OR処理される。 証明書 (ISO認証フレームワークとして知られている)X.509プロトコルの一部 として、証明書は信用のおける認証局によって割り当てられ、パーティーの アイデンティティまたはその他の属性と公開鍵との間を、強く関連付ける。 クライアント サーバに対してTLSコネクションを開始するアプリケーションエンティティ。 これには、クライアントが、ベースとなる転送コネクションを開始することが 含まれていてもいなくてもよい。サーバとクライアントの主要な操作上の 違いは、サーバは通常認証されるが、クライアントの認証は任意で行われる ことである。 クライアント書き出し鍵 データを暗号化し送信するためにクライアントが使用する鍵。 クライアント書き出しMACシークレット データを認証するためにクライアントが使用するシークレットデータ。 コネクション コネクションは、適切なサービスを提供する、(OSI階層モデル定義におい ての)トランスポート(転送)のことである。TLSにおいては、そのような コネクションはピアツーピア関係をもつ。コネクションは一時的である。 すべてのコネクションは、1つのセションと関連づけられる。 データ暗号化標準(Data Encryption Standard:DES) DESは非常に広く使用されている対称暗号アルゴリズムである。DESはブ ロック暗号で、鍵長は56ビット、ブロックサイズは8バイトである。TLSに おいては、鍵生成目的のために、DESは8バイト(64ビット)の鍵長をもつ ものとされる。しかしそれでも、56ビットの保護のみ提供される(それ ぞれの鍵バイトにおける最下位ビットは、その鍵バイトにおける奇数パリ ティを生成するように設定される)。DESはまた、3個の独立した鍵と3回の 暗号化をそれぞれのブロックのデータに対して適用することができる。 これは168ビット(TLSの鍵生成方式においては24バイト)の鍵を使用し、 112ビットのセキュリティと同等のセキュリティを提供する[DES], [3DES]。 デジタル署名標準(Digital Signature Standard :DSS) デジタル署名アルゴリズム(Digital Signing Algorithm:DSA)を含むデジ タル署名規格で、NIST(National Institute of Standards and Technology) により承認され、1994年5月に米国商務省より発行された、NIST FIPS PUB 186、「デジタル署名標準」で定義される[DSS]。 デジタル署名 デジタル署名は、公開鍵暗号と一方向ハッシュ関数を使用して、認証 が可能であり、また偽造、否認が困難であるような、データの署名を 作成することである。 ハンドシェイク トランザクションのパラメータを確立するために、クライアントとサーバの 間で行われる初期ネゴシエーション。 初期ベクトル(Initialization Vector : IV) ブロック暗号がCBCモードで使用されるときには、暗号化が行われる前に、 初期ベクトルと最初の平文ブロックとで排他的OR処理が行われる。 IDEA Xuejia LaiとJames Masseyによって設計された、64ビットブロック暗号 [IDEA]。 メッセージ認証コード(Message Authentication Code : MAC) メッセージ認証コードは、メッセージとシークレットデータから計算された 一方向ハッシュである。シークレットデータなしに偽造するのは困難 である。メッセージの改竄を検出するのがその目的である。 マスターシークレット 暗号化鍵、MACシークレット、IVを生成するための、安全なシークレット データ。 MD5 MD5は安全なハッシュ関数で、任意長のデータストリームを固定長(16 バイト)のダイジェストに変換する [MD5]。 公開鍵暗号 2個の鍵を使用する暗号技術の1分野。公開鍵で暗号化されたメッセージは、 関連する私有鍵でのみ復号することができる。逆に、私有鍵により署名 されたメッセージは、公開鍵を使用して検証することができる。 一方向ハッシュ関数 任意量のデータを固定長ハッシュに変換する一方向変換。逆変換や、衝突 を発見するのは困難である。MD5とSHAが一方向ハッシュ関数の例として 挙げられる。 RC2 [RC2] において記述されている、RSA Data Security, Inc [RSADSI] の Ron Rivestにより開発されたブロック暗号。 RC4 RSA Data Security [RSADSI] によってライセンスされるストリーム暗号。 RC4と互換性をもつ暗号は、[RC4]に示されている。 RSA 非常に広く使用されている公開鍵アルゴリズム暗号で、暗号化、デジタル 署名のどちらにも使用することができる [RSA]。 ソルト 秘密ではない乱数データで、輸出可能な暗号化鍵を、事前計算攻撃に対抗 できるようにするために使用される。 サーバ サーバとは、クライアントからのコネクションリクエストに応じるアプリ ケーションエンティティである。下記のクライアントの項を参照。 セション TLSセションは、クライアントとサーバとの関連付けである。セションは ハンドシェイクプロトコルによって生成される。セションでは、1つの暗号 セキュリティパラメータセットを定義する。このパラメータは複数のコネ クションにより共有することができる。セションは、それぞれのコネク ションにおいて新しいセキュリティパラメータをネゴシエーションする、 という高負荷処理を避けるのに使用される。 セション識別子 セション識別子は、サーバによって生成される値で、特定のセションを 識別するためのものである。 サーバ書き出し鍵 データを暗号化し送信するためにサーバが使用する鍵。 サーバ書き出しMACシークレット データを認証するためにサーバが使用するシークレットデータ。 SHA(Secure Hash Algorithm) SHAは、FIPS PUB 180-1で定義されている。これは20バイトのデータを出力 する。SHAと記載されているものはすべて、実際にはこれを修正したSHA-1 アルゴリズムを使用していることに注意 [SHA]。 SSL Netscape社の、Secure Socket Layer プロトコル[SSL3]。TLSは、SSL バージョン3.0をベースにしている。 ストリーム暗号 暗号化鍵を、暗号的に強度な鍵ストリームに変換する暗号化アルゴリズム。 その後平文と排他的OR処理を行う。 対称暗号 大量暗号の項を参照。 Transport Layer Security (TLS) 本プロトコル、またはInternet Engineering Task Force(IETF)の Transport Layer Securityワーキンググループのこと。本ドキュメントの 最後の「コメント」の項を参照。 C. 暗号スイートの定義 暗号スイート 輸出可能 鍵交換 暗号 ハッシュ TLS_NULL_WITH_NULL_NULL * NULL NULL NULL TLS_RSA_WITH_NULL_MD5 * RSA NULL MD5 TLS_RSA_WITH_NULL_SHA * RSA NULL SHA TLS_RSA_EXPORT_WITH_RC4_40_MD5 * RSA_EXPORT RC4_40 MD5 TLS_RSA_WITH_RC4_128_MD5 RSA RC4_128 MD5 TLS_RSA_WITH_RC4_128_SHA RSA RC4_128 SHA TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 * RSA_EXPORT RC2_CBC_40 MD5 TLS_RSA_WITH_IDEA_CBC_SHA RSA IDEA_CBC SHA TLS_RSA_EXPORT_WITH_DES40_CBC_SHA * RSA_EXPORT DES40_CBC SHA TLS_RSA_WITH_DES_CBC_SHA RSA DES_CBC SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA RSA 3DES_EDE_CBC SHA TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA * DH_DSS_EXPORT DES40_CBC SHA TLS_DH_DSS_WITH_DES_CBC_SHA DH_DSS DES_CBC SHA TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA DH_DSS 3DES_EDE_CBC SHA TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA * DH_RSA_EXPORT DES40_CBC SHA TLS_DH_RSA_WITH_DES_CBC_SHA DH_RSA DES_CBC SHA TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA DH_RSA 3DES_EDE_CBC SHA TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA * DHE_DSS_EXPORT DES40_CBC SHA TLS_DHE_DSS_WITH_DES_CBC_SHA DHE_DSS DES_CBC SHA TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA DHE_DSS 3DES_EDE_CBC SHA TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA * DHE_RSA_EXPORT DES40_CBC SHA TLS_DHE_RSA_WITH_DES_CBC_SHA DHE_RSA DES_CBC SHA TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA DHE_RSA 3DES_EDE_CBC SHA TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 * DH_anon_EXPORT RC4_40 MD5 TLS_DH_anon_WITH_RC4_128_MD5 DH_anon RC4_128 MD5 TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA DH_anon DES40_CBC SHA TLS_DH_anon_WITH_DES_CBC_SHA DH_anon DES_CBC SHA TLS_DH_anon_WITH_3DES_EDE_CBC_SHA DH_anon 3DES_EDE_CBC SHA * は、IsExportableがtrueであることを示す。 鍵交換 アルゴリズム 説明 鍵サイズ制限 DHE_DSS DSS署名を使用した一時的DH なし DHE_DSS_EXPORT DSS署名を使用した一時的DH DH = 512ビット DHE_RSA RSA署名を使用した一時的DH なし DHE_RSA_EXPORT RSA署名を使用した一時的DH DH = 512ビット RSA = なし DH_anon 匿名DH、署名なし なし DH_anon_EXPORT 匿名DH、署名なし DH = 512ビット DH_DSS DSSベースの証明書を使用したDH なし DH_DSS_EXPORT DSSベースの証明書を使用したDH DH = 512ビット DH_RSA RSAベースの証明書を使用したDH なし DH_RSA_EXPORT RSAベースの証明書を使用したDH DH = 512ビット RSA = なし NULL 鍵交換なし N/A RSA RSA鍵交換 なし RSA_EXPORT RSA鍵交換 RSA = 512ビット 鍵サイズ制限 鍵サイズ制限により、輸出可能な暗号スイートを使用して行う暗号化処理 において法律上適用が可能な、最大の公開鍵サイズが決定される。 鍵 拡張鍵 マテリ マテリ 有効鍵 IV ブロック 暗号 型 アル アル ビット サイズ サイズ NULL * Stream 0 0 0 0 N/A IDEA_CBC Block 16 16 128 8 8 RC2_CBC_40 * Block 5 16 40 8 8 RC4_40 * Stream 5 16 40 0 N/A RC4_128 Stream 16 16 128 0 N/A DES40_CBC * Block 5 8 40 8 8 DES_CBC Block 8 8 56 8 8 3DES_EDE_CBC Block 24 24 168 8 8 * は、IsExportableがtrueであることを示す。 型 ストリーム暗号であるか、CBCモードで実行されるブロック暗号であるか を示す。 鍵マテリアル 書き出し鍵を生成するのに使用されるkey_blockのバイト数。 拡張鍵マテリアル 実際に暗号化アルゴリズムに提供されるバイト数。 有効鍵ビット 暗号化ルーチンに提供される鍵マテリアルのエントロピー量。 IV サイズ 初期ベクトルを生成するのに必要なデータ量。ストリーム暗号ではゼロ である。ブロック暗号ではブロックサイズと同じである。 ブロックサイズ 1つのチャンクにおいて、ブロック暗号が暗号化を行うデータ量。CBCモード のブロック暗号では、ブロックサイズの整数倍長のデータのみを暗号化 することができる。 ハッシュ ハッシュ パディング 関数 サイズ サイズ NULL 0 0 MD5 16 48 SHA 20 40 D. 実装上の注意 TLSプロトコルでは、多くの一般的なセキュリティミスを防ぐことはできない。 この章では、実装者のためのさまざまな推奨事項を示す。 D.1. 一時的RSA鍵 米国の輸出制限では、暗号化処理に使用可能なRSA鍵は512ビットまでに制限され ているが、署名処理に使用可能なRSA鍵の長さには制限を設けていない。証明書 では、512ビットより長いビット長が必要となる場合がある。なぜならば、512 ビットのRSA鍵では、高額のトランザクションや、長期のセキュリティを必要と するアプリケーションでは、十分に安全であるとは言えないからである。また ある証明書では、署名目的のみと指定されている場合がある。この場合、鍵交換 においてこの証明書を使用することはできない。 証明書に記載されている公開鍵が暗号化処理に使用できない場合には、サーバ は一時的RSA鍵に署名し、その鍵を交換する。輸出可能なアプリケーションにお いては、一時的RSA鍵は、許容される最大の長さ(すなわち、512ビット)である べきである。 512ビットのRSA鍵はそれほど安全ではないので、一時的RSA鍵は ときどき変更するべきである。 典型的な電子商取引アプリケーションにおい ては、その鍵は一日ごと、または500トランザクションごと、できればそれ以上 の頻度で変更することを提案する。多くのトランザクションに対して、同じ 一時的鍵を使用することが出来るが、この鍵は、使用されるごとに署名されな ければならないということに注意すべきである。 RSA鍵生成処理には、かなりの時間を要する。多くの場合、鍵生成タスクは、 低い優先度をもつプロセスに対して割り当てられる。 新しい鍵が生成されたときには、これまでの一時的鍵を新しいものと取り替える ことができる。 D.2. 乱数生成とその種 TLSでは、暗号的に安全な擬似乱数生成器(pseudorandom number generator:PRNG) が必要である。PRNGの設計と種の生成は、十分に注意すべきである。セキュア ハッシュで最も有名なのはMD5とSHAであるが、これに基づくPRNGは許容すること ができる。しかし、乱数発生器ステータスのサイズより高いセキュリティを提供 することはできない。 (例えば、MD5ベースのPRNGは通常、128ビットステータス を提供する。) 生成する種の量を推定するために、それぞれの種バイトにおける予測すること のできない情報のビット数を加える。例えば、PCと互換性のある18.2Hzのタイマ から取得されたキーストロークタイミング値により、カウンタ値の全サイズが 16ビット以上であっても、1または2ビットの安全なビットが取得できる。 それゆえ、128ビットPRNGに対する種を生成するには、100個程度のそのような タイマ値が必要となることになる。 警告: RSAREFと、バージョン3.0より前のBSAFEの種関数は、順序非依存である。 例えば、種関数を1000回呼び出し、1度に1個、1000個の種ビットが提供 されるとき、PRNGは種データにおける種ビットの、0または1の数のみに 依存するステータスで終了する(すなわち、1001個の終了ステータスが 存在する)。BSAFEまたはRSAREFを使用しているアプリケーションでは、 適切な種処理がされていることに特に注意を払わなければならない。 これは、種ビットをバッファに蓄積しておき、すべてを一度に処理する、 もしくはすべての種ビットに対応する増加カウンタを使用することにより 実現される。どちらの方法も、種処理に関して順序依存性を導入する ものである。 D.3. 証明書と認証 実装においては、証明書の有効性について検証する責任があり、また一般に、 証明書失効メッセージをサポートするべきである。 証明書が信用のおける認証局に よって適切に署名されていることを、常に確認するべきである。信用のおけるCAの 選択と追加については、十分に気をつけるべきである。ユーザに対し、証明書に 関する情報と、ルートCAに関する情報を見ることができるようにするべきである。 D.4. 暗号スイート TLSでは、さまざまな鍵サイズとセキュリティレベルをサポートしている。これ には、セキュリティなし、すなわち最小のセキュリティ提供も含まれる。適切な 実装においてはおそらく、それほど多くの暗号スイートをサポートしないであろう。 例えば、40ビットの暗号化では容易に解読されてしまうので、高いセキュリティ が要求される実装では40ビットの鍵を認めるべきでない。同様に、匿名Diffie- Hellmanでは、なりすまし攻撃を防ぐことができないので、全く推奨されない。 また、アプリケーションでは最小と最大の鍵サイズを強制するようにするべき である。例えば、512ビットのRSA鍵または署名を含む証明書チェーンは、 高セキュリティアプリケーションにおいては適切ではない。 E. SSLの下位互換 歴史的な理由と、予約されるポート番号をいたずらに消費することを避けるために、 TLS 1.0、SSL 3.0、SSL 2.0によるセキュリティを持つアプリケーションプロト コルは、1つのコネクションポートを共有する。例えば、httpsプロトコル(SSL またはTLSによるセキュリティを持つHTTP)は、使用しているセキュリティプロ トコルにかかわらず、ポート443を使用する。したがって、様々なプロトコルを 区別し、ネゴシエーションするために、何らかのメカニズムが決定されなければ ならない。 TLSバージョン1.0とSSL 3.0は非常によく似ている。したがって、両方をサポート するのは簡単である。SSL 3.0をサポートするサーバとネゴシエーションしよう としているTLSクライアントは、SSL 3.0のレコードフォーマットとClientHello 構造体を使用し、バージョンフィールドに{3、1}、すなわちTLS 1.0をサポート しているということを知らせるClientHelloメッセージを送信するべきである。 もしサーバがSSL 3.0だけをサポートしている場合、サーバはSSL 3.0の ServerHelloで応答する。サーバがTLSをサポートしている場合には、TLSの ServerHelloで応答する。そして、ネゴシエーションはそのプロトコルで適切に 処理される。 同様に、SSL 3.0クライアントと通信しようとするTLSサーバは、もし SSL 3.0 のClientHelloを受信し、そのバージョンフィールドが{3, 0}であった場合、 すなわちこのクライアントはTLSをサポートしていないことが示されていた場合、 SSL 3.0のClientHelloメッセージを受理し、SSL 3.0のServerHelloメッセージ で応答すべきである。 クライアントが既に、サーバの最も高いプロトコルを知っている(例えば、 セションを再利用するときなどの)場合には、そのプロトコルを使用してコネ クションを開始するべきである。 SSLバージョン2.0をサポートしているTLS 1.0クライアントは、SSLバージョン 2.0 の ClientHelloメッセージを送信しなければならない[SSL2]。TLSサーバは、 もし同じコネクションポートでSSL 2.0クライアントをサポートしようとする ならば、どちらのClientHelloも受理するべきである。バージョン 2.0の仕様と 異なっている点は、バージョンの値が3であることを特定する能力と、CipherSpec で指定される暗号タイプがより多いことだけである。 警告:バージョン2.0のClientHelloメッセージを送信する機能は、迅速に、 段階的に廃止されるだろう。実装者はできるだけ早く、アップデート するためのあらゆる努力をするべきである。バージョン3.0では、より 新しいバージョンにアップデートするための、より良いメカニズムを 提供している。 以下の暗号仕様は、SSLバージョン2.0から引き継がれたものである。これらは 鍵交換と認証において、RSAを使用するものと仮定している。 V2CipherSpec TLS_RC4_128_WITH_MD5 = { 0x01,0x00,0x80 }; V2CipherSpec TLS_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 }; V2CipherSpec TLS_RC2_CBC_128_CBC_WITH_MD5 = { 0x03,0x00,0x80 }; V2CipherSpec TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 = { 0x04,0x00,0x80 }; V2CipherSpec TLS_IDEA_128_CBC_WITH_MD5 = { 0x05,0x00,0x80 }; V2CipherSpec TLS_DES_64_CBC_WITH_MD5 = { 0x06,0x00,0x40 }; V2CipherSpec TLS_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 }; TLS特有の暗号仕様は、以下の構文を使用することにより、バージョン2.0の ClientHelloメッセージに含めることができる。最初のバイトがゼロである V2CipherSpecの要素は、バージョン2.0サーバによって無視される。上記の V2CipherSpecsを送信するクライアントはまた、TLSにおける同等の値を含める べきである(付録 A.5を参照)。 V2CipherSpec (see TLS name) = { 0x00, CipherSuite }; E.1. バージョン2のClientHello バージョン2.0のClientHelloメッセージは、本ドキュメントでのプレゼンテー ションモデルを使用して、以下のように表される。真の定義は、SSLバージョン 2.0仕様書に記載されている。 uint8 V2CipherSpec[3]; struct { uint8 msg_type; Version version; uint16 cipher_spec_length; uint16 session_id_length; uint16 challenge_length; V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length]; opaque session_id[V2ClientHello.session_id_length]; Random challenge; } V2ClientHello; msg_type このフィールドは、versionフィールドと関連して、バージョン2の ClientHelloメッセージであることを示す。この値は1であるべきである。 version クライアントによってサポートされた最も高いプロトコルバージョン (これはProtocolVersion.versionに等しい。付録 A.1を参照)。 cipher_spec_length cipher_specsフィールドの長さ。ゼロであってはならず、V2CipherSpec の長さ(3)の倍数でなければならない。 session_id_length このフィールドの値は0または16でなければならない。もし0であれば、 クライアントは新規セションを生成していることを示す。もし16で あれば、session_idフィールドには16バイトのセション識別子が格納 される。 challenge_length サーバ認証のために、クライアントがサーバへ送信するchallengeの バイト長。これは32でなければならない。 cipher_specs クライアントが使用を望んでいる、また使用可能なすべてのCipherSpec のリストを表す。ここには少なくとも、サーバが受理可能な1つの CipherSpecがなければならない。 session_id もしこのフィールドの長さが0でなければ、ここにはクライアントが 再利用したいと望んでいるセション識別子が格納される。 challenge サーバを認証するための、サーバへの、サーバのためのクライアント challengeで、(おおよそ)任意長の乱数である。TLSサーバは本プロト コル規定に従い、challengeデータをClientHello.randomデータに 変更する(必要であれば、0をパディングする)。challengeの長さ が32バイトよりも長いときは、後ろの32バイトのみを使用する。 V3サーバが、16バイト未満のchallengeデータを含むV2のClientHelloを 拒絶することは認められる(ただし必要というわけではない)。 注: TLSセションの再利用リクエストでは、TLSのClientHelloを使用すべきで ある。 E.2. なりすましによるバージョンロールバック攻撃の回避 TLSクライアントがバージョン2.0との互換モードになった場合には、クライアント は特別な PKCS #1 ブロックフォーマットを使用すべきである。これを行うことに より、TLSサーバは、TLSが実行可能なクライアントとの間でのバージョン2.0 セションを拒否することができる。 TLSクライアントがバージョン2.0との互換モードであるときには、CLIENT-MASTER-KEY メッセージのENCRYPTED-KEY-DATAフィールドをRSAにより暗号化する際に、PKCS パディング(パディングの最後のNULLを含まない)における右側(最下位)の 8つのランダムバイトを0x03にセットする(他のパディングバイトはランダムで ある)。ENCRYPTED-KEY-DATAフィールドを復号した後、TLSをサポートするサーバ では、それら8つのパディングバイトが0x03であればエラーとすべきである。 バージョン2.0をサポートするサーバがこの方法によるパディングブロックを 受信したときには、通常通りの処理が行われる。 F. セキュリティ解析 TLSプロトコルは、安全ではないチャネル上で通信するクライアントとサーバとの 間で、安全なコネクションを確立するように設計されている。このドキュメント では、さまざまな伝統的仮定を行っている。これらの仮定には、攻撃者がかなりの コンピュータリソースを持っており、プロトコルの外からはシークレット情報を 得ることができないという仮定が含まれている。攻撃者は、通信チャネル上を 送信されるメッセージを捕獲し、変更し、削除し、再送し、その他みだりにいじり まわす能力を持っていると仮定している。この付録では、TLSがさまざまな攻撃に 耐えるためにどのように設計されているのかを概説する。 F.1. ハンドシェイクプロトコル ハンドシェイクプロトコルは、CipherSpecを選択し、マスターシークレットを 生成する。そしてこれらにより、安全なセションに関する主要な暗号パラメータ が生成される。ハンドシェイクプロトコルはまた、信用のおける認証局によって 署名された証明書を持つパーティー間での認証を、任意で行うことができる。 F.1.1. 認証と鍵交換 TLSは3つの認証モードをサポートしている: 双方の認証、サーバ認証と認証 されないクライアント、および完全な匿名である。サーバが認証されるときは、 そのチャネルはなりすまし攻撃に対しては安全であるが、完全な匿名セション では性質上そのような攻撃にさらされやすい。匿名サーバはクライアントを認証 することはできない。もしサーバが認証されるときは、その証明書メッセージは、 信用のおける認証局へ通じる、有効な認証局チェーンを提供していなければなら ない。同様に、認証されるクライアントは、サーバで受理することのできる証明 書を提示しなければならない。それぞれのパーティーでは、相手の証明書が有効 であり、期間が切れていないか、または取り消されていないか、ということを 確認する責任がある。 鍵交換プロセスの一般的な目的は、攻撃者との間ではなく、通信を行っている パーティーとの間でのみ、pre_master_secretを生成することである。 pre_master_secretは、master_secretを生成するのに使用される(第8.1章を参照)。 master_secretは、CertificateVerifyとFinishedメッセージ、暗号化鍵、MAC シークレットを生成するために必要である(第7.4.8、第7.4.9章、第6.3章を参照)。 正しいFinishedメッセージを送信することにより、2つのパーティーは、正確な pre_master_secretを知っていることを確認する。 F.1.1.1. 匿名鍵交換 鍵交換においてRSAまたはDiffie-Hellmanを使用することで、完全に匿名な セションを確立することができる。匿名RSAでは、クライアントはServerKeyExchange メッセージから抽出された、認証のされていないサーバの公開鍵を使用して pre_master_secretを暗号化する。処理結果は、ClientKeyExchangeメッセージで 送信される。盗聴者はサーバの私有鍵を知らないため、盗聴者がpre_master_secret を復号することは不可能である。(ただし、本ドキュメントでは匿名RSA暗号 スイートは定義されていない。) Diffie-Hellmanでは、サーバの公開パラメータはServerKeyExchangeメッセージ に含まれ、クライアントのパラメータはClientKeyExchangeメッセージで送信 される。私有値を知らない盗聴者は、Diffie-Hellman結果(すなわち pre_master_secret)を知ることは出来ない。 警告:完全に匿名なコネクションでは、受動的な盗聴者に対する保護しか提供 されない。改竄の行われない独立したチャネルを使用してFinishedメッ セージが攻撃者により置きかえられてはいないことを確認しない限り、 能動的ななりすまし攻撃の懸念がある環境では、サーバ認証が必要と なる。 F.1.1.2. RSA鍵交換と認証 RSAでは、鍵交換とサーバ認証には関連がある。公開鍵はサーバ証明書に含まれ ているものか、またはServerKeyExchangeメッセージで送信される一時的RSA 鍵である。一時的RSA鍵を使用した場合には、それらはサーバのRSAまたはDSS 証明書により署名される。署名には、カレントのClientHello.randomが含まれる。 そのため、古い署名や古い一時的鍵は再利用できない。サーバは1つの一時的RSA 鍵を、複数のネゴシエーションセションに使用することが出来る。 注:一時的RSA鍵オプションは、サーバでは長いビット長をもつ証明書が必要で あるが、鍵交換処理においては政府により規制された鍵長制限に従わなければ ならない場合に有効である。 サーバ証明書の検証後、クライアントはpre_master_secretをサーバの公開鍵 で暗号化する。pre_master_secretを復号し、それにより正しいFinishedメッ セージを生成することにより、サーバはサーバ証明書に対応する私有鍵を 知っていることを実証する。 鍵交換方式としてRSAを使用した際には、クライアントはCertificateVerify メッセージ(第7.4.8節参照)により認証される。クライアントは、master_secret とこれまでのすべてのハンドシェイクメッセージから得られた値に対して署名 を行う。これらのハンドシェイクメッセージには、ServerCertificateと ServerHello.randomが含まれる。ServerCertificateは、署名とサーバを関連 付けるものである。ServerHello.randomは、署名とカレントのハンドシェイク プロセスを関連付けるものである。 F.1.1.3. 認証を伴うDiffie-Hellman鍵交換 Diffie-Hellman鍵交換を使用する場合には、サーバは固定Diffie-Hellman パラメータを含む証明書を提供するか、またはServerKeyExchangeメッセージに より、DSSまたはRSA証明書により署名された一時的Diffie-Hellmanパラメータを 送信する。一時的パラメータは、署名される前にhello.random値によりハッシュ される。これは攻撃者が古いパラメータを再利用しないようにするためである。 どちらの場合でも、クライアントは証明書または署名を確認し、パラメータが サーバのものであることを検証することができる。 もしクライアントが固定Diffie-Hellmanパラメータを含む証明書を所有している ならば、その証明書には鍵交換に必要な情報がすべて含まれている。この場合 クライアントとサーバは、同じDiffie-Hellman値(すなわちpre_master_secret) を、通信するごとに生成することになる。pre_master_secretが必要以上に長く メモリ上に残ることを防ぐために、出来るだけ早くmaster_secretへ変換する 必要がある。クライアントのDiffie-Hellmanパラメータは、鍵交換を行うために、 サーバにより提供されるパラメータとの互換性が必要である。 もしクライアントが標準DSSまたはRSA証明書を所有している、もしくはクライ アントが認証されないならば、クライアントはClientKeyExchangeメッセージに おいて、サーバに対し一時的パラメータを送信する。そしてオプショナルで、 自身を認証するために、CertificateVerifyメッセージを使用する。 F.1.2. バージョンロールバック攻撃 TLSでは、SSLバージョン2.0からのかなりの改良を含んでいるため、攻撃者は、 TLSの実行可能なクライアントとサーバを、バージョン2.0に戻すように させるかもしれない。この攻撃は、2つのTLS実行可能なパーティーがSSL2.0 ハンドシェイクを使用している場合のみに起こりうる。 ランダムではない、PKCS #1のブロック型2メッセージパディングを使用した解決 方法はエレガントではないが、これはバージョン3.0をサポートしているサーバ が攻撃を検出することの出来る、適度に安全な方法を提供する。この解決方法は、 アプリケーションが指定した待ち時間を過ぎるまでに、鍵に対してブルート フォース攻撃を行い、(通常のパディングを行った)同じ鍵を含む新しい ENCRYPTED-KEY-DATAメッセージに交換する攻撃者に対しては安全ではない。この 種の攻撃を懸念するパーティーでは、とにかく40ビットの暗号鍵を使用すべき ではない。PKCSパディングにおいての最後の8バイトのパディングを変更しても、 プロトコルで使用している、署名されたハッシュサイズや、RSA鍵長に関する セキュリティには影響しない。なぜならば、入力ブロックサイズが8バイト増加 した、ということと本質的に同等であるからである。 F.1.3. ハンドシェイクプロトコルに対する攻撃の検出 攻撃者は、通常パーティーが選択する暗号アルゴリズムとは異なった暗号を 選択するように、ハンドシェイク処理に対して影響を及ぼそうとするかもしれ ない。多くの実装では、40ビットの輸出可能な暗号をサポートしており、また いくつかの実装ではNULL暗号とMACアルゴリズムのサポートさえ行うかもしれ ないため、この攻撃には特別の関心を払う必要がある。 この攻撃を行うためには、攻撃者は積極的に1つ以上のハンドシェイクメッセージを 変更しなければならない。これが起きた場合、クライアントとサーバはハンド シェイクメッセージのハッシュ値として異なった値を求めることになる。その 結果、パーティーはお互いのFinishedメッセージを受理することはない。 master_secretがなければ、攻撃者はFishiedメッセージを修正することができ ないので、その攻撃は発見されるであろう。 F.1.4. セションの再利用 セションを再利用することによってコネクションが確立されるとき、新しい ClientHello.randomとServerHello.random値は、セションのmaster_secretと 共にハッシュされる。もしmaster_secretが危険にさらされてなく、また暗号化 鍵とMACシークレットを生成するために使用されるハッシュ処理が安全であれば、 コネクションは安全で、以前のコネクションから独立している。攻撃者は、 安全なハッシュ処理(SHAとMD5の両方を使用する)を破ることなしに、既知の 暗号化鍵またはMACシークレットを使用して、master_secretを危険にさらす ことはできない。 クライアントとサーバの両方が合意しない場合、セションを再利用することは できない。どちらかのパーティーが、セションが危険にさらされている、もしく は証明書の有効期間が切れた、または取り消されたと考えたときには、完全な ハンドシェイクを強行するべきである。セションIDの生存時間は、最大でも 24時間であることを提案する。なぜならば、master_secretを入手した攻撃者は 対応するセションIDの有効期限が切れるまで、危険にさらされているパーティー を装うことができるからである。比較的安全でない環境で実行されるアプリケー ションでは、セションIDを静的な記憶装置に書き込むべきではない。 F.1.5. MD5とSHA TLSでは、ハッシュ関数を非常に保守的に使用する。可能なところでは、ある 1つのアルゴリズムに非壊滅的な欠点があっても、プロトコル全体を壊さない ことを確実にするために、MD5とSHAの両方をタンデムに使用する。 F.2. アプリケーションデータの保護 master_secretは、ClientHello.randomとServerHello.randomと共にハッシュ され、それぞれのコネクションにおいて使用される唯一のデータ暗号化鍵とMAC シークレットが作成される。 送信データは、送信される前にMACにより保護される。メッセージ再送または メッセージ修正攻撃を防ぐために、MACはMACシークレット、シーケンス番号、 メッセージ長、メッセージコンテンツ、そして2つの固定文字列から計算される。 メッセージタイプフィールドは、あるTLSレコード層クライアントへのメッセージ が、他へリダイレクトされないことを確実にするのに必要である。シーケンス 番号を使用することにより、メッセージの削除または再要求を行おうとする試み は確実に検出できる。シーケンス番号は64ビットであるので、オーバーフロー することはほとんどない。ある1つのパーティーからのメッセージを、他方の パーティーの出力メッセージの中に挿入することはできない。なぜならば、 パーティーは独立したMACシークレットを使用しているからである。同様に、 サーバ書き出し鍵とクライアント書き出し鍵は独立しているため、ストリーム 暗号鍵は一度だけしか使用されない。 攻撃者が暗号化鍵を解読したならば、その鍵で暗号化されるすべてのメッセージ は解読される。同様に、MAC鍵が危険にさらされた場合には、メッセージ変更攻撃 が可能となる。MACは暗号化されるため、メッセージ変更攻撃は一般に、MACを 破ることと同時に、暗号化アルゴリズムを解読することが必要となる。 注:MACシークレットは暗号化鍵よりも大きくしてもよいので、暗号化鍵が解読 されたとしても、メッセージは改竄に対する耐性を持っている。 F.3. 最終注記 TLSが安全なコネクションを提供できるようにするためには、クライアントと サーバの両方のシステム、鍵、およびアプリケーションは安全でなければなら ない。さらに、実装においてセキュリティエラーがあってはならない。 システムは、サポートしている最も弱い鍵交換アルゴリズム、最も弱い認証 アルゴリズムと同じ程度の強度しか持っていない。そして信頼できる暗号関数 だけが使用されるべきである。短い公開鍵、40ビットの大量暗号化鍵、およ び匿名サーバを使用するときには、十分に注意すべきである。実装者とユーザ は、どの証明書とどの認証局を受け入れるのかを決めるときには、十分に注意 しなければならない。不遜な認証局により、大変な損害を受けることがある。 G. 特許声明 本プロトコルにおいてその使用が提案されているいくつかの暗号アルゴリズム では、特許請求が行われている。また、Netscape Communications社は、この規格 の基になっているSecure Sockets Layer(SSL)の特許請求がある。RFC 2026に規定 されているインターネット標準化プロセスでは、適切な条件の下では、応募者に 対しライセンスが利用可能であるという特許所有者からの声明が必要であるとして いる。 マサチューセッツ工科大学は、RSA Data Security,Inc. に対し、アメリカ合衆 国において発行された次の特許への独占的なサブライセンス権を認めている。 Cryptographic Communications System and Method ("RSA"), No. 4,405,829 Netscape Communications社は、アメリカ合衆国において次のような特許の発行 を得ている。 Secure Socket Layer Application Program Apparatus And Method ("SSL"), No. 5,657,390 Netscape Communications社は、以下の声明を発行している。 Intellectual Property Rights Secure Sockets Layer The United States Patent and Trademark Office ("the PTO") recently issued U.S. Patent No. 5,657,390 ("the SSL Patent") to Netscape for inventions described as Secure Sockets Layers ("SSL"). The IETF is currently considering adopting SSL as a transport protocol with security features. Netscape encourages the royalty-free adoption and use of the SSL protocol upon the following terms and conditions: * If you already have a valid SSL Ref license today which includes source code from Netscape, an additional patent license under the SSL patent is not required. * If you don't have an SSL Ref license, you may have a royalty free license to build implementations covered by the SSL Patent Claims or the IETF TLS specification provided that you do not to assert any patent rights against Netscape or other companies for the implementation of SSL or the IETF TLS recommendation. What are "Patent Claims": Patent claims are claims in an issued foreign or domestic patent that: 1) must be infringed in order to implement methods or build products according to the IETF TLS specification; or 2) patent claims which require the elements of the SSL patent claims and/or their equivalents to be infringed. The Internet Society、Internet Architecture Board、Internet Engineering Steering Groupおよび The Corporation for National Research Initiativesは、 特許、特許アプリケーションの有効性または範囲、保証項目の適切さに関して、 どのような立場も取らない。The Internet Societyと前述の他のグループは、 この規格を実現する際に適用される可能性のあるその他の知的所有権に関しては、 どのような決定も行っていない。これらの事柄に関するさらなる考慮については、 ユーザの自己責任となる。 セキュリティに関する考察 セキュリティ問題は、このメモ全体を通じて議論されている。 参考文献 [3DES] W. Tuchman, "Hellman Presents No Shortcut Solutions To DES," IEEE Spectrum, v. 16, n. 7, July 1979, pp40-41. [BLEI] Bleichenbacher D., "Chosen Ciphertext Attacks against Protocols Based on RSA Encryption Standard PKCS #1" in Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462, pages: 1--12, 1998. [DES] ANSI X3.106, "American National Standard for Information Systems-Data Link Encryption," American National Standards Institute, 1983. [DH1] W. Diffie and M. E. Hellman, "New Directions in Cryptography," IEEE Transactions on Information Theory, V. IT-22, n. 6, Jun 1977, pp. 74-84. [DSS] NIST FIPS PUB 186, "Digital Signature Standard," National Institute of Standards and Technology, U.S. Department of Commerce, May 18, 1994. [FTP] Postel J., and J. Reynolds, "File Transfer Protocol", STD 9, RFC 959, October 1985. [HTTP] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996. [HMAC] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed- Hashing for Message Authentication," RFC 2104, February 1997. [IDEA] X. Lai, "On the Design and Security of Block Ciphers," ETH Series in Information Processing, v. 1, Konstanz: Hartung- Gorre Verlag, 1992. [MD2] Kaliski, B., "The MD2 Message Digest Algorithm", RFC 1319, April 1992. [MD5] Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321, April 1992. [PKCS1] RSA Laboratories, "PKCS #1: RSA Encryption Standard," version 1.5, November 1993. [PKCS6] RSA Laboratories, "PKCS #6: RSA Extended Certificate Syntax Standard," version 1.5, November 1993. [PKCS7] RSA Laboratories, "PKCS #7: RSA Cryptographic Message Syntax Standard," version 1.5, November 1993. [PKIX] Housley, R., Ford, W., Polk, W. and D. Solo, "Internet Public Key Infrastructure: Part I: X.509 Certificate and CRL Profile", RFC 2459, January 1999. [RC2] Rivest, R., "A Description of the RC2(r) Encryption Algorithm", RFC 2268, January 1998. [RC4] Thayer, R. and K. Kaukonen, A Stream Cipher Encryption Algorithm, Work in Progress. [RSA] R. Rivest, A. Shamir, and L. M. Adleman, "A Method for Obtaining Digital Signatures and Public-Key Cryptosystems," Communications of the ACM, v. 21, n. 2, Feb 1978, pp. 120- 126. [RSADSI] Contact RSA Data Security, Inc., Tel: 415-595-8782 [SCH] B. Schneier. Applied Cryptography: Protocols, Algorithms, and Source Code in C, Published by John Wiley & Sons, Inc. 1994. [SHA] NIST FIPS PUB 180-1, "Secure Hash Standard," National Institute of Standards and Technology, U.S. Department of Commerce, Work in Progress, May 31, 1994. [SSL2] Hickman, Kipp, "The SSL Protocol", Netscape Communications Corp., Feb 9, 1995. [SSL3] A. Frier, P. Karlton, and P. Kocher, "The SSL 3.0 Protocol", Netscape Communications Corp., Nov 18, 1996. [TCP] Postel, J., "Transmission Control Protocol," STD 7, RFC 793, September 1981. [TEL] Postel J., and J. Reynolds, "Telnet Protocol Specifications", STD 8, RFC 854, May 1993. [TEL] Postel J., and J. Reynolds, "Telnet Option Specifications", STD 8, RFC 855, May 1993. [X509] CCITT. Recommendation X.509: "The Directory - Authentication Framework". 1988. [XDR] R. Srinivansan, Sun Microsystems, RFC-1832: XDR: External Data Representation Standard, August 1995. あとがき Win Treese Open Market EMail: treese@openmarket.com 編集 Christopher Allen Tim Dierks Certicom Certicom EMail: callen@certicom.com EMail: tdierks@certicom.com 著者 Tim Dierks Philip L. Karlton Certicom Netscape Communications EMail: tdierks@certicom.com Alan O. Freier Paul C. Kocher Netscape Communications Independent Consultant EMail: freier@netscape.com EMail: pck@netcom.com 協力 Martin Abadi Robert Relyea Digital Equipment Corporation Netscape Communications EMail: ma@pa.dec.com EMail: relyea@netscape.com Ran Canetti Jim Roskind IBM Watson Research Center Netscape Communications EMail: canetti@watson.ibm.com EMail: jar@netscape.com Taher Elgamal Micheal J. Sabin, Ph. D. Securify Consulting Engineer EMail: elgamal@securify.com EMail: msabin@netcom.com Anil R. Gangolli Dan Simon Structured Arts Computing Corp. Microsoft EMail: gangolli@structuredarts.com EMail: dansimon@microsoft.com Kipp E.B. Hickman Tom Weinstein Netscape Communications Netscape Communications EMail: kipp@netscape.com EMail: tomw@netscape.com Hugo Krawczyk IBM Watson Research Center EMail: hugo@watson.ibm.com コメント IETF TLSワーキンググループのディスカッションリストは、電子メールアドレス で提供されている。グループに関する情報と、 リストに参加する方法に関する情報は、で提供 されている。 以下でリストのアーカイブを見ることができる。 著作権表示 Copyright (C) The Internet Society (1999). All Rights Reserved. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 日本語訳 西原 啓輔 2001年5月 訳者は、訳出した文書を利用することにより発生したいかなる損害に対しても 責任を負いません。 本文書には、技術的あるいは翻訳上の誤りがある可能性があります。技術的に 正しい知識を獲得しなければならない場合は、InterNIC/IETFから発行されて いる原文を参照してください。