EPdfKeychainError = class(Exception);
TPdfKeychainSignerProvider = class(TInterfacedObject, IPadesSignerProvider)
constructor Create(const KeychainPath: string = '');
function BackendName: string;
function Resolve(const Options: TPadesSignerOptions): TPadesResolvedSigner;
end;
TPdfKeychainCmsVerifier = class(TInterfacedObject, IPdfCmsVerifier)
function BackendName: string;
function VerifyDetached(const CmsDer: TBytes; Segment1: Pointer; Segment1Length: Cardinal; Segment2: Pointer; Segment2Length: Cardinal; const Options: TPdfCmsVerifyOptions): TPdfCmsVerifyResult;
function VerifyAttached(const CmsDer: TBytes; const Options: TPdfCmsVerifyOptions): TPdfCmsVerifyResult;
end;
function KeychainAvailable: Boolean;
function KeychainMissingSymbols: string;
function KeychainVerificationAvailable: Boolean;
function ConfigureKeychainSignerProvider: IPadesSignerProvider;
function ConfigureKeychainCmsVerifier: IPdfCmsVerifier;
procedure ConfigureKeychainTrustAnchors(const Anchors: TPadesChainCertArray);
procedure ConfigureKeychainOcspResponses(const Responses: TPadesChainCertArray);
FPdfCryptoMac 是 FPdfCrypto 與 FPdfCms 使用的 macOS 加密後端,它涵蓋平台整合的兩個部分:透過 Keychain 身分進行 PAdES 簽署,以及透過系統 CMS 解碼器與信任評估進行 CMS 驗證。Security.framework 與 CoreFoundation 在執行期按名稱載入並解析符號,而不是連結,因此本單元可以在所有目標平台上編譯,並在執行期回報平台服務是否真正可用
在簽署一側,TPdfKeychainSignerProvider 實作 IPadesSignerProvider。它的 Resolve 方法列舉 Keychain 身分,選出憑證與 TPadesSignerOptions 攜帶的 SHA-1 指紋相符的那一個,讀取憑證 DER 與對應的私鑰參照,並傳回 TPadesResolvedSigner,其 ICmsSigner 透過 Security.framework 對 CMS 已簽屬性進行簽章,因此私鑰從不離開 Keychain。選項中要求的填充方案會與金鑰實際支援的能力相調和,RSASSA-PSS 參數與其他後端產生的完全相同,因此在 macOS 上簽署的文件攜帶一致的 AlgorithmIdentifier。ConfigureKeychainSignerProvider 建構該提供者並將其安裝為目前的 PAdES 簽署後端,傳回它註冊的介面
驗證端的 TPdfKeychainCmsVerifier 以 CMSDecoder 與 SecTrust 實作 IPdfCmsVerifier。VerifyDetached 將簽章預留區兩側的已簽署位元組範圍串接為解碼器所需的分離內容,再據此驗證 CMS 值;VerifyAttached 驗證自帶內容的 CMS 值,時間戳記權杖正是此形式。兩者均傳回 TPdfCmsVerifyResult,分別回報簽章、信任與撤銷狀態,可選擇收集簽署者憑證與評估出的鏈,並遵循 TPdfCmsVerifyOptions 的撤銷、線上擷取及 Checkpoint 設定。ConfigureKeychainCmsVerifier 建立驗證器並註冊為目前的 CMS 驗證後端
簽章有效性與憑證信任保持為相互獨立的結果,因此不受信任或自簽鏈下的真實簽章仍然可與遭竄改的內容區分開
對於內含 RFC 3161 權杖,有上限的 DER 解析會將原始封裝的 TSTInfo 位元組交給原生解碼器,不變更內容類型或已簽署屬性。一般 CMS 驗證會從原生輸入排除未簽署屬性,避免自動時間戳記處理取代外層簽章自身的完整性或憑證鏈結果。這項驗證不檢查副簽章或其他未簽署屬性;ValidatePadesTrust 另外驗證每個原始時間戳記權杖、訊息摘要、TSA 憑證角色、信任與撤銷結果
將 Keychain 檔案路徑傳給 TPdfKeychainSignerProvider.Create,可透過僅作用於本次查詢的搜尋清單,將身分查詢限制在該 Keychain,再以 ConfigurePadesSignerProvider 註冊提供者。空路徑使用目前使用者的搜尋範圍。開啟或搜尋選定 Keychain 不會變更預設 Keychain、使用者搜尋清單或系統信任設定;無效路徑或無法使用範圍搜尋符號時,會拋出 EPdfKeychainError
Resolve 也會透過離線且僅作用於本次查詢的憑證查找與原生鏈建構,匯出簽署憑證可取得的簽發者鏈。候選憑證最多 4096 張、每張 1 MiB、總計 16 MiB;建構出的鏈最多 32 張憑證,包含葉憑證,葉憑證另行傳回,不放入 ChainCertDer。匯出憑證資料不代表建立信任或安裝信任錨點,也無法合成缺少的簽發者
| 函式 | 說明 |
|---|---|
KeychainAvailable | 當 Security.framework 與 CoreFoundation 已載入且簽署所需的全部符號解析成功時傳回 True |
KeychainMissingSymbols | 傳回解析失敗的名稱(以空格分隔),全部繫結成功時傳回空字串 |
ConfigureKeychainSignerProvider | 建構 TPdfKeychainSignerProvider,將其安裝為 PAdES 簽署後端,並作為 IPadesSignerProvider 傳回 |
TPdfKeychainSignerProvider.Create | 可選擇既有 Keychain 檔案限定身分查詢範圍,拒絕內含 NUL 字元或超過 4096 個字串碼元的路徑 |
TPdfKeychainSignerProvider.BackendName | 傳回簽署提供者所回報的後端識別碼 |
TPdfKeychainSignerProvider.Resolve | 將 TPadesSignerOptions 與 Keychain 身分進行比對,傳回持有簽署器、憑證 DER 與鏈的 TPadesResolvedSigner |
| 函式 | 說明 |
|---|---|
KeychainVerificationAvailable | 當 CMS 解碼器、信任政策與信任評估符號解析成功時傳回 True |
ConfigureKeychainCmsVerifier | 建構 TPdfKeychainCmsVerifier,將其安裝為 CMS 驗證後端,並作為 IPdfCmsVerifier 傳回 |
ConfigureKeychainTrustAnchors | 複製明確的 DER 信任錨點,供後續每次信任評估補充系統錨點,不改動 Keychain;上限為 64 張憑證、每張 4 MiB、總計 16 MiB,傳入空陣列即可清除 |
ConfigureKeychainOcspResponses | 複製明確的 DER OCSP 證據供原生 Security.framework 評估;上限為 8 份回應、每份 1 MiB、總計 4 MiB,傳入空陣列即可清除 |
TPdfKeychainCmsVerifier.BackendName | 傳回驗證後端所回報的後端識別碼 |
TPdfKeychainCmsVerifier.VerifyDetached | 使用給定的 TPdfCmsVerifyOptions,針對由 Segment1、Segment1Length、Segment2 與 Segment2Length 描述的兩個呼叫端內容段驗證分離的 CMS 值 |
TPdfKeychainCmsVerifier.VerifyAttached | 使用給定的 TPdfCmsVerifyOptions,驗證攜帶自身已簽章內容的內含 CMS 值 |
| 類型 | 成員與用途 |
|---|---|
EPdfKeychainError | 當 Security.framework 不可用、沒有 Keychain 身分與要求的簽署器相符,或平台簽署呼叫失敗時拋出的例外 |
TPdfKeychainSignerProvider | 實作 IPadesSignerProvider 的 PAdES 簽署後端,包含 BackendName 與 Resolve |
TPdfKeychainCmsVerifier | 實作 IPdfCmsVerifier 的 CMS 驗證後端,包含 BackendName、VerifyDetached 與 VerifyAttached |
KeychainAvailable 與 KeychainVerificationAvailable 分別回報簽署與驗證,因為兩部分需要不同的框架符號,系統可能繫結其中一個而未繫結另一個KeychainMissingSymbols 列出每一個解析失敗的符號,據此可以區分框架缺失與繫結問題:結果為空表示全部繫結成功;結果出現框架路徑表示框架沒有載入;結果出現具體進入點表示框架已載入但某個名稱未解析KeychainAvailable 與 KeychainVerificationAvailable 傳回 False,KeychainMissingSymbols 為空,設定函式則拋出 EPdfKeychainErrorTPadesSignerOptions 未攜帶憑證指紋時,將選擇 Keychain 中第一個可用的身分,這適合測試而不適合正式環境簽章pcvsUnsupported 並保留原生診斷,不會判定完整性有效或無效。請使用 OpenSSL CMS 驗證器處理這些值;混合簽署者診斷保留各簽署者獨立的演算法結果FreshOcspResponse 時間與 DER 預篩選,再進行原生回應者簽章、授權及憑證檢查。容許時差為 300 秒,producedAt 與 thisUpdate 的資料年齡上限為一天OnlineRetrieval=False 停用原生信任評估的網路擷取。原生 Security.framework 線上評估遵循平台行為;此後端的 UrlRetrievalTimeoutMs 不提供 OpenSSL 傳輸那種有上限的期限CollectSignerDiagnostics=True 傳回獨立的簽署者快照,數量受 MaxSignerCount 與硬性上限 64 限制。傳回憑證資料上限為每張 4 MiB、總計 64 MiB;收集不完整時回報 pcvsIndeterminateSignerDiagnosticsStatus=pcvsValid 表示收集完整,也包含驗證失敗的簽署者判定。RevocationError 帶有原生 Security.framework 狀態,此後端的 RevocationCertificate 則維持空值