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

6. TLSレコードプロトコル (The TLS Record Protocol)

TLSレコードプロトコル (TLS Record Protocol) は階層化されたプロトコルです。各層で、メッセージには長さ、説明、内容のフィールドが含まれる場合があります。レコードプロトコルは、送信されるメッセージを受け取り、データを管理可能なブロックに分割し、オプションでデータを圧縮し、MACを適用し、暗号化してから結果を送信します。受信したデータは、復号化、検証、解凍、再組み立てされてから、上位レベルのクライアントに配信されます。

このドキュメントでは、レコードプロトコルを使用する4つのプロトコルについて説明します: ハンドシェイクプロトコル、アラートプロトコル、暗号仕様変更プロトコル、およびアプリケーションデータプロトコルです。TLSプロトコルの拡張を可能にするため、レコードプロトコルは追加のレコードコンテンツタイプをサポートできます。新しいレコードコンテンツタイプの値は、セクション12で説明されているように、TLSコンテンツタイプレジストリでIANAによって割り当てられます。

実装は、何らかの拡張によってネゴシエートされない限り、このドキュメントで定義されていないレコードタイプを送信してはなりません (MUST NOT)。TLS実装が予期しないレコードタイプを受信した場合、unexpected_messageアラートを送信しなければなりません (MUST)。

TLS上で使用するように設計されたプロトコルは、それに対するすべての可能な攻撃に対処するよう慎重に設計する必要があります。実際問題として、これはプロトコル設計者がTLSが提供する、および提供しないセキュリティ属性を認識し、後者に安全に依存できないことを意味します。

特に、レコードのタイプと長さは暗号化によって保護されていないことに注意してください。この情報自体が機密である場合、アプリケーション設計者は情報漏洩を最小限に抑えるための対策 (パディング、カバートラフィック) を講じることをお勧めします。

6.1. 接続状態 (Connection States)

TLS接続状態 (TLS connection state) は、TLSレコードプロトコルの動作環境です。これは、圧縮アルゴリズム、暗号化アルゴリズム、およびMACアルゴリズムを指定します。さらに、これらのアルゴリズムのパラメータは既知です: 読み取りと書き込みの両方向での接続のMACキーとバルク暗号化キー。論理的には、常に4つの未処理の接続状態があります: 現在の読み取りおよび書き込み状態、および保留中の読み取りおよび書き込み状態です。すべてのレコードは、現在の読み取りおよび書き込み状態で処理されます。保留中の状態のセキュリティパラメータは、TLSハンドシェイクプロトコルによって設定でき、ChangeCipherSpecは保留中の状態のいずれかを選択的に現在の状態にすることができます。この場合、適切な現在の状態が破棄され、保留中の状態に置き換えられます。保留中の状態は空の状態に再初期化されます。セキュリティパラメータで初期化されていない状態を現在の状態にすることは違法です。初期の現在の状態は常に、暗号化、圧縮、またはMACが使用されないことを指定します。

TLS接続の読み取りおよび書き込み状態のセキュリティパラメータは、次の値を提供することによって設定されます:

connection end (接続エンド)

  • このエンティティがこの接続で「クライアント」と見なされるか「サーバー」と見なされるか。

PRF algorithm (PRFアルゴリズム)

  • マスターシークレットからキーを生成するために使用されるアルゴリズム (セクション5および6.3を参照)。

bulk encryption algorithm (バルク暗号化アルゴリズム)

  • バルク暗号化に使用されるアルゴリズム。この仕様には、このアルゴリズムのキーサイズ、それがブロック、ストリーム、またはAEAD暗号であるかどうか、暗号のブロックサイズ (該当する場合)、および明示的および暗黙的な初期化ベクトル (またはnonce) の長さが含まれます。

MAC algorithm (MACアルゴリズム)

  • メッセージ認証に使用されるアルゴリズム。この仕様には、MACアルゴリズムによって返される値のサイズが含まれます。

compression algorithm (圧縮アルゴリズム)

  • データ圧縮に使用されるアルゴリズム。この仕様には、アルゴリズムが圧縮を実行するために必要なすべての情報を含める必要があります。

