契約 / 簽章
簽章領域包含六項契約。它們定義如何產生 CMS 簽章、套用 RFC 3161 時間戳記、使用硬體金鑰簽章,並啟用長期驗證。Core 發布這些契約;Pro 與 Enterprise 版本則提供正式環境使用的實作。
composer require nextpdf/core:^3概念總覽
標題為「概念總覽」的區段PDF 數位簽章是儲存在簽章字典中的 CMS SignedData 結構。Contents 項目存放 DER 編碼的結構。ByteRange 項目指出摘要涵蓋的位元組範圍。摘要涵蓋整個檔案,但排除簽章值本身 —— 見 ISO 32000-2 §12.8.1。CMS 結構遵循 RFC 5652 §5.1:依序為版本、摘要演算法、封裝內容,以及簽章者資訊。
SignerInterface 是核心契約。它會為某段位元組範圍產生 CMS SignedData、為簽章值套用時間戳記,並回報自身是否支援長期驗證。它承載 ETSI EN 319 142 定義的 PAdES 基線等級內容,範圍從 B-B 到 B-LTA。每提升一個等級,都會加入相應材料。B-B 承載基本簽章。B-T 加上簽章時間戳記。B-LT 加上撤銷資料。B-LTA 加上封存時間戳記。
HsmSignerInterface 使用存放在硬體安全模組(HSM)內的金鑰進行簽章。私鑰不會離開硬體邊界。此契約以 DER 形式回傳簽章者憑證與憑證鏈,供 CMS 層建構結構。DeferredSignerInterface 擴充 SignerInterface 以支援非同步簽章。呼叫端提交資料後,取得一個工作識別碼、輪詢完成狀態,再取回結果。當遠端 HSM 或雲端金鑰服務無法立即回傳結果時,可使用它。
TimestampProviderInterface 會請求一個 RFC 3161 時間戳記權杖。此協定規範與時間戳記憑證機構(TSA)之間的請求與回應交換 —— 見 RFC 3161 §2.4。權杖中的 messageImprint 是簽章值的雜湊 —— RFC 3161 §2.4.2。LtvManagerInterface 用於啟用長期驗證。它會收集憑證鏈、擷取 OCSP 與 CRL 回應、建構文件安全儲存區,並為 B-LTA 加上文件時間戳記。CryptoPolicyInterface 會在任何密碼學運算執行之前,把關允許哪些雜湊、簽章與加密演算法,以及允許哪些金鑰強度。
API 介面
標題為「API 介面」的區段| 型別 | 種類 | 主要成員 | 穩定度 | 自版本 |
|---|---|---|---|---|
SignerInterface | 介面 | sign(string): SignatureResult、timestamp(string): string、supportsLtv(): bool | 穩定 | 1.0.0 |
HsmSignerInterface | 介面 | sign(string, string): string、getCertificateDer()、getCertificateChainDer()、getPublicKeyAlgorithm() | 穩定 | 1.0.0 |
DeferredSignerInterface | 介面 | submitForSigning(string): string、retrieveSignature(string)、isComplete(string)(擴充 SignerInterface) | 實驗性 | 3.0.0 |
TimestampProviderInterface | 介面 | getTimestamp(string): string | 實驗性 | 3.0.0 |
LtvManagerInterface | 介面 | enableLtv(...)、addDocumentTimestamp(...) | 穩定 | 1.10.0 |
CryptoPolicyInterface | 介面 | isHashAlgorithmAllowed()、isSignatureAlgorithmAllowed()、isEncryptionAlgorithmAllowed()、isKeyStrengthAllowed()、getPreferredHashAlgorithm()、getName() | 穩定 | 1.9.0 |
SignerInterface::sign() 會回傳一個 NextPDF\Security\Signature\SignatureResult。公開的 $cmsSignedData 屬性存放 DER 編碼的 CMS。公開的 $digestHex 屬性存放 SHA-256 摘要。公開的 $timestampToken 屬性存放選用的 TSA 權杖。存取方法為 toHex() / toHexPadded(int) / getSize() / hasTimestamp()。HsmSignerInterface::sign() 對 RSA 回傳 DER 編碼的位元組,對 ECDSA 回傳原始 r‖s 位元組。演算法引數使用 OpenSSL 識別碼。
程式碼範例 —— 快速入門
標題為「程式碼範例 —— 快速入門」的區段<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/** * Sign a byte range with any SignerInterface implementation. * * @param SignerInterface $signer A core or Premium signer. * @param string $byteRange The PDF byte range to sign. * * @return string Hex-encoded CMS SignedData for the PDF /Contents field. */function signByteRange(SignerInterface $signer, string $byteRange): string{ $result = $signer->sign($byteRange);
return $result->toHex();}SignerInterface::sign() 會回傳一個 SignatureResult。toHex() 會產生供寫入器放入 /Contents 欄位的十六進位字串;原始 DER 位元組則放在公開的 $cmsSignedData 屬性上。此函式依賴的是契約,而非具體類別。不論是 Core 的測試簽章器,還是 Premium 的 HSM 簽章器,都能滿足它。
程式碼範例 —— 正式環境
標題為「程式碼範例 —— 正式環境」的區段<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;use NextPDF\Contracts\SignerInterface;use NextPDF\Contracts\TimestampProviderInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class TimestampedSigningService{ public function __construct( private SignerInterface $signer, private TimestampProviderInterface $timestamps, private CryptoPolicyInterface $policy, private LoggerInterface $logger, ) {}
/** * Sign a byte range, then timestamp the CMS structure. * * @param string $byteRange The PDF byte range to sign. * * @return array{cms: string, digest: string, tst: string} */ public function sign(string $byteRange): array { if (!$this->policy->isHashAlgorithmAllowed($this->policy->getPreferredHashAlgorithm())) { throw new \LogicException('Preferred hash rejected by crypto policy.'); }
try { $signature = $this->signer->sign($byteRange); $token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return [ 'cms' => $signature->toHex(), 'digest' => $signature->digestHex, 'tst' => $token, ]; } catch (NextPdfException $e) { $this->logger->error('Signing failed', [ 'policy' => $this->policy->getName(), 'error' => $e->getMessage(), ]);
throw $e; } }}此服務注入三項契約。在執行簽章運算之前,會先查詢密碼學原則。SignatureResult 透過公開的 $cmsSignedData 屬性揭露 CMS 位元組,透過 $digestHex 揭露 SHA-256 摘要,並以 toHex() 產生 /Contents 十六進位字串。時間戳記提供者接收 CMS 位元組,並回傳一個 DER 編碼的權杖。catch 區塊會記錄原則名稱並重新拋出例外。它絕不會吞掉失敗。
邊界情況與陷阱
標題為「邊界情況與陷阱」的區段- 位元組範圍摘要必須排除簽章值。若摘要涵蓋
Contents項目,會產生永遠無法驗證的簽章 —— ISO 32000-2 §12.8.1。 SignerInterface::supportsLtv()回報的是能力,而非狀態。簽章器可以支援長期驗證,但在未設定時間戳記服務時,仍會產生 B-B 簽章。DeferredSignerInterface::retrieveSignature()在工作完成之前都會回傳null。請先輪詢isComplete(),以避免每次檢查都傳輸負載資料。結果一旦存在,取回操作即具有冪等性。LtvManagerInterface::addDocumentTimestamp()必須在文件安全儲存區寫入之後才執行。若先呼叫它,會產生無效的 B-LTA 結構。CryptoPolicyInterface在未設定任何原則時,對每個演算法都會回傳true。在受管制的環境中,請設定明確的原則;不要倚賴這個開放的預設值。HsmSignerInterface::getCertificateChainDer()不包含簽章者憑證。請以getCertificateDer()取得簽章者葉憑證,並以鏈方法取得中繼憑證。
簽章成本主要由密碼學運算與任何網路往返決定,而非由契約本身決定。本機軟體簽章通常是個位數毫秒。HSM 簽章會多出裝置往返時間。時間戳記會多出一次到時間戳記憑證機構的網路往返。長期驗證會為鏈中每張憑證多出一次 OCSP 或 CRL 擷取。1500 毫秒牆鐘時間的 performance_budget 涵蓋連線已預熱時、使用遠端 TSA 的單一帶時間戳記簽章。針對緩慢撤銷端點的長期驗證會超出此預算,應在請求路徑之外執行。可重現性設定檔是 structural,而非 bitwise。時間戳記會嵌入簽章當下的時間,因此兩次執行在時間戳記位元組上會有差異,而文件結構則維持相同。
安全注意事項
標題為「安全注意事項」的區段簽章契約是引擎的主要密碼學邊界,因此威脅模型很明確。金鑰保管是第一個考量:HsmSignerInterface 把私鑰保留在硬體邊界內,且此契約絕不揭露金鑰材料。演算法降級是第二個考量:CryptoPolicyInterface 會在運算之前封鎖弱雜湊與過短金鑰,讓部署不必分支引擎即可強制套用 FIPS 140-3 或 eIDAS 設定檔。時間戳記信任是第三個考量:RFC 3161 權杖的可信度僅及於其時間戳記憑證機構,因此提供者契約是可注入的,讓部署能釘選自己的憑證機構。長期驗證是第四個考量:撤銷材料會在簽章時擷取並儲存在文件安全儲存區,使驗證在憑證到期後仍能維持。請把每一筆簽章器輸入都視為不可信任。位元組範圍由引擎計算,絕不從呼叫端接受。由於這些契約掌管密碼學簽章,本頁標示為 export_control_class: legal-review-required。依照引用衛生原則,本文釋義所有規範性來源,並未引述其原文。
符合性
標題為「符合性」的區段| 主張 | 標準 | 條款 | 證據 |
|---|---|---|---|
簽章值以 DER 編碼儲存在簽章字典的 Contents 項目中,形式為 CMS SignedData 或 TimeStampToken。 | ISO 32000-2 | §12.8.1 | |
摘要是針對 ByteRange 陣列所定義的位元組範圍計算,並排除簽章值。 | ISO 32000-2 | §12.8.1 | , |
| 長期驗證材料承載於文件安全儲存區,內含 VRI、OCSP、CRL 與憑證項目。 | ISO 32000-2 | §12.8.4.3 | , |
| PAdES 長期驗證會把驗證資料放入 DSS 與 VRI 字典中。 | ETSI EN 319 142-2 | §6.3 | , |
RFC 3161 時間戳記權杖透過 messageImprint 綁定簽章值的雜湊,並以 TSA 請求與回應交換。 | RFC 3161 | §2.4.2、§2.4 | , |
| CMS SignedData 序列承載版本、摘要演算法、封裝內容與簽章者資訊。 | RFC 5652 | §5.1 |
所有條款皆為釋義。NextPDF 不會重製規範性文字。如需具權威性的措辭,請查閱已發布的標準。
商業脈絡
標題為「商業脈絡」的區段Core 發布並凍結簽章契約。HsmSignerInterface、LtvManagerInterface 以及延遲簽章器背後的正式環境實作,會隨 Pro 與 Enterprise 版本一同提供,包含 PKCS#11 硬體整合以及 PAdES B-LT 與 B-LTA。Core 會在執行階段以 class_exists() resolve(解析)這些實作並轉型為契約,因此開源引擎不帶任何商業相依性,且 API 在升級時不會改變。