Enterprise 版本
Security — 深度参考(HSM、PKCS#11、FIPS-mode)
本页是 NextPDF Enterprise 安全面的组合深度参考。它涵盖通过 PKCS#11 进行的硬件 token 签名、通过 OpenSSL 命令行界面(CLI)进行的子进程签名、FIPS 密码学策略预设、运行时 FIPS 守卫,以及开机自检守卫。另有两篇聚焦的配套文档:HSM — 深度参考 讲解签名器细节,FIPS 140 — 深度参考 讲解 FIPS 模块细节。后量子签名路径为预览版,不作任何符合性声明。NextPDF 不持有任何认证,也不授予任何认证;支持不等于符合,符合不等于认证。
可用性与授权
标题为“可用性与授权”的章节此能力随 NextPDF Enterprise(nextpdf/enterprise)发布,并通过 Enterprise 层级的授权信封(license envelope)激活。没有该授权的部署不会加载此能力的类。对比版本并获取授权。
公开 API 面
标题为“公开 API 面”的章节composer require nextpdf/enterprise:^3签名类型位于 NextPDF\Enterprise\Security\Signature\Hsm;FIPS 类型位于 NextPDF\Enterprise\Security\Fips;组合根位于 NextPDF\Enterprise\Bootstrap。两个签名器都实现 Core 的 NextPDF\Contracts\HsmSignerInterface 契约。该策略实现 Core 的 NextPDF\Contracts\CryptoPolicyInterface 与 NextPDF\Contracts\PreOperationalSelfTestInterface 契约。
| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
Pkcs11Signer::__construct() | string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null | 打开厂商库,登录 slot,加载证书与密钥算法元数据 | — | 当 ext-pkcs11 缺失或 token 访问失败时抛出 HsmOperationException | PIN 与 label 为 #[SensitiveParameter];每个进程按库路径缓存一个模块句柄 |
Pkcs11Signer::isAvailable() | 无 | 报告 ext-pkcs11 是否已加载 | bool | 无 | 静态方法;在构造之前检查 |
Pkcs11Signer::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | 在 token 上签名;原始 ECDSA 输出被转换为 DER ECDSA-Sig-Value | string 原始签名字节 | HsmOperationException(未找到密钥、token 失败);InvalidArgumentException(未映射的算法);接入 enforcer 时在签名前抛出 FipsViolationException / FipsModuleErrorStateException | 封闭算法集;参见行为契约 |
Pkcs11Signer::signPqs() | string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true | 除非设置了 $enablePostQuantum,否则拒绝;分派临时的 PKCS#11 后量子机制 | string 原始签名字节 | HsmOperationException(已禁用、token 失败、签名长度不匹配);InvalidArgumentException(context 超过 255 字节) | 预览版;不作符合性声明 |
Pkcs11Signer 访问器面 | 无 | 只读的构造结果 | bool / string / array<string> | 无 | isPostQuantumEnabled, getCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm |
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 被禁用、缺少 module/config/证书文件、无可用后端);InvalidArgumentException($keyUri 中含 pin-value) | Auto 优先选用 OpenSSL 3.x provider,其次是 engine |
OpenSslCliSigner::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | 在 openssl 子进程中签名;默认情况下 PIN 通过一个临时的 0600 pin-source 文件传递 | string 原始签名字节 | HsmOperationException(超时、PIN 被拒、未找到密钥、输出为空);InvalidArgumentException(未映射的算法);签名前的 FIPS 门异常 | 子进程在 $timeoutSeconds 之后被终止;stderr 被脱敏 |
OpenSslCliSigner 访问器面 | 无 | 只读的构造结果 | string / array<string> / OpenSslCliBackend | 无 | getCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion |
OpenSslCliBackend | — | 枚举:Provider、Engine、Auto | — | 无 | CLI 签名器的后端选择 |
Pkcs11PqsAlgorithm | — | ML-DSA 与 SLH-DSA 参数集的枚举 | — | 无 | 辅助方法:isMlDsa、isSlhDsa、mechanismId、parameterSetId、signatureLength、nistCategory |
PqsCapabilityStatus::current() | 无 | 为进程构建诚实的后量子态势 | PqsCapabilityStatus | 无 | 每个符合性声明布尔值都硬编码为 false;没有任何标志能将其翻转为开启 |
HsmSignerProviderAdapter | HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15 | 将 HSM 具体实现暴露为统一的 SignerProviderInterface | 依 SPI 而定 | KeyManagementException(非空 key 版本);SignatureFailedException(驱动失败、签名为空) | Provider id:pkcs11-{module-id}、openssl-cli |
HsmOperationException | — | 每条 HSM 签名路径的有类型失败 | — | — | 扩展 Core 的 NextPdfException |
FipsCryptoPolicy::strict() / ::standard() | ?FipsSelfTest $selfTest = null | 工厂预设;strict 为 FIPS 140-3 配置文件,standard 增加 AES-128-CBC | FipsCryptoPolicy | 无 | 不可变的允许清单;参见 FIPS-mode 行为 |
FipsCryptoPolicy 判定式面 | string / int 输入 | 允许清单成员检查 | bool / string | 无 | isHashAlgorithmAllowed, isSignatureAlgorithmAllowed, isEncryptionAlgorithmAllowed, isKeyStrengthAllowed, getPreferredHashAlgorithm, getName |
FipsCryptoPolicy::assertPreOperational() | 无 | 运行(或重放)开机自检 | void | FipsModuleErrorStateException | 由 Core 的强制执行接缝在首次密码学操作时驱动 |
FipsModeGuard::__construct() | CryptoPolicyInterface $policy, ?FipsBootGuard $bootGuard = null, ?FipsAuditLogger $auditLogger = null | 用断言式边界包裹一个策略 | — | 无 | 没有 boot guard 时,自检门缺失(仅策略) |
FipsModeGuard 断言面 | string / int 输入 | 先查拒绝目录,再查允许清单;在任何抛出之前记录审计 | void | FipsViolationException;FipsModuleErrorStateException(接入 boot guard 时) | assertHashAllowed、assertSignatureAlgorithmAllowed、assertEncryptionAllowed、assertKeyStrengthAllowed,以及 getPolicy |
FipsBootGuard::report() / ::rerun() | 无 | 运行自检套件(缓存 / 强制) | FipsSelfTestReport | 无 | 一份 ERROR 报告会锁定进程;通过的重新运行绝不清除该锁定 |
FipsBootGuard::assertOperational() | 无 | 断言模块处于 OPERATIONAL | void | FipsModuleErrorStateException | 黏性:进程级锁定的 ERROR 即使对一个干净实例也会拒绝 |
FipsBootGuard::status() | 无 | 报告缓存的状态 | FipsSelfTestStatus | 无 | PRE_OPERATIONAL、OPERATIONAL 或 ERROR |
FipsSelfTest::run() | 无 | 执行完整的已知答案测试(known-answer-test)套件;绝不短路 | FipsSelfTestReport | 无 | 构造函数接受可注入的哈希与随机字节提供方,以支持确定性测试 |
FipsSelfTestReport / FipsSelfTestResult / FipsSelfTestStatus | — | 报告值对象与状态枚举 | — | FipsSelfTestReport::assertOperational() 抛出 FipsModuleErrorStateException | results 始终列出每一个结果,作为审计证据 |
FipsSignatureEnforcer::assertSignatureGenerationAllowed() | string $algorithm, string $certificatePem | 解析签名 OID 与密钥强度,然后委托给守卫 | void | FipsViolationException(不被允许或无法分类,失败关闭) | FIPS 模式下两个签名器都在 sign() 开头调用的关卡 |
FipsAuditLogger | CryptoPolicyInterface $policy, LoggerInterface $logger | 对每个决策发出 ALLOW(INFO)/ DENY(WARNING)记录 | 每次记录调用返回 bool | 无 | logHashOperation、logSignatureOperation、logEncryptionOperation、logKeyStrengthCheck |
FipsTransitioningAlgorithms | string / int 输入 | 静态的 NIST SP 800-131A 拒绝目录 | bool / array | 无 | 位于每个守卫边界之下的显式拒绝层 |
FipsBootstrap::boot() / ::lazy() | ?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null, ?LoggerInterface $auditLogger = null | 组合 boot guard、策略与 mode guard;boot() 立即运行自检,lazy() 将其推迟到首个边界 | FipsModeGuard | boot():测试失败时抛出 FipsModuleErrorStateException | 默认使用 strict 策略 |
FipsBootstrap::signatureEnforcer() | ?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null | 启动模块并为签名器返回生成时的门 | FipsSignatureEnforcer | FipsModuleErrorStateException | 将结果传给签名器的 $fipsEnforcer 参数 |
FipsBootstrap::selfTestReport() | ?FipsSelfTest $selfTest = null | 按需运行套件并进行汇总 | array{status, operational, failed} | 无 | 面向健康检查端点与 CLI 子命令 |
FipsViolationException / FipsModuleErrorStateException | — | 有类型的 FIPS 失败 | — | — | 分别暴露 policyName / violatingItem / reason 与 failedResults |
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 static function isAvailable(): boolpublic function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): stringpublic function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): stringpublic 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 static function strict(?FipsSelfTest $selfTest = null): selfpublic static function standard(?FipsSelfTest $selfTest = null): selfpublic function assertPreOperational(): voidpublic function __construct(private CryptoPolicyInterface $policy, private ?FipsBootGuard $bootGuard = null, private ?FipsAuditLogger $auditLogger = null)public function assertHashAllowed(string $algorithm): voidpublic function assertSignatureAlgorithmAllowed(string $oid): voidpublic function assertEncryptionAllowed(string $algorithm): voidpublic function assertKeyStrengthAllowed(string $keyType, int $bitLength): voidpublic function getPolicy(): CryptoPolicyInterfacepublic static function boot(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null, ?LoggerInterface $auditLogger = null): FipsModeGuardpublic static function lazy(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null, ?LoggerInterface $auditLogger = null): FipsModeGuardpublic static function signatureEnforcer(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null): FipsSignatureEnforcerpublic static function selfTestReport(?FipsSelfTest $selfTest = null): array行为契约
标题为“行为契约”的章节- 契约解析。 两个签名器都实现 Core 的
HsmSignerInterface;该策略实现 Core 的CryptoPolicyInterface。调用方代码依赖契约,因此版本升级改变的是组合,而非调用点。 - 密钥托管。 私钥绝不离开 token 边界。
Pkcs11Signer将操作委托给 token;OpenSslCliSigner将一个 PKCS#11 URI 密钥引用传给子进程。NextPDF 不存储、不生成,也不保证签名密钥的安全。密钥保护是运营方的托管责任(NIST SP 800-57 Part 1 Rev.5 §5.5.2)。 - 会话与登录。 token 签名操作、会话与用户登录遵循 PKCS#11 v3.1 §5。证书 label 与私钥 label 可以不同;构造函数为这类 token 接受一个单独的 key label。
- 封闭算法集。 签名器精确接受:带 SHA-256/384/512 的 RSA PKCS#1 v1.5、带 SHA-256/384/512 的 RSASSA-PSS,以及带 SHA-256/384/512 的 ECDSA(
Pkcs11Signer还接受ecdsa-raw)。任何其他标识符都会引发InvalidArgumentException;绝不会签署任何替代算法。 - PSS salt 绑定。 对每个 PSS 变体,salt 长度等于摘要长度——32、48 或 64 字节——且哈希与掩码生成参数与所选摘要匹配(PKCS#11 v3.1 §5)。
- ECDSA 转换。 token 的 ECDSA 机制返回原始签名;
sign()将其转换为 DER 编码的ECDSA-Sig-Value形式,以便与 PDF 和 OpenSSL 互操作。签名生成遵循 FIPS 186-5 §6.3.2。 - 预设内容。 strict 预设允许 SHA-256/384/512;带这些哈希的 RSA 与 ECDSA 签名 OID;RSASSA-PSS;AES-256-CBC 与 AES-256-GCM;最小 RSA 2048 与 EC 256。standard 预设额外允许 AES-128-CBC 以兼容遗留互操作。任何 AES-GCM 使用都要求每个密钥有唯一的初始化向量(NIST SP 800-38D §5)。
- 两层强制执行。 每个守卫边界先查阅显式的 NIST SP 800-131A 拒绝目录,再查允许清单。拒绝层产生审计清晰的“不被允许”信号;允许清单仍具权威性。
- 开机自检。 该套件覆盖 SHA-256/384/512、HMAC-SHA-256、AES-256-CBC、AES-256-GCM、一个 ECDSA P-256 成对一致性测试,以及一个随机比特健康检查。Core 路径上该策略下的首次密码学操作会在每个进程运行它一次,失败关闭。一次失败会令模块进入 ERROR 状态;在重置之前,密码学服务被拒绝。此遵循 ISO/IEC 19790:2025 §7.10、§7.10.2、§7.10.3 与 §7.10.3.p3。
- 黏性 ERROR 状态。 一次观察到的 ERROR 会锁定整个进程。构造一个全新的策略或 boot guard 都无法将其洗白;通过的重新运行也不清除它。只有进程重启——一次真正的电源循环——才会重置该状态。
- 仅生成门。
FipsSignatureEnforcer管控生成新签名。对既有签名的验证属于遗留用途,绝不经过 enforcer。 - 审计轨迹。 当守卫与审计日志器组合时,每个边界都会在允许或拒绝操作之前发出一条 ALLOW 或 DENY 记录。日志器查阅守卫所强制执行的同一策略,因此记录的决策不会出现分歧。
边界情形与失败模式
标题为“边界情形与失败模式”的章节- 在没有
ext-pkcs11的情况下构造Pkcs11Signer会立即引发HsmOperationException;该扩展不随标准 PHP 发行版打包。 - 匹配不到任何 token 对象的证书 label 或私钥 label 会引发
HsmOperationException,并指明缺失的对象类。 OpenSslCliSigner在构造时拒绝含pin-value的$keyUri,失败关闭;PIN 改为通过安全的 pin-source 路径传递。- 在 FIPS 模式下,无法映射到已知签名 OID 的算法标识符会被失败关闭地拒绝;无法确定公钥强度的证书亦然。
- 未知密钥类型默认被拒绝;该策略绝不回退到更弱的算法。
- 一次失败的已知答案测试会引发
FipsModuleErrorStateException,并携带失败的结果;进程中之后的每个边界都会重复该失败,直至重启。 - 在没有 boot guard 的情况下构造的守卫会强制执行允许清单,但不提供自检门;生产环境的 FIPS 组合通过 bootstrap 提供一个。
- 除非设置了构造函数的主动启用,否则
signPqs()拒绝运行。超过 255 字节的 context 字符串会引发InvalidArgumentException(FIPS 204 §5.4)。字节长度与所选参数集不匹配的返回签名会在到达编码之前被拒绝。
FIPS-mode 行为
标题为“FIPS-mode 行为”的章节strict 模式下被 FIPS 允许的:SHA-256/384/512;带这些哈希的 RSA PKCS#1 v1.5 与 RSA-PSS;带这些哈希的 ECDSA;AES-256-CBC 与 AES-256-GCM;RSA 至少 2048 位,EC 至少 256 位。strict 模式下被 FIPS 拒绝的:更弱或遗留的哈希、非批准的签名 OID、AES-128(仅在 standard 预设中允许),以及任何低于最小强度的密钥。最小 RSA 密钥长度与过渡状态遵循 NIST SP 800-131A Rev.2 §3。ECDSA 曲线与哈希的配对遵循 FIPS 186-5 §6.1.1。该路径失败关闭,绝不替换为更弱的算法。
NextPDF Enterprise 不是经 FIPS 验证的密码学模块,也不作出任何 FIPS 认证声明。 仅当 NextPDF Enterprise 配置了经 FIPS 验证的密码学提供方——例如一个经 FIPS 验证的 OpenSSL 提供方——或一个经 FIPS 验证的 HSM 时,它才以 FIPS 兼容模式运行。FIPS-mode 策略辅助合规;它不是一项认证。本仓库中不存在任何 FIPS 认证工件。
符合性
标题为“符合性”的章节| 声明 | 标准 | 条款 |
|---|---|---|
| token 签名操作、会话与用户登录语义 | PKCS#11 v3.1 | §5 (sign) |
| PSS salt 长度等于摘要长度 | PKCS#11 v3.1 | §5 (PSS sLen) |
| ECDSA 签名生成;曲线与哈希配对 | FIPS 186-5 | §6.3.2; §6.1.1 |
| 最小 RSA 密钥长度与签名生成过渡状态 | NIST SP 800-131A Rev.2 | §3 |
| 自检类别、文档、条件触发、不相交集合 | ISO/IEC 19790:2025 | §7.10, §7.10.2, §7.10.3, §7.10.3.p3 |
| AES-GCM 初始化向量唯一性 | NIST SP 800-38D | §5 |
| 密钥保护与托管责任 | NIST SP 800-57 Part 1 Rev.5 | §5.5.2 |
| 后量子签名 context 字符串限于 255 字节 | FIPS 204 | §5.4 |
所有条款均为转述;不复制任何规范性文本。这些是关于 NextPDF 代码的能力声明,而非认证。所产生的签名能否通过验证,取决于验证方针对其自身信任配置作出的判定。FIPS-mode 策略是一项合规辅助功能,不是法律意见;请咨询你自己的合规与法律顾问。本模块涉及密码学功能;请在你自己的审查中将其视为对安全敏感。
开发说明
标题为“开发说明”的章节- 通过 bootstrap 组合 FIPS 模式:
boot()用于启动时的门,lazy()将套件推迟到首个边界,enforcer 工厂用于签名器的$fipsEnforcer参数。非 FIPS 部署传入null,行为不变。 bin/nextpdf-enterprise的fips:self-test子命令按需运行套件,并在 ERROR 状态下以非零退出;将其接入维护作业或仅限管理员的健康检查端点(ISO/IEC 19790:2025 按需自检)。FipsBootGuard::resetProcessErrorLatchForTesting()为@internal且仅供测试;生产代码绝不调用它,因为那会破坏黏性 ERROR 状态。- 构造签名器一次并复用;构造过程会登录并读取证书,而按库的模块缓存使得针对同一库的重复构造是安全的。
- 从 secret manager 提供 PIN。它是
#[SensitiveParameter],绝不被记录或序列化;不要将其提交到配置中。 - 运营方负责 token 配置、PIN 处理、slot 配置、对网络连接式 HSM 的网络防护,以及信任配置。本页不暴露 token PIN 策略内部机制或厂商凭据材料。
- 请勿为生产环境的 AdES 签名启用后量子预览。AdES 密码学套件目录尚未承认后量子套件,多数 PDF 阅读器会拒绝此类签名,且硬件往返验证尚未完成。内部机制细节留存于源仓库的内部文档,不在本手册范围之内。
发布边界
标题为“发布边界”的章节本页仅记录外部可观察的行为与受支持的公开 API 面。内部命名空间路径、辅助类、机制表、runbook 文件名与工单前缀不在范围之内。
另请参阅
标题为“另请参阅”的章节- Security — NextPDF Enterprise — 此面的能力页。
- 硬件安全模块签名(PKCS#11) — 设置、配置与验证步骤。
- FIPS 140 密码学策略 — FIPS 能力页。
- HSM — 深度参考 — 聚焦的签名器参考。
- FIPS 140 — 深度参考 — 聚焦的 FIPS 模块参考。
- Security — NextPDF Pro — Pro 层级的安全面。
- Security — NextPDF Core — Core 安全基线。