master secret (マスターシークレット)

  • 接続内の2つのピア間で共有される48バイトの秘密。

client random (クライアントランダム)

  • クライアントによって提供される32バイトの値。

server random (サーバーランダム)

  • サーバーによって提供される32バイトの値。

これらのパラメータは、プレゼンテーション言語で次のように定義されます:

enum { server, client } ConnectionEnd;

enum { tls_prf_sha256 } PRFAlgorithm;

enum { null, rc4, 3des, aes }
BulkCipherAlgorithm;

enum { stream, block, aead } CipherType;

enum { null, hmac_md5, hmac_sha1, hmac_sha256,
hmac_sha384, hmac_sha512} MACAlgorithm;

enum { null(0), (255) } CompressionMethod;

/* The algorithms specified in CompressionMethod, PRFAlgorithm,
BulkCipherAlgorithm, and MACAlgorithm may be added to. */

struct {
ConnectionEnd entity;
PRFAlgorithm prf_algorithm;
BulkCipherAlgorithm bulk_cipher_algorithm;
CipherType cipher_type;
uint8 enc_key_length;
uint8 block_length;
uint8 fixed_iv_length;
uint8 record_iv_length;
MACAlgorithm mac_algorithm;
uint8 mac_length;
uint8 mac_key_length;
CompressionMethod compression_algorithm;
opaque master_secret[48];
opaque client_random[32];
opaque server_random[32];
} SecurityParameters;

レコード層は、セキュリティパラメータを使用して次の6つの項目を生成します (一部の項目はすべての暗号で必要とされないため、空です):

  • client write MAC key (クライアント書き込みMACキー)
  • server write MAC key (サーバー書き込みMACキー)
  • client write encryption key (クライアント書き込み暗号化キー)
  • server write encryption key (サーバー書き込み暗号化キー)
  • client write IV (クライアント書き込みIV)
  • server write IV (サーバー書き込みIV)

クライアント書き込みパラメータは、サーバーがレコードを受信して処理するときに使用され、その逆も同様です。セキュリティパラメータからこれらの項目を生成するために使用されるアルゴリズムは、セクション6.3で説明されています。

セキュリティパラメータが設定され、キーが生成されると、それらを現在の状態にすることによって接続状態をインスタンス化できます。これらの現在の状態は、処理される各レコードに対して更新されなければなりません (MUST)。各接続状態には、次の要素が含まれます:

compression state (圧縮状態)

  • 圧縮アルゴリズムの現在の状態。

cipher state (暗号状態)

  • 暗号化アルゴリズムの現在の状態。これには、その接続のスケジュールされたキーが含まれます。ストリーム暗号の場合、これにはストリームがデータの暗号化または復号化を継続できるようにするために必要な状態情報も含まれます。

MAC key (MACキー)

  • この接続のMACキー。上記のように生成されます。

sequence number (シーケンス番号)

  • 各接続状態にはシーケンス番号が含まれており、読み取り状態と書き込み状態で個別に維持されます。接続状態がアクティブ状態になるたびに、シーケンス番号はゼロに設定されなければなりません (MUST)。シーケンス番号はuint64型で、2^64-1を超えることはできません。シーケンス番号は循環しません。TLS実装がシーケンス番号を循環する必要がある場合は、代わりに再ネゴシエートする必要があります。シーケンス番号は各レコードの後にインクリメントされます: 具体的には、特定の接続状態で送信される最初のレコードは、シーケンス番号0を使用しなければなりません (MUST)。

6.2. レコード層 (Record Layer)

TLSレコード層は、上位層から任意のサイズの非空ブロックで解釈されていないデータを受け取ります。

6.2.1. 分割 (Fragmentation)

レコード層は、情報ブロックをTLSPlaintextレコードに分割し、2^14バイト以下のチャンクでデータを運びます。クライアントメッセージの境界は、レコード層で保持されません (つまり、同じContentTypeの複数のクライアントメッセージは、単一のTLSPlaintextレコードに統合される場合があります (MAY)。または、単一のメッセージが複数のレコードにわたって分割される場合があります (MAY))。

struct {
uint8 major;
uint8 minor;
} ProtocolVersion;

enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

