6<- 目次 ->8


7. TLS ハンドシェイクプロトコル English

(準備中)

TLS ハンドシェイクプロトコルは、3 つのサブプロトコルから成る。双方のピアの間で、レコード層で使用するセキュリティパラメータの合意、相互認証、交渉済みのセキュリティパラメータのインスタンス生成、およびエラー状態の相互レポートを行うために、これらのプロトコルが使用される。

ハンドシェイクプロトコルは、セッションの交渉を行う義務がある。 これは以下の項目から構成されている。

セッション識別子
アクティブセッションステータスもしくは再利用可能セッションステータスを識別するために、サーバーによって選択される任意のバイト列。
 
ピア証明書
ピアの X.509v3 [X509] 証明書。ステータスにおけるこの要素はヌルでもよい。
 
圧縮方式
データを圧縮するためのアルゴリズム。暗号化の前に適用される。
 
暗号スペック
バルクデータ暗号化アルゴリズム(例えば null、DES など)と、MAC アルゴリズム (例えば MD5 や SHA など)を特定するもの。また、hash_sizeなどの暗号属性の定義も行う。(正式な定義に関しては 、付録 A.6 を参照。)
 
マスターシークレット
クライアントとサーバーの間で共有される 48バイトのシークレット。
 
再利用可能性
新しいコネクションを開始するのに、そのセッションを利用することができるかどうかを示すフラグ。

これらの項目は、セキュリティパラメータを生成するのに使用される。生成したパラメータは、アプリケーションデータを保護する際にレコード層により使用される。TLS ハンドシェイクプロトコルの再利用性により、1つのセッションを使用して、複数のコネクションのインスタンスを生成することができる。

7.1. ChangeCipherSpec プロトコル English

ChangeCipherSpec プロトコルは、暗号化ストラテジの変化を通知するために存在する。プロトコルは、 1つのメッセージから構成されている。このメッセージは、カレントの(保留中ではない)コネクションステータスのもとで暗号化、圧縮が行われる。メッセージは値 1 をもつ 1バイトで構成されている。

struct {

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

} ChangeCipherSpec;

ChangeCipherSpec メッセージは、クライアントとサーバーの両方によって送信されるもので、メッセージを受信した主体に対し、この後に続くデータは、新たに交渉された CipherSpec と鍵のもとに保護されていることを通知する。このメッセージを受信することにより、受信した側ではレコード層に対し、読み込み保留ステータスを、読み込みカレントステータスにすぐにコピーするように命令する。このメッセージを送信した直後に、送信した側ではレコード層に対し、書き出し保留ステータスを書き出しカレントステータスに変更するよう命令する( 6.1 章を参照)。ChangeCypherSpec メッセージは、セキュリティパラメータの合意後、検証終了メッセージが送信される前のハンドシェイク中に送信される(7.4.9章を参照)。

7.2. Alertプロトコル English

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. 終了アラート English

クライアントとサーバーは、トランケーション攻撃を避けるために、コネクションを終了しようとしているという情報を共有しなければならない。どちらの主体から終了メッセージの交換を始めてもよい。

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. エラーアラート English

TLS ハンドシェイクプロトコルにおけるエラー処理は非常に簡単である。エラーが検出されたとき、それを検出した主体は、もう一方の主体にメッセージを送信する。fatal レベルの Alert メッセージの送信または受信があると、双方の主体はすぐにコネクションを閉じる。サーバーとクライアントは、失敗したコネクションに関するすべてのセッション識別子、鍵、およびシークレットを忘れなければならない。 以下のエラーアラートが定義されている。

unexpected_message
不適当なメッセージを受信した。このアラートは常に fatal である。適切な実装間での通信では、絶対に検出されてはならない。
 
bad_record_mac
このアラートは、正しくない MAC をもつデータを受信したときに返される。このメッセージは常にfatalである。

decryption_failed
無効な方法により TLSCiphertext 構造体が復号された。これは、データがブロック長の整数倍ではない場合、またはパディング値をチェックした際に、それが正しくない場合のどちらかである。このメッセージは常にfatal である。
 
record_overflow
2^14+2048バイト以上のTLSCiphertextレコードを受け取った、または 2^14+1024 バイト以上の TLSCompressed レコードに復号された。このメッセージは常に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
ハンドシェイク暗号処理に失敗した。これには、署名の検証、鍵交換の復号、終了メッセージの検証などが正しく行われなかったケースも含まれる。
 
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. ハンドシェイクプロトコル概要 English

セッションステータスの暗号パラメータは、TLS ハンドシェイクプロトコルによって生成される。TLS ハンドシェイクプロトコルは、TLS レコード層の上位で処理されるプロトコルである。TLS クライアントとサーバーが最初に通信し始めるときには、プロトコルバージョン、暗号アルゴリズム選択、そして任意で相互認証、共有するシークレットを生成するための公開鍵暗号の使用、について合意が行われる。

