それでは登場したHandshake Protocolの主要メッセージをさらに詳しく見てみよう。Handshake Protocolは図35に示すフォーマットを取っている。以下に登場するメッセージは、このbody部分に格納されるものだ。
なお、Change Cipher SpecはHandshake Protocolのメッセージではなく、Change Cipher Spec Protocolのメッセージである。そのためここでは説明しない。フォーマットは図7を参照していただきたい。
メッセージフォーマットを図36に示す。versionはプロトコルバージョンを指定するフィールドで、TLS 1.0では、majorを3、minorを1に指定する。
version
プロトコルバージョンをメジャーバージョン、マイナーバージョンの2バイトで表現。具体的には、TLS1.0の場合、メジャーバージョン=3、マイナーバージョン=1となる
gmt_unix_time
メッセージを生成した時刻を表すUnixTime値(GMT)
random_bytes
クライアントが生成した28バイトの乱数。gmt_unix_timeを合わせた32バイトはクライアントランダムと呼ばれる値となる。クライアントランダムについては図27を参照のこと
session_id
セッションIDを表す最大32バイトの可変長値。新規セッションを確立する場合はlengthをゼロにして、値を格納するフィールドをなくす
cipher_suites
クライアントがサポートする暗号化アルゴリズムのリスト。クライアントが希望する順に並べる。既存セッションを再利用する場合、少なくとも当該セッションのcipher_suite値を含む必要がある
compression_methods
クライアントがサポートする圧縮アルゴリズムのリスト。クライアントが希望する順に並べる。既存セッションを再利用する場合、少なくとも当該セッションのcompression_method値を含む必要がある
gmt_unix_timeにはメッセージを生成した日付時刻情報をUnixTime形式でGMTで格納する。また、random_bytesはクライアントが生成した28バイトの乱数を格納する。この両者を合わせた情報は、クライアントランダムと呼ばれている。クライアントランダムについては、図27の説明をご覧いただきたい。
新規セッションを確立する場合、session_idは空にしておく。この場合、lengthの値は0に設定し、それ以外のデータ格納用エリアは用意しなくてよい。また、既存セッションを再利用する場合には、このフィールドに当該セッションのセッションIDを格納する。
cipher_suitesには、クライアントがサポートする暗号化アルゴリズムのリストを格納する。順番はクライアントが優先して使いたい順でよい。実際にこのリストで指定可能な値を表5に示した。この1つ1つはcipher suiteと呼ばれており、以下の情報を1組にしたものになっている。
例えばTLS_RSA_WITH_DES_CBC_SHAは、キー交換にRSA証明書、通信内容の暗号化にはCBCモードのDES、HMAC計算にはSHA-1を使用という組み合わせを表している。これらを1組にして、その通信で利用する暗号群(cipher suite)として指定するわけである。本表に示したcipher suiteはRFC2246に定義されているものだが、これ以外の組み合わせの利用も可能である。その場合、その定義をRFCとして発表しなければならないということである。このほか、1バイト目0xffのcipher_suiteはローカルな定義や実験的利用を示す値として予約されている。
なお、既存セッションを再利用する場合には、当該セッションで使用するcipher suite値を格納しておく。
compression_methodsには、クライアントがサポートする圧縮アルゴリズムのリストを格納する。RFC2246では具体的な圧縮アルゴリズムは定義されていないため、通常は圧縮なしのnull(0)を含むことになる。
なお、既存セッションを再利用する場合には、当該セッションで使用するcompression method値を格納しておく。
図37はこのメッセージのフォーマットだ。Client Helloとよく似たフォーマットになっているが、cipher_suiteとcompression_methodの両フィールドは、リストではなく単一の値を格納するようになっている。なぜなら、このメッセージはサーバが決定したcipher suiteとcompression method値を返却するために用いられるからである。
version
プロトコルバージョンをメジャーバージョン、マイナーバージョンの2バイトで表現。具体的には、TLS1.0の場合、メジャーバージョン=3、マイナーバージョン=1となる
gmt_unix_time
メッセージを生成した時刻を表すUnixTime値(GMT)
random_bytes
サーバが生成した28バイトの乱数。gmt_unix_timeを合わせた32バイトはサーバランダムと呼ばれる値となる。サーバランダムについては図27を参照のこと
session_id
セッションIDを表す最大32バイトの可変長値。新規セッションを確立する場合はサーバが新たにセッションID を生成して格納する。既存セッションを再利用する場合は、クライアントが通知してきた再利用セッションのセッションID をそのまま格納する
cipher_suites
クライアントが通知した暗号化アルゴリズムリストのうち、このコネクションで使用するべくサーバが選択した暗号化アルゴリズムを格納する
compression_methods
クライアントが通知した圧縮アルゴリズムリストのうち、このコネクションで使用するべくサーバが選択した圧縮アルゴリズムを格納する
これらのフィールドには、新セッション確立の場合、cipher_suiteにはサーバが選択したcipher_suite値、compression_methodにはサーバが選択したcompression_method値、それぞれが格納される。また、既存セッションの再利用の場合、session_id、cipher_suite、compression_methodそれぞれに、クライアントが指定したものと同じ値が入る。
このメッセージのフォーマットは図38のようにシンプルだ。サーバは、このメッセージにサーバ自身の証明書からルート証明機関の証明書に至るまでの、X.509v3証明書のリストを格納して、それをクライアントに通知する。クライアントはこのメッセージを受信することで、これから暗号化通信を開始しようとするサーバの証明書を取得できる。
certificate_list
そのサーバ証明書からルート証明機関の証明書にいたるまでのX.509v3証明書のリスト
図39にはメッセージフォーマットを示した。このメッセージはプリマスタシークレット(各暗号化パラメータの根源であるマスタシークレットを生成するための前提情報)を、クライアントからサーバに送出する目的で使用するものだ。
client_version
プロトコルバージョンをメジャーバージョン、マイナーバージョンの2バイトで表現。具体的には、TLS1.0の場合、メジャーバージョン=3、マイナーバージョン=1となる
random
クライアントが生成した46バイトの乱数。client_versionと合わせてプリマスタシークレットと呼ばれる。プリマスタシークレットについては図26を参照
Diffie&Hellman公開情報
自身の公開情報を格納する。Client Certificateメッセージですでに公開情報を通知している場合は空きとする
キー交換アルゴリズムにRSAを使用する場合、client_versionにプロトコルのバージョン番号(メジャー=3、マイナー=1)を、randomにクライアントが生成した46バイトの乱数をそれぞれ格納する。そして値全体をサーバ証明書から取得したサーバの公開鍵により暗号化する。このclient_versionとrandomを合わせた情報は、前出のプリマスタシークレットに相当する(図26)。
また、キー交換アルゴリズムにDiffie&Hellmanを使用する場合は、クライアントの公開情報を格納する。すでにClient Certificateメッセージでクライアント公開情報を通知済みの場合は空とする。
このメッセージのフォーマットを図40に示す。verify_dataは、マスタシークレット、文字列、ここまでのHandshakeプロトコルでやりとりした全メッセージのMD5値、同じくSHA-1値から生成した12バイトの値をPRF関数に与え生成した12バイトの値だ(図41)。このときの文字列は、自分がクライアントなら“client finished”、サーバなら“server finished”を用いる。
verify_data
マスタシークレット、文字列、直前までの通信内容から生成する暗号化仕様検証用データ
ここで重要なのは、このverify_data値は、サーバ、クライアントがともに知り得る共通情報であるという点だ。verify_data値を、新しい暗号化仕様で動作しているrecordレイヤを介して相手に送り、受信者はその内容が自分の知っている情報と同一かどうか確認する。この両者が一致するなら、新しい暗号化仕様は正常に機能していると見なすことができる。
難攻不落にも思えるSSL/TLSに対して、可能な限り分かりやすさに重点を置いた解説を試みてきた。読者諸氏の感想はいかがだろうか。
文中に多く登場する各種パラメータは、それ単体では意味が理解できずに頭を悩ませるかもしれなが、あまり心配はしなくていい。それらを理解する鍵は最終パートのメッセージシーケンスにある。
パラメータの生成者、パラメータの通知先、受け取ったパラメータから生成する情報などを注視して、最終パートのメッセージシーケンスを眺めてみるとよい。これまでバラバラでしかなかった各パラメータが、ネゴシーエションの成立過程でどのような役割を果たしているか、そのつながりが浮かび上がってくるはずだ。
本稿が諸氏のSSL/TLS理解の一助になることを願っている。
Copyright © ITmedia, Inc. All Rights Reserved.