第 3 章:离线授权协议

本章定义 Authorization_Descriptor 的完整生命周期协议流程,包括签发、本地存储、校验、撤销、更新五个阶段。本章流程对应蓝图 §2.1 的设计意图。

3.1 签发流程(Issuance)

签发流程由 Descriptor_Issuer 在收到授权人的明确授权后执行。本规范定义签发结果的格式约束,但不规定授权人与 Descriptor_Issuer 之间的具体交互方式(不同部署可采用 Web 表单、移动 App 授权、企业授权管理系统等不同形式)。

3.1.1 签发输入

Descriptor_Issuer 在签发时 MUST 已确认以下信息:

  1. 授权人身份(grantor_id)已通过 Descriptor_Issuer 自身的身份验证机制
  2. 授权范围(目标 subject_fay_idterminal_idgrants)由授权人明确指定
  3. 有效期(not_beforenot_after)由授权人明确指定或采用默认策略

3.1.2 签发步骤

Descriptor_Issuer MUST 按以下步骤生成 Authorization_Descriptor:

  1. 生成标识:分配新的 descriptor_id(UUID v7),MUST NOT 复用已使用过的 ID
  2. 构造载荷:按 §2.3.2 填充 DescriptorPayload,所有 required 字段 MUST 设置
  3. 校验约束:本地校验 not_after - not_before ≤ 90 天 等约束(参见 §2.3.2)
  4. CBOR 序列化:按 RFC 8949 确定性编码序列化 payload
  5. 数字签名:使用 Descriptor_Issuer 私钥按 §8 定义的算法对 payload 字节签名
  6. 组装结构:构造完整的 AuthorizationDescriptor,包含 version、payload、signature
  7. 登记记录:在 Descriptor_Issuer 内部状态库中登记该凭证(用于后续撤销管理)

3.1.3 签发后交付

签发完成后,Descriptor_Issuer 将 Authorization_Descriptor 交付给目标 Fay。交付方式不在本规范范围内,但 SHOULD 满足:

  1. 通过加密通道交付,避免凭证在传输过程中被截获
  2. 交付到 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 按以下顺序处理:

  1. 结构校验:验证 descriptor 符合 §2.3 定义的结构
  2. 签名校验:使用对应 key_id 的 Verification_Key 校验 signature(参见 §3.3.4)
  3. 去重检查:若本地已存储同 descriptor_id 的凭证,且新提交的内容与已存储的字节级一致,返回成功;否则按重复 ID 错误拒绝
  4. 存储:将 Authorization_Descriptor 加密存储到本地安全存储区域(参见 §3.2.3)
  5. 返回结果:向 iFay_Runtime 返回 DescriptorSubmitResult 消息,包含成功或错误码

3.2.3 存储要求

终端 MUST:

  1. 加密存储 Authorization_Descriptor,加密密钥不可被未授权进程读取
  2. 存储介质 SHOULD 具备防物理拆解能力(如安全芯片、TEE 等)
  3. 存储容量上限 SHOULD 不少于 1024 份凭证;超过上限时按 LRU 策略淘汰已过期的凭证

终端 MUST NOT:

  1. 将 Authorization_Descriptor 以明文形式存储
  2. 在存储前修改 descriptor 的任何字段(包括 metadata)

3.2.4 错误码

错误码触发条件
E_INVALID_STRUCTURE结构不符合 §2.3
E_INVALID_SIGNATURE签名校验失败
E_UNKNOWN_ISSUERkey_id 对应的 Verification_Key 未在终端注册
E_DUPLICATE_DESCRIPTOR_ID与已存储的 descriptor_id 冲突且内容不一致
E_STORAGE_FULL存储容量已满且无法淘汰
E_VALIDITY_OUT_OF_RANGEnot_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

  1. Grant.resource_pattern 按 §2.3.5 规则匹配 AuthRequest.resource_id
  2. Grant.modes 包含 AuthRequest.access_mode
  3. 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 签名校验细节

签名校验的具体步骤:

  1. 提取 descriptor.signature.key_id,在终端 Verification_Key 存储中查找对应公钥
  2. 验证该 Verification_Key 在当前时间有效(valid_from ≤ 当前时间 ≤ valid_until,若 valid_until 已设置)
  3. 按 §2.3.3 规则将 descriptor.payload 重新 CBOR 序列化
  4. 使用 Verification_Key 和 descriptor.signature.algorithm 校验序列化字节的签名
  5. 校验成功后 MUST 缓存结果(同一 descriptor 在生命周期内仅需校验一次签名)

3.4 撤销流程(Revocation)

3.4.1 撤销发起

授权人通过 Descriptor_Issuer 发起撤销请求。撤销请求的具体交互形式不在本规范范围内。

Descriptor_Issuer 收到撤销请求后 MUST:

  1. 验证撤销请求来自原始授权人或具备撤销权限的实体
  2. 按 §2.8 生成 RevocationStatement
  3. 使用与原始 Authorization_Descriptor 相同的签名密钥对撤销声明签名
  4. 将撤销声明加入 Descriptor_Issuer 维护的撤销列表

3.4.2 撤销分发

撤销声明通过以下方式分发到终端,终端 MUST 至少支持其中两种:

  1. 拉取同步(Pull-based):终端联网时主动从 Descriptor_Issuer 或撤销服务拉取增量撤销列表。同步频率由终端策略决定,SHOULD 不低于每小时一次(联网期间)
  2. 推送通知(Push-based):Descriptor_Issuer 通过 Registration_Authority 或专门的撤销分发服务向终端推送撤销声明
  3. 凭证内嵌(In-band):在 Trusted_Ticket 的 metadata 中携带最近撤销列表的摘要,使联网期间获取的票据自动捎带撤销信息

3.4.3 终端撤销列表维护

终端的本地撤销列表 MUST:

  1. 永久存储所有未过期的撤销声明
  2. 在凭证 not_after 时间过去后 MAY 删除对应的撤销声明(凭证已自然失效)
  3. 验证每条撤销声明的签名,拒绝无效签名的撤销声明

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 更新策略

授权人或自动续期机制可在以下场景触发更新:

  1. 凭证临近 not_after 且授权关系仍然有效
  2. 授权范围需要调整(增加/减少 grants)
  3. 授权约束需要调整(修改 constraints)

3.5.2 更新流程

更新过程:

  1. Descriptor_Issuer 按 §3.1 流程签发新的 Authorization_Descriptor,使用新的 descriptor_id
  2. 新凭证按 §3.2 流程提交到终端并存储
  3. 旧凭证 MAY 由签发方主动撤销(按 §3.4),也 MAY 由其自然过期失效

终端在新旧凭证并存期间,处理优先级:

  • 校验请求 MUST 优先匹配未过期的凭证
  • 多个未过期凭证均匹配时,使用 issued_at 最近的凭证

3.5.3 不允许的更新行为

实现 MUST NOT:

  1. 修改已发布凭证的任何字段(包括 metadata)
  2. 复用旧凭证的 descriptor_id
  3. 在旧凭证仍有效期间修改其语义(必须通过撤销 + 新签发实现)

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