跳到內容

安全性 / 簽章:CMS、RFC 3161 時間戳記、LTV 與信任

本頁說明 NextPDF Core 隨附的簽章介面:產生 CMS 簽章、套用 RFC 3161 時間戳記、依 RFC 5280 驗證憑證鏈,並透過 OCSP 與 CRL 檢查撤銷狀態。內容著重在行為層級。Core 的實作類別屬內部實作——正式環境的程式碼依賴 SignerInterface 這份契約,而不是具體的 NextPDF\Security\Signature 型別。已產生的簽章是否能通過驗證,取決於驗證端以及它所設定的信任錨點。這個結果不在產生端的控制範圍內,本頁會在相關段落明確指出這一點。

Terminal window
composer require nextpdf/core:^3

Core 會從位元組範圍建構 CMS SignedData 結構,再以 DER 編碼存入簽章字典的 Contents 項目——ISO 32000-2 §12.8.1。此結構帶有 SignerInfo 的已簽署屬性,其中包含 content-type 與 message-digest——RFC 5652 §5.3。驗證端會重新計算內容摘要,並與 message-digest 屬性比對。兩者必須相符,簽章才算有效——RFC 5652 §5.4。SignerInfo 也會帶有摘要演算法識別碼與已簽署屬性區塊——RFC 5652 §5。Core 隨附的軟體簽章路徑會透過 phpseclib3 進行簽章:RSA、RSASSA-PSS、ECDSA 與 Ed25519。

RFC 3161 時間戳記是與時間戳記機構(Time-Stamping Authority)之間的一次請求/回應往返,機構會回傳 TSTInfo 結構——RFC 3161 §2.4.1。每個權杖都帶有一個對發行該權杖的 TSA 而言唯一的 serialNumber——RFC 3161 §2.4.2——以及一個以 UTC 表示、代表權杖建立瞬間的 genTime——RFC 3161 §2.4.2。

信任驗證包含兩項檢查。路徑驗證會從簽署者憑證一路驗證到信任錨點,沿途檢查基本限制條件與路徑建構輸入——RFC 5280 §6.1。撤銷檢查會向 OCSP 回應方查詢,或讀取 CRL:一則 OCSP 回應會回報 goodrevokedunknown——RFC 6960 §2.2——而回應的 thisUpdatenextUpdate 則界定了該狀態的新鮮度——RFC 6960 §4.2。信任錨點與撤銷新鮮度政策都由呼叫端提供。引擎只依取得的輸入進行驗證,並不隨附內建的信任清單。

