いったんセッションが設定されると、セッション内部にはどういった情報が保存されているのだろうか。そのヒントは2つ。まず、セッションの設定はHandshake Protocolにより行われること。そして、セッションは通信相手とのネゴシエーションにより合意した関係であること。この2点から考えれば、セッション内部に保存されている情報の種類は、なんとなく想像がつくはずだ。
セッション識別子
サーバが選択した任意のバイトシーケンス。アクティブセッション状態や再開セッション状態を特定する
ピア証明書
対向マシンのX.509v3証明書。この要素はnullになることもある
圧縮アルゴリズム
暗号化に先立って利用されるデータ圧縮アルゴリズム
暗号化アルゴリズム
バルクデータ暗号化アルゴリズム(null、DESなど)と、MACアルゴリズム(MD5、SHAなど)を指定する。またハッシュサイズなど暗号化属性も定義する
マスタシークレット
クライアントとサーバ間で共有する48バイトのシークレット値
再開可否フラグ
このセッションが新しいコネクション作成に利用され得るかどうかを表すフラグ
セッションが保持している情報の概略を図22に示す。「セッション識別子」は、そのセッションを特定するIDで、セッションを管理するうえでは不可欠なものだ。「ピア証明書」は、通信相手から受け取った相手の証明書である。この証明書を使って、通信相手の身元を確認したり、暗号化のための公開キーを入手することができる。「圧縮アルゴリズム」はデータ圧縮に用いるアルゴリズムに関する情報だ。ちなみにSSL/TLSの基本ドラフトでは圧縮アルゴリズムについて具体的な規定をしていない。
次の「暗号化アルゴリズム」は重要な情報だ。これには、データの暗号化アルゴリズムのほか、MAC算出のためのアルゴリズムやハッシュサイズなど、両者で合意した暗号化に関するコアとなる情報が含まれている。「マスタシークレット」もまた、とても重要な情報だ。この情報はサーバとクライアントが共有する秘密情報に当たる。実際の通信で使用する暗号化キーなどは、このマスタシークレットから生成する。具体的な方法については後述する。
最後の「再開可否フラグ」は、このセッションに2つ目のコネクションを作ることを許可するかどうかを表すフラグだ。このフラグが再開可になっているセッションについては、そのセッションで合意済みの情報を使って、新しいコネクションを張ることができる。「再開」という言葉からは、セッションの停止や再開ができるようにも受け取れるが、意味としては「複数コネクション利用可否フラグ」に近い。
ここで1つ意識していただきたいのは、セッションが保持する情報に、暗号化キーの情報を含まない点だ。暗号化キーは、暗号アルゴリズムが使用する情報で、対称暗号を使う場合には通信する両者が同じものになる。
こういった通信の具体的なパラメータとでも呼べる情報は、次に説明するコネクションの保持情報に含まれる。
コネクションが保持する情報を一言でいえば、セッションが保持する情報をもとに、より具体的なパラメータとして構築した情報、および、現在の暗号化状態を表す情報だ。前者はセキュリティパラメータと呼ばれる。また後者はここでは状態変数と名付けることにしよう。
図23にはセキュリティパラメータと状態変数の内訳を示した。セキュリティパラメータには、セッションの内部情報と重複したものがいくつかある。これは、セキュリティパラメータが、セッションの情報をベースに、さらに具体化した情報を収集して構築されているためだ。大きくは、「コネクションエンド情報」「クライアントランダム」「サーバランダム」が追加されたと見なすことができる。
コネクションエンド情報
そのコネクションで自エンティティがクライアントなのかサーバなのかを表す
バルク暗号化アルゴリズム
バルク暗号化に用いるアルゴリズムを表す。この情報には利用アルゴリズムのキーサイズ、ブロック暗号かストリーム暗号か、必要なら暗号のブロックサイズ、また輸出可能な暗号かどうかを含む
MACアルゴリズム
メッセージ認証に使用するアルゴリズムを表す。この仕様には、MACアルゴリズムが返却するハッシュ値のサイズを含む
圧縮アルゴリズム
データ圧縮に使用するアルゴリズムを表す。この仕様には、そのアルゴリズムが圧縮を行うために必要なすべての情報を含まなければならない
マスタシークレット
48バイトのシークレット値。そのコネクションの両エンティティで共有される
クライアントランダム
クライアントが提供する32バイトの値
サーバランダム
サーバが提供する32バイトの値
圧縮ステート値
圧縮アルゴリズムの現在のステート値
暗号化ステート値
暗号化アルゴリズムの現在のステート値。このコネクションで使用するキーのほかに、CBCモードで実行するブロック暗号では、IV(初期ベクタ)も格納される。その内容はレコードが処理されるたびに、前ブロックの暗号文で更新される。またストリーム暗号では、データの暗号化・複合化を行うために必要なすべての状態情報を含むことになる
MACシークレット
あらかじめ生成されたこのコネクションのMACシークレット
シーケンス番号
各コネクション状態のシーケンス番号。読み書き別々に管理されている。シーケンス番号はコネクション状態がアクティブになったおき、つねにゼロに設定される。シーケンス番号は8バイトで、2の64乗−1を超えない。シーケンス番号は各レコードごとにインクリメントしていく。最初のレコードは0とする
「コネクションエンド情報」はそのコネクションで自身がクライアントなのかサーバなのかを表す。「クライアントランダム」と「サーバランダム」は、クライアント、サーバそれぞれが生成した乱数だ。これはマスタシークレットなどと併せて、暗号化キーの生成などに利用する。
これらのセキュリティパラメータをもとにして、より具体的な暗号化通信のための情報を含み持つのが、図右側の状態変数部分だ。最初の「圧縮ステート」は圧縮アルゴリズムに関する情報を含むものだが、具体的には規定がないので省略する。
SSL/TLSでの暗号化を考えるに当たって最も重要なパラメータが、次の「暗号化ステート値」と「MACシークレット」である。「暗号化ステート値」には、暗号化キーおよびDESなどのブロック暗号で使用する初期ベクタ(IV)情報が含まれる。また「MACシークレット」は、HMAC関数によりMACを生成する際に使用する秘密情報で、正しい通信相手と通信していることを保証する機能を持つ。
これらの情報は、いずれもマスタシークレットなどから生成されるもので、そのアルゴリズムについては後述する。
最後のシーケンス番号はレコード単位でインクリメントしていくカウンタだ。このカウンタの値もMAC生成の際に使用されているもので、主に通信途中でのデータ改ざんを防止する役割を果たしている。
こういった情報が、各コネクション単位で管理されていて、暗号化された通信が進むに従って、刻々と内容が変化していくわけだ。
暗号化に関する知識が少ない方のために、暗号化キーと初期ベクタについて簡単に説明しよう。
●暗号化キー
いまここに暗号化したい文字列 "Hello" があるとする。これをなんらかの方法で暗号化して相手に送り、相手がそれを "Hello" という文字列に復元できれば、暗号化した状態での通信という目的が達成されたと見なされる。
もし通信相手との間で、暗号化のルールを「3つ先の文字に置き換える」と取り決めたのであれば、
"Hello" → "Khoor"
と変換して相手に送出することになる。相手は文字を3つ戻して、
"Khoor" → "Hello"
と元の文字列を復元することができればよい。
この方法には特に大きな問題はないのだが、話を一般化しようとすると少々難があることに気付く。例えば、複数の相手と暗号化通信したい場合、通信相手ごとに暗号化のルールを決めなければならない。
そこで考え出されたのが、暗号化アルゴリズムと暗号化キーを分離するというアイデアだ。これを前例に適用すると、「暗号化アルゴリズム」は「キーで指定したn個目の文字に置き換える」というものになり、「暗号化キー」には「33333」が用いられることになる。
こうしておくと、各通信相手とは「暗号化アルゴリズム」として「キーで指定したn個目の文字に置き換える」という点だけ合意しておき、暗号化キーをそれぞれの相手ごとに変えてやれば、1つの暗号化アルゴリズムで複数の相手と合理的に通信できる。暗号化キーを自分と通信相手だけの秘密にしておけば安全性上も問題はない。
暗号化関数を f、元の文章を "Hello" として、キーを変えることで暗号文も変化する様子は、次から簡単に読み取れるだろう。
相手Aとの通信(キー "33333" )
暗号化: f ("33333","Hello") → "Khoor"(暗号文)
復号: f'("33333","Khoor") → "Hello"(平文)
相手Bとの通信(キー "12345" )
暗号化: f ("12345","Hello") → "Igopt"(暗号文)
復号: f'("12345","Igopt") → "Hello"(平文)
このように暗号化キーという考え方を導入することで、優れた暗号化アルゴリズムが普遍的に利用可能となり、だれにでも安全に暗号が利用可能になるわけだ。
●初期ベクタ
元データを特定のブロックサイズに区切り暗号化してゆく「ブロック暗号」では、暗号をより破られにくくする工夫の1つとして、前ブロックの結果を利用する方式が考案されている。この方式では、あるブロックを暗号化するために、元データ、暗号化キーのほかに、1つ前のブロックの情報を使用している。これにより1個のブロックだけ取り出して復号することはより困難になり、暗号の安全性がより高くなる。
ブロック n の暗号化
= f(元データ n, 暗号化キー, ブロック n−1 の情報)
この方式を使用する場合、最初のブロックの暗号化で、前ブロックのデータがないことになる。そこで、最初のブロックに使用する前ブロックデータを、初期値として与えている。これを初期ベクタと呼ぶ。
ところで、1つのコネクションに対しては、こういった内部情報が合計4つ存在している。その内訳は、
なぜこんなにあるのだろうか?
カレントステートは、現在利用している暗号化に関するものなので特に説明の必要はないだろう。ペンディングステートが少々分かりにくいが、これはいってみれば次に使用する暗号化パラメータの情報だ。
ずいぶん前の説明になるが、Change Cipher Spec Protocolを送信することで、新しい暗号化仕様の利用を開始する、という説明をした。これは、Change Cipher Spec Protocolの送信により、送信ペンディングステートを送信カレントステートにコピーする、ということに等しい。同様に、Change Cipher Spec Protocolを受信すると、受信ペンディングステートを受信カレントステートにコピーすることになる(図24)。
つまり、Handshake Protocolにより合意を形成した段階の暗号化仕様は、まずは一時的にペンディングステートに保存される。そして、前の送信がすべて完了した段階で、Change Cipher Spec Protocolにより、カレントステートにコピーされ、実際の暗号化通信に利用されるようになるのである。4つもあるのはこういった理由による。
Copyright © ITmedia, Inc. All Rights Reserved.