メインコンテンツまでスキップ

7. TLSハンドシェイクプロトコル (The TLS Handshaking Protocols)

TLSハンドシェイクプロトコル (TLS Handshake Protocol) は以下の機能を担当します:

  • TLSバージョンと暗号スイートのネゴシエーション
  • サーバーとクライアントの認証
  • 暗号化パラメータとキーのネゴシエーション
  • 伝送エラーの検出

ハンドシェイクプロトコルは3つのサブプロトコルで構成されます:

7.1. 暗号仕様変更プロトコル (Change Cipher Spec Protocol)

暗号仕様変更プロトコル (Change Cipher Spec Protocol) は、以降のレコードが新しくネゴシエートされたCipherSpecとキーで保護されることをピアに通知するために使用されます。このプロトコルは単一のメッセージで構成され、そのメッセージは現在の (保留中ではない) CipherSpecで暗号化および圧縮されます。メッセージは値1の単一バイトで構成されます。

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

ChangeCipherSpecメッセージは、セキュリティパラメータが合意された後、ハンドシェイク中に送信されます。ChangeCipherSpecメッセージの受信者は、読み取り保留状態を読み取り現在状態に更新しなければなりません (MUST)。このメッセージの直後に、新しいアルゴリズム、キー、およびシークレットを使用してFinishedメッセージが送信されます。実装は、ハンドシェイクが完了するまでChangeCipherSpecメッセージを送信してはなりません (MUST NOT)。このメッセージの後に受信される最初のメッセージは、Finishedメッセージでなければなりません (MUST)。

7.2. アラートプロトコル (Alert Protocol)

TLSは、ピアエンティティにアラートを伝達するためのAlertメッセージを提供します。他のメッセージと同様に、alertメッセージも現在の接続状態を使用して暗号化および圧縮されます。

enum { warning(1), fatal(2), (255) } AlertLevel;

enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed_RESERVED(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
no_certificate_RESERVED(41),
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_RESERVED(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
unsupported_extension(110),
(255)
} AlertDescription;

struct {
AlertLevel level;
AlertDescription description;
} Alert;

7.2.1. クロージャアラート (Closure Alerts)

クライアントとサーバーは、接続の書き込み側を閉じる前にクロージャ情報を共有しなければなりません (MUST)。いずれかの当事者は、close_notifyアラートを送信することで接続のクロージャを開始できます。クロージャアラートを受信した当事者は、接続を介して新しいデータの送信を直ちに停止しなければなりません (MUST)。close_notifyを送信した後、実装はその接続でデータを送信してはなりません (MUST NOT)。

7.2.2. エラーアラート (Error Alerts)

TLSプロトコルでのエラー処理は非常にシンプルです。エラーが検出されると、検出側がピアにメッセージを送信します。致命的なアラートの送信または受信時に、両当事者は直ちに接続を閉じなければなりません (MUST)。サーバーとクライアントは、失敗した接続で確立されたシークレット値とキーを忘れなければなりません (MUST)。

以下のエラーアラートが定義されています:

  • unexpected_message: 不適切なメッセージが受信されました。このアラートは、適切に実装された当事者によって観察されるべきではありません。
  • bad_record_mac: 不正なMACを持つレコードが受信された場合、このアラートが返されます。このメッセージは常に致命的 (fatal) です。
  • record_overflow: 長さが2^14+2048バイトを超えるTLSCiphertextレコードが受信されたか、2^14バイトを超えるTLSCompressedレコードに復号化されました (または接続状態の他のネゴシエートされた制限)。このメッセージは常に致命的です。
  • handshake_failure: 利用可能なオプションを考慮して、許容可能なセキュリティパラメータのセットをネゴシエートできませんでした。
  • bad_certificate: 証明書が破損していたり、正しく検証されない署名が含まれていたりしました。
  • unsupported_certificate: サポートされていない証明書タイプでした。
  • certificate_revoked: 証明書が署名者によって取り消されました。
  • certificate_expired: 証明書が期限切れであるか、現在有効ではありません。
  • certificate_unknown: 証明書の処理中に他の (不特定の) 問題が発生し、受け入れられなくなりました。
  • illegal_parameter: ハンドシェイクのフィールドが範囲外であるか、他のフィールドと矛盾していました。このメッセージは常に致命的です。
  • unknown_ca: 有効な証明書チェーンまたは部分的なチェーンが受信されましたが、CA証明書が見つからないか、既知の信頼されたCAと照合できなかったため、証明書が受け入れられませんでした。
  • access_denied: 有効な証明書が受信されましたが、アクセス制御が適用されたとき、送信者はネゴシエーションを続行しないことを決定しました。
  • decode_error: 一部のフィールドが指定された範囲外であったか、メッセージの長さが正しくなかったため、メッセージを復号化できませんでした。このメッセージは常に致命的です。
  • decrypt_error: ハンドシェイク暗号操作が失敗しました。これには、署名を正しく検証できない、Finishedメッセージを検証できないなどが含まれます。
  • protocol_version: ピアがネゴシエートしようとしたプロトコルバージョンは認識されていますが、サポートされていません。
  • insufficient_security: ネゴシエーションが失敗した場合、特にサーバーがクライアントがサポートするよりも安全な暗号を必要とする場合に、handshake_failureの代わりに返されます。
  • internal_error: ピアまたはプロトコルの正確性とは関係のない内部エラー (メモリ割り当ての失敗など) により、続行できなくなりました。このメッセージは常に致命的です。
  • user_canceled: このハンドシェイクは、プロトコルの失敗とは関係のない理由でキャンセルされています。
  • no_renegotiation: helloリクエストへの応答としてクライアントによって送信されるか、初期ハンドシェイク後のclient helloへの応答としてサーバーによって送信されます。このメッセージは常に警告です。
  • unsupported_extension: 拡張を理解できないサーバーによって送信されます。

7.3. ハンドシェイクプロトコルの概要 (Handshake Protocol Overview)

TLSハンドシェイクプロトコルには次のステップが含まれます:

  • アルゴリズムに合意し、ランダム値を交換し、セッション再開をチェックするためにhelloメッセージを交換します。
  • クライアントとサーバーがプリマスターシークレットに合意できるようにするために必要な暗号パラメータを交換します。
  • クライアントとサーバーが自身を認証できるようにするために証明書と暗号情報を交換します。
  • プリマスターシークレットと交換されたランダム値からマスターシークレットを生成します。
  • レコード層にセキュリティパラメータを提供します。
  • クライアントとサーバーが、ピアが同じセキュリティパラメータを計算したこと、およびハンドシェイクが攻撃者によって改ざんされることなく発生したことを検証できるようにします。

注意: このドキュメントは、TLS 1.2ハンドシェイクプロトコルの概要のみを提供します。完全な技術的詳細については、RFC 5246のセクション7.4以降を参照してください。

7.4. ハンドシェイクプロトコル (Handshake Protocol)

TLSハンドシェイクプロトコルは、TLSレコード層の定義された上位レベルクライアントの1つです。このプロトコルは、接続のセキュリティ属性をネゴシエートするために使用されます。ハンドシェイクメッセージは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;

ハンドシェイクプロトコルメッセージは明示的な長さで提示され、ハンドシェイクレコードの境界をまたいで断片化することはできません。つまり、各ハンドシェイクメッセージは、単一のハンドシェイクレコードに完全に収まるか、複数のハンドシェイクレコードにまたがる必要があり、各レコードには整数個のハンドシェイクメッセージが含まれます。受信者は、同じハンドシェイクレコード内のハンドシェイクメッセージの後に他のデータがないことを確認しなければなりません (MUST)。ただし、そのデータ自体が有効なハンドシェイクメッセージを構成する場合を除きます。

完全なハンドシェイクメッセージタイプと詳細な形式については、RFC 5246のセクション7.4のサブセクションを参照してください。