type

  • 囲まれたフラグメントを処理するために使用される上位レベルのプロトコル。

version

  • 使用されているプロトコルのバージョン。このドキュメントでは、バージョン 3 を使用するTLSバージョン1.2について説明します。バージョン値3.3は歴史的なもので、TLS 1.0が 1 を使用したことに由来します (付録A.1を参照)。複数のバージョンのTLSをサポートするクライアントは、ServerHelloを受信する前にどのバージョンが使用されるかを知らない場合があることに注意してください。ClientHelloで使用すべきレコード層のバージョン番号についての議論は、付録Eを参照してください。

length

  • 次のTLSPlaintext.fragmentの長さ (バイト単位)。長さは2^14を超えてはなりません (MUST NOT)。

fragment

  • アプリケーションデータ。このデータは透過的であり、typeフィールドで指定された上位レベルのプロトコルによって処理される独立したブロックとして扱われます。

実装は、ハンドシェイク、アラート、またはChangeCipherSpecコンテンツタイプの長さゼロのフラグメントを送信してはなりません (MUST NOT)。アプリケーションデータの長さゼロのフラグメントは、トラフィック分析対策として有用である可能性があるため、送信される場合があります (MAY)。

注意: 異なるTLSレコード層のコンテンツタイプのデータは交互に配置される場合があります (MAY)。アプリケーションデータは、通常、他のコンテンツタイプと比較して送信の優先度が低くなります。ただし、レコードはChangeCipherSpecメッセージの境界をまたいではなりません (MUST NOT)。

6.2.2. レコードの圧縮と解凍 (Record Compression and Decompression)

すべてのレコードは、現在のセッション状態で定義された圧縮アルゴリズムを使用して圧縮されます。常にアクティブな圧縮アルゴリズムが存在します。ただし、最初はCompressionMethod.nullとして定義されています。圧縮アルゴリズムは、TLSPlaintext構造をTLSCompressed構造に変換します。圧縮は可逆的である必要があり、コンテンツの長さを1024バイトを超えて増加させてはなりません。解凍関数が、解凍すると2^14バイトを超える長さになるTLSCompressed.fragmentに遭遇した場合、致命的なdecompression_failureアラートを報告しなければなりません (MUST)。

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed;

length

  • 次のTLSCompressed.fragmentの長さ (バイト単位)。長さは2^14 + 1024を超えてはなりません (MUST NOT)。

fragment

  • TLSPlaintext.fragmentの圧縮形式。

注意: CompressionMethod.null操作は恒等操作です。フィールドは変更されません。

実装上の注意: 解凍関数は、メッセージが内部バッファオーバーフローを引き起こさないことを保証する責任があります。

6.2.3. レコードペイロード保護 (Record Payload Protection)

暗号化およびMAC関数は、TLSCompressed構造をTLSCiphertextに変換します。復号化関数はこのプロセスを逆転します。レコードのMACにはシーケンス番号も含まれるため、欠落、追加、または繰り返しのメッセージが検出可能です。

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (SecurityParameters.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
case aead: GenericAEADCipher;
} fragment;
} TLSCiphertext;

type

  • typeフィールドはTLSCompressed.typeと同一です。

version

  • versionフィールドはTLSCompressed.versionと同一です。

length

  • 次のTLSCiphertext.fragmentの長さ (バイト単位)。長さは2^14 + 2048を超えてはなりません (MUST NOT)。

fragment

  • MACを含むTLSCompressed.fragmentの暗号化形式。

6.2.3.1. NULLまたは標準ストリーム暗号 (Null or Standard Stream Cipher)

ストリーム暗号 (BulkCipherAlgorithm.nullを含む。付録A.6を参照) は、TLSCompressed.fragment構造をストリームTLSCiphertext.fragment構造に変換します。

stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
} GenericStreamCipher;

MACは次のように生成されます:

MAC(MAC_write_key, seq_num +
TLSCompressed.type +
TLSCompressed.version +
TLSCompressed.length +
TLSCompressed.fragment);

ここで、"+" は連結を示します。

seq_num

  • このレコードのシーケンス番号。

MAC

  • SecurityParameters.mac_algorithmで指定されたMACアルゴリズム。

