Enterprise 版本
簽章驗證 — 深入參考
本頁是 NextPDF Enterprise 中 AdES 驗證端介面的深度參考。進入點為 NextPDF\Enterprise\Security\Validation\AdESValidationEngine。它實作 NextPDF 以 ETSI 建模的驗證流程,涵蓋基本、含時間、長期與封存時間戳檢查:基本驗證、含時間驗證、含長期資料驗證,以及封存 DocTimeStamp 覆蓋鏈驗證。結果為 ValidationReport 值,攜帶帶有 ETSI URN 字串值的 MainIndication 與 SubIndication 列舉案例。本頁另記載的支援介面:SignatureDataExtractor SPI 及其 CmsSignatureDataExtractor 實作、PdfSignatureDictionaryScanner 位元組層級掃描器、NextPDF\Enterprise\Security\Pki 路徑驗證面,以及 BatchSignatureValidator。工作流程層級的指引請見簽章驗證:AdES / PAdES 密碼學驗證端。
供應與授權
標題為「供應與授權」的區段此能力隨 NextPDF Enterprise(nextpdf/enterprise)出貨,並以 Enterprise 級授權封套啟用。未持有該權利的部署不會載入此能力的類別。比較各版本並取得授權。
公開 API 介面
標題為「公開 API 介面」的區段| 符號 | 參數 | 預設行為 | 回傳 | 拋出或失敗於 | 備註 |
|---|---|---|---|---|---|
AdESValidationEngine::__construct | 11 個可選參數:?PathValidatorInterface $chainValidator、?SignatureDataExtractor $extractor、ClockInterface $clock、?LoggerInterface $logger、string $defaultPolicy、NetworkPolicy $networkPolicy,以及五個可選的驗證協作者 | 所有預設皆為 fail-closed:以引擎時鐘運作的 Pki 路徑驗證器、無擷取器、無 TSA 信任儲存 | 新引擎 | 不拋出 | 沒有信任儲存時,TSA 鏈評估回報 untrusted;其對應為 INDETERMINATE,永不通過 |
AdESValidationEngine::validateBasic | string $signedData、string $signature | 基本驗證:格式、摘要、密碼學、弱演算法、鏈、來源受控的撤銷 | ValidationReport | 不拋出;擷取與路徑失敗對應為 fail-closed 報告 | 無擷取器時只做守衛檢查;見邊界情況 |
AdESValidationEngine::validateWithTime | string $signedData、string $signature、DateTimeImmutable $claimedTime | 先做基本驗證;憑證有效期窗與撤銷再與宣稱時間比對 | ValidationReport | 不拋出 | 屬性存在時採嚴格簽章時間戳閘;$claimedTime 仍為時間錨 |
AdESValidationEngine::validateWithLongTermData | string $signedData、string $signature、array $dssData(certs/ocsps/crls) | 需先通過基本驗證;以 TSA-at-genTime 武裝簽章時間戳閘;POE、DSS 撤銷與封存閘 | ValidationReport | 不拋出 | NetworkPolicy::STRICT_OFFLINE 搭配內嵌資料不足時,產生 INDETERMINATE / TRY_LATER |
AdESValidationEngine::validateArchivalTimestampChain | string $pdfBytes、array $dssData = []、?TrustAnchorStoreInterface $anchors = null | 以證據為基礎的 DocTimeStamp 覆蓋鏈,涵蓋確切 ByteRange 位元組 | ValidationReport | 對敵意位元組不拋出 | 唯有受信任、涵蓋至 EOF 的鏈才是 TOTAL_PASSED |
MainIndication | — | 字串支撐的列舉,三個案例 | — | — | ETSI URN 值;見下方案例列表 |
SubIndication | — | 字串支撐的列舉,十五個案例 | — | — | ETSI URN 值;見下方案例列表 |
ValidationReport::__construct | MainIndication $mainIndication、?SubIndication $subIndication、DiagnosticData $diagnosticData、DateTimeImmutable $validationTime、string $validationPolicy = '' | 不可變(final readonly)的驗證結果 | 新報告 | 不拋出 | isPassed()、isFailed()、isIndeterminate()、toArray() |
DiagnosticData::__construct | array $certificateChain、array $timestamps、array $revocationData、string $validationPolicy、string $signatureFormat、array $warnings(皆有預設值) | 不可變的證據容器;僅供稽核軌跡 | 新值 | 不拋出 | toArray() 序列化參照以供報告 |
SignatureDataExtractor::extract | string $signedData、string $signature | SPI:解析 CMS 並擷取驗證元件 | ExtractedSignatureData | 無法解析簽章時拋出 SignatureExtractionException | 介面;將 ASN.1 解析與引擎解耦 |
CmsSignatureDataExtractor::extract | string $signedData、string $signature | 擷取,並密碼學地驗證一個分離式 PAdES 基本簽章 | ExtractedSignatureData | 唯有 CMS 完全無法解析時才拋出 SignatureExtractionException | 密碼學或綁定失敗會回傳 cryptoValid / hashValid 為 false 的資料;對此情況永不拋出 |
PdfSignatureDictionaryScanner::scan | string $pdfBytes | 位元組層級掃描 /ByteRange + /Contents 字典,並以精準吻合的反欺偽交叉檢查 | list<PdfSignatureOccurrence> | 全函數;永不拋出;格式異常的候選會被略過 | 依覆蓋結束位置排序,最早者在前 |
PathValidatorInterface::validate | array $chain、?DateTimeImmutable $validationTime = null、array $initialPolicies = [] | 帶政策處理的 RFC 5280 §6.1.4 路徑驗證 | PathValidationResult | 鏈結構無效或觸犯敵意上限時拋出 PathValidationException | 鏈為終端實體在前、錨在後 |
PathValidatorInterface::validateWithAiaChasing | array $chain、?DateTimeImmutable $validationTime = null | 以 AIA 解析缺失的中介憑證,然後驗證 | PathValidationResult | PathValidationException | 擷取受逾時與位元組上限約束 |
CertificateChainValidator | 建構子:引擎、PathValidationOptions、時鐘、記錄器;靜態 withDefaults() | 帶預設敵意上限的 SPI 實作 | 兩個方法皆回傳 PathValidationResult | PathValidationException | 當 OpenSSLCertificate 無法匯出為 PEM 時也會拋出 |
PathValidationOptions::__construct | 上限(maxDepth、maxPolicyFanout、fetchTimeoutSeconds、fetchSizeCapBytes)加上政策旗標、?TrustAnchorStoreInterface $trustAnchors、bool $requireTrustedAnchor | 深度 32、扇出 64、每次擷取 5 秒、每次擷取 10 MiB;所有旗標皆為 false | 新選項 | 不拋出 | 工廠方法:defaults()、strict()、withTrustAnchors() |
PathValidationResult::__construct | bool $valid、string $trustAnchorFingerprint、DateTimeImmutable $validatedAt、array $validPolicies、?RevocationCheckResult $revocation、bool $trustAnchorTrusted、array $fetchedCertificates、array $failureReasons | 不可變結果;trustAnchorTrusted 預設為 false(fail-closed) | 新值 | 不拋出 | 信任成員身分與結構有效性有別 |
PolicyProcessor | 建構子:PolicyTreeState $state、PathValidationOptions $options;processCertificate(string $certDer, int $depth, bool $selfIssued)、finalizeWrapUp()、tree() | RFC 5280 §6.1.4 政策樹擴張、映射與收尾 | void / list<non-empty-string> / PolicyTree | 任何政策處理失敗時拋出 PathValidationException(fail-closed) | 收尾回傳存活的政策 OID,排除 anyPolicy |
PolicyTree | attach(PolicyTreeNode $node, PathValidationOptions $options)、enforceFanout(...)、remove(...),以及讀取查詢 | 帶深度索引的 valid_policy_tree 狀態 | 各方法而異 | 存活葉節點數超過扇出上限時拋出 PathValidationException | 公開 ANY_POLICY_OID(2.5.29.32.0) |
NameConstraintsChecker::processCertificate | string $certDer、bool $applyNameCheck | 依 RFC 5280 §6.1.4(g) 累積並強制允許/排除子樹 | void | 觸犯子樹、約束中出現不支援的 GeneralName 形式,或觸犯上限時拋出 PathValidationException | 不可比較的名稱以 fail-closed 處理 |
TrustAnchorStoreInterface::containsFingerprint | string $anchorDerSha256Hex | 以錨憑證 DER 之小寫十六進位 SHA-256 判定成員身分 | bool | 不拋出 | 路徑驗證器諮詢的信任接縫 |
BatchSignatureValidator::validate | array $inputs(list<DocumentSignatureInput>) | 多文件簽章驗證,帶每批次撤銷快取 | BatchValidationReport | 空列表時拋出 InvalidArgumentException;資源守衛拒絕超過 1000 份文件的批次 | 位於 NextPDF\Enterprise\Signature |
final class AdESValidationEnginepublic function validateBasic(string $signedData, string $signature): ValidationReportpublic function validateWithTime( string $signedData, string $signature, DateTimeImmutable $claimedTime,): ValidationReportpublic function validateWithLongTermData( string $signedData, string $signature, array $dssData,): ValidationReportpublic function validateArchivalTimestampChain( string $pdfBytes, array $dssData = [], ?TrustAnchorStoreInterface $anchors = null,): ValidationReportpublic function validate( array $chain, ?DateTimeImmutable $validationTime = null, array $initialPolicies = [],): PathValidationResult;public function validateWithAiaChasing( array $chain, ?DateTimeImmutable $validationTime = null,): PathValidationResult;public static function withDefaults( ?ClockInterface $clock = null, ?AiaChaser $aiaChaser = null, ?LoggerInterface $logger = null,): selfpublic function containsFingerprint(string $anchorDerSha256Hex): bool;public function extract(string $signedData, string $signature): ExtractedSignatureData;public function scan(string $pdfBytes): arraypublic function validate(array $inputs): BatchValidationReport判定列舉。 MainIndication 案例:TOTAL_PASSED、TOTAL_FAILED、INDETERMINATE。支撐值遵循 urn:etsi:019102:mainindication:total-passed(小寫、連字號)的模式。SubIndication 案例:HASH_FAILURE、SIG_CRYPTO_FAILURE、REVOKED、EXPIRED、NOT_YET_VALID、NO_POE、TRY_LATER、CERTIFICATE_CHAIN_GENERAL_FAILURE、FORMAT_FAILURE、REVOKED_CA_NO_POE、CRYPTO_CONSTRAINTS_FAILURE、POLICY_PROCESSING_FAILURE、REVOCATION_OUT_OF_BOUNDS_NO_POE、NO_SIGNING_CERTIFICATE_FOUND、TIMESTAMP_ORDER_FAILURE。每一個都以 urn:etsi:019102:subindication:<CASE_NAME> 為支撐,並帶有確切的案例名稱。
行為契約
標題為「行為契約」的區段- 報告進、報告出。 四個引擎進入點對敵意輸入回傳
ValidationReport而非拋出。被捕捉的SignatureExtractionException導向守衛路徑;被捕捉的PathValidationException對應為TOTAL_FAILED/CERTIFICATE_CHAIN_GENERAL_FAILURE。 - 基本驗證順序。 先做格式檢查;無法解析的結構為
TOTAL_FAILED/FORMAT_FAILURE(EN 319 102-1 §5.3.4)。接著是摘要(HASH_FAILURE)與密碼學驗證(SIG_CRYPTO_FAILURE),對應 EN 319 102-1 §5.2.7.4 的建構區塊結果。摘要由驗證器重新計算,並與messageDigest簽署屬性比對(RFC 5652 §5.6);生產者提供的摘要永不受信。 - 弱演算法降級。 在 SHA-1 下通過驗證的簽章,或帶有弱簽署憑證綁定者,回傳
INDETERMINATE/CRYPTO_CONSTRAINTS_FAILURE,永不TOTAL_PASSED。時間路徑會重申此點,因此弱簽章永不會被洗成一個時間有效的通過。 - 撤銷來源閘。 唯有擷取器確實執行了撤銷檢查(
revocationChecked為 true)時才諮詢擷取器的撤銷旗標。未經檢查的預設既非「已驗證未撤銷」,也非REVOKED觸發。撤銷證據由 DSS 路徑建立。 - 非通過傳遞。 時間與長期路徑永不升級一個非通過的基本結果。存在一個例外:基本的
INDETERMINATE/REVOKED會對$claimedTime做解析;在宣稱時間或之前的撤銷為TOTAL_FAILED/REVOKED。這反映 EN 319 102-1 §5.3.4 以時間證據解析撤銷相關不確定的模式。當無法執行比對時,未解析的基本報告會被原封不動地傳遞。 - 嚴格簽章時間戳綁定(fail-closed;BC 破壞)。 當 CMS 攜帶
id-aa-timeStampToken未簽署屬性時,其存在會在時間與長期路徑中觸發強制執行;沒有僅警告模式。基數必須恰為一個屬性且恰含一個值(EN 319 122-1 §5.3);任何其他形狀皆為TOTAL_FAILED/FORMAT_FAILURE。權杖必須端到端密碼學地驗證通過;無法驗證的權杖、解析器差異衝突,或印記不符為INDETERMINATE/TIMESTAMP_ORDER_FAILURE。不支援或 SHA-1 的印記演算法為INDETERMINATE/CRYPTO_CONSTRAINTS_FAILURE。綁定規則為 RFC 3161 Appendix A:權杖的messageImprint必須等於 SignerInfosignature值八位元組的雜湊,以常數時間比對。 - 長期路徑閘。 在標註 clause 5.4 的路徑中,綁定的簽章時間戳另會在權杖的
genTime接受 TSA 憑證評估;不受信的錨為INDETERMINATE/CERTIFICATE_CHAIN_GENERAL_FAILURE,永不通過。NetworkPolicy::STRICT_OFFLINE搭配內嵌 DSS 材料不足時,回傳INDETERMINATE/TRY_LATER。存在性證明、DSS 撤銷與封存鏈的發現各自短路至INDETERMINATE並帶對應的子判定。 - 封存鏈閘。 無 DocTimeStamp 存在為
INDETERMINATE/NO_POE。結構不符的 ByteRange 為TOTAL_FAILED/FORMAT_FAILURE。每個權杖都必須驗證通過、將其印記綁定到 ByteRange 涵蓋的確切位元組,並通過 TSA-at-genTime 面向映射(EXPIRED、NOT_YET_VALID、REVOKED_CA_NO_POE、CERTIFICATE_CHAIN_GENERAL_FAILURE,或在 strict-offline 下的TRY_LATER)。順序受強制執行:不遞減的genTime、嚴格遞進的覆蓋,以及後續權杖包含前一權杖的/Contents空洞。最新的權杖必須涵蓋最後一個位元組;尾隨位元組為TIMESTAMP_ORDER_FAILURE。genTime超前驗證器時鐘逾 300 秒為TIMESTAMP_ORDER_FAILURE。 - 診斷永不決策。
DiagnosticData::$timestamps的存在性證明項目僅供稽核軌跡。它們永不改變判定,且累加器在每個進入點重置。 - Pki 上限先於密碼學。
PathValidationOptions上限(深度 32、政策扇出 64、每次擷取 5 秒與 10 MiB)在昂貴工作之前檢查。PathValidationResult::$trustAnchorTrusted有別於$valid;requireTrustedAnchor會讓未經確認的終點無效。strict()啟用requireExplicitPolicy、硬失敗撤銷傳輸,以及requireTrustedAnchor。路徑有效性依 RFC 5280 §6.1 是相對於錨的:一條有效路徑始於作為輸入提供的信任錨。 - 批次介面。
BatchSignatureValidator::validate()對空列表拋出InvalidArgumentException,並透過資源守衛拒絕超過 1000 份文件的批次。該流程中所有密碼學驗證皆由 PHP 掌管。
邊界情況與失敗模式
標題為「邊界情況與失敗模式」的區段- 預設引擎無擷取器。
new AdESValidationEngine()只做守衛檢查:空的簽章或簽署資料為TOTAL_FAILED;任何非空的配對解析為INDETERMINATE/NO_SIGNING_CERTIFICATE_FOUND,永不TOTAL_PASSED。注入NextPDF\Enterprise\Security\Validation\CmsSignatureDataExtractor以取得密碼學驗證。 - 預設 TSA 信任檢查無儲存。 每條 TSA 鏈於是回報 untrusted,因此封存與長期簽章時間戳結果維持
INDETERMINATE。透過validateArchivalTimestampChain(..., $anchors)或已設定的TsaCertificateAtGenTimeCheck提供錨。 - 空的
$pdfBytes。validateArchivalTimestampChain('')回傳TOTAL_FAILED/FORMAT_FAILURE。 - 修正前的簽章時間戳無法通過。 由嚴格綁定修正之前的 NextPDF 版本產生的權杖,印記的是不同的輸入。它們永久無法通過 Appendix A 綁定;重新簽署並重新加蓋時間戳以恢復正向結果。這是一個刻意且有記載的 BC 破壞。
- 重複或重疊的 DocTimeStamp。 同修訂版重複、相等或重疊的覆蓋,或後續權杖未包含前一權杖的簽章空洞者,皆無法通過順序閘。
- 掃描器為全函數且位元組層級。
scan()靜默略過格式異常或欺偽的候選;內容串流內的誘餌/ByteRange會被拒絕。它不解析間接物件,也不走訪交叉參照表。 - 是覆蓋,而非可達性。
validateArchivalTimestampChain()證明密碼學上的位元組範圍覆蓋直至檔案結尾。物件層級的可達性分析(例如涵蓋修訂版內被重新指向的文件根)宣告為範圍外。 - 直接使用 Pki 會拋出。 直接呼叫
PathValidatorInterface實作,對結構無效的鏈、觸犯上限、不支援的約束形式,以及OpenSSLCertificate控點的 PEM 匯出失敗,會浮現PathValidationException。引擎會捕捉此類別;你自己的呼叫端則必須處理它。
FIPS 模式行為
標題為「FIPS 模式行為」的區段驗證端接受帶 SHA-2 的 RSA PKCS#1 v1.5,以及 P-256/P-384/P-521 上的 ECDSA。RSASSA-PSS、EdDSA 與 SHA-3 權杖以不支援 fail closed;SHA-1 降級為 CRYPTO_CONSTRAINTS_FAILURE。在 Enterprise FIPS 140-3 密碼政策設定檔下(隨安全模組記載),此約束作用於接受哪些演算法;驗證流程本身——摘要重算、簽章檢查、綁定、路徑驗證——維持不變。NextPDF 不持有 FIPS 140-3 憑證,本頁亦不主張任何憑證。
符合性
標題為「符合性」的區段| 主張 | 標準 | 條款 |
|---|---|---|
| 基本簽章驗證是供時間戳與含時間驗證重複使用的建構區塊。 | ETSI EN 319 102-1 | §5.3.1 |
完整性失敗對應 HASH_FAILURE;簽章檢查失敗對應 SIG_CRYPTO_FAILURE。 | ETSI EN 319 102-1 | §5.2.7.4 |
| 格式檢查先執行,且非通過會停止流程。 | ETSI EN 319 102-1 | §5.3.4 |
| 撤銷相關的不確定可以用時間證據解析。 | ETSI EN 319 102-1 | §5.3.4 |
| 有效的憑證路徑始於作為輸入提供的信任錨。 | RFC 5280 | §6.1 |
驗證器重算內容摘要;它必須等於 messageDigest 簽署屬性。 | RFC 5652 | §5.6 |
簽章時間戳的 messageImprint 雜湊 SignerInfo signature 欄位值。 | RFC 3161 | Appendix A |
signature-time-stamp 屬性攜帶恰好一個 AttributeValue。 | ETSI EN 319 122-1 | §5.3 |
所有條款皆為改寫;NextPDF 不重製規範文字。NextPDF 不作任何 AdES / PAdES 符合性或憑證主張。 支援某標準不等於符合該標準,而符合亦不等於憑證——NextPDF 不持有任何憑證,也不授予任何憑證。引擎將所引用的驗證程序實作為一種能力;它不是合格或經憑證的驗證服務,而 TOTAL_PASSED 報告是一項密碼學陳述,並非法律裁定。列舉值重用 ETSI URN 識別碼模式以利報告資料的互通性;該重用不主張任何背書。
開發備註
標題為「開發備註」的區段- 條款標籤映射。 套件原始碼將這些進入點標註為 EN 319 102-1 的 clause 5.2、5.3 與 5.4。符合性語料庫將基本簽章驗證流程本身置於 clause 5.3,而密碼學建構區塊置於 5.2.7.4。本頁引用擷取到的條款編號;具權威性的是行為契約,而非標籤。
- 確定性測試。 每一次時間比對都流經注入的 PSR-20
ClockInterface。注入一個凍結時鐘以測試有效期窗檢查、300 秒的 genTime 偏斜界限,以及 CRL 新鮮度決策。 - 組合。 所有引擎協作者皆由建構子注入且為可選,帶 fail-closed 預設。預設路徑驗證器是以引擎時鐘運作的
CertificateChainValidator::withDefaults();預設選項對符合且無約束的輸入,讓政策與名稱約束處理維持為 no-op。 - 命名空間。 引擎介面位於
NextPDF\Enterprise\Security\Validation,路徑驗證介面位於NextPDF\Enterprise\Security\Pki,批次協調器位於NextPDF\Enterprise\Signature。 - 報告衛生。 報告為不可變且可透過
toArray()序列化。診斷情境在每個進入點重置,因此報告永不會攜帶同一引擎實例上前一次執行的證據。
另請參閱
標題為「另請參閱」的區段- 簽章驗證:AdES / PAdES 密碼學驗證端 — 能力頁:工作流程、演算法表、升級備註。
- 簽章 — 深度參考 — PAdES B-LT / B-LTA 生產端。
- 驗證 — 深度參考 — 不含密碼學的結構政策檢查。
- 安全 — 深度參考 — 合併的 Enterprise 安全介面,含 FIPS 設定檔。
- PAdES 基線映射 — 跨各版本的 B-B、B-T、B-LT、B-LTA。
出版邊界
標題為「出版邊界」的區段本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、runbook 檔名與工單前綴皆屬範圍外。