摘要

  • 在 RFC 2412 的三消息激进交换中,双方可以验证签名并把 KEYID 标为已认证,同时把 Diffie–Hellman 密钥材料保留在 uncomputed 状态。
  • 因此,“通信证明”不能替代共享秘密的计算证明;计算也不能替代双端安全关联安装、受保护报文或应用结果的证明。

安全系统最容易制造误会的地方,往往不是密码公式,而是一个看起来已经结束的状态词。

RFC 2412 在 1998 年 11 月以 Informational 文档发布。它描述 OAKLEY:两个经过认证的参与方以 Diffie–Hellman 为基本机制,协商秘密密钥材料,并可选择辅助算法、获得前向保密、定义群结构、更新密钥,或把带外密钥纳入流程。它不是 Internet 标准,也没有声称替代消费这些密钥材料的 AH、ESP 或安全关联管理。

真正值得回看的,是文档对“完成”的拆分。

在激进示例中,发起方首先发送 cookie、群标识、公开半密钥 g^x、算法选项、双方身份和 nonce,并对这些字段签名。响应方返回自己的 cookie、g^y、选定算法、两个 nonce 与签名。发起方再发送第三条签名消息,把完整交换收束起来。

RFC 2412 说,数字签名可形成“通信证明”,可以保存并在日后向第三方出示。但紧接着,它又说明:由群指数隐含的密钥材料并不是完成交换所必需的。

实现可以保存自己的私有指数 x 和对端公开值 g^y,把密钥材料标记为 uncomputed,稍后再算。

处理步骤把时间差写得更具体。发起方收到响应后,先验证 cookie 与响应方签名,把 g^y 和算法选择写入状态。它可以计算 (g^y)^x = g^xy,也可以等到最后一条回复发出以后再做。与此同时,它已经把由两个 cookie 构成的 KEYID 标为已认证。响应方收到最后一条消息并验证签名后,也把密钥状态标为已认证,然后“应当”计算 g^xy 并将其关联到 KEYID。

认证边界已经跨过,计算边界却未必跨过。

KEYID 的命名方式使这一点格外清晰。两个 cookie 既承担较弱的地址验证和抗阻塞作用,又拼接成密钥材料的可复用名称。sKEYID 则是这个名称所指向的秘密材料;它不在网络上传输,在该示例中由 g^xy、双方 nonce 和 cookie 共同派生。名称可以先于内容存在。名称被认证,也不等于内容已经生成。

一旦运维界面只保留一个绿色指示灯,这个区别就会消失。“已认证”被读成“已就绪”,“已就绪”被读成“双端都已安装”,“已安装”又被读成“流量已经受到正确保护”。每次推断都借用了下一层的事实,却没有下一层的收据。

延后计算本身并不荒谬。模幂运算在当时成本很高。把它移出最后一条消息的关键路径,可以降低可见握手时延或分散 CPU 压力。对端收到的签名字段并未因此改变。只要共享协议保持一致,每台机器何时执行本地运算,本可保留一定自主空间。

但是,节省眼前计算,就会增加状态保管义务。实现必须保存正确的私有指数、对端公开值、所选群、双方 cookie、双方 nonce、身份与算法,并确保它们不会同另一会话混接。它还必须先验证输入,再计算共享值、派生材料、绑定身份与 KEYID,最后送入正确的运行时安全关联。

进程崩溃、状态过期、句柄复用或重启丢失,都可能让签名 transcript 依旧完整,却让密钥永远无法产生。此时,“通信证明”仍是真的;“可用安全通道”却从未成真。

所以需要一条分层证据链。Transcript 收据证明预期签名覆盖了预期字段。输入验证收据证明公开群元素满足当前协议要求。计算收据证明 g^xy 与派生材料确已产生。绑定收据证明这些材料属于预期身份、算法与 KEYID。安装收据证明正确状态进入本端安全关联。双端收据证明对端也完成相应动作。报文收据证明受保护流量通过。应用收据才证明服务目标实现。

前一张收据不能替后一张签字。

RFC 2412 已经要求 nonce、cookie 和指数使用良好随机源,并建议拒绝若干退化的模幂值。它的已发布勘误纠正了“安全素数”和“Sophie Germain 素数”的术语倒置,但没有改变延后计算机制。

后来的 RFC 6989 对 IKEv2 的 Diffie–Hellman 公钥验证提出了更明确要求,包括针对小子群的检查。无效的 KE 载荷必须被丢弃,不能用于创建 IKE SA。这份 2013 年文档不能倒推某个 1998 年 OAKLEY 或 IKEv1 实现究竟做了什么;它只能再次提醒我们:收到字节不是验证成功,验证成功也不是密钥已经安装。

OAKLEY 的思路随后进入 RFC 2409 所定义的 IKEv1。其 Aggressive Mode 同样允许最后一条消息不受 ISAKMP SA 保护,从而把指数运算推迟到交换完成之后。但 IKEv1 的密钥派生仍依赖真实的 g^xy。消息发完可以先发生,密钥材料却不能从“完成”这个词里凭空产生。

IKEv2 后来重组了这套结构。RFC 4306、RFC 5996 与 RFC 7296 构成前后相继的协议世代。RFC 7296 以双方 nonce 和临时 Diffie–Hellman 共享秘密计算 SKEYSEED,再派生不同用途的加密、完整性、认证与后续派生密钥。它还区分:IKE SA 可以已经认证,而 Child SA 或配置请求仍可能失败。

这不是把 RFC 2412 的状态机原样延续到今天。它说明的是另一个持续存在的工程事实:控制平面某一层的成功,不会自动创造依赖它的数据平面状态。

文档状态也不能替代运行状态。RFC 2412 是 Informational;RFC 2409 走过标准轨道;IKEv2 随后取代 IKEv1;算法要求继续更新;RFC 9395 最终弃用 IKEv1 与若干旧算法。发布、取代与弃用会改变当前规范,但不会远程卸载每一台设备上的旧代码。

这正是 Lu Heng“运行代码优先”框架可以发挥作用的地方。规范可以定义一项状态转移的意义,只有执行中的实现才能证明它真的发生。“现实层”不是机构可以任选的叙事版本,而是一串有依赖关系的事实:消息抵达、签名通过、公开值验证、共享秘密计算、材料绑定、SA 安装、报文接受、业务成功。

“最小初始规范”则给出建设性边界。独立实现必须共享签名字段、派生规则、群参数和状态语义;但只要不破坏安全与互操作,就不必由中心文档规定每台机器必须在哪一个 CPU 周期执行指数运算。本地决策可以保留,本地责任不能消失。

选择延后计算的一方控制着一段对外不可见的时间。它可能得到更短的表面时延,而应用与运营者承担密钥未能生成的后果。因此,实现必须准确暴露这段状态、妥善保存输入,并在计算失败时撤销所有依赖它的更强声明。不能让“已认证”成为一张无限透支的支票。

RFC 2412 最诚实的遗产,也许正是 uncomputed 这个看似临时的词。它承认当前证据有效,同时拒绝假装下一项事实已经发生。

交换已经认证。共享秘密仍需计算。安全关联仍需绑定和安装。报文仍需通过。服务仍需验证。

可信系统的第一项能力,就是把这些动词逐一说清。

来源