Skip to content
getnextpdf.com

Enterprise editionstability: Experimental

Post-quantum signing preview — Deep Reference

This page is the contract-level reference for the post-quantum signing (PQS) preview surface in NextPDF Enterprise. It covers three public symbols: the Pkcs11PqsAlgorithm parameter-set enum, the PqsPreviewFeature process gate, and the PqsCapabilityStatus descriptor. It also documents the NEXTPDF_FEATURE_PREVIEW_PQS_HSM environment gate.

The surface is experimental and default-off. It recognises ML-DSA (FIPS 204) and SLH-DSA (FIPS 205) algorithm identifiers, parameter sets, and signature lengths. Recognition is not a validation verdict. There is no post-quantum verification path. No AdES, FIPS-validation, or conformance claim is made, and the preview flag cannot create one. The consuming signing entry point, Pkcs11Signer::signPqs(), is described on the capability page.

This capability ships in NextPDF Enterprise (nextpdf/enterprise) and activates with an Enterprise-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.

The license activates the Enterprise PKCS#11 surface as a whole. The post-quantum path inside it stays a preview regardless of license tier. Two independent opt-ins are still required: the process gate documented here and the per-signer constructor flag on Pkcs11Signer.

SymbolParametersDefault behaviorReturnsThrows or fails withNotes
Pkcs11PqsAlgorithmstring-backed enum, 15 casesNames one FIPS 204 / FIPS 205 parameter set per caseenum caseNothing on case accessCase values are the parameter-set names, e.g. ML-DSA-65.
Pkcs11PqsAlgorithm::isMlDsa()noneFamily testboolDoes not throwtrue for MlDsa44, MlDsa65, MlDsa87.
Pkcs11PqsAlgorithm::isSlhDsa()noneNegation of isMlDsa()boolDoes not throwtrue for the twelve SLH-DSA cases.
Pkcs11PqsAlgorithm::mechanismId()noneMaps the family to the candidate PKCS#11 v3.1 PQ mechanism idintPHP Error when the runtime lacks the provisional Pkcs11 PQ constantsCKM_ML_DSA or CKM_SLH_DSA; both ids are provisional.
Pkcs11PqsAlgorithm::parameterSetId()noneMaps the case to the OASIS parameter-set discriminatorintPHP Error when the runtime lacks the provisional Pkcs11 PQ constantsCKP_* values; provisional.
Pkcs11PqsAlgorithm::signatureLength()noneFIPS-mandated signature byte length for the caseint (positive)Does not throwConsumed by the signing path to reject a returned signature of unexpected length.
Pkcs11PqsAlgorithm::nistCategory()noneClaimed NIST security-strength categoryintDoes not throwReturns 1, 2, 3, or 5.
PqsPreviewFeaturestring-backed enum, 1 caseSingle case PREVIEW_PQS_HSM; constant ENV_PREVIEW_PQS_HSMenum caseNothing on case accessThe process-level preview gate.
PqsPreviewFeature::isEnabled()noneReads getenv() live; strict comparison against the string 1boolDoes not throwAbsent variable or any other value, including 0, true, yes, is off.
PqsCapabilityStatus::__construct()nine named readonly fieldsBuilds an arbitrary descriptor instancePqsCapabilityStatusDoes not throwcurrent() is the canonical constructor.
PqsCapabilityStatus::current()noneBuilds the descriptor for the surrounding processPqsCapabilityStatusDoes not throwEvery claim boolean is fixed; only hsmRoundtripPreviewEnabled varies with the gate.
PqsCapabilityStatus::summary()noneOne-line status textstringDoes not throwPhrasing carries no availability, archival, or validation claim.
enum Pkcs11PqsAlgorithm: string
case MlDsa44 = 'ML-DSA-44';
case MlDsa65 = 'ML-DSA-65';
case MlDsa87 = 'ML-DSA-87';
case SlhDsaSha2_128s = 'SLH-DSA-SHA2-128s';
case SlhDsaShake_128s = 'SLH-DSA-SHAKE-128s';
case SlhDsaSha2_128f = 'SLH-DSA-SHA2-128f';
case SlhDsaShake_128f = 'SLH-DSA-SHAKE-128f';
case SlhDsaSha2_192s = 'SLH-DSA-SHA2-192s';
case SlhDsaShake_192s = 'SLH-DSA-SHAKE-192s';
case SlhDsaSha2_192f = 'SLH-DSA-SHA2-192f';
case SlhDsaShake_192f = 'SLH-DSA-SHAKE-192f';
case SlhDsaSha2_256s = 'SLH-DSA-SHA2-256s';
case SlhDsaShake_256s = 'SLH-DSA-SHAKE-256s';
case SlhDsaSha2_256f = 'SLH-DSA-SHA2-256f';
case SlhDsaShake_256f = 'SLH-DSA-SHAKE-256f';
public function isMlDsa(): bool
public function isSlhDsa(): bool
public function mechanismId(): int
public function parameterSetId(): int
public function signatureLength(): int
public function nistCategory(): int
enum PqsPreviewFeature: string
case PREVIEW_PQS_HSM = 'preview_pqs_hsm';
public const string ENV_PREVIEW_PQS_HSM = 'NEXTPDF_FEATURE_PREVIEW_PQS_HSM';
public function isEnabled(): bool
final readonly class PqsCapabilityStatus
public const string MATURITY_PREVIEW_EXPERIMENTAL = 'preview-experimental';
public const string MECHANISM_STATUS_PROVISIONAL = 'provisional';
public function __construct(
public bool $hsmRoundtripPreviewEnabled,
public bool $generallyAvailable,
public bool $adesCompliant,
public bool $verificationAvailable,
public bool $conformanceClaimed,
public bool $recognitionOnly,
public string $maturity,
public string $mechanismIdStatus,
public string $envGate,
)
public static function current(): self
public function summary(): string
  • Parameter-set catalogue. NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11PqsAlgorithm enumerates three ML-DSA sets (FIPS 204) and twelve SLH-DSA sets (FIPS 205 §11.p12, Table 2). Each case maps to a provisional mechanism id, a parameter-set discriminator, a FIPS-mandated signature byte length, and a claimed NIST category.
  • Signature lengths. signatureLength() returns 2420, 3309, and 4627 bytes for MlDsa44, MlDsa65, and MlDsa87, per FIPS 204 §4.p15 (Table 2). The SLH-DSA cases return 7856, 17088, 16224, 35664, 29792, and 49856 bytes by level and variant, per FIPS 205 §11 (Table 2). The consuming signer throws HsmOperationException when a returned signature has a different length, mirroring the FIPS 204 §x34 length-rejection discipline.
  • Categories. nistCategory() returns 2, 3, and 5 for the ML-DSA cases, per FIPS 204 §4.p9. The SLH-DSA cases return 1, 3, and 5 by security-parameter level.
  • Process gate. PqsPreviewFeature::PREVIEW_PQS_HSM is off by default. isEnabled() returns true only when the environment variable NEXTPDF_FEATURE_PREVIEW_PQS_HSM equals the string 1 exactly. The read is live on every call; nothing is memoised.
  • Complementary gating. The process gate is separate from the per-signer $enablePostQuantum constructor opt-in on Pkcs11Signer. The signing call fails closed without the per-signer opt-in. The process gate exists as a single auditable boundary for any future round-trip or archival behavior.
  • Honesty invariant. NextPDF\Enterprise\Security\Signature\Hsm\PqsCapabilityStatus::current() hard-codes generallyAvailable, adesCompliant, verificationAvailable, and conformanceClaimed to false, and recognitionOnly to true. No configuration, constructor option, or environment flag flips a claim on. Only hsmRoundtripPreviewEnabled reflects the gate.
  • No verification path. NextPDF has no post-quantum verification path. A recognised algorithm identifier or a well-formed signature length is never an acceptance verdict.
  • Setting the gate variable to 0, true, yes, on, or an empty string leaves the gate off. Only the exact string 1 enables it.
  • putenv() changes take effect on the next isEnabled() call because the read is live. A gate toggled mid-process is observed immediately.
  • mechanismId() and parameterSetId() resolve constants from the Pkcs11 extension namespace. A runtime without the provisional post-quantum extension constants fails with a PHP Error (undefined constant) at call time.
  • The mechanism and parameter-set ids are provisional. OASIS has not finalised the PKCS#11 v3.1 post-quantum registry. A token whose firmware assigns different ids will fail at the PKCS#11 layer; operators must confirm firmware ids before enabling the preview.
  • The signing context accepted by the consuming signer is bounded at 255 bytes, matching the FIPS 204 signing input contract (§x43.p2). A longer context throws InvalidArgumentException before any token call.
  • PqsCapabilityStatus::__construct() is public, so a hand-built instance can carry arbitrary booleans. Such an instance is only a value object. It does not alter any signing behavior. current() is the canonical, hard-coded constructor.
  • The randomized-versus-deterministic choice on the consuming signer follows FIPS 205 §x65.p7 semantics: hedged signing is the default. The flag is ignored for ML-DSA, which always randomises via its own nonce.

