SSLハンドシェイクでは、通信相手(サーバとクライアント)の認証や暗号化に使用する共通鍵の生成といった、暗号通信のための準備を行います。以前の記事ではSSLハンドシェイクの概要を説明しましたが、この記事ではSSLハンドシェイクでやり取りされる実際のシーケンスを追いかけながら更に詳細を説明します。

SSLハンドシェイク

上図で示しているのは、SSL/TLS通信を始める際にやり取りされるハンドシェイク部分です。破線矢印となっているやり取りは省略可能であることを示します。ハンドシェイクが終わると、アプリケーションデータの暗号化通信が始まりますので、それまでのやり取りは全て平文となります。そのため、パケットキャプチャでハンドシェイク部分を見ることもできます。

ハンドシェイクのシーケンスを追いかけていくことで、SSL/TLSの提供する機能である暗号化・改ざん検知・認証がなぜ実現できるかが見えてくると思います。

1.Client Hello

クライアントは、クライアントがサポートする暗号スイート一覧をサーバーへ送信します。暗号スイート一覧は、クライアントが希望する順に並べます。暗号スイートについては以前の記事でも説明しましたが、簡単に言うと暗号化方式やサーバー認証の方式、改ざん検知の方式をまとめたものです。
その他、SSL/TLSバージョン、現在時刻、セッションID、共通鍵作成に使用するclient random(challenge)など、サーバーと合わせておかないといけない各種パラメータを送ります。

2.Server Hello

サーバーは、クライアントが送信してきた暗号スイート一覧の中から使用できるものがあった場合、その暗号スイート(ひとつ)とセッションIDを送信します。暗号スイート一覧の中に使用できるものがない場合、そのハンドシェイクは失敗します。セッションIDはクライアントからの再接続用に送信します。サーバーがキャッシュしない場合(再接続を認めない場合)はセッションIDは空で返します。
その他、共通鍵作成に使用するserver randomなど、クライアントと合わせておかないといけない各種パラメータを含めて「Server Hello」として返します。

3.Server Certificate

サーバーは、サーバー証明書と、サーバー証明書とチェーンでつながる証明書(中間証明書、ルート証明書)をこの順に並べて送信します。ただし、ルート証明書は省略されることがあります。また、認証なしの暗号スイートを採用した場合はこのメッセージは省略されます。(とはいえ、省略されることは稀です。)

4.Server Key Exchange