型別種類角色穩定度起始版本
SignerInterface介面(NextPDF\Contracts呼叫端所依賴的簽章契約穩定1.0.0
SignatureLevelenum(列舉)PAdES 等級選擇器與可用性偵測穩定1.0.0
Rfc5280PathValidator介面憑證路徑驗證的進入點(validate(...)穩定(自 3.1.0 起凍結)3.1.0
RevocationStatus列舉OCSP / CRL 結果:good、revoked、unknown穩定3.1.0
CaTrustAnchorBundle型別由呼叫端提供的一組信任錨點穩定3.1.0
TstInfo型別已剖析的 RFC 3161 時間戳記欄位穩定3.2.0

SignerInterface::sign() 會回傳一個 SignatureResult,其 toHex() 會產生 /Contents 的十六進位字串,而 cmsSignedData 屬性則持有原始的 DER 位元組。實作這些行為的具體 NextPDF\Security\Signature 類別屬內部實作(在模組資訊清單中標為 stability: internal);它們並非公開 API 的一部分,可能在未提升主版號的情況下變更。請依賴上述契約與列舉。

examples/contracts/signing-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/**
* Produce the CMS SignedData hex for a PDF /Contents field.
*
* @param SignerInterface $signer A Core or Premium signer.
* @param string $byteRange The PDF byte range to sign.
*
* @return string Hex-encoded CMS SignedData.
*/
function sign(SignerInterface $signer, string $byteRange): string
{
return $signer->sign($byteRange)->toHex();
}

呼叫端依賴的是契約。Core 的軟體簽章器與 Premium 的 HSM 簽章器都滿足 SignerInterface,因此這段程式碼在不同版本之間維持不變。

examples/contracts/signing-trust.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* The timestamp's trust still depends on the verifier accepting the
* Time-Stamping Authority; this method only produces the structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, tst: string}
*/
public function sign(string $byteRange): array
{
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}

時間戳記提供者以注入方式提供,讓每個部署環境都能釘選自己的時間戳記機構(Time-Stamping Authority)。catch 區塊會記錄並重新拋出例外。它絕不吞掉失敗,讓簽章路徑維持 fail-closed(失敗即關閉)。

  • 已產生的簽章並非已驗證的簽章。路徑驗證與撤銷檢查是在驗證端,並以該驗證端的信任錨點執行。產生端無法判定其結果。
  • 位元組範圍摘要會排除簽章值本身。涵蓋 Contents 八位元組的摘要無法通過驗證——ISO 32000-2 §12.8.1。
  • 撤銷狀態有一個新鮮度時間窗。一則 OCSP 回應的有效期限,只到它的 thisUpdate / nextUpdate 區間為止——RFC 6960 §4.2。陳舊的回應無法取代驗證當下的一次即時檢查。
  • 引擎不隨附內建的信任清單。CaTrustAnchorBundle 由呼叫端提供;空的 bundle(套件)依設計表示沒有任何憑證鏈能通過驗證。
  • OCSP 的 unknown 並不等於 good。必須把 unknown 視為無法判定,而非隱含通過——RFC 6960 §2.2。
  • HSM 金鑰保管、延後簽章與雲端簽章,以及 PAdES B-LT / B-LTA 產生器,都不在 Core 之中。在 Core 散布版本中選用這些路徑時,會 fail closed(失敗即關閉),並以訊息指出所缺的 Enterprise 元件名稱。

一次軟體簽章只需個位數毫秒。加上時間戳記時,則會多一次往返 TSA 的網路呼叫。憑證一旦載入記憶體,路徑驗證便屬本機作業;撤銷檢查則會為鏈中每張憑證各增加一次 OCSP 或 CRL 擷取。1500 毫秒的整體預算,涵蓋的是在連線已暖機的情況下、向遠端 TSA 取得時間戳記的單次簽章。若對緩慢端點進行撤銷檢查,會超出此預算,應移到請求路徑之外處理。可重現性設定檔為 structural:時間戳記會嵌入簽署的瞬間,因此兩次執行的時間戳記位元組會不同,但文件結構完全相同。

這是引擎主要的密碼學邊界,因此威脅模型在此明確列出。位元組範圍由引擎計算,絕不接受由呼叫端提供。簽章路徑為 fail-closed:密碼原語失敗或能力缺口都會拋出具型別的例外,絕不會悄悄降級為較弱的演算法。在需要時間戳記的等級(B-T、B-LT、B-LTA)下,回傳空權杖(empty token)的時間戳記機構(Time-Stamping Authority)屬於終端故障:簽章會被拒絕,而不會悄悄略過時間戳記、以降級狀態發出;除非有已接線的故障處理常式,明確授權一項已記載的降級。信任依設計由呼叫端掌控——錨點與撤銷政策都是輸入,而非引擎預設——因為若由產生端斷定自身的信任,就等於斷定一個只有驗證端能確立的事實。時間戳記的信任取決於對時間戳記機構(Time-Stamping Authority)的信任,而後者可注入,讓每個部署環境都能釘選自己的機構。本頁標示為 export_control_class: legal-review-required,因為其涉及密碼學簽章;依照引用衛生原則,每一份規範性來源皆經改述,且未重製任何內容。

主張標準條款佐證
CMS 簽章以 DER 編碼存入簽章字典的 Contents 項目。ISO 32000-2§12.8.1
SignerInfo 帶有 content-type 與 message-digest 已簽署屬性。RFC 5652§5.3
驗證端會重新計算內容摘要,並與 message-digest 屬性比對。RFC 5652§5.4
時間戳記權杖由 RFC 3161 TSA 產生,並帶有唯一的 serialNumber 與一個 UTC 的 genTime。RFC 3161§2.4.1, §2.4.2,,
憑證路徑驗證會檢查基本限制條件,以及從簽署者到信任錨點的路徑輸入。RFC 5280§6.1,
OCSP 會回報 certStatus 為 good、revoked 或 unknown,並以 thisUpdate / nextUpdate 為界。RFC 6960§2.2, §4.2,

所有條款皆以改述方式呈現。NextPDF 不重製規範性原文。權威用語請參閱已發布的標準。

Core 隨附軟體 CMS 簽章器(RSA、RSASSA-PSS、ECDSA、Ed25519)、RFC 3161 時間戳記消費、RFC 5280 路徑驗證,以及 OCSP / CRL 撤銷檢查。HSM 與 PKCS#11 金鑰保管、延後簽章與雲端簽章、PAdES B-LT 與 B-LTA 產生器,以及 FIPS 140-3 密碼學政策設定檔,則隨附於 Pro 與 Enterprise 版本。Core 會在執行期依契約 resolve(解析)這些元件,因此這套開源引擎不帶任何商業相依,升級時 API 也不會改變。