第 3 章:离线授权协议
本章定义 Authorization_Descriptor 的完整生命周期协议流程,包括签发、本地存储、校验、撤销、更新五个阶段。本章流程对应蓝图 §2.1 的设计意图。
3.1 签发流程(Issuance)
签发流程由 Descriptor_Issuer 在收到授权人的明确授权后执行。本规范定义签发结果的格式约束,但不规定授权人与 Descriptor_Issuer 之间的具体交互方式(不同部署可采用 Web 表单、移动 App 授权、企业授权管理系统等不同形式)。
3.1.1 签发输入
Descriptor_Issuer 在签发时 MUST 已确认以下信息:
- 授权人身份(
grantor_id)已通过 Descriptor_Issuer 自身的身份验证机制 - 授权范围(目标
subject_fay_id、terminal_id、grants)由授权人明确指定 - 有效期(
not_before、not_after)由授权人明确指定或采用默认策略
3.1.2 签发步骤
Descriptor_Issuer MUST 按以下步骤生成 Authorization_Descriptor:
- 生成标识:分配新的
descriptor_id(UUID v7),MUST NOT 复用已使用过的 ID - 构造载荷:按 §2.3.2 填充
DescriptorPayload,所有 required 字段 MUST 设置 - 校验约束:本地校验
not_after - not_before ≤ 90 天等约束(参见 §2.3.2) - CBOR 序列化:按 RFC 8949 确定性编码序列化 payload
- 数字签名:使用 Descriptor_Issuer 私钥按 §8 定义的算法对 payload 字节签名
- 组装结构:构造完整的
AuthorizationDescriptor,包含 version、payload、signature - 登记记录:在 Descriptor_Issuer 内部状态库中登记该凭证(用于后续撤销管理)
3.1.3 签发后交付
签发完成后,Descriptor_Issuer 将 Authorization_Descriptor 交付给目标 Fay。交付方式不在本规范范围内,但 SHOULD 满足:
- 通过加密通道交付,避免凭证在传输过程中被截获
- 交付到 Fay 所属的
iFay_Runtime,由 iFay_Runtime 代为持有
3.2 本地存储流程(Local Storage)
Fay 通过 iFay_Runtime 将 Authorization_Descriptor 提交给目标终端进行本地存储。
3.2.1 提交消息
iFay_Runtime 向 Protocol_Engine 发送 DescriptorSubmit 消息:
DescriptorSubmit (body of ProtocolMessage) {
required descriptor : AuthorizationDescriptor
}
3.2.2 终端处理
终端收到 DescriptorSubmit 后 MUST 按以下顺序处理:
- 结构校验:验证
descriptor符合 §2.3 定义的结构 - 签名校验:使用对应
key_id的 Verification_Key 校验 signature(参见 §3.3.4) - 去重检查:若本地已存储同
descriptor_id的凭证,且新提交的内容与已存储的字节级一致,返回成功;否则按重复 ID 错误拒绝 - 存储:将 Authorization_Descriptor 加密存储到本地安全存储区域(参见 §3.2.3)
- 返回结果:向 iFay_Runtime 返回
DescriptorSubmitResult消息,包含成功或错误码
3.2.3 存储要求
终端 MUST:
- 加密存储 Authorization_Descriptor,加密密钥不可被未授权进程读取
- 存储介质 SHOULD 具备防物理拆解能力(如安全芯片、TEE 等)
- 存储容量上限 SHOULD 不少于 1024 份凭证;超过上限时按 LRU 策略淘汰已过期的凭证
终端 MUST NOT:
- 将 Authorization_Descriptor 以明文形式存储
- 在存储前修改 descriptor 的任何字段(包括 metadata)
3.2.4 错误码
| 错误码 | 触发条件 |
|---|---|
E_INVALID_STRUCTURE | 结构不符合 §2.3 |
E_INVALID_SIGNATURE | 签名校验失败 |
E_UNKNOWN_ISSUER | key_id 对应的 Verification_Key 未在终端注册 |
E_DUPLICATE_DESCRIPTOR_ID | 与已存储的 descriptor_id 冲突且内容不一致 |
E_STORAGE_FULL | 存储容量已满且无法淘汰 |
E_VALIDITY_OUT_OF_RANGE | not_after - not_before 超出限制 |
3.3 校验流程(Validation)
校验流程在每次资源访问请求时执行。本节定义校验的完整步骤和判定规则。
3.3.1 校验触发
当 iFay_Runtime 发送 AuthRequest 请求资源访问时,终端 Protocol_Engine 触发校验流程:
AuthRequest (body of ProtocolMessage) {
required fay_id : Fay_ID
required resource_id : Resource_ID
required access_mode : AccessMode
required credential : CredentialReference
}
CredentialReference {
required type : enum["descriptor", "ticket"]
required id : string // descriptor_id 或 jti
}
注意:本规范的离线授权场景下,credential 引用的是已存储在终端的 Authorization_Descriptor,不需要在请求中传输完整凭证。
3.3.2 校验步骤(按顺序执行)
终端 MUST 按以下顺序执行校验。任一步骤失败立即返回对应错误码,不继续执行后续步骤。
第 1 步:凭证存在性
终端在本地存储中查找 credential.id 对应的 Authorization_Descriptor。
- 未找到 → 返回
E_DESCRIPTOR_NOT_FOUND
第 2 步:撤销状态
终端检查本地撤销列表,确认该 descriptor_id 未被撤销。
- 已撤销 → 返回
E_DESCRIPTOR_REVOKED
第 3 步:有效期
终端检查当前时间在 [not_before, not_after] 区间内。
- 当前时间 <
not_before→ 返回E_DESCRIPTOR_NOT_YET_VALID - 当前时间 ≥
not_after→ 返回E_DESCRIPTOR_EXPIRED
终端时钟来源:MUST 使用经过校准的系统时钟。终端 SHOULD 在长时间未联网时谨慎处理校验请求(参见 §3.6 时钟漂移处理)。
第 4 步:主体匹配
终端验证 payload.subject_fay_id == AuthRequest.fay_id。
- 不匹配 → 返回
E_SUBJECT_MISMATCH
第 5 步:终端匹配
终端验证 payload.terminal_id == 当前终端 ID。
- 不匹配 → 返回
E_TERMINAL_MISMATCH
第 6 步:资源与模式匹配
终端遍历 payload.grants,查找满足以下条件的 Grant:
Grant.resource_pattern按 §2.3.5 规则匹配AuthRequest.resource_idGrant.modes包含AuthRequest.access_mode- 若
Grant.constraints非空,所有约束条件满足(约束的语义参见 §7.4)
- 找不到满足的 Grant → 返回
E_AUTHORIZATION_INSUFFICIENT
第 7 步:签名校验
终端使用 signature.key_id 对应的 Verification_Key 重新校验 payload 的签名。
注意:步骤 1–6 的快速校验完成后才执行签名校验,以提供合理的失败语义(如先告知"凭证已撤销"而非"签名失败")。但在校验通过返回成功前,签名校验 MUST 已执行并通过。
- 签名校验失败 → 返回
E_INVALID_SIGNATURE - 签名密钥已撤销或过期 → 返回
E_VERIFICATION_KEY_INVALID
3.3.3 校验通过后
所有 7 步均通过后,终端按第 5 章流程创建 Session,并向 iFay_Runtime 返回:
AuthResult (body of ProtocolMessage, success) {
required status : "granted"
required session_id : Session_ID
required granted_modes : array<AccessMode>
required session_expires_at : timestamp
}
session_expires_at SHOULD 等于 min(not_after, 当前时间 + 默认会话最长时间)。
3.3.4 签名校验细节
签名校验的具体步骤:
- 提取
descriptor.signature.key_id,在终端 Verification_Key 存储中查找对应公钥 - 验证该 Verification_Key 在当前时间有效(
valid_from ≤ 当前时间 ≤ valid_until,若 valid_until 已设置) - 按 §2.3.3 规则将
descriptor.payload重新 CBOR 序列化 - 使用 Verification_Key 和
descriptor.signature.algorithm校验序列化字节的签名 - 校验成功后 MUST 缓存结果(同一 descriptor 在生命周期内仅需校验一次签名)
3.4 撤销流程(Revocation)
3.4.1 撤销发起
授权人通过 Descriptor_Issuer 发起撤销请求。撤销请求的具体交互形式不在本规范范围内。
Descriptor_Issuer 收到撤销请求后 MUST:
- 验证撤销请求来自原始授权人或具备撤销权限的实体
- 按 §2.8 生成
RevocationStatement - 使用与原始 Authorization_Descriptor 相同的签名密钥对撤销声明签名
- 将撤销声明加入 Descriptor_Issuer 维护的撤销列表
3.4.2 撤销分发
撤销声明通过以下方式分发到终端,终端 MUST 至少支持其中两种:
- 拉取同步(Pull-based):终端联网时主动从 Descriptor_Issuer 或撤销服务拉取增量撤销列表。同步频率由终端策略决定,SHOULD 不低于每小时一次(联网期间)
- 推送通知(Push-based):Descriptor_Issuer 通过 Registration_Authority 或专门的撤销分发服务向终端推送撤销声明
- 凭证内嵌(In-band):在 Trusted_Ticket 的 metadata 中携带最近撤销列表的摘要,使联网期间获取的票据自动捎带撤销信息
3.4.3 终端撤销列表维护
终端的本地撤销列表 MUST:
- 永久存储所有未过期的撤销声明
- 在凭证
not_after时间过去后 MAY 删除对应的撤销声明(凭证已自然失效) - 验证每条撤销声明的签名,拒绝无效签名的撤销声明
3.4.4 撤销生效时间
撤销声明的生效时间为:
生效时间 = max(撤销声明到达终端的时间, RevocationStatement.revoked_at)
终端 MUST 确保撤销声明到达后的下次校验请求即拒绝该凭证。终端 MAY 主动检查所有活跃 Session 是否引用了被撤销的凭证,若是则按第 5 章规则强制终止这些 Session。
3.4.5 撤销延迟窗口
由于离线分发的固有延迟,存在以下不可避免的撤销延迟窗口:
| 场景 | 最大延迟 |
|---|---|
| 终端持续联网 | 一次同步周期(默认 ≤ 1 小时) |
| 终端短期离线 | 重新联网后的下次同步 |
| 终端长期离线 | 最长延迟为凭证 not_after - 撤销时间,但不超过 90 天(凭证最长有效期) |
签发方 SHOULD 通过设置较短的 not_after(如 7 天)来限制最长撤销延迟。
3.5 更新流程(Renewal)
更新本质上是签发新的 Authorization_Descriptor 替代旧版本,并非修改现有凭证。
3.5.1 更新策略
授权人或自动续期机制可在以下场景触发更新:
- 凭证临近
not_after且授权关系仍然有效 - 授权范围需要调整(增加/减少 grants)
- 授权约束需要调整(修改 constraints)
3.5.2 更新流程
更新过程:
- Descriptor_Issuer 按 §3.1 流程签发新的 Authorization_Descriptor,使用新的
descriptor_id - 新凭证按 §3.2 流程提交到终端并存储
- 旧凭证 MAY 由签发方主动撤销(按 §3.4),也 MAY 由其自然过期失效
终端在新旧凭证并存期间,处理优先级:
- 校验请求 MUST 优先匹配未过期的凭证
- 多个未过期凭证均匹配时,使用
issued_at最近的凭证
3.5.3 不允许的更新行为
实现 MUST NOT:
- 修改已发布凭证的任何字段(包括 metadata)
- 复用旧凭证的
descriptor_id - 在旧凭证仍有效期间修改其语义(必须通过撤销 + 新签发实现)
3.6 时钟漂移处理
终端时钟可能因长期离线或硬件问题出现漂移。本节定义时钟漂移情况下的处理规则。
3.6.1 时钟容差
终端在校验有效期时 MAY 引入容差:
- 对
not_before:可允许至多 5 分钟的早期容差(接受当前时间 ≥ not_before - 5min) - 对
not_after:MUST NOT 引入容差(过期就是过期)
容差仅用于补偿短期时钟偏移,不应用于绕过有效期约束。
3.6.2 时钟可信性
终端 SHOULD 检测以下时钟异常并采取保护措施:
- 时钟显著回退(系统时钟向过去跳变 > 1 小时):拒绝校验请求直至时钟同步
- 时钟显著前移(系统时钟向未来跳变 > 24 小时):拒绝校验请求直至时钟同步
3.7 完整流程示意
[Descriptor_Issuer] [Fay/iFay_Runtime] [Terminal/Protocol_Engine]
│ │ │
│── 签发 AuthorizationDescriptor ─────→│ │
│ (含数字签名) │ │
│ │ │
│ │── DescriptorSubmit ─────────────────→│
│ │ │── 校验签名 + 存储
│ │←─ DescriptorSubmitResult ──────────── │
│ │ │
│ │── AuthRequest(带 descriptor_id)───→│
│ │ │── 7 步校验
│ │←─ AuthResult(granted)──────────────│
│ │ │── 创建 Session
│ │ │
│ │ 【Fay 持续访问资源】 │
│ │ │
│── 撤销 RevocationStatement ──────────────────────────────────────────────────→│
│ │ │── 加入撤销列表
│ │ │── 强制终止关联 Session