サーバーは、暗号化通信を行うための基になる値(プレマスターシークレット)を交換するための情報がまだない場合にのみ、プレマスターシークレットを秘密裏に交換するための情報をこのメッセージで送信します。プレマスターシークレットを交換するための情報がない場合(このメッセージを送信する場合)とは、認証なしのSSL/TLS通信をするためServer Certificateメッセージを省略した場合か、一時的に生成したパラメタにより、DH鍵交換を実施する場合等です。(Server Certificateが省略されることは稀なので、このメッセージを送信するための鍵交換にDHEやECDHEを使用する暗号スイートを最小した場合がほとんどです。DH、DHE、ECDHについては、「公開鍵暗号」を参照してください。

5. Certificate Request

サーバーは、クライアントに認証を求める場合、クライアント証明書を要求するためにこのメッセージを送信します。クライアントに認証を求めない場合はこのメッセージを送信しません。SSL/TLS では、クライアントの認証はオプションとなっています。サーバーのみを認証する場合を片方向認証、サーバーとクライアントの双方で認証する場合を双方向認証といいます。
このメッセージには、許容可能な認証局のDN(Distinguished Name)のリストを含めて送信します。これは、この後のClient Certificateメッセージで、クライアントからこの認証局から発行された証明書(または証明書のチェーン)を送信することを求めています。この認証局のリストを空にした場合は、許容可能な認証局を指定しないことを意味しています(いかなる認証局によって発行された証明書も認めないと言う意味ではありません)。

6.Server Hello Done

サーバーは、Server Helloと関連するメッセージの終わりを示すためにこのメッセージを送信します。端的に言えば、「私の情報は全て送り終わりました」ということをServer Hello Doneで通知しています。このメッセージは送信した後、サーバーはクライアントからの応答を待ちます。

7.Client Certificate

クライアントは、サーバーがクライアントに認証を求めた場合にのみこのメッセージを送信します。このメッセージには、Certificate Requestメッセージで指定された認証局から発行された証明書(または証明書のチェーン)を含めて送信します。適切な証明書(または証明書のチェーン)を返せない場合は、証明書を含まずにこのメッセージを送信します。サーバーは、クライアントが証明書を送信してこない場合、クライアントの認証をせずに続けるかエラーを応答します。

8.Client Key Exchange

クライアントは、プリマスターシークレット(premaster secret)を公開鍵で暗号化してサーバーに送ります。プリマスターシークレットは暗号化通信を行うための基になる値です。受け取ったサーバーは、秘密鍵で復号してプリマスターシークレットを取り出します

9.Certificate Verify

クライアントは、クライアントが証明書を送信した場合にのみこのメッセージを送信します。クライアントは、今までに受信したHelloメッセージからディジタル署名 (Certificate Verify) を生成し、サーバーに送信します。ディジタル署名を受け取ったサーバーは、クライアントから受け取った証明書を使い、ディジタル署名の検証を行います。(クライアントの証明書に含まれる公開鍵でこのディジタル署名を復号化することで、ディジタル署名の検証とクライアントの認証を完了します。)検証が成功すると、その証明書が間違いなくクライアントのものであることが確認できます。

10.Change Cipher Spec

クライアントは、client randomやserver randomと合わせてプリマスタシークレットからマスタシークレットを生成し、さらにマスタシークレットから暗号化通信用の共通鍵を生成します。その他、ブロック暗号用のIV、HMAC用の共通鍵を生成します。これらの値は、Finishedメッセージ以降で使用します。
次に、使用する暗号アルゴリズムの準備が整ったことをサーバーに通知します。※厳密には、このメッセージはハンドシェイクメッセージではありません。

11.Finished

クライアントは、鍵交換と認証処理が成功し、ハンドシェイクの終わりを示すためにこのメッセージを送信します。このメッセージはクライアントとサーバーで共有した秘密鍵で暗号化されたはじめのメッセージで、このメッセージより前にハンドシェイクで送受信した全てのデータのHMACを含めて送信します。サーバーは、このHMACが正しいか検証します。このメッセージによりサーバー、ハンドシェイクは改ざんされておらず、クライアントが秘密鍵を知っていることを確認できます。

12.Change Cipher Spec

サーバーは、クライアントから受信した暗号化されたプリマスタシークレットを、自身の秘密鍵を使い復号します。次に復号したプリマスタシークレット及びclient random、server randomと合わせてマスタシークレットを生成し、さらにマスタシークレットから共通鍵を生成します。この共通鍵は、クライアントが生成した共通鍵と同じ鍵になります。その他、ブロック暗号用のIV、HMAC用の共通鍵を生成します。
次に、使用する暗号アルゴリズムの準備が整ったことをクライアントに通知します。※厳密には、このメッセージはハンドシェイクメッセージではありません。

13.Finished

サーバーは、鍵交換と認証処理が成功し、ハンドシェイクの終わりを示すためにこのメッセージを送信します。このメッセージには、このメッセージより前にハンドシェイクで送受信した全てのデータのHMACを含めて送信します。このHMACは、クライアントから送信されたFinishedメッセージを含むハッシュ値のため、クライアントから送信されたハッシュ値と異なります。クライアントは、このハッシュ値が正しいか検証します。つまり、今までやり取りしたメッセージが改ざんされていないこと、 暗号化通信用の共通鍵 と HMAC用の共通鍵(MAC鍵)がお互い同じものが生成されていることを確認します。

アプリケーションデータの暗号化通信

ここからはデータ転送フェーズになります。ハンドシェイクフェーズで合意したアルゴリズム及び鍵を使用して、クライアント・サーバー双方で改ざん検知をしながらアプリケーションのデータを、暗号化された状態で安全に送受信します。

⇒次のカテゴリー「ディジタル証明書