跳转到内容
getnextpdf.com

Enterprise 版本

Security — 深度参考(HSM、PKCS#11、FIPS-mode)

本页是 NextPDF Enterprise 安全面的组合深度参考。它涵盖通过 PKCS#11 进行的硬件 token 签名、通过 OpenSSL 命令行界面(CLI)进行的子进程签名、FIPS 密码学策略预设、运行时 FIPS 守卫,以及开机自检守卫。另有两篇聚焦的配套文档:HSM — 深度参考 讲解签名器细节,FIPS 140 — 深度参考 讲解 FIPS 模块细节。后量子签名路径为预览版,不作任何符合性声明。NextPDF 不持有任何认证,也不授予任何认证;支持不等于符合,符合不等于认证。

此能力随 NextPDF Enterprisenextpdf/enterprise)发布,并通过 Enterprise 层级的授权信封(license envelope)激活。没有该授权的部署不会加载此能力的类。对比版本并获取授权

Terminal window
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\CryptoPolicyInterfaceNextPDF\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 访问失败时抛出 HsmOperationExceptionPIN 与 label 为 #[SensitiveParameter];每个进程按库路径缓存一个模块句柄
Pkcs11Signer::isAvailable()报告 ext-pkcs11 是否已加载bool静态方法;在构造之前检查
Pkcs11Signer::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'在 token 上签名;原始 ECDSA 输出被转换为 DER ECDSA-Sig-Valuestring 原始签名字节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,探测二进制,解析后端,加载证书HsmOperationExceptionproc_open 被禁用、缺少 module/config/证书文件、无可用后端);InvalidArgumentException$keyUri 中含 pin-valueAuto 优先选用 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> / OpenSslCliBackendgetCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion
OpenSslCliBackend枚举:ProviderEngineAutoCLI 签名器的后端选择
Pkcs11PqsAlgorithmML-DSA 与 SLH-DSA 参数集的枚举辅助方法:isMlDsaisSlhDsamechanismIdparameterSetIdsignatureLengthnistCategory
PqsCapabilityStatus::current()为进程构建诚实的后量子态势PqsCapabilityStatus每个符合性声明布尔值都硬编码为 false;没有任何标志能将其翻转为开启
HsmSignerProviderAdapterHsmSignerInterface $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-CBCFipsCryptoPolicy不可变的允许清单;参见 FIPS-mode 行为
FipsCryptoPolicy 判定式面string / int 输入允许清单成员检查bool / stringisHashAlgorithmAllowed, isSignatureAlgorithmAllowed, isEncryptionAlgorithmAllowed, isKeyStrengthAllowed, getPreferredHashAlgorithm, getName
FipsCryptoPolicy::assertPreOperational()运行(或重放)开机自检voidFipsModuleErrorStateException由 Core 的强制执行接缝在首次密码学操作时驱动
FipsModeGuard::__construct()CryptoPolicyInterface $policy, ?FipsBootGuard $bootGuard = null, ?FipsAuditLogger $auditLogger = null用断言式边界包裹一个策略没有 boot guard 时,自检门缺失(仅策略)
FipsModeGuard 断言面string / int 输入先查拒绝目录,再查允许清单;在任何抛出之前记录审计voidFipsViolationExceptionFipsModuleErrorStateException(接入 boot guard 时)assertHashAllowedassertSignatureAlgorithmAllowedassertEncryptionAllowedassertKeyStrengthAllowed,以及 getPolicy
FipsBootGuard::report() / ::rerun()运行自检套件(缓存 / 强制)FipsSelfTestReport一份 ERROR 报告会锁定进程;通过的重新运行绝不清除该锁定
FipsBootGuard::assertOperational()断言模块处于 OPERATIONALvoidFipsModuleErrorStateException黏性:进程级锁定的 ERROR 即使对一个干净实例也会拒绝
FipsBootGuard::status()报告缓存的状态FipsSelfTestStatusPRE_OPERATIONALOPERATIONALERROR
FipsSelfTest::run()执行完整的已知答案测试(known-answer-test)套件;绝不短路FipsSelfTestReport构造函数接受可注入的哈希与随机字节提供方,以支持确定性测试
FipsSelfTestReport / FipsSelfTestResult / FipsSelfTestStatus报告值对象与状态枚举FipsSelfTestReport::assertOperational() 抛出 FipsModuleErrorStateExceptionresults 始终列出每一个结果,作为审计证据
FipsSignatureEnforcer::assertSignatureGenerationAllowed()string $algorithm, string $certificatePem解析签名 OID 与密钥强度,然后委托给守卫voidFipsViolationException(不被允许或无法分类,失败关闭)FIPS 模式下两个签名器都在 sign() 开头调用的关卡
FipsAuditLoggerCryptoPolicyInterface $policy, LoggerInterface $logger对每个决策发出 ALLOW(INFO)/ DENY(WARNING)记录每次记录调用返回 boollogHashOperationlogSignatureOperationlogEncryptionOperationlogKeyStrengthCheck
FipsTransitioningAlgorithmsstring / 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() 将其推迟到首个边界FipsModeGuardboot():测试失败时抛出 FipsModuleErrorStateException默认使用 strict 策略
FipsBootstrap::signatureEnforcer()?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null启动模块并为签名器返回生成时的门FipsSignatureEnforcerFipsModuleErrorStateException将结果传给签名器的 $fipsEnforcer 参数
FipsBootstrap::selfTestReport()?FipsSelfTest $selfTest = null按需运行套件并进行汇总array{status, operational, failed}面向健康检查端点与 CLI 子命令
FipsViolationException / FipsModuleErrorStateException有类型的 FIPS 失败分别暴露 policyName / violatingItem / reasonfailedResults
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(): bool
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
public function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): string
public 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'): string
public static function strict(?FipsSelfTest $selfTest = null): self
public static function standard(?FipsSelfTest $selfTest = null): self
public function assertPreOperational(): void
public function __construct(private CryptoPolicyInterface $policy, private ?FipsBootGuard $bootGuard = null, private ?FipsAuditLogger $auditLogger = null)
public function assertHashAllowed(string $algorithm): void
public function assertSignatureAlgorithmAllowed(string $oid): void
public function assertEncryptionAllowed(string $algorithm): void
public function assertKeyStrengthAllowed(string $keyType, int $bitLength): void
public function getPolicy(): CryptoPolicyInterface
public static function boot(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null, ?LoggerInterface $auditLogger = null): FipsModeGuard
public static function lazy(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null, ?LoggerInterface $auditLogger = null): FipsModeGuard
public static function signatureEnforcer(?CryptoPolicyInterface $policy = null, ?FipsSelfTest $selfTest = null): FipsSignatureEnforcer
public 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)。字节长度与所选参数集不匹配的返回签名会在到达编码之前被拒绝。

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-enterprisefips: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 文件名与工单前缀不在范围之内。