第 4 章:在线票据协议
本章定义 Trusted_Ticket 的签发、查询、转换和降级流程。本章流程对应蓝图 §2.2 的设计意图。
4.1 适用前提
Trusted_Ticket 仅在终端能够联网访问 Ticket_Issuer 或在线撤销服务时使用。当在线服务不可用时,终端按 §4.5 自动回退到离线授权。
终端 MUST 同时支持 Authorization_Descriptor(第 3 章)和 Trusted_Ticket。终端 MUST NOT 拒绝接受合法签名的 Trusted_Ticket,即使该终端策略偏好离线授权。
4.2 签发流程
4.2.1 签发请求
授权人通过支持 CAP 的客户端(如手机 App、Web 控制台)向 Ticket_Issuer 发起签发请求。客户端与 Ticket_Issuer 之间的交互不在本规范范围内,但 Ticket_Issuer MUST:
- 验证请求来源是经过身份认证的授权人
- 验证授权人有权对目标 Fay 和资源进行授权
- 应用本地策略校验授权范围(如最长有效期、资源白名单)
4.2.2 签发步骤
Ticket_Issuer MUST 按以下步骤生成 Trusted_Ticket:
- 构造 Header:按 §2.4.2 设置
alg、typ、kid - 构造 Payload:按 §2.4.3 填充 TicketPayload,所有 required 字段 MUST 设置
- 校验约束:本地校验
exp - nbf ≤ 7 天 - JSON 序列化:将 Header 和 Payload 序列化为 UTF-8 JSON 字节
- Base64URL 编码:对 Header 和 Payload 字节分别进行 Base64URL 编码
- 签名:按 RFC 7515 计算签名输入
base64url(header) + "." + base64url(payload) - 生成 Compact Serialization:拼接为
header.payload.signature字符串 - 登记记录:在 Ticket_Issuer 内部维护已签发票据状态(用于撤销查询)
4.2.3 签发后交付
Trusted_Ticket 通过 HTTPS 等加密通道交付给目标 Fay 或其 iFay_Runtime。交付的具体方式不在本规范范围内。
4.3 终端校验流程
终端校验 Trusted_Ticket 与校验 Authorization_Descriptor 的差异在于:
- Trusted_Ticket 在请求时由 iFay_Runtime 完整传输给终端(不预先存储)
- 终端在联网时 MAY 实时查询 Ticket_Issuer 的撤销状态
- 校验失败时的错误码以
E_TICKET_*前缀
4.3.1 校验请求
iFay_Runtime 发送的 AuthRequest 携带完整 Trusted_Ticket:
AuthRequest (body of ProtocolMessage) {
required fay_id : Fay_ID
required resource_id : Resource_ID
required access_mode : AccessMode
required credential : CredentialContent
}
CredentialContent {
required type : enum["descriptor_ref", "ticket"]
oneof:
descriptor_id : string // type == "descriptor_ref"
ticket : string // type == "ticket",JWS Compact 字符串
}
4.3.2 校验步骤(按顺序执行)
终端 MUST 按以下顺序执行校验。任一步骤失败立即返回错误。
第 1 步:JWS 解析
终端解析 JWS Compact 字符串:
- 拆分
header.payload.signature三部分 - Base64URL 解码 header 和 payload
- 验证
header.typ == "cap-ticket+jws" - 验证
header.alg在 §8 允许的算法集合内
任一步骤失败 → 返回 E_TICKET_MALFORMED
第 2 步:签名校验
终端使用 header.kid 对应的 Verification_Key 校验 JWS 签名(按 RFC 7515)。
- 签名校验失败 → 返回
E_INVALID_SIGNATURE kid对应的密钥未注册或已撤销 → 返回E_VERIFICATION_KEY_INVALID
第 3 步:有效期
按 §3.3.2 第 3 步的规则校验 nbf 和 exp。
第 4 步:主体、终端、资源、模式匹配
按 §3.3.2 第 4–6 步的规则进行匹配。错误码使用 E_TICKET_* 前缀(参见 §9)。
第 5 步:在线撤销查询(可选)
若终端策略要求在线撤销验证,终端 MAY 向 Ticket_Issuer 发起撤销状态查询:
TicketRevocationQuery {
required jti : uuid
}
TicketRevocationResponse {
required jti : uuid
required revoked : boolean
optional revoked_at : timestamp
}
- 查询超时(默认 2 秒)→ 终端 SHOULD 拒绝该请求并返回
E_REVOCATION_QUERY_TIMEOUT,但 MAY 配置为允许通过(接受撤销延迟风险) - 查询返回
revoked == true→ 返回E_TICKET_REVOKED - 查询失败(如服务不可达)→ 终端 MAY 按本地缓存的撤销状态决定,超出缓存有效期则按超时处理
终端 SHOULD 缓存撤销查询结果,缓存有效期不超过 5 分钟。
4.3.3 校验通过后
校验通过后处理与 §3.3.3 一致,创建 Session 并返回 AuthResult。
4.4 转换为离线 Authorization_Descriptor
当 TicketPayload.convertible == true(默认)时,终端可在校验通过后将 Trusted_Ticket 转换为本地 Authorization_Descriptor 以供离线使用。
4.4.1 转换触发
转换 SHOULD 在以下情况自动执行:
- Trusted_Ticket 校验通过且
convertible == true - 终端策略允许离线后续访问
TicketPayload.exp距当前时间足够长(建议 > 1 小时)
4.4.2 转换步骤
- 字段映射:按 §2.4.4 表格将 TicketPayload 字段映射到 DescriptorPayload
- 有效期约束:转换后的
not_afterMUST 不超过min(TicketPayload.exp, 转换时间 + 7 天) - 元数据保留:将原始 Trusted_Ticket 的关键审计信息存入 metadata:
metadata["origin"] = "converted_from_ticket"metadata["origin_jti"] = TicketPayload.jtimetadata["origin_iss"] = TicketPayload.issmetadata["origin_kid"] = TicketHeader.kid
- 本地签名:终端使用其本地存储密钥对转换后的 payload 重新签名(参见 §4.4.3)
- 本地存储:将转换后的 Authorization_Descriptor 按 §3.2.3 加密存储
4.4.3 终端本地签名密钥
为支持转换流程,终端 MUST 持有一对本地签名密钥:
- 私钥:保存在终端安全存储中,仅供本地转换流程使用
- 公钥:作为
source == "pre-installed"类型的 Verification_Key 注册到自身的密钥存储
转换后的 Authorization_Descriptor 的 signature.key_id MUST 标识该本地密钥,且 payload.issuer_id MUST 设置为 "local-conversion:" + terminal_id。
终端在校验本地转换的 Authorization_Descriptor 时,使用本地公钥校验签名。这种设计确保:
- 转换后的凭证可独立离线校验,不依赖原始 Ticket_Issuer
- 转换信任链锚定在终端自身的密钥安全性
4.4.4 转换的局限性
本地转换的 Authorization_Descriptor MUST NOT:
- 在其他终端被信任(其签名 key_id 是本地的)
- 跨终端迁移使用
- 通过 Descriptor_Issuer 的撤销机制被撤销(必须通过本地删除)
终端 SHOULD 在以下情况主动删除本地转换的 Authorization_Descriptor:
- 收到原始 Trusted_Ticket 的撤销通知(通过 jti 关联)
- 凭证已过期超过 24 小时
4.5 在线到离线降级
4.5.1 降级触发
终端持续监测在线服务可用性。当满足以下任一条件时,触发降级:
- 与 Ticket_Issuer 的连接超过 30 秒不可达
- 撤销查询请求连续 3 次超时
- 网络栈报告全局网络不可用
4.5.2 降级行为
降级后,终端按以下规则处理:
- 拒绝接受新的 Trusted_Ticket(除非配置为离线接受)——避免无法在线验证撤销状态
- 已转换为本地 Authorization_Descriptor 的票据继续按 §3 规则使用
- 直接以 Authorization_Descriptor 进行授权校验的请求不受降级影响
- 终端 MAY 提示 iFay_Runtime 当前处于离线模式,使 Fay 可调整行为策略
4.5.3 恢复
终端检测到在线服务恢复后 MUST:
- 优先同步撤销列表,将离线期间可能漏掉的撤销声明应用到本地状态
- 重新检查活跃 Session,对于使用本地转换 Authorization_Descriptor 且已被原始 ticket 撤销的 Session,按第 5 章规则强制终止
- 恢复正常的 Trusted_Ticket 接受策略
恢复过程对 iFay_Runtime 透明,但终端 MAY 通过 SessionStateChanged 通知模式变更。
4.6 双凭证场景的优先级
当一个 Fay 同时持有针对同一资源的 Trusted_Ticket 和 Authorization_Descriptor 时,iFay_Runtime 的选择策略:
| 网络状态 | 推荐选择 | 原因 |
|---|---|---|
| 在线且 Ticket_Issuer 可达 | Trusted_Ticket | 时效性更强,可实时撤销 |
| 离线 | Authorization_Descriptor 或转换后的本地凭证 | Trusted_Ticket 无法在线验证撤销 |
iFay_Runtime MAY 在 AuthRequest 中提供回退凭证,使终端在主凭证校验失败时尝试备用凭证。本规范不强制定义回退机制的具体格式,但 SHOULD 通过两次独立的 AuthRequest 实现以避免协议复杂化。
4.7 Trusted_Ticket 与 Authorization_Descriptor 的语义一致性
当 iFay_Runtime 同时使用两种凭证类型时,终端 MUST 保证:
- 校验结果一致性:相同授权范围在两种凭证下校验通过/拒绝的判定结果一致
- 错误码语义一致性:等价的失败原因(如有效期、签名、撤销)使用语义对应的错误码(参见第 9 章)
- Session 创建一致性:通过两种凭证创建的 Session 在生命周期管理上无差异
