跳到內容
getnextpdf.com

Enterprise 版本

簽章驗證 — 深入參考

本頁是 NextPDF Enterprise 中 AdES 驗證端介面的深度參考。進入點為 NextPDF\Enterprise\Security\Validation\AdESValidationEngine。它實作 NextPDF 以 ETSI 建模的驗證流程,涵蓋基本、含時間、長期與封存時間戳檢查:基本驗證、含時間驗證、含長期資料驗證,以及封存 DocTimeStamp 覆蓋鏈驗證。結果為 ValidationReport 值,攜帶帶有 ETSI URN 字串值的 MainIndicationSubIndication 列舉案例。本頁另記載的支援介面:SignatureDataExtractor SPI 及其 CmsSignatureDataExtractor 實作、PdfSignatureDictionaryScanner 位元組層級掃描器、NextPDF\Enterprise\Security\Pki 路徑驗證面,以及 BatchSignatureValidator。工作流程層級的指引請見簽章驗證:AdES / PAdES 密碼學驗證端

此能力隨 NextPDF Enterprisenextpdf/enterprise)出貨,並以 Enterprise 級授權封套啟用。未持有該權利的部署不會載入此能力的類別。比較各版本並取得授權

符號參數預設行為回傳拋出或失敗於備註
AdESValidationEngine::__construct11 個可選參數:?PathValidatorInterface $chainValidator?SignatureDataExtractor $extractorClockInterface $clock?LoggerInterface $loggerstring $defaultPolicyNetworkPolicy $networkPolicy,以及五個可選的驗證協作者所有預設皆為 fail-closed:以引擎時鐘運作的 Pki 路徑驗證器、無擷取器、無 TSA 信任儲存新引擎不拋出沒有信任儲存時,TSA 鏈評估回報 untrusted;其對應為 INDETERMINATE,永不通過
AdESValidationEngine::validateBasicstring $signedDatastring $signature基本驗證:格式、摘要、密碼學、弱演算法、鏈、來源受控的撤銷ValidationReport不拋出;擷取與路徑失敗對應為 fail-closed 報告無擷取器時只做守衛檢查;見邊界情況
AdESValidationEngine::validateWithTimestring $signedDatastring $signatureDateTimeImmutable $claimedTime先做基本驗證;憑證有效期窗與撤銷再與宣稱時間比對ValidationReport不拋出屬性存在時採嚴格簽章時間戳閘;$claimedTime 仍為時間錨
AdESValidationEngine::validateWithLongTermDatastring $signedDatastring $signaturearray $dssDatacerts/ocsps/crls需先通過基本驗證;以 TSA-at-genTime 武裝簽章時間戳閘;POE、DSS 撤銷與封存閘ValidationReport不拋出NetworkPolicy::STRICT_OFFLINE 搭配內嵌資料不足時,產生 INDETERMINATE / TRY_LATER
AdESValidationEngine::validateArchivalTimestampChainstring $pdfBytesarray $dssData = []?TrustAnchorStoreInterface $anchors = null以證據為基礎的 DocTimeStamp 覆蓋鏈,涵蓋確切 ByteRange 位元組ValidationReport對敵意位元組不拋出唯有受信任、涵蓋至 EOF 的鏈才是 TOTAL_PASSED
MainIndication字串支撐的列舉,三個案例ETSI URN 值;見下方案例列表
SubIndication字串支撐的列舉,十五個案例ETSI URN 值;見下方案例列表
ValidationReport::__constructMainIndication $mainIndication?SubIndication $subIndicationDiagnosticData $diagnosticDataDateTimeImmutable $validationTimestring $validationPolicy = ''不可變(final readonly)的驗證結果新報告不拋出isPassed()isFailed()isIndeterminate()toArray()
DiagnosticData::__constructarray $certificateChainarray $timestampsarray $revocationDatastring $validationPolicystring $signatureFormatarray $warnings(皆有預設值)不可變的證據容器;僅供稽核軌跡新值不拋出toArray() 序列化參照以供報告
SignatureDataExtractor::extractstring $signedDatastring $signatureSPI:解析 CMS 並擷取驗證元件ExtractedSignatureData無法解析簽章時拋出 SignatureExtractionException介面;將 ASN.1 解析與引擎解耦
CmsSignatureDataExtractor::extractstring $signedDatastring $signature擷取,並密碼學地驗證一個分離式 PAdES 基本簽章ExtractedSignatureData唯有 CMS 完全無法解析時才拋出 SignatureExtractionException密碼學或綁定失敗會回傳 cryptoValid / hashValid 為 false 的資料;對此情況永不拋出
PdfSignatureDictionaryScanner::scanstring $pdfBytes位元組層級掃描 /ByteRange + /Contents 字典,並以精準吻合的反欺偽交叉檢查list<PdfSignatureOccurrence>全函數;永不拋出;格式異常的候選會被略過依覆蓋結束位置排序,最早者在前
PathValidatorInterface::validatearray $chain?DateTimeImmutable $validationTime = nullarray $initialPolicies = []帶政策處理的 RFC 5280 §6.1.4 路徑驗證PathValidationResult鏈結構無效或觸犯敵意上限時拋出 PathValidationException鏈為終端實體在前、錨在後
PathValidatorInterface::validateWithAiaChasingarray $chain?DateTimeImmutable $validationTime = null以 AIA 解析缺失的中介憑證,然後驗證PathValidationResultPathValidationException擷取受逾時與位元組上限約束
CertificateChainValidator建構子:引擎、PathValidationOptions、時鐘、記錄器;靜態 withDefaults()帶預設敵意上限的 SPI 實作兩個方法皆回傳 PathValidationResultPathValidationExceptionOpenSSLCertificate 無法匯出為 PEM 時也會拋出
PathValidationOptions::__construct上限(maxDepthmaxPolicyFanoutfetchTimeoutSecondsfetchSizeCapBytes)加上政策旗標、?TrustAnchorStoreInterface $trustAnchorsbool $requireTrustedAnchor深度 32、扇出 64、每次擷取 5 秒、每次擷取 10 MiB;所有旗標皆為 false新選項不拋出工廠方法:defaults()strict()withTrustAnchors()
PathValidationResult::__constructbool $validstring $trustAnchorFingerprintDateTimeImmutable $validatedAtarray $validPolicies?RevocationCheckResult $revocationbool $trustAnchorTrustedarray $fetchedCertificatesarray $failureReasons不可變結果;trustAnchorTrusted 預設為 false(fail-closed)新值不拋出信任成員身分與結構有效性有別
PolicyProcessor建構子:PolicyTreeState $statePathValidationOptions $optionsprocessCertificate(string $certDer, int $depth, bool $selfIssued)finalizeWrapUp()tree()RFC 5280 §6.1.4 政策樹擴張、映射與收尾void / list<non-empty-string> / PolicyTree任何政策處理失敗時拋出 PathValidationException(fail-closed)收尾回傳存活的政策 OID,排除 anyPolicy
PolicyTreeattach(PolicyTreeNode $node, PathValidationOptions $options)enforceFanout(...)remove(...),以及讀取查詢帶深度索引的 valid_policy_tree 狀態各方法而異存活葉節點數超過扇出上限時拋出 PathValidationException公開 ANY_POLICY_OID2.5.29.32.0
NameConstraintsChecker::processCertificatestring $certDerbool $applyNameCheck依 RFC 5280 §6.1.4(g) 累積並強制允許/排除子樹void觸犯子樹、約束中出現不支援的 GeneralName 形式,或觸犯上限時拋出 PathValidationException不可比較的名稱以 fail-closed 處理
TrustAnchorStoreInterface::containsFingerprintstring $anchorDerSha256Hex以錨憑證 DER 之小寫十六進位 SHA-256 判定成員身分bool不拋出路徑驗證器諮詢的信任接縫
BatchSignatureValidator::validatearray $inputslist<DocumentSignatureInput>多文件簽章驗證,帶每批次撤銷快取BatchValidationReport空列表時拋出 InvalidArgumentException;資源守衛拒絕超過 1000 份文件的批次位於 NextPDF\Enterprise\Signature
final class AdESValidationEngine
public function validateBasic(string $signedData, string $signature): ValidationReport
public function validateWithTime(
string $signedData,
string $signature,
DateTimeImmutable $claimedTime,
): ValidationReport
public function validateWithLongTermData(
string $signedData,
string $signature,
array $dssData,
): ValidationReport
public function validateArchivalTimestampChain(
string $pdfBytes,
array $dssData = [],
?TrustAnchorStoreInterface $anchors = null,
): ValidationReport
public 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,
): self
public function containsFingerprint(string $anchorDerSha256Hex): bool;
public function extract(string $signedData, string $signature): ExtractedSignatureData;
public function scan(string $pdfBytes): array
public function validate(array $inputs): BatchValidationReport

