FIPS 140-2/3 cryptographic policy and self-test
At a glance
Section titled “At a glance”NextPDF Enterprise limits the cryptographic choices a signing or encryption operation can make to a Federal Information Processing Standards (FIPS) approved set, and refuses any choice outside that set. A runtime guard checks each hash, signature algorithm identifier, encryption algorithm, and key strength before the operation runs. A power-on self-test battery runs once when the process starts. If any known-answer test fails, the module enters an error state. This page describes the behavior: what the policy allows, what the guard refuses, what the self-test covers, and the explicit certification stance.
NextPDF Enterprise helps with compliance. It is not a certified cryptographic module. See Security and compliance for the explicit non-certification stance.
The front matter lists prerequisites, and Prerequisites repeats them.
Edition and licensing
Section titled “Edition and licensing”The FIPS-mode crypto-policy profile, runtime guard, and power-on self-test guard ship in the nextpdf/enterprise package and require the enterprise license feature flag. NextPDF Core and NextPDF Pro do not provide a FIPS-mode profile. The guard and self-test run in process; policy checks and self-tests do not send document content off the host. Compare editions.
What this capability does
Section titled “What this capability does”The capability has three parts: a crypto policy, a runtime guard, and a power-on self-test.
The crypto policy limits cryptographic choices to an approved set, with two presets:
- Strict (aligned with the FIPS 140-3 generation) — SHA-256, SHA-384, and SHA-512 hashes; RSA and ECDSA signature object identifiers (OIDs) with those hashes; AES-256-CBC encryption; and minimum key sizes of RSA 2048 and elliptic-curve 256.
- Standard (aligned with the FIPS 140-2 generation) — matches strict, and also permits AES-128-CBC for older interoperability.
For signature generation, NIST SP 800-131A Rev.2 §3 accepts an RSA key of at least 2048 bits and an ECDSA order of at least 224 bits; the strict preset’s 2048/256 floors meet or exceed those minimums. The policy denies an unknown key type by default — it does not silently accept an unrecognized type.
The runtime guard wraps the policy and exposes assert-style methods for a hash, a signature OID, an encryption algorithm, and a key strength. When a choice is disallowed, it raises a typed violation that names the policy and the offending item, then stops the operation. The path fails closed: the policy never relaxes itself and never substitutes a weaker algorithm. For an RSASSA-PSS signature, the generation gate binds the message digest explicitly. Every PSS variant shares one signature OID; the hash lives in the PSS parameters, not the OID. An OID allowlist alone cannot prove the effective digest, so the gate asserts that the digest is FIPS-approved (SHA-256/384/512). It denies fail-closed any PSS token whose digest is unknown or not approved, for example SHA-1 PSS, before any signer dispatch (FIPS 186-5 §5.4(b)).
The power-on self-test runs a known-answer-test (KAT) battery once at process start. The battery covers the approved hash, message-authentication, encryption, authenticated-encryption, signature, and random-bit functions. Under ISO/IEC 19790:2025 §7.10.4.2, a known-answer test fails when the calculated output does not equal the known answer. On any failure, the module enters an error state and refuses cryptographic services (ISO/IEC 19790:2025 §7.2.4.3). The error state is process-sticky: after any boot guard in the process observes an error, the whole process stays fail-closed for its lifetime. Constructing a fresh boot guard or policy cannot clear it. A later passing self-test re-run does not clear a latched error — only a process restart (a true power cycle) does, per ISO/IEC 19790:2025 §7.10.2. The result is cached for the process lifetime; you can run an on-demand re-run for an admin endpoint or a command, but it serves the periodic self-test obligation, not error recovery.
The policy requires a unique initialization vector (IV) per key for authenticated-encryption use, per NIST SP 800-38D §5.2.1.
Prerequisites
Section titled “Prerequisites”- Install NextPDF Core and the Enterprise package, and maintain an active Enterprise license.
- To claim FIPS-compatible operation, configure NextPDF with a FIPS-validated cryptographic provider — for example a FIPS-validated OpenSSL provider — or a FIPS-validated hardware security module (HSM). NextPDF Enterprise performs structural assembly, digest computation, and policy enforcement; the underlying primitive runs in the validated boundary you supply.
- Choose the preset: strict for FIPS 140-3-aligned enforcement, or standard where AES-128-CBC interoperability is required.
Configuration
Section titled “Configuration”- Preset — choose strict or standard. Strict allows only AES-256-CBC; standard also allows AES-128-CBC.
- Guard — construct the guard with the chosen policy. Use the guard as the boundary where you assert each cryptographic choice.
- Self-test wiring — wire the boot guard at application bootstrap so each worker process runs its own self-test cycle. Each process instance runs its own power-on self-test.
Step-by-step
Section titled “Step-by-step”- At application bootstrap, run the power-on self-test through the boot guard and assert that the module is operational. Stop the process if it is not.
- Construct the guard with the strict or standard policy.
- Before each cryptographic operation, assert the hash, signature OID, encryption algorithm, and key strength through the guard.
- Catch the typed violation, log a structural message, and refuse the operation. Do not fall back to a weaker choice.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Enterprise\Security\Fips\FipsBootGuard;use NextPDF\Enterprise\Security\Fips\FipsCryptoPolicy;use NextPDF\Enterprise\Security\Fips\FipsModeGuard;use NextPDF\Enterprise\Security\Fips\FipsSelfTest;use NextPDF\Enterprise\Security\Fips\FipsModuleErrorStateException;use Psr\Log\LoggerInterface;
/** * Run the power-on self-test, then build a guard on the strict policy. * * The self-test runs once per process. A known-answer failure raises a * module-error-state exception; the caller must stop rather than proceed * with an unverified crypto path. * * @param LoggerInterface $logger Structural diagnostics only — never secrets. * * @throws FipsModuleErrorStateException When a power-on known-answer test fails. * * @return FipsModeGuard A guard ready to assert each cryptographic choice. */function bootFipsGuard(LoggerInterface $logger): FipsModeGuard{ $bootGuard = new FipsBootGuard(new FipsSelfTest());
try { $bootGuard->assertOperational(); } catch (FipsModuleErrorStateException $e) { $logger->critical('FIPS power-on self-test failed; refusing crypto services.', [ 'reason' => $e->getMessage(), ]);
throw $e; }
return new FipsModeGuard(FipsCryptoPolicy::strict());}<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Enterprise\Security\Fips\FipsModeGuard;use NextPDF\Enterprise\Security\Fips\FipsViolationException;use Psr\Log\LoggerInterface;
final readonly class FipsCheckedSigning{ public function __construct( private FipsModeGuard $guard, private LoggerInterface $logger, ) {}
/** * Assert the signing choices against the active policy before signing. * * A disallowed hash, signature OID, or key strength raises a typed * violation; the operation is refused rather than downgraded. * * @param string $hash The hash algorithm name (e.g. 'sha256'). * @param string $signatureOid The signature algorithm OID. * @param string $keyType The key type (e.g. 'rsa', 'ec'). * @param positive-int $keyBits The key length in bits. * * @throws FipsViolationException When any choice is not approved. */ public function assertApproved( string $hash, string $signatureOid, string $keyType, int $keyBits, ): void { try { $this->guard->assertHashAllowed($hash); $this->guard->assertSignatureAlgorithmAllowed($signatureOid); $this->guard->assertKeyStrengthAllowed($keyType, $keyBits); } catch (FipsViolationException $e) { $this->logger->error('FIPS policy violation', ['reason' => $e->getMessage()]);
throw $e; } }}Verification
Section titled “Verification”- Run the power-on self-test and confirm that it reports operational. Confirm that it exercises every approved algorithm class — hash, message-authentication, encryption, authenticated-encryption, signature, and random-bit.
- Assert an approved choice, for example SHA-256, RSA 2048, and confirm that it passes. Assert a disallowed choice, for example SHA-1, RSA 1024, and confirm that it raises a typed violation.
- Inject a deliberately broken hash or random source into the self-test and confirm that the module enters the error state and refuses services.
- Confirm that an unknown key type is denied by default rather than accepted.
Security and compliance
Section titled “Security and compliance”- Fail-closed. When a cryptographic choice is disallowed, the guard raises a typed violation and stops the operation. The policy never relaxes itself and never substitutes a weaker algorithm.
- Self-test refuses on mismatch. A known-answer-test failure puts the module into a process-sticky error state. The whole process stays fail-closed; a fresh boot guard or policy cannot recover it, and a passing re-run does not lift the latch. Only a process restart clears it (ISO/IEC 19790:2025 §7.10.4.2; §7.10.2).
- Key strength. The strict preset enforces RSA 2048 and elliptic-curve 256 minimums, which meet or exceed the acceptable floors in NIST SP 800-131A Rev.2 §3.
- IV uniqueness. Authenticated-encryption use requires a unique IV per key (NIST SP 800-38D §5.2.1).
This page is marked export_control_class: legal-review-required because it concerns cryptographic policy. Every normative source is paraphrased; no normative text is reproduced. Legal sign-off is required before the publish flag is set.
NextPDF Enterprise is not a FIPS-validated cryptographic module and makes no FIPS certification claim. It operates in FIPS-compatible mode only when you configure it with a FIPS-validated cryptographic provider — for example a FIPS-validated OpenSSL provider — or a FIPS-validated hardware security module (HSM). The FIPS-mode policy assists compliance; it is not a certification and not a legal opinion. Consult your own compliance and legal advisers for your regulatory obligations.
Failure handling
Section titled “Failure handling”- Self-test failure at boot. The boot guard raises a module-error-state exception. Stop the process; do not proceed with an unverified crypto path.
- Policy violation. The guard raises a typed violation that names the policy and the offending item. Refuse the operation; do not downgrade.
- Unknown key type. The policy denies it by default. Map the key type explicitly only if it is genuinely approved.
- Self-test re-run. A re-run is available on demand for an admin endpoint or a command, satisfying the periodic on-demand self-test obligation. It is not a recovery mechanism: a failing re-run also latches the process, and a passing re-run does not lift an existing latch. Recovering a module in the error state requires a process restart.
Commercial context
Section titled “Commercial context”NextPDF Core ships the software signer and encryption without a FIPS-mode profile. NextPDF Enterprise adds the FIPS-mode crypto-policy profile, runtime guard, and power-on self-test guard, so you can restrict cryptographic choices to an approved set and fail closed on a self-test mismatch. Pair it with HSM signing to run the primitive inside a FIPS-validated device. Compare editions.
See also
Section titled “See also”- Security — NextPDF Enterprise — the combined Enterprise security controls.
- HSM signing — NextPDF Enterprise — Public-Key Cryptography Standards #11 (PKCS#11) hardware key custody.
- Signature — NextPDF Enterprise — the PDF Advanced Electronic Signatures (PAdES) B-LT and B-LTA long-term producer.
- Security — NextPDF Core — the core encryption and signature surface.
- FIPS mode · KAT · authenticated encryption (AEAD) — glossary terms.