跳到內容
getnextpdf.com

Enterprise 版本

硬體安全模組簽署(PKCS#11)

NextPDF Enterprise 會以一把保存在硬體安全模組(HSM)內的金鑰簽署一份 PDF。你將簽署器指向一個 PKCS#11 符記——一張智慧卡、一個通用序列匯流排(USB)符記,或一個網路連接 HSM——而簽署操作會在該裝置上執行。私鑰永不離開符記邊界。本頁屬於行為層級:它說明簽署器做了什麼、你提供什麼,以及金鑰保管在何處不再是 NextPDF 的責任。

HSM 簽署器透過 Core 簽署器合約解析,因此你的應用程式依賴的是合約,而非具體的 Enterprise 型別。它擴充 Core 所使用的同一條密碼學訊息語法(CMS)簽署路徑,差別僅在於密碼學運算被委派給符記。

先決條件陳述於前置資料中,並在 先決條件 處重申,使你不會在任務中途感到意外。

此能力隨附於 NextPDF Enterprisenextpdf/enterprise),並以一個 Enterprise 層級的授權封套啟用。一個不具該權利的部署不會載入此能力的類別。比較各版本並取得授權

NextPDF Core 隨附一個軟體 CMS 簽署器,它將金鑰保存在行程內,或透過 Core 簽署策略合約接受一把金鑰;NextPDF Pro 新增遠端與雲端金鑰管理服務(KMS)簽署策略。透過 PKCS#11 的硬體金鑰保管是一項 Enterprise 能力,不由 Core 或 Pro 提供。

一個 PKCS#11 符記會在一個廠商共用函式庫背後,公開密碼學物件——憑證與私鑰。Enterprise 簽署器會轉接該函式庫:

  1. 它每個行程開啟符記的共用函式庫一次,並快取模組 handle,因為 PKCS#11 要求該模組每個行程恰好初始化一次。
  2. 它在所設定的 slot 上開啟一個工作階段,並以所提供的 PIN 登入。該登入會在任何私鑰操作之前驗證使用者,依 PKCS#11 v3.1 §5.6.8。
  3. 它以標籤在符記上定位簽署憑證、以辨別編碼規則(DER)形式讀取該憑證,並偵測公鑰演算法。
  4. 在簽署時,它以標籤定位私鑰——在某些符記上可能與憑證標籤不同——並請符記計算簽章。要簽署的資料被傳入;金鑰留在裝置上。

簽署器支援帶 PKCS#1 v1.5 填補的 RSA(SHA-256、SHA-384、SHA-512)、帶機率簽章方案(PSS)填補且鹽長度等於摘要長度的 RSA,以及帶 SHA-256、SHA-384 與 SHA-512 的橢圓曲線數位簽章演算法(ECDSA)。ECDSA 曲線與摘要按慣例配對——P-256 配 SHA-256、P-384 配 SHA-384、P-521 配 SHA-512——遵循 RFC 5480 中的建議配對。符記會以兩個整數的原始串接形式回傳一個 ECDSA 簽章;簽署器會將它轉換為 PDF 與 OpenSSL 所預期的 DER 編碼形式。

就簽章產生而言,一把至少 2048 位元的 RSA 金鑰,以及一個至少 224 位元階的 ECDSA 曲線,是依 NIST SP 800-131A Rev.2 §3 可接受的最低值。請以等於或高於那些大小供裝你的符記金鑰。

存在一條替代的 OpenSSL-engine 路徑供 engine 支撐的符記使用。在 OpenSSL 3.x 上,PHP OpenSSL 擴充不公開 engine 應用程式介面(API),因此 engine 類別已棄用;受支援的 engine 支撐路線是執行 OpenSSL 命令列二進位檔。在你的符記具備 PKCS#11 函式庫之處,請優先採用直接的 PKCS#11 路徑。

