跳到主要内容

2.8. Rekeying (重密钥)

2.8. Rekeying (重密钥)

IKE, ESP 与 AH 安全关联 (Security Association, SA) 使用的密钥只应在有限时间内使用并保护有限量的数据. 这限制了整个 SA 的生存期. 当 SA 生存期届满时, 绝对不能继续使用该 SA. 若有需要, 可以建立新的 SA. 为取代到期 SA 而重新建立 SA 称为 "rekeying" (重密钥).

为允许最小化 IPsec 实现, 在不重启整个 IKE SA 的情况下重密钥 SA 的能力是可选的. 实现可以拒绝 IKE SA 内的所有 CREATE_CHILD_SA 请求. 若 SA 已到期或即将到期, 且按本文机制进行的重密钥尝试失败, 实现必须关闭 IKE SA 及所有关联 Child SA, 然后可以启动新的. 实现可希望支持原地重密钥 SA, 因为这样性能更好, 且可能减少过渡期间丢失的分组数.

要在已有 IKE SA 内重密钥 Child SA, 应创建新的等价 SA (见下文 2.17 节), 新 SA 建立后删除旧的. 注意, 重密钥时, 新 Child SA 不应与旧的有不同的 Traffic Selector (流量选择子) 与算法.

要重密钥 IKE SA, 在现有 IKE SA 内使用 CREATE_CHILD_SA 与共享旧 IKE SA 的对等方建立新的等价 IKE SA (见下文 2.18 节). 如此创建的 IKE SA 继承原 IKE SA 的全部 Child SA, 新 IKE SA 用于维护这些 Child SA 所需的全部控制消息. 新的等价 IKE SA 创建后, 发起方删除旧 IKE SA, 且删除自身的 Delete 载荷必须是经旧 IKE SA 发送的最后一条请求.

应主动重密钥 SA, 即在新 SA 到期不可用之前先建立新 SA. 新 SA 建立与旧 SA 变为不可用之间应留出足够时间, 以便将流量切换到新 SA.

IKEv1 与 IKEv2 的一点差异是: IKEv1 会协商 SA 生存期. 在 IKEv2 中, SA 的每一端负责执行自身的生存期策略并在需要时重密钥. 若两端策略不同, 生存期较短的一端将总是发起重密钥的一方. 若 SA 长期无活动, 且端点在无流量时本不会发起该 SA, 则当生存期届满时端点可以选择关闭 SA 而非重密钥. 若自上次重密钥以来一直无流量, 亦可如此.

注意 IKEv2 有意允许在相同端点之间并行存在具有相同 Traffic Selector 的 SA. 目的之一是支持不同 SA 之间的流量服务质量 (QoS) 差异 (见 [DIFFSERVFIELD], [DIFFSERVARCH] 与 [DIFFTUNNEL] 的 4.1 节). 因此与 IKEv1 不同, 端点与 Traffic Selector 的组合未必能唯一标识其间的 SA, 故不应使用 IKEv1 基于重复 Traffic Selector 删除 SA 的启发式做法.

存在时间窗口, 尤其在丢包时, 两端可能对某 SA 的状态认识不一致. CREATE_CHILD_SA 的响应方必须准备在发送对创建请求的响应之前就在某 SA 上接受消息, 这样对发起方没有歧义. 发起方可以在处理完响应后立即开始在 SA 上发送. 但发起方在收到并处理完对其 CREATE_CHILD_SA 请求的响应之前, 无法在新创建的 SA 上接收. 那么响应方如何知道何时可以在新 SA 上发送?

从技术正确性与互操作性角度, 响应方可以在发送对 CREATE_CHILD_SA 请求的响应后立即开始在 SA 上发送. 但在某些情况下这可能导致分组被不必要丢弃, 因此实现可以推迟此类发送.

