RFC6479:IPsec Anti-Replay Algorithm without Bit Shifting,January 2012
梗概
本文档介绍了另一种方法来执行 IP 身份验证报文头 (Authentication Header,AH) 和封装安全协议 (Encapsulating Security Protocol,ESP) 的抗重放检查和更新。本文档中定义的方法消除了对位移的需要,并减少了调整抗重放窗口的次数。
本备忘录的状态
本文档不是 Internet Standards Track 规范;它是为了提供信息而发布的。
这是对 RFC 系列的贡献,独立于任何其他 RFC 流。RFC 编辑器自行决定发布此文档,并且未声明其实施或部署的价值。经 RFC 编辑批准发布的文档不属于任何级别的 Internet 标准;请参阅 RFC 5741 的第 2 节。
有关本文档当前状态、勘误表以及如何提供反馈的信息,请访问 http://www.rfc-editor.org/info/rfc6479。
版权声明
版权所有 (c) 2012 IETF Trust 和文件作者。版权所有。
本文件受 BCP 78 和 IETF 信托关于 IETF 文件的法律规定 (http://trustee.ietf.org/license-info) 的约束,在本文件发布之日有效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。
1、 简介
“IP Authentication Header” [RFC4302] 和“IP Encapsulating Security Payload (ESP)” [RFC4303] 定义了一种采用滑动窗口机制的抗重放服务。当接收方启用该机制时,使用大小为 W 的抗重放窗口。该窗口限制了数据包的乱序程度,相对于迄今为止已通过身份验证的具有最高序列号的数据包。窗口可以用范围[WB,WT]表示,其中WB=WT-W+1。整个抗重放窗口可以被认为是一串比特。每个比特的值表示具有该序列号的数据包是否已被接收和验证,以便可以检测和拒绝重放数据包。如果数据包被接收到,接收方就得到数据包中的序列号S。如果 S 在窗口内(S<=WT 且 S>=WB),则接收器检查窗口中的相应位(位置为 S-WB)以查看该 S 是否已被看到。如果 S<WB,则丢弃数据包。如果 S>WT 并且被验证,则窗口前进 (S-WT) 位。新窗口变为 [WB+S-WT, S]。这个新窗口中的新位被设置为指示没有接收到具有这些序列号的数据包。典型的实现(例如,完整性算法 [RFC4302])是通过移位 (S-WT) 位来完成的。在正常情况下,数据包按顺序到达,这会导致持续更新和位移操作。
[RFC4302] 和 [RFC4303] 定义了 32 和 64 的最小窗口大小。但是对于超过 64 个数据包的最小或推荐窗口大小没有建立要求。窗口大小需要基于对数据包重新排序的合理预期。对于具有多个加密内核的高端、多核网络处理器,由于不同内核导致的 IPsec 处理延迟不同,因此需要大于 64 或 128 的窗口大小。在这种情况下,即使使用硬件加速来进行位移,窗口滑动的成本也非常高。本文档描述了一种避免位移的替代方法。只讨论接收端的抗重放处理。处理始终是安全的,并且没有互操作性影响。即使窗口大小大于通常的 32 位或 64 位窗口,也不会导致互操作性问题。
但是,任何采用可能导致超出通常的 32 位或 64 位窗口重新排序的做法的节点都可能导致互操作性或性能问题。例如,如果发送节点或路径上的路由器导致重大的重新排序,这可能导致接收 IPsec 端点无法处理数据包,因为许多当前的实现不支持本备忘录中定义的扩展。类似地,这种重新排序可能会导致传输和上层协议出现重大问题,通常最好避免。
2、 新的抗重放算法说明
在这里,我们提供了一种仅更新窗口索引的简单方法,同时还减少了窗口更新次数。基本思想如下图所示。假设我们配置了窗口大小 W,它由 M-1 个块组成,其中 M 是2的幂。每个块包含 N 位,其中 N 也是2的幂。它可以是一个字节(8 位)或字(32 位)或多个字。支持的滑动窗口大小为 (M-1)*N。但是,它覆盖了 M 个块(如图 1 所示的四个块)。所有这些 M 个块都被循环并成为一个块环,每个块有 N 个比特。这样,当窗口滑动时,支持的滑动窗口(M-1个块)始终是实际窗口的子窗口。
最初,实际窗口由低端和高端索引 [WB, WT] 定义,如图 1 所示。
图 1:滑动窗口 [WB, WT]
其中 WT 是最后验证的序列号,支持的窗口大小 W 为 WT-WB+1。(x=无关位,c=检查位)
如果我们收到一个序列号 (S) 大于 WT 的数据包,我们滑动窗口。但是我们只通过将差异(S-WT)添加到 WT 和 WB 来更改窗口索引(WB 会随着窗口大小的固定而自动更改)。因此,S 成为接收数据包的最大序列号。图2显示了接收到序列号为S=WT+1的数据包的情况。
图2:S=WT+1后的滑动窗口[WB, WT]
如果 S 与 WT 位于不同的块中,我们必须将块中的所有位值初始化为 0 而不进行位移。如果 S 通过几个块,我们必须初始化几个块而不是只初始化一个块。图 3 显示序列号已经通过了块边界。更新后,WT 所在的块中的所有校验位都应为 0。
图3:S经过边界后的滑动窗口[WB, WT]
更新后,新窗口仍然覆盖配置的窗口。这意味着配置的子窗口也会滑动,符合滑动窗口协议。实际效果有点像移动方块。这样,位移被认为是不必要的。
使用序列号检查窗口也更容易和更快,因为序列号检查不依赖于最低索引 WB。相反,它只取决于接收到的数据包的序列号。如果我们收到一个序列号S,位位置是序列号的最低几位,这仅取决于块大小(N)。块索引在位置位之前几位,这仅取决于窗口大小(M)。
我们没有指定需要多少冗余位,只是为了计算效率,它应该是2的幂。如果微处理器是 32 位,则 32 可能是更好的选择,而 64 可能更适合 64 位微处理器。对于支持高速缓存的微处理器,一个高速缓存行也是一个不错的选择。它还取决于滑动窗口的大小。如果我们有 N 个冗余位(例如上面描述的 32 位),我们只需要更新 1/N 次块,与 [RFC4302] 中的位移算法相比。
这种方法的代价是额外的字节被用作冗余窗口。如果窗口大小足够大,成本将是最低的。实际上,额外的冗余位并没有完全浪费。我们可以重用索引 WB 所在的块中未使用的位,即支持的窗口大小可以是 (M-1)*N,加上最后一个块中的未使用位。
3、 新的抗重放算法示例
这是实现抗重放检查和更新算法的示例代码,在前面的部分中进行了描述。
<CODE BEGINS> /** * 版权所有 (c) 2012 IETF Trust 和代码作者。版权所有。 * 根据 IETF 信托与 IETF 文件有关的法律规定第 4.c 节中规定的简化 BSD 许可证中包含的许可条款,允许以源代码和二进制形式重新分发和使用,无论是否经过修改 (http://trustee.ietf.org/license-info)。*/ /** * 在此算法中,隐藏窗口大小必须是 2 的幂,例如 1024 位。冗余位也必须是 2 的幂,例如 32 位。因此,支持的抗重放窗口大小是隐藏窗口大小减去冗余位,在本例中为 992。整数的大小取决于微处理器架构。在本例中,我们假设软件在 32 位微处理器上运行。所以整数的大小是32。为了将位图转换为整数数组,整数的总数是隐藏窗口大小除以整数大小。 * struct ipsec_sa 包含窗口和窗口相关参数,例如窗口大小和最后确认的序列号。 * 宏的所有值都可以更改,但必须遵循算法中定义的规则。*/ #define SIZE_OF_INTEGER 32 /** 32-bit microprocessor */ #define BITMAP_LEN (1024/ SIZE_OF_INTEGER) /** in terms of the 32-bit integer */ #define BITMAP_INDEX_MASK (IPSEC_BITMAP_LEN-1) #define REDUNDANT_BIT_SHIFTS 5 #define REDUNDANT_BITS (1<<REDUNDANT_BIT_SHIFTS) #define BITMAP_LOC_MASK (IPSEC_REDUNDANT_BITS-1) int ipsec_check_replay_window (struct ipsec_sa *ipsa, uint32_t sequence_number) { int bit_location; int index; /** *重放关闭*/ if (ipsa->replaywin_size == 0) { return 1; } /** * first == 0 or wrapped */ if (sequence_number == 0) { return 0; } /** *首先检查序列号是否在范围内*/ if (sequence_number>ipsa->replaywin_lastseq) { return 1; /**越大越好*/ } /** * 报文太久并且超出窗口*/ if ((sequence_number + ipsa->replaywin_size) < ipsa->replaywin_lastseq) { return 0; } /** * 序列在滑动窗口内 * 现在检查位图中的位 * 位位置仅取决于序列号*/ bit_location = sequence_number&BITMAP_LOC_MASK; index = (sequence_number>>REDUNDANT_BIT_SHIFTS)&BITMAP_INDEX_MASK; /* *这个数据包已经收到*/ if (ipsa->replaywin_bitmap[index]&(1<<bit_location)) { return 0; } return 1; } int ipsec_update_replay_window (struct ipsec_sa *ipsa, uint32_t sequence_number) { int bit_location; int index, index_cur, id; int diff; if (ipsa->replaywin_size == 0) { /** replay shut off */ return 1; } if (sequence_number == 0) { return 0; /** first == 0 or wrapped */ } /** *包太旧,不需要更新*/ if ((ipsa->replaywin_size + sequence_number) <ipsa->replaywin_lastseq) { return 0; } /** *现在更新位 */ index = (sequence_number>>REDUNDANT_BIT_SHIFTS); /** *首先检查序列号是否在范围内 */ if (sequence_number>ipsa->replaywin_lastseq) { index_cur = ipsa->replaywin_lastseq>>REDUNDANT_BIT_SHIFTS; diff = index - index_cur; if (diff > BITMAP_LEN) { /* something unusual in this case */ diff = BITMAP_LEN; } for (id = 0; id < diff; ++id) { ipsa->replaywin_bitmap[(id+index_cur+1)&BITMAP_INDEX_MASK]= 0; } ipsa->replaywin_lastseq = sequence_number; } index &= BITMAP_INDEX_MASK; bit_location = sequence_number&BITMAP_LOC_MASK; /* this packet has already been received */ if (ipsa->replaywin_bitmap[index]&(1<<bit_location)) { return 0; } ipsa->replaywin_bitmap[index] |= (1<<bit_location); return 1; } <CODE ENDS>
4、 安全考虑
本文档不会更改 [RFC4302] 或 [RFC4303]。它为抗重放提供了另一种方法。
5、 致谢
本文档中的想法来自一个高性能多核网络处理器上的软件设计。新的网络处理器核心以分布式方式集成了十几个加密核心,这使得硬件防重放服务变得不可能。
6、 规范性参考
[RFC4302] Kent, S., "IP Authentication Header", RFC 4302, December 2005. [RFC4303] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC 4303, December 2005.