TLS 记录协议如何重组接收到的数据?
How does the TLS Record Protocol reassemble received data?
我找不到有关 TLS 记录协议如何重组接收到的数据的详细信息。在 RFC 5246 中:
Received data is decrypted, verified, decompressed, reassembled,
and then delivered to higher-level clients.
但是怎么做呢?这是记录层数据的样子:
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
长度字段就是片段的长度:
The length (in bytes) of the following TLSPlaintext.fragment
我希望在记录协议中看到完整的长度 Header。 Google 几乎没有给出任何结果,这让我觉得我遗漏了一些明显的东西......
TLS 在流上执行,这些流中的数据被放入一个或多个片段(最大 2^14 字节)。这叫做碎片化。
规范本身的内容如下:
Client
message boundaries are not preserved in the record layer (i.e.,
multiple client messages of the same ContentType MAY be coalesced
into a single TLSPlaintext record, or a single message MAY be
fragmented across several records).
这与将它们放入一个流中,然后再次将流分成单独的片段是一样的。
如果您通过 TLS 接收数据,则必须从单独的片段中重新创建该流。因此,发生的 "reassembly" 是将片段简单地串联成一个流。
套接字包含输出和输入流。输出流需要分片,输入流需要重组。
没有什么神奇的事情发生,这可能就是为什么你找不到太多东西的原因。
然而,应用层通常会被提供一个相对较低级别的 TLS 层接口,这将允许它包装或发送自己的片段。例如,此 API by IBM 表明它允许用户包装和发送或接收和解包每条消息本身。在这种情况下,库的用户需要处理任何消息碎片/重组。
由于 TLS 未指定分段/组装的实际方法,因此应将其视为特定于实现。
我也有过同样的疑问,通过一些研究我得出以下结论:如果你在可靠的协议(例如 TCP)之上使用 TLS,那么重组只是串联的结果收到的记录协议片段。由于这样一个可靠的协议保证数据以与发送时相同的顺序接收(当然,没有损坏),接收到的字节的简单连接就足以进行重组,并且由客户端知道如何解释那些接收到的字节。但是,当 TLS 不是 运行 通过像 TCP 这样的可靠协议时会发生什么?有一个名为 Datagram Transport Layer Security 的协议可以做到这一点。直接引用自维基百科:
because it uses UDP or SCTP, the application has to deal with packet reordering, loss of datagram and data larger than the size of a datagram network packet
在这种情况下它究竟是如何工作的?我从 IETF 找到了这个 draft,它概述了 DTLS 的工作原理。包含应用程序数据的消息的问题已通过以下约束解决:
Each DTLS message MUST fit within a single transport layer datagram
然而,握手消息是另一回事:
However, handshake messages are potentially bigger than the maximum record size. Therefore, DTLS provides a mechanism for fragmenting a handshake message over a number of records, each of which can be transmitted separately, thus avoiding IP fragmentation
具体的握手消息格式如下:
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
uint16 message_seq; /* DTLS-required field */
uint24 fragment_offset; /* DTLS-required field */
uint24 fragment_length; /* DTLS-required field */
select (HandshakeType) {
case client_hello: ClientHello;
case server_hello: ServerHello;
case end_of_early_data: EndOfEarlyData;
case hello_retry_request: HelloRetryRequest;
case encrypted_extensions: EncryptedExtensions;
case certificate_request: CertificateRequest;
case certificate: Certificate;
case certificate_verify: CertificateVerify;
case finished: Finished;
case new_session_ticket: NewSessionTicket;
case key_update: KeyUpdate; /* reserved */
} body;
} Handshake;
如您所见,它包括一个序列号、一个片段偏移量和一个片段长度。这些是我还希望在 TLS 记录协议的消息 header 中看到的字段,但结果证明在使用 TCP 时不需要它们。
我希望你会觉得这有用。
我找不到有关 TLS 记录协议如何重组接收到的数据的详细信息。在 RFC 5246 中:
Received data is decrypted, verified, decompressed, reassembled, and then delivered to higher-level clients.
但是怎么做呢?这是记录层数据的样子:
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
长度字段就是片段的长度:
The length (in bytes) of the following TLSPlaintext.fragment
我希望在记录协议中看到完整的长度 Header。 Google 几乎没有给出任何结果,这让我觉得我遗漏了一些明显的东西......
TLS 在流上执行,这些流中的数据被放入一个或多个片段(最大 2^14 字节)。这叫做碎片化。
规范本身的内容如下:
Client message boundaries are not preserved in the record layer (i.e., multiple client messages of the same ContentType MAY be coalesced into a single TLSPlaintext record, or a single message MAY be fragmented across several records).
这与将它们放入一个流中,然后再次将流分成单独的片段是一样的。
如果您通过 TLS 接收数据,则必须从单独的片段中重新创建该流。因此,发生的 "reassembly" 是将片段简单地串联成一个流。
套接字包含输出和输入流。输出流需要分片,输入流需要重组。
没有什么神奇的事情发生,这可能就是为什么你找不到太多东西的原因。
然而,应用层通常会被提供一个相对较低级别的 TLS 层接口,这将允许它包装或发送自己的片段。例如,此 API by IBM 表明它允许用户包装和发送或接收和解包每条消息本身。在这种情况下,库的用户需要处理任何消息碎片/重组。
由于 TLS 未指定分段/组装的实际方法,因此应将其视为特定于实现。
我也有过同样的疑问,通过一些研究我得出以下结论:如果你在可靠的协议(例如 TCP)之上使用 TLS,那么重组只是串联的结果收到的记录协议片段。由于这样一个可靠的协议保证数据以与发送时相同的顺序接收(当然,没有损坏),接收到的字节的简单连接就足以进行重组,并且由客户端知道如何解释那些接收到的字节。但是,当 TLS 不是 运行 通过像 TCP 这样的可靠协议时会发生什么?有一个名为 Datagram Transport Layer Security 的协议可以做到这一点。直接引用自维基百科:
because it uses UDP or SCTP, the application has to deal with packet reordering, loss of datagram and data larger than the size of a datagram network packet
在这种情况下它究竟是如何工作的?我从 IETF 找到了这个 draft,它概述了 DTLS 的工作原理。包含应用程序数据的消息的问题已通过以下约束解决:
Each DTLS message MUST fit within a single transport layer datagram
然而,握手消息是另一回事:
However, handshake messages are potentially bigger than the maximum record size. Therefore, DTLS provides a mechanism for fragmenting a handshake message over a number of records, each of which can be transmitted separately, thus avoiding IP fragmentation
具体的握手消息格式如下:
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
uint16 message_seq; /* DTLS-required field */
uint24 fragment_offset; /* DTLS-required field */
uint24 fragment_length; /* DTLS-required field */
select (HandshakeType) {
case client_hello: ClientHello;
case server_hello: ServerHello;
case end_of_early_data: EndOfEarlyData;
case hello_retry_request: HelloRetryRequest;
case encrypted_extensions: EncryptedExtensions;
case certificate_request: CertificateRequest;
case certificate: Certificate;
case certificate_verify: CertificateVerify;
case finished: Finished;
case new_session_ticket: NewSessionTicket;
case key_update: KeyUpdate; /* reserved */
} body;
} Handshake;
如您所见,它包括一个序列号、一个片段偏移量和一个片段长度。这些是我还希望在 TLS 记录协议的消息 header 中看到的字段,但结果证明在使用 TCP 时不需要它们。
我希望你会觉得这有用。