若 (1) 已在 SA 对的另一半上收到密码学上有效的消息, 或 (2) 新 SA 重密钥某已有 SA 且收到关闭被替换 SA 的 IKE 请求, 则响应方可确信发起方已准备好在该 SA 上接收. 重密钥 SA 时, 响应方继续在旧 SA 上发送流量, 直到上述事件之一发生. 建立新 SA 时, 响应方可以推迟在新 SA 上发送消息, 直到收到来自对端的消息或发生超时. 若发起方在某 SA 上收到消息, 但尚未收到对其 CREATE_CHILD_SA 请求的响应, 则将其解释为可能丢包并重传 CREATE_CHILD_SA 请求. 若队列中没有消息, 发起方可以在新创建的 ESP SA 上发送哑 ESP 消息, 以向响应方表明已准备好接收.

2.8.1. Child SA 同时重密钥

若两端生存期策略相同, 双方可能同时发起重密钥 (导致冗余 SA). 为降低概率, 重密钥请求的时机应该加入抖动 (在发现需要重密钥后随机延迟一段时间).

这种重密钥可能暂时在相同节点对之间产生多个相似 SA. 当有两个 SA 均可接收分组时, 节点必须能通过任一 SA 接受入站分组. 若因碰撞产生冗余 SA, 应用两次交换中所用四个 nonce 中最低者创建的那条 SA 应该由创建它的端点关闭. "最低" 指按字节比较 (而非例如将 nonce 当作大整数比较). 即从第一字节开始比较; 若相等则比较下一字节, 依此类推. 若某一 nonce 先结束, 则该 nonce 更低. 发起存活重密钥 SA 的一方应在新 SA 建立后删除被替换的 SA.

以下说明对实现的影响. 假定主机 A 与 B 有 SPI 为 (SPIa1,SPIb1) 的 Child SA 对, 双方同时开始重密钥:

Host A                            Host B
-------------------------------------------------------------------
send req1: N(REKEY_SA,SPIa1),
SA(..,SPIa2,..),Ni1,.. -->
<-- send req2: N(REKEY_SA,SPIb1),
SA(..,SPIb2,..),Ni2
recv req2 <--

此时 A 知道正在发生同时重密钥, 但尚不能知道哪次交换的 nonce 更低, 因此只记录情况并照常响应.

send resp2: SA(..,SPIa3,..),
Nr1,.. -->
--> recv req1

此时 B 也知道同时重密钥正在进行, 照常响应.

                              <--  send resp1: SA(..,SPIb3,..),
Nr2,..
recv resp1 <--
--> recv resp2

此时 A 与 B 之间有三对 Child SA (旧的一对与两对新的). A 与 B 可比较 nonce. 假定 resp2 中 Nr1 为最低; 则 B (req2 的发送方) 删除冗余的新 SA, A (发起存活重密钥 SA 的节点) 删除旧 SA.

send req3: D(SPIa1) -->
<-- send req4: D(SPIb2)
--> recv req3
<-- send resp3: D(SPIb1)
recv req4 <--
send resp4: D(SPIa3) -->

重密钥完成.

但若网络丢包导致重传, 还可能出现另一序列. 重密钥照常开始, 但 A 的第一个分组 (req1) 丢失.

Host A                            Host B
-------------------------------------------------------------------
send req1: N(REKEY_SA,SPIa1),
SA(..,SPIa2,..),
Ni1,.. --> (lost)
<-- send req2: N(REKEY_SA,SPIb1),
SA(..,SPIb2,..),Ni2
recv req2 <--
send resp2: SA(..,SPIa3,..),
Nr1,.. -->
--> recv resp2
<-- send req3: D(SPIb1)
recv req3 <--
send resp3: D(SPIa1) -->
--> recv resp3

从 B 看来重密钥已完成, 且尚未收到 A 的 req1, 甚至不知道曾发生同时重密钥. 但 A 会继续重传, 最终到达 B.

resend req1 -->
--> recv req1