承載性的決定是私鑰永不離開符記。因此簽署器將密碼學運算委派給裝置,只將要簽署的資料移動跨越 PKCS#11 接縫。它絕不在 PHP 記憶體中讀取或重建金鑰素材。它透過 Core HsmSignerInterface 合約解析,而非一個具體的 Enterprise 型別,因此無論金鑰位於軟體、雲端 KMS 或硬體符記,簽署程式碼皆相同。它每個行程快取模組 handle 一次,因為 PKCS#11 每個行程恰好初始化每個模組一次,接著將符記的原始 ECDSA 輸出轉換為 DER,使驗證器看到它們所預期的編碼。驅動此形態的是保管,而非便利:信任邊界維持在裝置邊緣。

設計背景:HSM 支撐的簽署

在你以 HSM 簽署之前,請確認每一項:

  1. 安裝 NextPDF Core 與 Enterprise 套件:composer require nextpdf/core:^3composer require nextpdf/enterprise
  2. 持有一份有效的 NextPDF Enterprise 授權;在 Private Packagist 上以你的授權憑證解析此套件。
  3. 在主機上安裝符記廠商的 PKCS#11 共用函式庫(例如 Linux 上的 .so 或 Windows 上的 .dll),並記下其絕對路徑、slot 編號,以及物件標籤。
  4. 載入 ext-pkcs11 PHP 擴充。它未隨標準 PHP 一併提供,必須另行安裝。當擴充不存在時,簽署器建構子會引發一個具型別的操作錯誤。

提供這些輸入給簽署器:

  • 函式庫路徑 — 廠商 PKCS#11 共用函式庫的絕對路徑。
  • Slot 識別碼 — 符記的 slot 編號,通常為 0
  • PIN — 符記 PIN。請將它視為一個機密:從你的機密管理器提供它,絕不可來自原始碼或日誌。簽署器將 PIN 參數標記為敏感,因此它被排除於堆疊追蹤與序列化之外。
  • 憑證標籤 — 符記上憑證物件的標籤。
  • 金鑰標籤 — 私鑰物件的標籤,當它與憑證標籤不同時。
  • 憑證鏈 — 當符記不保有它們時,以 DER 形式提供的選用中介憑證。

在你建構簽署器之前,請先檢查符記可用性。建構會從符記讀取憑證,因此一個設定錯誤的 slot 或標籤會以一個具型別的錯誤快速失敗,而非在簽署時才失敗。

  1. 透過檢查擴充可用性,確認執行階段支援 PKCS#11。當擴充不存在時,請勿建構簽署器。
  2. 將 PIN 從你的機密管理器讀入一個絕不會被記錄的變數。
  3. 以函式庫路徑、slot、PIN 與各標籤建構 HSM 簽署器。建構會登入並讀取憑證。
  4. 透過 HsmSignerInterface 將簽署器傳給 Core 簽署協調器。協調器會計算位元組範圍、建構 CMS 已簽署屬性、將資料交給符記,並組裝已簽署的 PDF。
  5. 捕捉最具體的失敗、記錄一則不含 PIN 的結構性訊息,並重新拋出。
examples/contracts/hsm-signer-availability.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HsmSignerInterface;
/**
* Build a hardware-token signer only when the runtime supports it.
*
* The concrete PKCS#11 signer is resolved through the Core contract so the
* caller depends on the interface, not the Enterprise implementation type.
* The PIN arrives from a secret resolver; it is never written to source.
*
* @param callable(): bool $pkcs11Available Reports ext-pkcs11 availability.
* @param callable(): HsmSignerInterface $signerFactory Builds the configured token signer.
*
* @throws \RuntimeException When the PKCS#11 extension is not loaded.
*
* @return HsmSignerInterface The token signer, ready for the Core orchestrator.
*/
function resolveHsmSigner(callable $pkcs11Available, callable $signerFactory): HsmSignerInterface
{
if ($pkcs11Available() !== true) {
throw new \RuntimeException(
'PKCS#11 signing requires the ext-pkcs11 extension; install it before signing.',
);
}
return $signerFactory();
}

正式環境接線——確切的建構子引數清單與具型別的例外型別——記載於 HSM 深入參考

