第 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:

  1. 驗證請求來源是經過身分驗證的授權人
  2. 驗證授權人有權對目標 Fay 和資源進行授權
  3. 套用本地策略校驗授權範圍(如最長有效期、資源白名單)

4.2.2 簽發步驟

Ticket_Issuer MUST 按以下步驟產生 Trusted_Ticket:

  1. 建構 Header:按 §2.4.2 設定 algtypkid
  2. 建構 Payload:按 §2.4.3 填充 TicketPayload,所有 required 欄位 MUST 設定
  3. 校驗約束:本地校驗 exp - nbf ≤ 7 天
  4. JSON 序列化:將 Header 和 Payload 序列化為 UTF-8 JSON 位元組
  5. Base64URL 編碼:對 Header 和 Payload 位元組分別進行 Base64URL 編碼
  6. 簽章:按 RFC 7515 計算簽章輸入 base64url(header) + "." + base64url(payload)
  7. 產生 Compact Serialization:拼接為 header.payload.signature 字串
  8. 登記記錄:在 Ticket_Issuer 內部維護已簽發票據狀態(用於撤銷查詢)

4.2.3 簽發後交付

Trusted_Ticket 透過 HTTPS 等加密通道交付給目標 Fay 或其 iFay_Runtime。交付的具體方式不在本規範範圍內。

4.3 終端校驗流程

終端校驗 Trusted_Ticket 與校驗 Authorization_Descriptor 的差異在於:

  1. Trusted_Ticket 在請求時由 iFay_Runtime 完整傳輸給終端(不預先儲存)
  2. 終端在聯網時 MAY 即時查詢 Ticket_Issuer 的撤銷狀態
  3. 校驗失敗時的錯誤碼以 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 步的規則校驗 nbfexp

第 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 在以下情況自動執行:

  1. Trusted_Ticket 校驗通過且 convertible == true
  2. 終端策略允許離線後續存取
  3. TicketPayload.exp 距目前時間足夠長(建議 > 1 小時)

4.4.2 轉換步驟

  1. 欄位對映:按 §2.4.4 表格將 TicketPayload 欄位對映到 DescriptorPayload
  2. 有效期約束:轉換後的 not_after MUST 不超過 min(TicketPayload.exp, 轉換時間 + 7 天)
  3. 元資料保留:將原始 Trusted_Ticket 的關鍵稽核資訊存入 metadata:
    • metadata["origin"] = "converted_from_ticket"
    • metadata["origin_jti"] = TicketPayload.jti
    • metadata["origin_iss"] = TicketPayload.iss
    • metadata["origin_kid"] = TicketHeader.kid
  4. 本地簽章:終端使用其本地儲存金鑰對轉換後的 payload 重新簽章(參見 §4.4.3)
  5. 本地儲存:將轉換後的 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:

  1. 在其他終端被信任(其簽章 key_id 是本地的)
  2. 跨終端遷移使用
  3. 透過 Descriptor_Issuer 的撤銷機制被撤銷(必須透過本地刪除)

終端 SHOULD 在以下情況主動刪除本地轉換的 Authorization_Descriptor:

  1. 收到原始 Trusted_Ticket 的撤銷通知(透過 jti 關聯)
  2. 憑證已過期超過 24 小時

4.5 線上到離線降級

4.5.1 降級觸發

終端持續監測線上服務可用性。當滿足以下任一條件時,觸發降級:

  1. 與 Ticket_Issuer 的連線超過 30 秒不可達
  2. 撤銷查詢請求連續 3 次逾時
  3. 網路堆疊回報全域網路不可用

4.5.2 降級行為

降級後,終端按以下規則處理:

  1. 拒絕接受新的 Trusted_Ticket(除非配置為離線接受)——避免無法在線驗證撤銷狀態
  2. 已轉換為本地 Authorization_Descriptor 的票據繼續按 §3 規則使用
  3. 直接以 Authorization_Descriptor 進行授權校驗的請求不受降級影響
  4. 終端 MAY 提示 iFay_Runtime 目前處於離線模式,使 Fay 可調整行為策略

4.5.3 恢復

終端偵測到線上服務恢復後 MUST:

  1. 優先同步撤銷清單,將離線期間可能漏掉的撤銷聲明套用到本地狀態
  2. 重新檢查活躍 Session,對於使用本地轉換 Authorization_Descriptor 且已被原始 ticket 撤銷的 Session,按第 5 章規則強制終止
  3. 恢復正常的 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 保證:

  1. 校驗結果一致性:相同授權範圍在兩種憑證下校驗通過/拒絕的判定結果一致
  2. 錯誤碼語意一致性:等價的失敗原因(如有效期、簽章、撤銷)使用語意對應的錯誤碼(參見第 9 章)
  3. Session 建立一致性:透過兩種憑證建立的 Session 在生命週期管理上無差異