MACは暗号化の前に計算されることに注意してください。ストリーム暗号は、MACを含むブロック全体を暗号化します。

6.2.3.2. CBCブロック暗号 (CBC Block Cipher)

ブロック暗号 (3DESやAESなど) の場合、暗号化およびMAC関数は、TLSCompressed.fragment構造をブロックTLSCiphertext.fragment構造に変換します。

struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;

MACはセクション6.2.3.1で説明されているように生成されます。

IV

  • 初期化ベクトル (IV) はランダムに選択されるべきであり (SHOULD)、予測不可能でなければなりません (MUST)。TLS 1.1より前のバージョンでは、IVフィールドがなく、前のレコードの最後の暗号文ブロック (「CBC残余」) がIVとして使用されていたことに注意してください。これは、[CBCATT] で説明されている攻撃を防ぐために変更されました。ブロック暗号の場合、IV長はSecurityParameters.record_iv_lengthの長さであり、SecurityParameters.block_lengthと等しくなります。

padding

  • 平文の長さをブロック暗号のブロック長の整数倍にするために追加されるパディング。パディングは、TLSCiphertext.lengthがブロック長の整数倍になる限り、255バイトまでの任意の長さである場合があります (MAY)。必要以上に長い長さは、交換されるメッセージの長さの分析に基づくプロトコルに対する攻撃を阻止するために望ましい場合があります。パディングデータベクトル内の各uint8は、パディング長の値で埋められなければなりません (MUST)。受信者はこのパディングをチェックしなければならず (MUST)、パディングが正しくない場合はbad_record_macアラートを返さなければなりません (MUST)。受信者は、パディングが正しいかどうかに関係なく、可能な限り均一な応答時間を提供するために、パディングをできるだけ少なく検査すべきです (SHOULD)。

padding_length

  • パディング長は、GenericBlockCipher構造の合計サイズが暗号のブロック長の倍数になるようなものでなければなりません (MUST)。有効な値の範囲は、0から255までです (両端を含む)。この長さは、padding_lengthフィールド自体を除くパディングフィールドの長さを指定します。

暗号化されたデータ長 (TLSCiphertext.length) は、SecurityParameters.block_length、TLSCompressed.length、SecurityParameters.mac_length、およびpadding_lengthの合計より1大きくなります。

例: ブロック長が8バイト、コンテンツ長 (TLSCompressed.length) が61バイト、MAC長が20バイトの場合、パディング前の長さは82バイトです (これにはIVは含まれません)。したがって、合計長さがブロック長 (8バイト) の偶数倍になるようにするには、パディング長を8で割った余りが6でなければなりません。パディング長は6、14、22などから254まで可能です。パディング長が必要最小限の6である場合、パディングは6バイトで、それぞれに値6が含まれます。したがって、ブロック暗号化前のGenericBlockCipherの最後の8オクテットは xx 06 06 06 06 06 06 06 となります。ここで、xxはMACの最後のオクテットです。

注意: CBCモード (Cipher Block Chaining) のブロック暗号では、暗号文が送信される前にレコードの平文全体が既知であることが重要です。そうでない場合、攻撃者は [CBCATT] で説明されている攻撃を仕掛けることが可能です。

実装上の注意: Canvelら [CBCTIME] は、MACの計算に必要な時間に基づくCBCパディングに対するタイミング攻撃を実証しました。この攻撃を防ぐために、実装はパディングが正しいかどうかに関係なく、レコード処理時間が本質的に同じであることを保証しなければなりません (MUST)。一般に、これを行う最善の方法は、パディングが正しくない場合でもMACを計算し、その後にのみパケットを拒否することです。たとえば、パディングが正しくないように見える場合、実装は長さゼロのパディングを仮定してからMACを計算する場合があります。これにより、MACパフォーマンスがある程度データフラグメントのサイズに依存するため、小さなタイミングチャネルが残りますが、既存のMACの大きなブロックサイズとタイミング信号の小ささのため、悪用できるほど大きくはないと考えられています。

6.2.3.3. AEAD暗号 (AEAD Ciphers)

