跳到主要内容

4.2. Sequence Number and Epoch (序列号和时期)

4.2. Sequence Number and Epoch (序列号和时期)

DTLS使用显式或部分显式的序列号, 而不是隐式序列号, 该序列号携带在记录的sequence_number字段中。序列号为每个epoch单独维护, 每个epoch的每个sequence_number初始值为0。

epoch编号最初为零, 并且每次密钥材料更改且发送方旨在重新密钥时递增。更多详细信息在第6.1节中提供。

4.2.1. Processing Guidelines (处理指南)

由于DTLS记录可能会被重新排序, 来自epoch M的记录可能在epoch N (其中N > M)开始后被接收。实现应该丢弃来自较早epoch的记录, 但可以选择保留来自先前epoch的密钥材料最长至为TCP [RFC0793]指定的默认MSL, 以允许数据包重新排序。(请注意, 这里的意图是实现者使用IETF关于MSL的当前指导, 如[RFC0793]或其后续规范中所指定, 而不是尝试查询系统TCP堆栈正在使用的MSL。)

相反, 使用新epoch保护的记录可能在握手完成之前被接收。例如, 服务器可能发送其Finished消息, 然后开始传输数据。实现可以缓冲或丢弃此类记录, 但是当DTLS在可靠传输上使用时(例如, SCTP [RFC4960]), 应该在握手完成后缓冲并处理它们。请注意, TLS对何时可以发送记录的限制仍然适用, 并且接收方将记录视为以正确顺序发送。

实现必须使用与原始传输相同的epoch和密钥材料发送丢失消息的重传。

实现必须在允许序列号回绕之前放弃关联或重新密钥。

实现绝对不能允许epoch回绕, 而必须建立新关联, 终止旧关联。

4.2.2. Reconstructing the Sequence Number and Epoch (重构序列号和时期)

当接收受保护的DTLS记录时, 接收方在记录中没有完整的epoch或序列号值, 因此存在一些歧义的机会。因为完整序列号用于计算每个记录的nonce, 而epoch确定密钥, 所以无法重构这些值会导致无法解保护记录, 因此实现可以使用其选择的机制来确定完整值。本节提供了一个相对简单的算法, 建议实现遵循该算法。

如果epoch位与当前epoch的位匹配, 则实现应该通过计算数值上最接近当前epoch中最高成功解保护记录的序列号加一的完整序列号来重构序列号。

在握手阶段, epoch位明确指示要使用的正确密钥。握手完成后, 如果epoch位与当前epoch的位不匹配, 则实现应该使用具有匹配位的最近过去的epoch, 然后如上所述重构该epoch的序列号。

4.2.3. Record Number Encryption (记录号加密)

在DTLS 1.3中, 当记录被加密时, 记录序列号也被加密。基本模式是使用与AEAD算法一起使用的底层加密算法生成掩码, 然后将该掩码与序列号进行XOR运算。

当AEAD基于AES时, 通过在密文的前16个字节上计算AES-ECB来生成掩码:

Mask = AES-ECB(sn_key, Ciphertext[0..15])

当AEAD基于ChaCha20时, 通过将密文的前4个字节视为块计数器, 将接下来的12个字节视为nonce, 将它们传递给ChaCha20块函数(CHACHA的第2.3节)来生成掩码:

Mask = ChaCha20(sn_key, Ciphertext[0..3], Ciphertext[4..15])

sn_key的计算如下:

[sender]_sn_key = HKDF-Expand-Label(Secret, "sn", "", key_length)

[sender]表示发送方。要使用的每个epoch的Secret值在[TLS13]的第7.3节中描述。请注意, 每个epoch使用一个新密钥: 因为epoch以明文发送, 所以这不会导致歧义。

加密的序列号通过将掩码的前导字节与序列号的线上表示进行XOR运算来计算。解密通过相同过程完成。

此过程要求密文长度至少为16个字节。接收方必须拒绝较短的记录, 如同它们解保护失败一样, 如第4.5.2节所述。发送方必须填充短明文(使用常规记录填充机制)以生成合适长度的密文。请注意, 大多数DTLS AEAD算法都有16字节的认证标签, 不需要填充。但是, 某些算法, 例如TLS_AES_128_CCM_8_SHA256, 具有较短的认证标签, 对于短输入可能需要填充。

未来不基于AES或ChaCha20的密码套件必须定义自己的记录序列号加密才能与DTLS一起使用。

请注意, 序列号加密仅应用于DTLSCiphertext结构, 而不应用于DTLSPlaintext结构, 即使它也包含序列号。