判定列舉。 MainIndication 案例:TOTAL_PASSEDTOTAL_FAILEDINDETERMINATE。支撐值遵循 urn:etsi:019102:mainindication:total-passed(小寫、連字號)的模式。SubIndication 案例:HASH_FAILURESIG_CRYPTO_FAILUREREVOKEDEXPIREDNOT_YET_VALIDNO_POETRY_LATERCERTIFICATE_CHAIN_GENERAL_FAILUREFORMAT_FAILUREREVOKED_CA_NO_POECRYPTO_CONSTRAINTS_FAILUREPOLICY_PROCESSING_FAILUREREVOCATION_OUT_OF_BOUNDS_NO_POENO_SIGNING_CERTIFICATE_FOUNDTIMESTAMP_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 必須等於 SignerInfo signature 值八位元組的雜湊,以常數時間比對。
  • 長期路徑閘。 在標註 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 面向映射(EXPIREDNOT_YET_VALIDREVOKED_CA_NO_POECERTIFICATE_CHAIN_GENERAL_FAILURE,或在 strict-offline 下的 TRY_LATER)。順序受強制執行:不遞減的 genTime、嚴格遞進的覆蓋,以及後續權杖包含前一權杖的 /Contents 空洞。最新的權杖必須涵蓋最後一個位元組;尾隨位元組為 TIMESTAMP_ORDER_FAILUREgenTime 超前驗證器時鐘逾 300 秒為 TIMESTAMP_ORDER_FAILURE
  • 診斷永不決策。 DiagnosticData::$timestamps 的存在性證明項目僅供稽核軌跡。它們永不改變判定,且累加器在每個進入點重置。
  • Pki 上限先於密碼學。 PathValidationOptions 上限(深度 32、政策扇出 64、每次擷取 5 秒與 10 MiB)在昂貴工作之前檢查。PathValidationResult::$trustAnchorTrusted 有別於 $validrequireTrustedAnchor 會讓未經確認的終點無效。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。引擎會捕捉此類別;你自己的呼叫端則必須處理它。

驗證端接受帶 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_FAILUREETSI 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 3161Appendix A
signature-time-stamp 屬性攜帶恰好一個 AttributeValueETSI 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() 序列化。診斷情境在每個進入點重置,因此報告永不會攜帶同一引擎實例上前一次執行的證據。

本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、runbook 檔名與工單前綴皆屬範圍外。