examples/contracts/hsm-sign-guarded.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HsmSignerInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class HsmSigningService
{
public function __construct(
private HsmSignerInterface $signer,
private LoggerInterface $logger,
) {}
/**
* Sign data on the token through the Core HSM contract.
*
* The byte range is computed by the engine, never accepted from the
* caller. The token performs the signing operation; the private key
* does not leave the device.
*
* @param string $data The bytes the orchestrator hands to the token.
* @param string $algorithm The OpenSSL-style signing algorithm identifier.
*
* @throws NextPdfException When the token operation fails.
*
* @return string The raw signature bytes returned by the token.
*/
public function sign(string $data, string $algorithm): string
{
try {
return $this->signer->sign($data, $algorithm);
} catch (NextPdfException $e) {
// Structural message only — never the PIN or key material.
$this->logger->error('HSM signing failed', ['reason' => $e->getMessage()]);
throw $e;
}
}
}

請以驗證器的方式確認結果:

  1. 從簽署器以 DER 形式讀回簽署者憑證與憑證鏈,並確認它們與供裝在符記上的憑證相符。
  2. 在一個以你信任錨點設定的驗證器中開啟已簽署的 PDF,並確認該簽章被回報為密碼學上完整。一個產生的簽章不是一個已驗證的簽章;信任決定屬於驗證器及其信任錨點,而非產生者。
  3. 對於一個 ECDSA 簽章,請確認嵌入的簽章是 DER 編碼的——簽署器已為你轉換符記的原始輸出,因此一個拒絕原始串接形式的驗證器仍應接受嵌入的簽章。
  4. 確認你的應用程式日誌中沒有出現任何 PIN、符記標籤或金鑰素材。
  • 金鑰留在符記上。 要簽署的資料被交給符記;簽署操作在符記邊界內執行。私鑰永不被載入 PHP 記憶體。
  • PIN 是一個機密。 它是一個敏感的建構子參數,被排除於日誌與序列化之外。請從一個機密管理器提供它。反覆失敗的重新驗證可能在符記端鎖定 PIN;強制該政策的是符記,而非 NextPDF。
  • Fail-closed。 一個符記或 HSM 錯誤會引發一個具型別的例外。簽署器不會產生一個未簽署或部分簽署的結果,且絕不替換成較弱的演算法。
  • 演算法強度。 請供裝至少 2048 位元的 RSA 金鑰,以及至少 224 位元階的 ECDSA 曲線,這是依 NIST SP 800-131A Rev.2 §3 簽章產生可接受的最低值。
  • 後量子簽署為實驗性,且預設關閉。 一條後量子路徑存在於一個明確選用旗標之後。標準 PDF 進階電子簽章(PAdES)長期封存設定檔尚未辨識後量子套件,而大多數檢視器會在驗證時拒絕它們。請勿在正式環境的 PAdES 簽章中啟用它。

本頁涉及密碼學簽署與硬體安全模組整合。每一項規範性來源皆為改寫;不重製任何規範性文字。 ### 金鑰保管邊界

NextPDF Enterprise 會整合一個 PKCS#11 符記或 HSM。它不儲存、不產生,也不保證簽署金鑰的安全。金鑰安全取決於符記或 HSM、部署環境,以及操作者——而非單靠 NextPDF Enterprise。你負責符記供裝、PIN 處理、slot 設定,以及網路連接 HSM 的網路保護。

  • 擴充不存在。ext-pkcs11 未載入時,建構 PKCS#11 簽署器會引發一個具型別的操作例外。請先檢查可用性。
  • 以標籤找不到憑證或金鑰。 建構或簽署會引發一個具型別的例外,並指名缺少的物件。請確認標籤與 slot。
  • 已經登入。 當數個簽署器實例共用同一個 slot 的快取模組時,簽署器會登出再重新登入,以提供一次新鮮的 PIN 驗證——具「每次都要 PIN」政策的個人身分驗證符記需要此行為。
  • 不支援的演算法。 請求一個簽署器未對應的演算法,會引發一個引數錯誤,而非以一個替代演算法簽署。
  • 網路 HSM 無法連線。 一個網路或裝置錯誤會引發一個具型別的例外;簽署器絕不默默產生一份未簽署的文件。

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