ML-DSA and SLH-DSA are FIPS 204 and FIPS 205 algorithms, but this preview carries no FIPS 140-3 validation claim. No FIPS-validated post-quantum HSM round-trip has been established for this path. The Enterprise FIPS-mode crypto-policy profile, documented on the Security deep reference, gates the classical signing algorithms; it does not admit the PQS surface into a validated set. Enabling FIPS mode does not make post-quantum signing FIPS-validated. Do not deploy the preview where a FIPS-validated signature is required.

ClaimStandardClause
ML-DSA-44/65/87 carry claimed NIST categories 2, 3, 5.FIPS 204§4.p9
ML-DSA signature sizes are 2420, 3309, 4627 bytes.FIPS 204§4.p15 (Table 2)
The signing context byte string is bounded at 255 bytes.FIPS 204§x43.p2
A wrong-length signature or key must be rejected.FIPS 204§x34
Twelve SLH-DSA parameter sets are approved.FIPS 205§11.p12 (Table 2)
SLH-DSA signature sizes follow Table 2 (7856 bytes for 128s).FIPS 205§11.p6
Hedged signing is the default; a deterministic variant exists.FIPS 205§x65.p7
The CAdES/PAdES suites catalogue profiles RSA and EC-DSA only.ETSI TS 119 312 V1.5.1§7.x7.p10 (Table A.1)
The PKCS#11 PQ mechanism ids are provisional.OASIS PKCS#11 v3.1product-source grounded

All clauses are paraphrased. NextPDF does not reproduce normative text. The statements above are structural-alignment statements about identifiers, lengths, and bounds. PqsCapabilityStatus encodes this preview posture in code: conformanceClaimed is false, adesCompliant is false, and verificationAvailable is false, in every configuration. A signature produced by this preview is not AdES-compliant for long-term archival, and most PDF viewers reject it at validation time.

  • The OASIS PKCS#11 post-quantum mechanism registry is not finalised; the CKM_ML_DSA / CKM_SLH_DSA ids and parameter-set constants used here are provisional and grounded from the product source, not a spec citation.

  • The present milestone is mock-tested readiness. No real post-quantum-firmware HSM round-trip has been validated yet.

  • Keep both gates off in production. The preview adds no production capability that the classical RSA/ECDSA PKCS#11 path lacks.

  • Before any evaluation with real hardware, confirm the token firmware’s mechanism and parameter-set ids against the provisional values. A mismatch fails at the PKCS#11 layer, not inside NextPDF.

  • Treat PqsCapabilityStatus::current() as the single source of truth when surfacing PQS status in tooling or UI. Do not restate its booleans by hand.

  • summary() output is safe for logs and status endpoints; it is phrased to carry no availability or validation claim.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.