@agentunion/fastaun-browser 0.2.18 → 0.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/_packed_docs/CHANGELOG.md +26 -0
  3. package/_packed_docs/agent.md/SCHEMA.md +173 -0
  4. package/_packed_docs/agent.md/examples/codeagent-claudecode.md +61 -0
  5. package/_packed_docs/agent.md/examples/human-developer.md +60 -0
  6. package/_packed_docs/agent.md/examples/openclaw-lobster.md +52 -0
  7. package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +43 -0
  8. package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +205 -0
  9. package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +197 -0
  10. package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +549 -0
  11. package/_packed_docs/protocol/02-/350/257/201/344/271/246/344/270/216/344/277/241/344/273/273/344/275/223/347/263/273.md +810 -0
  12. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +262 -0
  13. package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +180 -0
  14. package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +164 -0
  15. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1135 -0
  16. package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +234 -0
  17. package/_packed_docs/protocol/08-AUN-E2EE-Group.md +900 -0
  18. package/_packed_docs/protocol/08-AUN-E2EE.md +413 -0
  19. package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +316 -0
  20. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +804 -0
  21. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +271 -0
  22. package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +329 -0
  23. package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +141 -0
  24. package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +170 -0
  25. package/_packed_docs/protocol/README.md +71 -0
  26. package/_packed_docs/protocol/agent.md/SCHEMA.md +118 -0
  27. package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +61 -0
  28. package/_packed_docs/protocol/agent.md/examples/human-developer.md +60 -0
  29. package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +52 -0
  30. package/_packed_docs/protocol/aun-docs-guide.md +49 -0
  31. package/_packed_docs/protocol/index.md +114 -0
  32. package/_packed_docs/protocol//350/215/211/346/241/210-agent.md/347/255/276/345/220/215/345/215/217/350/256/256.md +205 -0
  33. package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +249 -0
  34. package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +337 -0
  35. package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +80 -0
  36. package/_packed_docs/protocol//351/231/204/345/275/225C-/347/247/201/351/222/245/347/256/241/347/220/206/344/270/216/350/272/253/344/273/275/346/201/242/345/244/215.md +704 -0
  37. package/_packed_docs/protocol//351/231/204/345/275/225D-Root_CA_/346/262/273/347/220/206/346/234/272/345/210/266.md +620 -0
  38. package/_packed_docs/protocol//351/231/204/345/275/225E-Root_CA_/345/207/206/345/205/245/346/265/201/347/250/213.md +605 -0
  39. package/_packed_docs/protocol//351/231/204/345/275/225F-Issuer_CA_/347/224/263/350/257/267/346/265/201/347/250/213.md +548 -0
  40. package/_packed_docs/protocol//351/231/204/345/275/225G-AID_/345/255/244/345/204/277/351/242/204/351/230/262/344/270/216/346/225/221/346/217/264/346/234/272/345/210/266.md +513 -0
  41. package/_packed_docs/protocol//351/231/204/345/275/225H-Identity/346/234/215/345/212/241/345/256/236/347/216/260/346/214/207/345/215/227.md +619 -0
  42. package/_packed_docs/protocol//351/231/204/345/275/225I-/350/267/250/345/237/237/346/266/210/346/201/257/350/267/257/347/224/261/345/256/236/347/216/260/346/214/207/345/215/227.md +492 -0
  43. package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +402 -0
  44. package/_packed_docs/protocol//351/231/204/345/275/225K-Agent_Web/345/217/221/347/216/260/345/215/217/350/256/256.md +130 -0
  45. package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +267 -0
  46. package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +367 -0
  47. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +223 -0
  48. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +354 -0
  49. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +172 -0
  50. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +373 -0
  51. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +611 -0
  52. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +1152 -0
  53. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +150 -0
  54. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +89 -0
  55. package/_packed_docs/sdk/09-custody-api-manual.md +445 -0
  56. package/_packed_docs/sdk/09-group-rpc-manual.md +1895 -0
  57. package/_packed_docs/sdk/09-message-rpc-manual.md +597 -0
  58. package/_packed_docs/sdk/09-meta-rpc-manual.md +142 -0
  59. package/_packed_docs/sdk/09-payload-reference.md +702 -0
  60. package/_packed_docs/sdk/09-storage-rpc-manual.md +408 -0
  61. package/_packed_docs/sdk/09-stream-rpc-manual.md +275 -0
  62. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +72 -0
  63. package/_packed_docs/sdk/INDEX.md +131 -0
  64. package/_packed_docs/sdk/README.md +307 -0
  65. package/dist/auth.d.ts +11 -1
  66. package/dist/auth.d.ts.map +1 -1
  67. package/dist/auth.js +92 -17
  68. package/dist/auth.js.map +1 -1
  69. package/dist/client.d.ts +51 -9
  70. package/dist/client.d.ts.map +1 -1
  71. package/dist/client.js +394 -122
  72. package/dist/client.js.map +1 -1
  73. package/dist/e2ee.d.ts.map +1 -1
  74. package/dist/e2ee.js +20 -0
  75. package/dist/e2ee.js.map +1 -1
  76. package/dist/keystore/index.d.ts +11 -0
  77. package/dist/keystore/index.d.ts.map +1 -1
  78. package/dist/keystore/indexeddb.d.ts +35 -0
  79. package/dist/keystore/indexeddb.d.ts.map +1 -1
  80. package/dist/keystore/indexeddb.js +91 -0
  81. package/dist/keystore/indexeddb.js.map +1 -1
  82. package/dist/namespaces/auth.d.ts +10 -3
  83. package/dist/namespaces/auth.d.ts.map +1 -1
  84. package/dist/namespaces/auth.js +94 -15
  85. package/dist/namespaces/auth.js.map +1 -1
  86. package/dist/transport.d.ts +9 -1
  87. package/dist/transport.d.ts.map +1 -1
  88. package/dist/transport.js +24 -0
  89. package/dist/transport.js.map +1 -1
  90. package/package.json +4 -1