AEAD [AEAD] 暗号 (CCMまたはGCMなど) の場合、AEAD関数はTLSCompressed.fragment構造をAEAD TLSCiphertext.fragment構造に変換します。

struct {
opaque nonce_explicit[SecurityParameters.record_iv_length];
aead-ciphered struct {
opaque content[TLSCompressed.length];
};
} GenericAEADCipher;

AEAD暗号は、[AEAD] のセクション2.1で説明されているように、単一のキー、nonce、平文、および認証チェックに含める「追加データ」を入力として受け取ります。キーはclient_write_keyまたはserver_write_keyのいずれかです。MACキーは使用されません。

各AEA​​D暗号スイートは、AEAD操作に供給されるnonceの構成方法と、GenericAEADCipher.nonce_explicit部分の長さを指定しなければなりません (MUST)。多くの場合、[AEAD] のセクション3.2.1で説明されている部分的に暗黙的なnonce技術を使用することが適切です。record_iv_lengthは明示的な部分の長さです。この場合、暗黙的な部分はkey_blockからclient_write_ivおよびserver_write_ivとして派生されるべきであり (SHOULD) (セクション6.3で説明されているように)、明示的な部分はGenericAEADCipher.nonce_explicitに含まれます。

平文はTLSCompressed.fragmentです。

additional_dataと表記する追加の認証データは、次のように定義されます:

additional_data = seq_num + TLSCompressed.type +
TLSCompressed.version + TLSCompressed.length;

ここで、"+" は連結を示します。

aead_outputは、AEAD暗号化操作によって出力される暗号文で構成されます。長さは一般にTLSCompressed.lengthよりも大きくなりますが、AEAD暗号によって異なる量だけ大きくなります。暗号にはパディングが組み込まれている場合があるため、オーバーヘッドの量はTLSCompressed.lengthの値によって異なる場合があります。各AEAD暗号は、1024バイトを超える拡張を生成してはなりません (MUST NOT)。記号的には、

AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext,
additional_data)

復号化して検証するために、暗号はキー、nonce、「additional_data」、およびAEADEncrypted値を入力として受け取ります。出力は、平文または復号化が失敗したことを示すエラーのいずれかです。個別の整合性チェックはありません。つまり:

TLSCompressed.fragment = AEAD-Decrypt(write_key, nonce,
AEADEncrypted,
additional_data)

復号化が失敗した場合、致命的なbad_record_macアラートを生成しなければなりません (MUST)。

6.3. キー計算 (Key Calculation)

レコードプロトコルには、ハンドシェイクプロトコルによって提供されるセキュリティパラメータから、現在の接続状態 (付録A.6を参照) に必要なキーを生成するアルゴリズムが必要です。

マスターシークレットは、安全なバイトのシーケンスに拡張され、次にクライアント書き込みMACキー、サーバー書き込みMACキー、クライアント書き込み暗号化キー、およびサーバー書き込み暗号化キーに分割されます。これらのそれぞれは、その順序でバイトシーケンスから生成されます。未使用の値は空です。一部のAEAD暗号は、さらにクライアント書き込みIVおよびサーバー書き込みIVを必要とする場合があります (セクション6.2.3.3を参照)。

キーとMACキーが生成されるとき、マスターシークレットはエントロピーソースとして使用されます。

キーマテリアルを生成するには、次を計算します

key_block = PRF(SecurityParameters.master_secret,
"key expansion",
SecurityParameters.server_random +
SecurityParameters.client_random);

十分な出力が生成されるまで。次に、key_blockは次のように分割されます:

client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]

現在、最大のキーマテリアル要件はAES_256_CBC_SHA256です。これには、2 x 32バイトのキーと2 x 32バイトのMACキーが必要で、合計128バイトのキーマテリアルが必要です。対照的に、クライアントとサーバーによって提供されるランダムデータ (合計64バイト) で十分です。追加のデータもPRFによって提供される場合がありますが、TLS 1.2の場合、常に空の文字列に設定されます。

エクスポート可能な暗号化アルゴリズム (現在サポートされていません) は、key_blockから短いキーを導出するために追加の処理が必要でした。エクスポート暗号は、新しい実装では使用すべきではありません (SHOULD NOT)。