Enterprise エディション
HSM署名 — 詳細リファレンス
このページは NextPDF Enterprise の HSM 署名サーフェスの詳細リファレンスです。3 つの公開型を扱います。NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11Signer は ext-pkcs11 拡張を介して PKCS#11 トークンで署名します。NextPDF\Enterprise\Security\Signature\Hsm\OpenSslCliSigner は、PHP の ext-openssl が読み込めないプロバイダーまたはエンジン支援の鍵向けに、サブプロセス内の openssl バイナリを介して署名します。NextPDF\Enterprise\Security\Signature\Hsm\Provider\HsmSignerProviderAdapter は、いずれの具象型も統一された SignerProviderInterface として公開します。いずれの経路でも秘密鍵はトークン境界の内側に留まり、NextPDF は署名対象のバイト列を渡して署名を受け取ります。ポスト量子経路(signPqs)はプレビューです。既定で無効化されており、適合性の主張を伴わず、現行の PDF バリデーターにサポートされる検証経路はありません。NextPDF はいかなる認証も保有せず、いかなる認証も付与しません。サポートは適合性と等しくなく、適合性は認証と等しくありません。
提供状況とライセンス
「提供状況とライセンス」という見出しのセクションこの機能は NextPDF Enterprise(nextpdf/enterprise)に含まれ、Enterprise ティアのライセンスエンベロープで有効化されます。その資格を持たないデプロイメントでは、この機能のクラスは読み込まれません。エディションを比較してライセンスを取得。
公開 API サーフェス
「公開 API サーフェス」という見出しのセクション3 つの型はすべて NextPDF\Enterprise\Security\Signature\Hsm に存在し、アダプターはその Provider サブ名前空間に位置します。両署名器は Core の NextPDF\Contracts\HsmSignerInterface 契約を実装します。
| シンボル | パラメーター | 既定動作 | 戻り値 | スロー/失敗 | 備考 |
|---|---|---|---|---|---|
Pkcs11Signer::__construct() | string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null | ベンダーライブラリを開き、スロットにログインし、証明書と鍵アルゴリズムのメタデータをトークンから読み込む | — | ext-pkcs11 が不在、またはトークンアクセスが失敗した場合に HsmOperationException | モジュールハンドルはプロセスごと・ライブラリパスごとに 1 つキャッシュ。PIN とラベルは #[SensitiveParameter] |
Pkcs11Signer::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | トークン上で署名。生の ECDSA 出力は DER ECDSA-Sig-Value に変換 | string(生の署名バイト) | HsmOperationException(鍵が見つからない、トークン障害)、InvalidArgumentException(未対応アルゴリズム)、エンフォーサー接続時は署名前の FIPS ゲート例外 | 閉じたアルゴリズム集合。動作契約を参照 |
Pkcs11Signer::signPqs() | string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true | $enablePostQuantum が設定されていなければ拒否。暫定的な PKCS#11 PQ メカニズムをディスパッチ | string(生の署名バイト) | HsmOperationException(無効化、トークン障害、署名長不一致)、InvalidArgumentException(コンテキストが 255 バイト超) | プレビュー。適合性の主張なし。メカニズム識別子は暫定 |
Pkcs11Signer::isPostQuantumEnabled() | なし | コンストラクターのオプトインフラグを報告 | bool | なし | — |
Pkcs11Signer::getCertificateDer() | なし | トークンから読み取った署名者証明書を返す | string(DER) | なし | 構築時に一度読み込み |
Pkcs11Signer::getCertificateChainDer() | なし | コンストラクターで指定された中間証明書を返す | array<string>(DER) | なし | 署名者証明書を除く |
OpenSslCliSigner::__construct() | string $keyUri, string $certPath, string $pin, array $extraCertPaths = [], OpenSslCliBackend $backend = OpenSslCliBackend::Auto, string $opensslBinary = 'openssl', int $timeoutSeconds = 30, ?string $modulePath = null, ?string $configPath = null, bool $legacyPinDelivery = false, ?FipsSignatureEnforcer $fipsEnforcer = null | proc_open を検証し、バイナリとバージョンを探査し、バックエンドを解決し、証明書を読み込む | — | HsmOperationException(proc_open 無効、モジュール/設定/証明書ファイルの欠落、バイナリ失敗、バックエンドなし)、InvalidArgumentException($keyUri 内の pin-value) | OpenSslCliBackend::Auto は OpenSSL 3.x プロバイダーを優先し、次にエンジン |
OpenSslCliSigner::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | サブプロセスで openssl dgst を実行。PIN は既定で一時的な 0600 の pin-source ファイルを経由 | string(生の署名バイト) | HsmOperationException(タイムアウト、PIN 拒否、鍵が見つからない、モジュール読み込み失敗、空出力、pin ファイル失敗)、InvalidArgumentException(未対応アルゴリズム)、署名前の FIPS ゲート例外 | サブプロセスは $timeoutSeconds 後に強制終了。stderr はメッセージに達する前に伏字化 |
OpenSslCliSigner のアクセサーサーフェス | なし | 読み取り専用の構築結果 | string / array<string> / OpenSslCliBackend | なし | getCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion |
HsmSignerProviderAdapter::__construct() | HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15 | HSM 具象型を SignerProviderInterface としてラップ | — | なし | プロバイダー ID の慣例: pkcs11-{module-id}, openssl-cli |
HsmSignerProviderAdapter::providerId() | なし | コンストラクターで指定された ID を返す | non-empty-string | なし | — |
HsmSignerProviderAdapter::supportsAlgorithm() | SignatureAlgorithm $algo | 列挙型を OpenSSL 形式の名前にマップし、バックエンドの許可集合と積を取る | bool | なし | ダイジェスト専用アルゴリズムは拒否。openssl-engine の ID は何も広告しない |
HsmSignerProviderAdapter::sign() | string $data, ?string $keyVersion = null | 構成済みアルゴリズムでラップした署名器を通じてディスパッチ | non-empty-string | KeyManagementException(非 null の $keyVersion)、SignatureFailedException(マップ不能アルゴリズム、ドライバー障害、空署名) | フェイルクローズドな SPI 契約。あらゆるドライバーエラーが型付きで表面化 |
public function __construct(private readonly string $libraryPath, private readonly int $slotId, #[SensitiveParameter] private readonly string $pin, #[SensitiveParameter] private readonly string $certLabel, #[SensitiveParameter] private readonly ?string $keyLabel = null, array $chainDer = [], private readonly bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null)public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): stringpublic function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): stringpublic function isPostQuantumEnabled(): boolpublic function getCertificateDer(): stringpublic function getCertificateChainDer(): arraypublic function __construct(private string $keyUri, string $certPath, #[SensitiveParameter] private string $pin, array $extraCertPaths = [], private OpenSslCliBackend $backend = OpenSslCliBackend::Auto, private string $opensslBinary = 'openssl', private int $timeoutSeconds = 30, private ?string $modulePath = null, private ?string $configPath = null, private bool $legacyPinDelivery = false, private ?FipsSignatureEnforcer $fipsEnforcer = null)public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): stringpublic function getCertificateDer(): stringpublic function getCertificateChainDer(): arraypublic function getPublicKeyAlgorithm(): stringpublic function getCertificatePem(): stringpublic function getResolvedBackend(): OpenSslCliBackendpublic function getOpensslVersion(): stringpublic function __construct(private HsmSignerInterface $hsm, private string $providerId, private SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15)public function providerId(): stringpublic function supportsAlgorithm(SignatureAlgorithm $algo): boolpublic function sign(string $data, ?string $keyVersion = null): string- 鍵保管。 秘密鍵がトークン境界を離れることはありません。
Pkcs11Signerは操作をトークンに委譲し、OpenSslCliSignerは鍵の参照(PKCS#11 URI)をopensslサブプロセスに渡します。いずれの署名器も鍵をエクスポートできません。 - セッションとログイン。 トークンインターフェースはプロセスごとにちょうど一度初期化しなければならないため、
Pkcs11Signerはプロセスごと・ライブラリパスごとに PKCS#11 モジュールハンドルを 1 つキャッシュします。各操作はセッションを開き、PIN でログインします。ログインは秘密鍵の使用前にユーザーを認証します(PKCS#11 v3.1 §5.6.8)。スロットが既存のログインを報告した場合、署名器はログアウトして再度ログインするため、操作ごとに新しい PIN を要求するトークンにもそれが提供されます。 - アルゴリズム集合(閉じている)。 両署名器は次のものだけを受け付けます。
sha256WithRSAEncryption、sha384WithRSAEncryption、sha512WithRSAEncryption、RSASSA-PSS、RSASSA-PSS-SHA256、RSASSA-PSS-SHA384、RSASSA-PSS-SHA512、ecdsa-with-SHA256、ecdsa-with-SHA384、ecdsa-with-SHA512。Pkcs11Signerはさらにecdsa-rawを受け付けます。それ以外の識別子はInvalidArgumentExceptionを送出します。代替アルゴリズムが署名されることは一切ありません。 - PSS ソルトの束縛。 すべての PSS 派生形について、ソルト長はダイジェスト長(32、48、または 64 バイト)と等しく、ハッシュと MGF のパラメーターは選択したダイジェストと一致します。これは、ソルト長が通常メッセージハッシュ長である PSS メカニズムパラメーター構造に従います(PKCS#11 v3.1 §6.1.9)。両署名器は同じ対応付けを適用するため、一方のバックエンドで有効な構成は他方でも有効です。
- ECDSA 変換。 トークンは ECDSA 署名を、r と s の生でゼロ埋めされた連結として返します(PKCS#11 v3.1 §6.3.1)。
Pkcs11Signer::sign()はその出力を、PDF バリデーターと OpenSSL が期待する DER エンコードのECDSA-Sig-Value形式に変換します。呼び出し側が生の形式を扱うことはありません。 - PIN の受け渡し(CLI 経路)。 安全な既定では、PIN は所有者のみの権限で排他的に作成された一時ファイルに書き込まれ、PKCS#11 URI の
pin-source属性を通じて参照され、サブプロセス終了後にリンク解除されます。このモードでは PIN はコマンドラインに置かれず、サブプロセス環境にもエクスポートされません。$legacyPinDelivery = trueの場合、PIN は URI 内にpin-valueとして埋め込まれ、これはプロセスのコマンドライン上で観測可能です。このモードはオプトイン限定です。 - サブプロセスの規律。
OpenSslCliSignerは引数配列でバイナリを起動し(シェル展開なし)、$timeoutSecondsを強制し、期限切れ時にサブプロセスを強制終了し、stderr を型付きエラーに分類します。秘密情報は、例外メッセージに引用される前に stderr から伏字化されます。 - アダプターのセマンティクス。 HSM トークンには管理された鍵バージョンの概念がなく、トークン上の鍵がバージョンそのものです。したがって
HsmSignerProviderAdapter::sign()は、非 null の$keyVersionを無視するのではなくKeyManagementExceptionで拒否します。supportsAlgorithm()は列挙型のマッピングとラップしたバックエンドの受理集合との積を取るため、アダプターがバックエンドの署名時に拒否されるメカニズムを広告することはありません。ドライバーからの空署名はSignatureFailedExceptionを送出します。 - ポスト量子プレビュー。
signPqs()は$enablePostQuantumコンストラクターフラグの背後にゲートされており、それ以外の場合は実行を拒否します。コンテキスト文字列は ML-DSA コンテキスト境界に合わせて 255 バイトに制限されます(FIPS 204)。返される署名は選択されたPkcs11PqsAlgorithmパラメーター集合の正確なバイト長と一致しなければならず、さもなければ呼び出しは失敗します。メカニズム識別子は暫定的な PKCS#11 PQ 拡張に従い、最終版ではありません。PAdES プロファイルはポスト量子スイートを認識せず、ほとんどの PDF バリデーターはそのような署名を拒否し、NextPDF はそれらに対する検証経路を提供しません。適合性は主張されません。
エッジケースと障害モード
「エッジケースと障害モード」という見出しのセクションext-pkcs11なしでPkcs11Signerを構築すると、即座にHsmOperationExceptionを送出します。この拡張は標準の PHP ディストリビューションにはバンドルされていません。- トークン上のどのオブジェクトにも一致しない証明書ラベルまたは秘密鍵ラベルは、欠落しているオブジェクトクラスを示す
HsmOperationExceptionを送出します。トークンによっては、鍵ラベルが証明書ラベルと正当に異なることがあります。 - ログイン失敗の繰り返しはトークン側で PIN をロックすることがあります。そのポリシーを強制するのは NextPDF ではなくトークンです。使用のたびに認証を要求する鍵を持つトークンには、ログアウトして再試行する経路を通じて新しいログインが提供されます(PKCS#11 v3.1、always-authenticate セマンティクス)。
OpenSslCliSignerは、構築時にpin-valueを既に含む$keyUriをフェイルクローズドで拒否します。その受け渡しは安全な PIN 経路を回避してしまうためです。- Windows では、安全な pin ファイルモードは
HsmOperationExceptionでフェイルクローズドになります。そこではファイル権限ビットが ACL の読み取り付与を制限できないため、署名器は一時ディレクトリの ACL に平文の PIN を残すことを拒否します。レガシー PIN 受け渡しは、信頼された Windows ホスト向けに文書化されたオプトインの代替手段です。 - バックエンドの自動検出はプロバイダー経路に OpenSSL 3.x を必要とします。LibreSSL がプロバイダーに解決されることは決してありません。プロバイダーもエンジンの探査も成功しない場合、失敗を署名時に先送りせず、構築が
HsmOperationExceptionで失敗します。 $timeoutSecondsを超えたサブプロセスは終了され、タイムアウトとして報告されます。空の出力で正常終了したサブプロセスは、空署名の失敗として報告されます。いずれの状況も部分的に署名された文書を生成することはありません。- 選択されたパラメーター集合とバイト長が一致しないポスト量子署名は、CMS エンコードに達する前に拒否されます。
- 廃止された
openssl-engineプロバイダー ID を持つHsmSignerProviderAdapterはアルゴリズムを何も広告しないため、古い構成は署名時ではなくプロバイダー選択時に失敗します。
FIPS モードの動作
「FIPS モードの動作」という見出しのセクション両署名器はオプションの FipsSignatureEnforcer を受け付けます。これが接続されると、その署名器では FIPS モードが有効になります。sign() は、トークンまたはサブプロセスでの署名が発生する前に、許可されない署名アルゴリズムやフロア未満の鍵を拒否します。フロアは署名生成テーブルに従い、2048 ビット未満の RSA モジュラスと 224 ビット未満の ECDSA 位数は許可されません(NIST SP 800-131A Rev.2 §3 Table 2)。エンフォーサーがなければ動作は変わりません。このゲートは古典的な sign() 経路のみを対象とし、signPqs() は独自のプレビューフラグに支配されます。これらは NextPDF コードに関する能力の主張です。FIPS 140-3 の検証は CMVP を通じて暗号モジュールに付随し、このデプロイメントではそれはオペレーターの HSM またはプロバイダーです。NextPDF は検証済みモジュールではなく、いかなる認証も保有せず、いかなる認証も付与しません。
| 主張 | 標準 | 条項 |
|---|---|---|
| ログインは秘密鍵操作の前にユーザーをトークンに認証し、誤った PIN はアクセスを拒否する。 | PKCS#11 v3.1 | §5.6.8 |
| Always-authenticate 鍵は使用ごとに新しいログインを要し、再認証の失敗を繰り返すと PIN がロックされることがある。 | PKCS#11 v3.1 | CKA_ALWAYS_AUTHENTICATE re-authentication |
| トークンの ECDSA 署名は生の r‖s 連結であり、署名器はそれを PDF 相互運用のために DER へ変換する。 | PKCS#11 v3.1 | §6.3.1 |
| PSS パラメーターはハッシュ、MGF、ソルト長を束縛し、署名器はソルトをダイジェスト長と等しく設定する。 | PKCS#11 v3.1 | §6.1.9 |
| FIPS ゲートは 2048 ビット未満の RSA または 224 ビット未満の ECDSA 位数での署名生成を拒否する。 | NIST SP 800-131A Rev.2 | §3 Table 2 |
| ポスト量子コンテキスト文字列は 255 バイトに制限される。 | FIPS 204 | HashML-DSA context handling |
| FIPS 140-3 の検証は CMVP を通じて暗号モジュールに付随する。 | FIPS 140-3 | CMVP program scope |
すべての条項は言い換えであり、規範的なテキストは再現されていません。NextPDF はいかなる認証の主張も行いません。 署名器は、能力として、引用された条項に自らの動作を整合させます。生成された署名が検証されるか否かは、検証者が自らのトラストアンカーに対して下す決定です。鍵のセキュリティはトークン、HSM、オペレーターに依存するものであり、NextPDF のみに依存するものではありません。
開発上の注意
「開発上の注意」という見出しのセクション-
PIN の受け渡しメカニズムは PKCS#11 URI の
pin-source慣例(RFC 7512)に従います。この RFC は引用対象のコーパス外であるため、上記の動作は仕様の引用ではなく製品ソースを根拠とします。 -
Pkcs11Signerを構築する前に、ランタイムがext-pkcs11を読み込むことを確認してください。拡張が不在の場合、構築は早期に失敗します。CLI 署名器はproc_openの有効化と、PKCS#11 プロバイダーまたはエンジンがインストールされたopensslバイナリを必要とします。 -
PIN、証明書ラベル、鍵ラベルは
#[SensitiveParameter]であるため、スタックトレースから除外されます。PIN はシークレットマネージャーから供給してください。ソース、バージョン管理にコミットされる構成、ログに書き込んではなりません。 -
両署名器とも構築が高コストの工程です。PKCS#11 経路はログインして証明書を読み取り、CLI 経路はバイナリとバックエンドを探査します。一度構築してインスタンスを再利用してください。ライブラリごとのモジュールキャッシュにより、同じライブラリに対する繰り返しの構築は安全です。
-
呼び出し側が
SignerProviderInterfaceを通じて動作する場合は、署名器をHsmSignerProviderAdapterでラップしてください。能力チェックが正しいバックエンドの許可集合を使うよう、ラップするクラスの正規のプロバイダー ID(pkcs11-{module-id}またはopenssl-cli)を渡してください。 -
ポスト量子プレビューを有効化する前に、トークンファームウェアのメカニズム識別子を、NextPDF が登録する暫定値と照合してください。不一致は署名時に失敗します。本番の PAdES 出力に対してプレビューを有効化しないでください。
-
getResolvedBackend()とgetOpensslVersion()は証拠記録のために存在します。コンプライアンスプログラムが再現性を要求する場合は、署名の証拠とともにそれらを保持してください。
- ハードウェアセキュリティモジュール署名(PKCS#11) — セットアップ、構成、検証手順を含む機能ページ。
- セキュリティ — 詳細リファレンス — 統合された Enterprise セキュリティサーフェス。
- 署名 — 詳細リファレンス — PAdES B-LT / B-LTA の長期プロデューサー。
- FIPS 140 — 詳細リファレンス — 暗号ポリシー、自己テストバッテリー、
FipsSignatureEnforcerゲート。 - PQC プレビュー — 詳細リファレンス — ポスト量子プレビューサーフェスとその境界。
- セキュリティ/署名(Core) — Core の CMS 署名器と署名契約。
このページは外部から観測可能な動作とサポートされる公開 API サーフェスのみを文書化します。内部の名前空間パス、ヘルパークラス、メカニズムテーブル、ランブックのファイル名、チケットの接頭辞は対象外です。