5. Record Protocol (Record-Protokoll)
Das TLS-Record-Protokoll nimmt zu übertragende Nachrichten entgegen, fragmentiert die Daten in handhabbare Blöcke, schützt die Records und überträgt das Ergebnis. Empfangene Daten werden verifiziert, entschlüsselt, wieder zusammengesetzt und dann an höherstufige Clients ausgeliefert.
TLS-Records sind typisiert, was es ermöglicht, mehrere höherstufige Protokolle über dieselbe Record-Schicht zu multiplexen. Dieses Dokument spezifiziert vier Inhaltstypen: handshake, application_data, alert und change_cipher_spec. Der change_cipher_spec-Record wird nur zu Kompatibilitätszwecken verwendet (siehe Anhang D.4).
Eine Implementierung kann (MAY) jederzeit nach dem Senden oder Empfangen der ersten ClientHello-Nachricht und vor dem Empfang der Finished-Nachricht des Peers einen unverschlüsselten Record des Typs change_cipher_spec empfangen, der aus dem einzelnen Bytewert 0x01 besteht, und muss (MUST) ihn ohne weitere Verarbeitung einfach verwerfen. Beachten Sie, dass dieser Record an einer Stelle des Handshakes auftreten kann, an der die Implementierung geschützte Records erwartet, sodass es notwendig ist, diesen Zustand zu erkennen, bevor versucht wird, den Record zu entschützen. Implementierungen, die einen anderen change_cipher_spec-Wert empfangen oder einen geschützten change_cipher_spec-Record empfangen, müssen (MUST) den Handshake mit einem "unexpected_message"-Alarm abbrechen. Wenn eine Implementierung einen change_cipher_spec-Record erkennt, der vor der ersten ClientHello-Nachricht oder nach der Finished-Nachricht des Peers empfangen wurde, muss (MUST) er als unerwarteter Record-Typ behandelt werden (obwohl zustandslose Server diese Fälle möglicherweise nicht von zulässigen Fällen unterscheiden können).
Implementierungen dürfen (MUST NOT) keine Record-Typen senden, die in diesem Dokument nicht definiert sind, es sei denn, sie werden durch eine Erweiterung ausgehandelt. Wenn eine TLS-Implementierung einen unerwarteten Record-Typ empfängt, muss (MUST) sie die Verbindung mit einem "unexpected_message"-Alarm beenden. Neue Werte für Record-Inhaltstypen werden von IANA im TLS-ContentType-Register zugewiesen, wie in Abschnitt 11 beschrieben.
5.1. Record Layer (Record-Schicht)
Die Record-Schicht fragmentiert Informationsblöcke in TLSPlaintext-Records, die Daten in Blöcken von 2^14 Bytes oder weniger tragen. Nachrichtengrenzen werden je nach zugrunde liegendem ContentType unterschiedlich behandelt. Alle künftigen Inhaltstypen müssen (MUST) geeignete Regeln angeben. Beachten Sie, dass diese Regeln strenger sind als die, die in TLS 1.2 durchgesetzt wurden.
Handshake-Nachrichten dürfen (MAY) zu einem einzigen TLSPlaintext-Record zusammengefasst oder über mehrere Records fragmentiert werden, sofern:
-
Handshake-Nachrichten dürfen (MUST NOT) nicht mit anderen Record-Typen verschachtelt werden. Das heißt, wenn eine Handshake-Nachricht über zwei oder mehr Records aufgeteilt wird, darf (MUST NOT) sich zwischen ihnen kein anderer Record befinden.
-
Handshake-Nachrichten dürfen (MUST NOT) keine Schlüsselwechsel überspannen. Implementierungen müssen (MUST) überprüfen, dass alle Nachrichten, die einem Schlüsselwechsel unmittelbar vorausgehen, an einer Record-Grenze ausgerichtet sind; andernfalls müssen (MUST) sie die Verbindung mit einem "unexpected_message"-Alarm beenden. Da die Nachrichten ClientHello, EndOfEarlyData, ServerHello, Finished und KeyUpdate einem Schlüsselwechsel unmittelbar vorausgehen können, müssen (MUST) Implementierungen diese Nachrichten in Ausrichtung an einer Record-Grenze senden.
Implementierungen dürfen (MUST NOT) keine Fragmente der Länge null vom Typ Handshake senden, selbst wenn diese Fragmente Padding enthalten.
Alarm-Nachrichten (Abschnitt 6) dürfen (MUST NOT) nicht über Records fragmentiert werden, und mehrere Alarm-Nachrichten dürfen (MUST NOT) nicht zu einem einzigen TLSPlaintext-Record zusammengefasst werden. Mit anderen Worten: Ein Record vom Typ Alert muss (MUST) genau eine Nachricht enthalten.
Application-Data-Nachrichten enthalten Daten, die für TLS undurchsichtig sind. Application-Data-Nachrichten sind immer geschützt. Fragmente der Länge null von Application Data dürfen (MAY) gesendet werden, da sie als Gegenmaßnahme gegen Verkehrsanalyse potenziell nützlich sind. Application-Data-Fragmente dürfen (MAY) über mehrere Records aufgeteilt oder zu einem einzigen Record zusammengefasst werden.
enum {
invalid(0),
change_cipher_spec(20),
alert(21),
handshake(22),
application_data(23),
(255)
} ContentType;
struct {
ContentType type;
ProtocolVersion legacy_record_version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
type: Das höherstufige Protokoll, das zur Verarbeitung des eingeschlossenen Fragments verwendet wird.
legacy_record_version: Muss (MUST) für alle Records, die von einer TLS-1.3-Implementierung erzeugt werden, auf 0x0303 gesetzt werden, mit Ausnahme eines initialen ClientHello (d. h. eines, das nicht nach einem HelloRetryRequest erzeugt wurde), bei dem es zu Kompatibilitätszwecken auch 0x0301 sein darf (MAY). Dieses Feld ist veraltet und muss (MUST) für alle Zwecke ignoriert werden. Frühere Versionen von TLS verwendeten unter bestimmten Umständen andere Werte in diesem Feld.
length: Die Länge (in Bytes) des folgenden TLSPlaintext.fragment. Die Länge darf (MUST NOT) 2^14 Bytes nicht überschreiten. Ein Endpunkt, der einen Record empfängt, der diese Länge überschreitet, muss (MUST) die Verbindung mit einem "record_overflow"-Alarm beenden.
fragment: Die zu übertragenden Daten. Dieser Wert ist transparent und wird als unabhängiger Block behandelt, der von dem durch das Feld type angegebenen höherstufigen Protokoll verarbeitet wird.
Dieses Dokument beschreibt TLS 1.3, das die Version 0x0304 verwendet. Dieser Versionswert ist historisch und leitet sich aus der Verwendung von 0x0301 für TLS 1.0 und 0x0300 für SSL 3.0 ab. Um die Abwärtskompatibilität zu maximieren, sollte (SHOULD) ein Record, der ein initiales ClientHello enthält, die Version 0x0301 haben (was TLS 1.0 widerspiegelt), und ein Record, der ein zweites ClientHello oder ein ServerHello enthält, muss (MUST) die Version 0x0303 haben (was TLS 1.2 widerspiegelt). Beim Aushandeln früherer TLS-Versionen folgen Endpunkte dem in Anhang D angegebenen Verfahren und den dortigen Anforderungen.
Wenn der Record-Schutz noch nicht aktiviert wurde, werden TLSPlaintext-Strukturen direkt auf die Leitung geschrieben. Sobald der Record-Schutz begonnen hat, werden TLSPlaintext-Records geschützt und wie im folgenden Abschnitt beschrieben gesendet. Beachten Sie, dass Application-Data-Records nicht ungeschützt auf die Leitung geschrieben werden dürfen (MUST NOT) (Einzelheiten siehe Abschnitt 2).
5.2. Record Payload Protection (Schutz der Record-Nutzlast)
Die Record-Schutzfunktionen übersetzen eine TLSPlaintext-Struktur in eine TLSCiphertext-Struktur. Die Entschützungsfunktionen kehren den Prozess um. In TLS 1.3 werden, anders als in früheren TLS-Versionen, alle Chiffren als "Authenticated Encryption with Associated Data" (AEAD) modelliert [RFC5116]. AEAD-Funktionen bieten eine einheitliche Ver- und Entschlüsselungsoperation, die Klartext in authentifizierten Chiffretext und wieder zurück verwandelt. Jeder verschlüsselte Record besteht aus einem Klartext-Header, gefolgt von einem verschlüsselten Body, der selbst einen Typ und optionales Padding enthält.
struct {
opaque content[TLSPlaintext.length];
ContentType type;
uint8 zeros[length_of_padding];
} TLSInnerPlaintext;
struct {
ContentType opaque_type = application_data; /* 23 */
ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
uint16 length;
opaque encrypted_record[TLSCiphertext.length];
} TLSCiphertext;
content: Der Wert TLSPlaintext.fragment, der die Byte-Kodierung einer Handshake- oder Alarm-Nachricht oder die Rohbytes der zu sendenden Anwendungsdaten enthält.
type: Der Wert TLSPlaintext.type, der den Inhaltstyp des Records enthält.
zeros: Nach dem Feld type darf (MAY) eine Folge von Nullbytes beliebiger Länge im Klartext erscheinen. Dies bietet Absendern die Möglichkeit, jeden TLS-Record um einen gewählten Betrag zu padden, solange die Gesamtgröße innerhalb der Record-Größengrenzen bleibt. Weitere Einzelheiten siehe Abschnitt 5.4.
opaque_type: Das äußere Feld opaque_type eines TLSCiphertext-Records wird immer auf den Wert 23 (application_data) gesetzt, um die Abwärtskompatibilität mit Middleboxes zu wahren, die an das Parsen früherer TLS-Versionen gewöhnt sind. Der tatsächliche Inhaltstyp des Records findet sich nach der Entschlüsselung in TLSInnerPlaintext.type.
legacy_record_version: Das Feld legacy_record_version ist immer 0x0303. TLS-1.3-TLSCiphertexts werden erst nach der Aushandlung von TLS 1.3 erzeugt, sodass es keine historischen Kompatibilitätsbedenken gibt, bei denen andere Werte empfangen werden könnten. Beachten Sie, dass das Handshake-Protokoll, einschließlich der Nachrichten ClientHello und ServerHello, die Protokollversion authentifiziert, sodass dieser Wert redundant ist.
length: Die Länge (in Bytes) des folgenden TLSCiphertext.encrypted_record, die die Summe der Längen von Inhalt und Padding ist, plus eins für den inneren Inhaltstyp, plus jede durch den AEAD-Algorithmus hinzugefügte Erweiterung. Die Länge darf (MUST NOT) 2^14 + 256 Bytes nicht überschreiten. Ein Endpunkt, der einen Record empfängt, der diese Länge überschreitet, muss (MUST) die Verbindung mit einem "record_overflow"-Alarm beenden.
encrypted_record: Die AEAD-verschlüsselte Form der serialisierten TLSInnerPlaintext-Struktur.
AEAD-Algorithmen erhalten als Eingabe einen einzelnen Schlüssel, eine Nonce, einen Klartext und "additional data", die in die Authentifizierungsprüfung einbezogen werden, wie in Abschnitt 2.1 von [RFC5116] beschrieben. Der Schlüssel ist entweder client_write_key oder server_write_key, die Nonce wird aus der Sequenznummer und client_write_iv oder server_write_iv abgeleitet (siehe Abschnitt 5.3), und die Eingabe für additional data ist der Record-Header.
Das heißt,
additional_data = TLSCiphertext.opaque_type ||
TLSCiphertext.legacy_record_version ||
TLSCiphertext.length
Die Klartext-Eingabe für den AEAD-Algorithmus ist die kodierte TLSInnerPlaintext-Struktur. Die Ableitung der Traffic-Schlüssel ist in Abschnitt 7.3 definiert.
Die AEAD-Ausgabe besteht aus der Chiffretext-Ausgabe der AEAD-Verschlüsselungsoperation. Die Länge des Klartexts ist größer als das entsprechende TLSPlaintext.length, weil TLSInnerPlaintext.type und jegliches vom Absender bereitgestellte Padding enthalten sind. Die Länge der AEAD-Ausgabe ist im Allgemeinen größer als der Klartext, jedoch um einen Betrag, der mit dem AEAD-Algorithmus variiert. Da die Chiffren Padding einbeziehen können, kann der Overhead mit unterschiedlichen Klartextlängen variieren. Symbolisch:
AEADEncrypted =
AEAD-Encrypt(write_key, nonce, additional_data, plaintext)
Das Feld encrypted_record von TLSCiphertext wird auf AEADEncrypted gesetzt.
Zum Entschlüsseln und Verifizieren erhält die Chiffre den Schlüssel, die Nonce, die additional data und den Wert AEADEncrypted als Eingabe. Die Ausgabe ist entweder der Klartext oder ein Fehler, der angibt, dass die Entschlüsselung fehlgeschlagen ist. Es gibt keine separate Integritätsprüfung. Symbolisch:
plaintext of encrypted_record =
AEAD-Decrypt(peer_write_key, nonce,
additional_data, AEADEncrypted)
Wenn die Entschlüsselung fehlschlägt, muss (MUST) der Empfänger die Verbindung mit einem "bad_record_mac"-Alarm beenden.
Ein in TLS 1.3 verwendeter AEAD-Algorithmus darf (MUST NOT) keine Erweiterung von mehr als 255 Oktetten erzeugen. Ein Endpunkt, der von seinem Peer einen Record mit TLSCiphertext.length größer als 2^14 + 256 Oktette empfängt, muss (MUST) die Verbindung mit einem "record_overflow"-Alarm beenden. Diese Grenze leitet sich aus der maximalen TLSInnerPlaintext-Länge von 2^14 Oktetten + 1 Oktett für ContentType + der maximalen AEAD-Erweiterung von 255 Oktetten ab.
5.3. Per-Record Nonce (Pro-Record-Nonce)
Eine 64-Bit-Sequenznummer wird für das Lesen und Schreiben von Records getrennt geführt. Die passende Sequenznummer wird nach dem Lesen oder Schreiben jedes Records um eins erhöht. Jede Sequenznummer wird zu Beginn einer Verbindung und bei jedem Schlüsselwechsel auf null gesetzt; der erste unter einem bestimmten Traffic-Schlüssel übertragene Record muss (MUST) die Sequenznummer 0 verwenden.
Da die Größe der Sequenznummern 64 Bit beträgt, sollten sie nicht überlaufen. Wenn eine TLS-Implementierung eine Sequenznummer überlaufen lassen müsste, muss (MUST) sie entweder die Schlüssel erneuern (Abschnitt 4.6.3) oder die Verbindung beenden.
Jeder AEAD-Algorithmus gibt einen Bereich möglicher Längen für die Pro-Record-Nonce an, von N_MIN Bytes bis N_MAX Bytes Eingabe [RFC5116]. Die Länge der TLS-Pro-Record-Nonce (iv_length) wird auf den größeren Wert von 8 Bytes und N_MIN für den AEAD-Algorithmus gesetzt (siehe [RFC5116], Abschnitt 4). Ein AEAD-Algorithmus, bei dem N_MAX kleiner als 8 Bytes ist, darf (MUST NOT) nicht mit TLS verwendet werden. Die Pro-Record-Nonce für die AEAD-Konstruktion wird wie folgt gebildet:
-
Die 64-Bit-Record-Sequenznummer wird in Netzwerk-Byte-Reihenfolge kodiert und links mit Nullen auf iv_length aufgefüllt.
-
Die aufgefüllte Sequenznummer wird mit dem statischen client_write_iv oder server_write_iv (je nach Rolle) XOR-verknüpft.
Die resultierende Größe (der Länge iv_length) wird als Pro-Record-Nonce verwendet.
Hinweis: Dies ist eine andere Konstruktion als die in TLS 1.2, die eine teilweise explizite Nonce spezifizierte.
5.4. Record Padding (Record-Padding)
Alle verschlüsselten TLS-Records können gepaddet werden, um die Größe des TLSCiphertext aufzublähen. Dies ermöglicht es dem Absender, die Größe des Verkehrs vor einem Beobachter zu verbergen.
Beim Erzeugen eines TLSCiphertext-Records können (MAY) Implementierungen sich für Padding entscheiden. Ein ungepaddeter Record ist einfach ein Record mit einer Padding-Länge von null. Padding ist eine Zeichenfolge von Nullbytes, die vor der Verschlüsselung an das Feld ContentType angehängt wird. Implementierungen müssen (MUST) die Padding-Oktette vor der Verschlüsselung alle auf null setzen.
Application-Data-Records dürfen einen TLSInnerPlaintext.content der Länge null enthalten, wenn der Absender dies wünscht. Dies ermöglicht die Erzeugung von Deckverkehr plausibler Größe in Kontexten, in denen das Vorhandensein oder Fehlen von Aktivität sensibel sein kann. Implementierungen dürfen (MUST NOT) keine Handshake- und Alert-Records senden, die einen TLSInnerPlaintext.content der Länge null haben; wenn eine solche Nachricht empfangen wird, muss (MUST) die empfangende Implementierung die Verbindung mit einem "unexpected_message"-Alarm beenden.
Das gesendete Padding wird automatisch durch den Record-Schutzmechanismus verifiziert; nach erfolgreicher Entschlüsselung eines TLSCiphertext.encrypted_record durchsucht die empfangende Implementierung das Feld vom Ende zum Anfang, bis sie ein von null verschiedenes Oktett findet. Dieses von null verschiedene Oktett ist der Inhaltstyp der Nachricht. Dieses Padding-Schema wurde gewählt, weil es ermöglicht, jeden verschlüsselten TLS-Record um eine beliebige Größe zu padden (von null bis zu den TLS-Record-Größengrenzen), ohne neue Inhaltstypen einzuführen. Das Design erzwingt außerdem ausschließlich aus Nullen bestehende Padding-Oktette, was eine schnelle Erkennung von Padding-Fehlern ermöglicht.
Implementierungen müssen (MUST) ihr Durchsuchen auf den vom AEAD-Entschlüsselung zurückgegebenen Klartext beschränken. Wenn eine empfangende Implementierung kein von null verschiedenes Oktett im Klartext findet, muss (MUST) sie die Verbindung mit einem "unexpected_message"-Alarm beenden.
Das Vorhandensein von Padding ändert die Gesamtgrößengrenzen des Records nicht: Das vollständige kodierte TLSInnerPlaintext darf (MUST NOT) 2^14 + 1 Oktette nicht überschreiten. Wenn die maximale Fragmentlänge reduziert wird — etwa durch die Erweiterung record_size_limit aus [RFC8449] — gilt die reduzierte Grenze für den vollständigen Klartext, einschließlich Inhaltstyp und Padding.
Die Auswahl einer Padding-Richtlinie, die angibt, wann und wie viel gepaddet werden soll, ist ein komplexes Thema und liegt außerhalb des Geltungsbereichs dieser Spezifikation. Wenn das Anwendungsschichtprotokoll über TLS sein eigenes Padding hat, kann es vorzuziehen sein, Application-Data-TLS-Records innerhalb der Anwendungsschicht zu padden. Padding für verschlüsselte Handshake- oder Alert-Records muss jedoch weiterhin auf der TLS-Schicht behandelt werden. Spätere Dokumente können Padding-Auswahlalgorithmen definieren oder einen Mechanismus zur Anforderung einer Padding-Richtlinie über TLS-Erweiterungen oder andere Mittel definieren.
5.5. Limits on Key Usage (Grenzen der Schlüsselverwendung)
Es gibt kryptographische Grenzen für die Menge an Klartext, die unter einem gegebenen Schlüsselsatz sicher verschlüsselt werden kann. [AEAD-LIMITS] liefert eine Analyse dieser Grenzen unter der Annahme, dass die zugrunde liegende Primitive (AES oder ChaCha20) keine Schwächen aufweist. Implementierungen sollten (SHOULD) eine Schlüsselaktualisierung wie in Abschnitt 4.6.3 beschrieben durchführen, bevor diese Grenzen erreicht werden.
Für AES-GCM können bis zu 2^24.5 Records voller Größe (etwa 24 Millionen) auf einer gegebenen Verbindung verschlüsselt werden, während ein Sicherheitsabstand von etwa 2^-57 für die Authenticated-Encryption-(AE-)Sicherheit gewahrt bleibt. Bei ChaCha20/Poly1305 würde die Record-Sequenznummer überlaufen, bevor die Sicherheitsgrenze erreicht wird.