@@ -0,0 +1,316 @@
1
+ ## 9. 安全考虑
2
+
3
+ ### 9.1 威胁模型
4
+
5
+ AUN 在 `gateway`、`peer`、`relay` 三种模式下都面临安全威胁,只是攻击面位置不同:
6
+ - 未授权访问
7
+ - 中间人攻击
8
+ - DDoS 攻击
9
+ - 会话劫持
10
+ - 私钥泄露
11
+ - 协议降级与链路劫持
12
+ - 假地址注入与恶意升级信令
13
+
14
+ ### 9.2 防护措施
15
+
16
+ **传输层安全**:
17
+ - 强制 TLS (wss://)
18
+ - 证书验证
19
+ - 最低 TLS 1.2
20
+
21
+ **认证**:
22
+ - JWT token 身份认证(Auth 服务签发,ECDSA 签名)
23
+ - token 过期机制(建议 1-24 小时)
24
+ - token 刷新机制
25
+ - 会话隔离(不同用户消息严格隔离)
26
+ - Peer / Relay 模式下的证书链验证与双向 nonce challenge
27
+
28
+ > **授权说明**:AUN 协议层仅定义身份认证(authentication),不定义细粒度授权(authorization)。JWT claim 中的 `aid` 标识请求者身份,各 AUN 服务根据 `aid` 和自身业务逻辑实现资源访问控制。协议通过三个错误码区分不同的拒绝场景:`-32013` 表示未完成握手、`-32005` 表示 token 过期需重新登录、`-32003` 表示业务层权限拒绝。
29
+
30
+ **限流与防护**(推荐实现):
31
+ - 连接频率限制
32
+ - 消息速率限制
33
+ - 最大消息大小限制
34
+ - IP 黑名单
35
+
36
+ > 注:以上防护措施是实现层面的建议,不是协议强制要求。实现者可根据实际需求选择合适的防护策略。
37
+
38
+ **私钥安全**:
39
+ - Gateway 不持有用户 AID 私钥
40
+ - 私钥完全由客户端管理
41
+ - 私钥永远不传输到 Gateway
42
+ - Gateway 使用 Auth 服务签发的 JWT token 代表用户身份
43
+ - 客户端负责私钥的安全存储(详见第 3.5 节)
44
+
45
+ ### 9.3 责任边界
46
+
47
+
48
+ **Gateway 的责任**:
49
+ - **消息路由**:根据 AID 转发消息到目标
50
+ - **JWT token 验证**:验证客户端提供的 token 有效性
51
+ - **请求转发**:将 `auth.*` 等请求转发到对应的 AUN 服务(Auth、Message 等)
52
+
53
+ > **重要**:Gateway 不处理业务逻辑。AID 创建、两步登录等所有 `auth.*` 方法由 Auth 服务处理,Gateway 只负责路由转发。
54
+
55
+ **应用开发者的责任**:
56
+ - 用户身份管理
57
+ - 客户端私钥生成和安全存储
58
+ - 私钥访问控制(本地)
59
+ - 跨设备同步策略(可选)
60
+ - 密钥备份和恢复机制
61
+
62
+ **客户端的责任**:
63
+ - 私钥本地生成
64
+ - 私钥安全存储(Keychain/Keystore/IndexedDB)
65
+ - 用私钥签名 nonce 完成认证
66
+ - 私钥永远不离开客户端
67
+
68
+ **关键点**:
69
+ - Gateway 是 AUN 网络的一种接入网关
70
+ - 私钥管理完全由客户端控制
71
+ - Gateway 不参与私钥管理
72
+ - 符合零信任安全模型
73
+
74
+ ### 9.4 JWT 信任模型分析
75
+
76
+ #### 9.4.1 单一信任根架构
77
+
78
+ AUN 的 JWT 认证基于**单一信任根**:只有 Auth 服务持有签发私钥,所有其他服务通过公钥验证。
79
+
80
+ ```
81
+ ┌─────────────────────────────────────────────────┐
82
+ │ 单一信任根架构 │
83
+ ├─────────────────────────────────────────────────┤
84
+ │ │
85
+ │ Auth 服务 │
86
+ │ ├─ 持有私钥(唯一能签发 token) │
87
+ │ └─ 签发 JWT token │
88
+ │ │
89
+ │ 所有 AUN 服务 │
90
+ │ ├─ HB (Heartbeat) │
91
+ │ ├─ MSG (Message) │
92
+ │ ├─ Storage │
93
+ │ ├─ Group │
94
+ │ └─ 都持有 Auth 服务的公钥证书 │
95
+ │ └─ 可以验证 token(ECDSA 非对称签名) │
96
+ │ │
97
+ │ Gateway │
98
+ │ ├─ 只能转发认证请求 │
99
+ │ ├─ 无法伪造 Auth 服务的签名 │
100
+ │ └─ 恶意 Gateway 签发的假 token 会被拒绝 │
101
+ │ │
102
+ └─────────────────────────────────────────────────┘
103
+ ```
104
+
105
+ #### 9.4.2 防止 Gateway 作恶
106
+
107
+ 1. **无法伪造 token**:
108
+ - Gateway 没有 Auth 服务的私钥
109
+ - 无法生成有效的 ECDSA 签名
110
+ - 所有服务都会拒绝无效签名的 token
111
+
112
+ 2. **无法冒充其他用户**:
113
+ - Token 中的 `aid` 字段标识用户身份
114
+ - 即使恶意 Gateway 用自己的 AID 获取 token
115
+ - 也无法访问其他用户的资源(token 中的 aid 与资源归属不匹配)
116
+
117
+ 3. **私钥不经过 Gateway**:
118
+ - 客户端本地签名 nonce
119
+ - Gateway 只转发签名,看不到私钥
120
+ - 无法伪造用户签名
121
+
122
+ #### 9.4.3 跨域消息路由安全
123
+
124
+ 跨 Issuer 通信的安全由多层机制保障:
125
+
126
+ 1. **mTLS 双向认证**:Gateway 间通过 mTLS 建立连接,双方证书链必须可验证到受信 Root CA
127
+ 2. **Issuer 验证**:接收方验证消息 `from` 字段的 Issuer 与 mTLS 证书 Issuer 一致,防止跨 Issuer 伪造
128
+ 3. **发送者签名**:消息携带发送者的 ECDSA 签名,接收方可用发送者公钥验证消息真实性
129
+ 4. **E2EE 保护**:消息内容端到端加密,中转 Gateway 仅转发密文,无法解密
130
+
131
+ **攻击隔离**:
132
+ - 即使某个 Issuer 的 Gateway 被攻破,也只能影响该 Issuer 的用户
133
+ - 无法伪造其他 Issuer 用户的消息(Issuer 验证机制)
134
+ - 无法解密消息内容(E2EE 保护)
135
+
136
+ ### 9.5 连接升级与模式切换安全
137
+
138
+ `peer.offer` 允许把现有稳定通道升级为更优链路,但也引入了新的攻击面。实现方必须把升级视为独立的安全敏感流程,而不是普通业务消息。
139
+
140
+ #### 9.5.1 降级攻击
141
+
142
+ 攻击者可能阻断 `peer.offer`、`peer.accept` 或 `peer.switch`,迫使双方长期停留在 `gateway` 或 `relay` 通道。
143
+
144
+ **影响**:
145
+ - 无法使用低延迟直连
146
+ - 更容易暴露链路元数据
147
+ - 可能诱导实现方错误地把“升级失败”视为“对端不可用”
148
+
149
+ **要求**:
150
+ - 升级失败时,客户端 **MUST** 保持原有已认证通道可继续工作
151
+ - 实现 **MUST NOT** 因升级失败而丢弃当前业务连接
152
+ - 实现 **SHOULD** 对升级失败与业务通道失败分别记录日志
153
+
154
+ #### 9.5.2 假地址注入
155
+
156
+ 攻击者可能通过伪造 `peer.offer` 中的 `endpoints`,诱导一方去连接恶意地址。
157
+
158
+ **风险**:
159
+ - 目标被引导连接攻击者控制的主机
160
+ - 实现若错误地“只看地址不验身份”,可能造成链路劫持
161
+
162
+ **要求**:
163
+ - `peer.offer` 只能作为“尝试建立新通道”的信令,**MUST NOT** 单独构成身份信任依据
164
+ - 新通道建立后,双方 **MUST** 重新执行 `initialize(mode=peer)` 与完整 `peer.*` 认证
165
+ - 只有在新通道 `peer.confirmed` 成功后,才可发送 `peer.switch`
166
+ - 实现 **SHOULD** 对 `peer.offer.endpoints` 做基本策略校验,如协议、端口范围、地址白名单或 NAT 策略检查
167
+
168
+ #### 9.5.3 回退通道滥用
169
+
170
+ 若实现保留旧通道作为 fallback,攻击者可能利用“主通道/备通道并存”造成重复投递、状态不一致或把敏感流量强制打回旧通道。
171
+
172
+ **要求**:
173
+ - 切换期间旧通道 **MUST** 只作为 fallback,不应与新主通道无序并发发送同一业务消息
174
+ - 实现 **SHOULD** 为主通道选择维护显式状态,如 `primary` / `fallback`
175
+ - `meta.status` **SHOULD** 暴露当前主通道与 fallback 状态,便于诊断
176
+
177
+ #### 9.5.4 升级信令重放
178
+
179
+ 旧的 `peer.offer`、`peer.accept`、`peer.switch` 被重放,可能导致重复切换、错误回退或异常连接风暴。
180
+
181
+ **要求**:
182
+ - 升级控制消息 **MUST** 带 `session_id`
183
+ - 升级控制消息 **SHOULD** 限定短有效期,如 `expires_in <= 30s`
184
+ - 实现 **SHOULD** 对已处理的 `session_id` 去重
185
+ - 超时或已完成的升级会话 **MUST NOT** 被再次接受
186
+
187
+ #### 9.5.5 连接升级的最小安全原则
188
+
189
+ 1. 原通道先存在且已认证
190
+ 2. 升级信令仅交换地址和意图,不直接授予信任
191
+ 3. 新通道重新执行完整认证
192
+ 4. 新通道认证成功后再切换主通道
193
+ 5. 旧通道在切换确认前保持可用
194
+ 6. 升级失败时安全回退,不影响业务可用性
195
+
196
+ ### 9.6 公开 AP 同步与 Agent 发现安全
197
+
198
+ `search.*` 与公开 AP 同步把 `agent.md` 从“单点公开页面”提升为“可在全网传播的索引对象”,因此攻击面不再只是页面内容本身,还包括来源伪造、镜像污染、快照篡改和抓取滥用。
199
+
200
+ #### 9.6.1 来源伪造与索引投毒
201
+
202
+ 攻击者可能伪造 `source_ap`、伪造 `agent_md_url` 或向公开 AP 注入伪造的 `agent.md`,诱导聚合器把恶意记录加入全网搜索结果。
203
+
204
+ **要求**:
205
+ - 聚合器 **MUST NOT** 仅凭 `aid` 字符串就信任一条 `agent.md`
206
+ - 聚合器 **SHOULD** 校验 `origin_url` 是否与该 `aid` 的公开 Web 入口规则一致
207
+ - 聚合器 **SHOULD** 记录 `source_ap`、`origin_url`、`agent_md_sha256` 和抓取时间,便于审计与回滚
208
+ - 对无法验证来源、缺少更新时间或频繁抖动的记录,聚合器 **SHOULD** 降权或隔离
209
+
210
+ #### 9.6.2 快照篡改与增量插入
211
+
212
+ 若公开 AP 返回的 `search.snapshot` 或 `search.changes` 被中间人篡改,聚合器可能同步到错误内容,导致全网目录污染。
213
+
214
+ **要求**:
215
+ - 公开 AP 同步接口 **MUST** 运行在 TLS 保护的通道上
216
+ - 公开 AP **SHOULD** 为快照、增量页或其摘要提供签名校验材料
217
+ - 聚合器 **SHOULD** 对 `snapshot_version`、`sequence`、`cursor` 单调性做校验,发现倒退或跳变时拒绝直接覆盖本地索引
218
+ - 若校验失败,聚合器 **MUST** 将该来源标记为异常,并停止继续应用该来源的增量变更
219
+
220
+ #### 9.6.3 删除传播与误删风险
221
+
222
+ 删除事件若处理不当,可能导致恶意 AP 通过伪造 `delete` 批量清空公开索引,或让聚合器误以为某个 Agent 已永久下线。
223
+
224
+ **要求**:
225
+ - 聚合器 **MUST** 把 `delete` 解释为“该来源撤回了该公开记录”,而不是默认代表全网永久删除
226
+ - 聚合器 **MUST** 结合原始来源与其他有效来源判断是否真正移除某个 `aid`
227
+ - 对高价值 Agent,聚合器 **SHOULD** 采用延迟删除、二次确认或多来源确认策略
228
+
229
+ #### 9.6.4 抓取滥用与资源消耗
230
+
231
+ 公开 AP 若无节制暴露快照和增量接口,可能被恶意客户端反复抓取,造成带宽、存储和 CPU 消耗。
232
+
233
+ **要求**:
234
+ - 实现 **SHOULD** 对 `search.snapshot`、`search.changes` 施加速率限制、分页上限与并发控制
235
+ - 实现 **SHOULD** 为大快照提供分页、压缩和缓存
236
+ - 实现 **SHOULD** 区分普通终端查询和 AP 同步抓取的限额策略
237
+ - 对异常频繁的游标回退、全量重拉或大规模枚举行为,服务端 **SHOULD** 记录审计日志并触发告警
238
+
239
+ #### 9.6.5 最小安全原则
240
+
241
+ 1. 公开搜索结果默认视为最终一致,而非绝对真相
242
+ 2. 来源元数据必须和内容一起传播
243
+ 3. 快照与增量都应可校验、可审计、可回放
244
+ 4. 删除语义必须谨慎,不能让单个镜像来源删除全网记录
245
+ 5. 聚合器要能隔离异常来源,而不是把异常扩散到全网索引
246
+
247
+ ### 9.7 证书轮换后的验签时序校验
248
+
249
+ 仅验证“签名数学正确 + 证书链有效 + 证书未过期”不足以满足 AUN 的证书轮换安全要求。
250
+
251
+ 如果旧证书在数据库中已被标记为 `verify_only`,但验签方不检查签名时间,那么攻击者仍可能使用旧私钥伪造“看起来合法”的新消息。因此,AUN 要求验签流程增加证书状态与时间窗口校验。
252
+
253
+ #### 9.7.1 额外校验规则
254
+
255
+ 验签方除标准 PKI 校验外,还应执行以下逻辑:
256
+
257
+ 1. 根据 `cert_sn` 精确定位签名所用证书
258
+ 2. 获取证书状态:`active_signing`、`verify_only`、`revoked`、`expired`
259
+ 3. 校验 `sign_time` 是否落在证书有效期内
260
+ 4. 若证书状态为 `verify_only`,则必须额外满足:
261
+ - `sign_time < deactivated_at`
262
+ 5. 若证书状态为 `revoked`,默认拒绝
263
+
264
+ #### 9.7.2 在线验签与历史验签
265
+
266
+ AUN 建议区分两类验签场景:
267
+
268
+ | 场景 | 推荐策略 |
269
+ |------|---------|
270
+ | 在线实时消息 | 要求签名证书在 `sign_time` 时处于 `active_signing` |
271
+ | 历史审计/归档验证 | 可接受 `verify_only`,但仍要求 `sign_time` 落在其活跃期内 |
272
+
273
+ #### 9.7.3 参考伪代码
274
+
275
+ ```python
276
+ def verify_message(envelope, payload, cert_store):
277
+ cert = cert_store.get_by_serial(envelope["cert_sn"])
278
+ if cert is None:
279
+ return False, "cert not found"
280
+
281
+ if cert.lifecycle_state == "revoked":
282
+ return False, "cert revoked"
283
+
284
+ if envelope["sign_time"] < cert.valid_notbefore or envelope["sign_time"] > cert.valid_notafter:
285
+ return False, "sign_time outside cert validity"
286
+
287
+ if cert.lifecycle_state == "verify_only":
288
+ if cert.deactivated_at is None:
289
+ return False, "missing deactivated_at"
290
+ if envelope["sign_time"] >= cert.deactivated_at:
291
+ return False, "signature created after cert deactivation"
292
+
293
+ signed_bytes = canonical_encode({
294
+ "aid": envelope["aid"],
295
+ "cert_sn": envelope["cert_sn"],
296
+ "alg": envelope["alg"],
297
+ "sign_time": envelope["sign_time"],
298
+ "msg_id": envelope["msg_id"],
299
+ "payload_hash": envelope["payload_hash"],
300
+ })
301
+
302
+ return verify_signature(cert.public_key, envelope["sig"], signed_bytes, envelope["alg"])
303
+ ```
304
+
305
+ #### 9.7.4 与实现层的职责分工
306
+
307
+ 该安全规则需要多层配合:
308
+
309
+ - **签发/轮换服务**:更新证书状态,将旧证书从 `active_signing` 切换为 `verify_only`
310
+ - **持钥组件**:只允许当前 `active_signing` 证书产生新签名
311
+ - **验签组件**:执行状态与时间窗口校验
312
+
313
+ 若缺少最后一层,旧私钥在协议层仍可能被用来伪造“新消息”。
314
+
315
+
316
+ ---