TLS ハンドシェイクプロトコルには、以下のステップがある。

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. ハンドシェイクプロトコル English

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 メッセージ English

Hello フェーズのメッセージは、クライアントとサーバーの間で、それぞれが可能なセキュリティ処理能力に関する情報を交換するのに使用される。新しいセッションを開始するときには、レコード層のコネクションステータスにおける暗号化、ハッシュ、および圧縮アルゴリズムは null に初期化される。カレントのコネクションステータスは再共有メッセージに適用される。

7.4.1.1. HelloRequest メッセージ English

メッセージが送信されるとき:

HelloRequest メッセージは、サーバーがいつでも送信することができる。

メッセージの意味:

HelloRequest は単純な通知である。クライアントは都合のよいときに ClientHello メッセージを送信することにより、新たな共有プロセスを開始するべきであることを通知する。クライアントがセッションの共有中であるときには、このメッセージはクライアントによって無視される。セッションの再共有を望まない場合には、クライアントはそれを無視するか、もしくは no_renegotiation アラートで応答する。ハンドシェイクメッセージは、アプリケーションデータよりも優先されて送信されるため、クライアントからアプリケーションデータを受信する前にその共有が開始されることが期待されている。サーバーが HelloRequest を送信したにもかかわらず、レスポンスとして ClientHello を受信しなかった場合には、fatal レベルのアラートによりコネクションを終了してもよい。

HelloRequest を送信した後は、サーバーはその後のハンドシェイクネゴシエーションが完了するまで、リクエストを繰り返すべきでない。

メッセージの構造:

struct { } HelloRequest;

注:このメッセージは、ハンドシェイクを通じて維持され、Finished メッセージ、 CertificateVerify メッセージで使用されるメッセージハッシュに含めてはならない。

7.4.1.2. ClientHello メッセージ English

メッセージが送信されるとき:

クライアントが最初にサーバーに接続するときには、その最初のメッセージとして ClientHello メッセージを送信することが必要である。クライアントはまた、 HelloRequest のレスポンスとして ClientHello を送信することができる。また現存するコネクションにおけるセキュリティパラメータの再共有を行うために、クライアントから送信することも できる。

メッセージの構造:

ClientHelloメッセージには、Random 構造体が含まれる。これはプロトコル処理の後の方で使用される。

struct {

uint32 gmt_unix_time;
opaque random_bytes[28];

} Random;
gmt_unix_time

送信者の内部クロックにおける標準 UNIX 32ビットフォーマットの現在時間と日付(グリニッジ標準時1970年 1月 1日午前 0時から起算した秒数)。基本的な 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メッセージ English

メッセージが送信されるとき:

サーバーは、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 のリストから、サーバーによって選択されたひとつの圧縮アルゴリズム。セッションの再利用においては、このフィールドは 、再利用されたセッションステータスから取得された値が格納される。

7.4.2. ServerCertificateメッセージ English

メッセージが送信されるとき:

サーバーは、クライアントとの間で合意された鍵交換方式が匿名方式でないときには、サーバー証明書を送信しなければならない。このメッセージは常に、 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メッセージ English

メッセージが送信されるとき:

このメッセージは、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メッセージ English

メッセージが送信されるとき:

匿名ではないサーバーは、選択された暗号スイートにおいて適切であるならば、任意でクライアントに対し証明書を要求することができる。 このメッセージが送信される場合には、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 は [X.509] から導入されている。

注: 匿名サーバーがクライアント証明書を要求した場合には、fatal レベルの handshake_failure アラートとなる。

7.4.5. ServerHelloDoneメッセージ English

メッセージが送信されるとき:

ServerHelloDone メッセージはサーバーから送信されるもので、ServerHello と、それに関連するメッセージの終了を示す。このメッセージを送信した後、サーバーはクライアントからのレスポンスを待つ。

メッセージの意味:

このメッセージは、鍵交換をサポートするためのメッセージの送信を、サーバーが完了したことを意味する。そしてクライアント側で、鍵交換フェーズを続行していくことができる。

ServerHelloDone メッセージを受信したならば、クライアントは、もし要求されているのであれば、サーバーが有効な証明書を提供しているかどうかを検証するべきである。また、ServerHello パラメータが受理できるか否かをチェックすべきである。

メッセージの構造:

struct { } ServerHelloDone;

7.4.6. ClientCertificateメッセージ English

メッセージが送信されるとき:

これは、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メッセージ English

メッセージが送信されるとき:

このメッセージは、必ずクライアントから送信される。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 メッセージ English

メッセージの意味:

鍵交換と認証方式として 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値 English

メッセージの意味:

これは、クライアントの 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メッセージ English

メッセージが送信されるとき:

このメッセージは、クライアント証明書の検証を行うのに使用される。このメッセージは、署名可能なクライアント証明書(すなわち、固定 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メッセージ English

メッセージが送信されるとき:

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 メッセージも、ハッシュ計算には含めない。


6<- 目次 ->8