跳到主要内容

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].