Skip to content

FIPS 140-2/3 cryptographic policy and self-test

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.

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.

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.

  1. Install NextPDF Core and the Enterprise package, and maintain an active Enterprise license.
  2. 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.
  3. Choose the preset: strict for FIPS 140-3-aligned enforcement, or standard where AES-128-CBC interoperability is required.
  • 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.
  1. 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.
  2. Construct the guard with the strict or standard policy.
  3. Before each cryptographic operation, assert the hash, signature OID, encryption algorithm, and key strength through the guard.
  4. Catch the typed violation, log a structural message, and refuse the operation. Do not fall back to a weaker choice.
examples/enterprise/fips-boot-and-guard.php
<?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());
}
examples/enterprise/fips-assert-choices.php
<?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;
}
}
}
  1. 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.
  2. 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.
  3. Inject a deliberately broken hash or random source into the self-test and confirm that the module enters the error state and refuses services.
  4. Confirm that an unknown key type is denied by default rather than accepted.
  • 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.

  • 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.

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.