对 B 而言 A 似乎在重密钥已不存在的 SA; 因此 B 以非致命方式响应, 例如 CHILD_SA_NOT_FOUND.

                               <--  send resp1: N(CHILD_SA_NOT_FOUND)
recv resp1 <--

A 收到该错误时已知曾发生同时重密钥, 可忽略该错误消息.

2.8.2. IKE SA 同时重密钥

最复杂的情况可能是双方同时尝试重密钥 IKE_SA. 基本上 2.8 节的文字也适用于此; 但必须确保 Child SA 由正确的 IKE_SA 继承.

两端都察觉到同时重密钥时, 与 Child SA 情形相同. CREATE_CHILD_SA 交换后, A 与 B 之间存在三条 IKE SA: 旧的与两条新的. 含最低 nonce 的新 IKE SA 应该由创建它的节点删除, 另一条存活的新 IKE SA 必须继承所有 Child SA.

除正常同时重密钥外, 还有一种特例: 一方在完成重密钥时尚未注意到另一方也在重密钥. 若仅一方检测到同时重密钥, 不会产生冗余 SA. 此时, 未察觉的一方收到重密钥其已成功重密钥的 IKE SA 的请求时, 应该返回 TEMPORARY_FAILURE, 因为它正在尝试关闭该 IKE SA (无论是否已发送该 SA 的删除通知). 若察觉到同时重密钥的一方收到对端删除旧 IKE SA 的请求, 可知对端未检测到同时重密钥, 第一方可以放弃自身的重密钥尝试.

Host A                      Host B
-------------------------------------------------------------------
send req1:
SA(..,SPIa1,..),Ni1,.. -->
<-- send req2: SA(..,SPIb1,..),Ni2,..
--> recv req1
<-- send resp1: SA(..,SPIb2,..),Nr2,..
recv resp1 <--
send req3: D() -->
--> recv req3

此时主机 B 看到关闭 IKE_SA 的请求, 除照常回复外没有太多可做. 但此时 B 应停止重传 req2, 因为一旦 A 收到 resp3, 将删除与旧 IKE_SA 相关的全部状态, 无法再对其作出回应.

                          <-- send resp3: ()

TEMPORARY_FAILURE 通知未包含在 RFC 4306 中, 对 TEMPORARY_FAILURE 的支持也未协商. 因此仅实现 RFC 4306 而未实现本文档的旧对等方可能收到这些通知. 此时它们会像对待任何其他未知错误通知一样处理并停止交换. 由于对方已重密钥该交换, 这样做并无不良后果.

2.8.3. IKE SA 重密钥与重新认证

在 IKEv2 中, IKE SA 重密钥与重新认证 (reauthentication) 是不同的概念. 重密钥 IKE SA 为 IKE SA 建立新密钥并重置 Message ID 计数器, 但不再次认证双方 (不涉及 AUTH 或 EAP 载荷).

虽然在某些环境中重密钥 IKE SA 很重要, 重新认证 (验证双方仍拥有长期凭据) 往往更重要.

IKEv2 对重新认证没有专门支持. 重新认证通过从零创建新 IKE SA (使用 IKE_SA_INIT/IKE_AUTH 交换, 不带任何 REKEY_SA Notify 载荷), 在新 IKE SA 内创建新 Child SA (不带 REKEY_SA Notify 载荷), 最后删除旧 IKE SA (同时删除旧 Child SA) 来完成.

这意味着重新认证也会为 IKE SA 与 Child SA 建立新密钥. 因此, 虽然重密钥可以比重新认证更频繁, 但 "认证生存期" 短于 "密钥生存期" 的情形没有意义.

虽然任一方 (原 IKE SA 中的发起方或响应方) 都可发起创建新 IKE SA, 但 EAP 与/或 Configuration 载荷的使用意味着实践中重新认证须由原 IKE SA 的同一方发起. IKEv2 目前不允许响应方在此情形下请求重新认证; 不过有扩展可增加此能力, 例如 [REAUTH].