Crypto-agility and PQC¶
Crypto-agility means being able to change algorithm or certificate authority without rebuilding the estate. Post-quantum cryptography (PQC, here ML-DSA, FIPS 204) is the main reason to prepare for it. PKIFactor offers several approaches, which do not have the same requirements:
| Approach | What is issued | Requires |
|---|---|---|
| Crypto-agile profile | 2 or 3 independent certificates for the same service, one per authority (for example one classical, one ML-DSA) | Existing profiles on any connectors |
| Pure post-quantum certificate | One certificate with an ML-DSA key | A CA that signs ML-DSA |
| Composite certificate | One certificate with a composite key (classical and ML-DSA combined) | A CA that offers composite issuance (ZetaCA) |
| Hybrid certificate | One classical certificate carrying a second, post-quantum signature (X.509 AltSignatureValue) | A CA that offers it (ZetaCA) |
Crypto-agile profiles¶
A crypto-agile profile does not point to one CA: it lists 2 or 3 authorities, each one an existing profile. One request then issues one independent certificate per authority, with the same names and subject. If one authority is compromised or its algorithm broken, the other certificates stay valid. The mechanism is independent of the CA type: each certificate is an ordinary issuance through its own profile (Vault, AD CS, EJBCA, ZetaCA, public CA...).
Create one¶
- Create the ordinary profiles first, one per authority (for example TLS classical on your current CA, TLS ML-DSA on a post-quantum CA).
- In the Administration workspace, Infrastructure > Certificate Profiles > New Profile, PKI Connector = Crypto-agility (several authorities) (last entry of the list).
- In Crypto-agility: several authorities, Add an authority for each family: a family name and Choose an issuance profile…. The form shows the CA and the algorithms of each choice and marks post-quantum ones.
The form refuses fewer than two authorities and the same profile twice, and warns when two authorities rely on the same connector ("this is not real agility, they fall together"). Three authorities at most.
Key algorithm of each family
A family can declare its own key algorithm (key_algorithm in crypto_agile_families). The editor of this version does not set it: a family without one is generated with the default algorithm of its own profile, that is the first algorithm allowed by that profile (and by its CA and the issuance policies). Put the intended algorithm first in each family's profile, or set the family's algorithm through the API. A post-quantum family whose profile resolves to a classical algorithm is refused at issuance (see below).
Via the API: families with their algorithm
curl -s -b jar -X PUT https://clm.example.com/api/v1/clm/templates/21 \
-H "Content-Type: application/json" \
-d '{"crypto_agile_families":[
{"name":"classical","mapped_pki_template_id":4,"key_algorithm":"ECC-P256"},
{"name":"ml-dsa","mapped_pki_template_id":9,"pqc":true,"key_algorithm":"ML-DSA-65"}]}'
mapped_pki_template_id is the identifier of the profile used for that family. pqc: true declares the family post-quantum and turns on the check below.
What a request does¶
- The requester chooses the crypto-agile profile in New Request, in Generate key pair mode: PKIFactor generates one key per family. A single CSR cannot carry several keys, so the CSR mode is refused.
- The certificates form a group. The group becomes active only if every member is issued. If one fails, it is incomplete, and the members already issued are revoked by default, so that no partial set is left behind. A member that waits for approval or domain validation counts as not issued.
- Crypto-agile profiles are used from the web interface and the API. Requests through ACME, EST, SCEP or CMP are not routed to the group mechanism in this version.
- In a group of two, revoking one member also revokes the other. Group revocation for three members is not available in this version.
No false post-quantum¶
For a family declared post-quantum, PKIFactor refuses the request before issuing anything if the chain would contain a classical link:
- the leaf key must be post-quantum (ML-DSA, SLH-DSA, or composite);
- the issuing CA must sign with a post-quantum key. PKIFactor reads it from the CA chain of the connector; an explicit
pki_family(pqc,compositeorclassical) in the connector'sprovider_metadataoverrides it. An issuing CA whose family cannot be established is treated as classical.
A post-quantum key signed by a classical CA can be forged as soon as the classical algorithm falls; this is why it is refused (error code FAUX_PQC).
Deploy a group on one device (co-location)¶
A group can be deployed on one serving object of a device: the server presents all the certificates and each client picks the one it supports, through the signature_algorithms extension of TLS 1.3.
- Operations > Endpoints, open the device, Crypto-agile group (next to Add a binding).
- Choose the group, the serving object (client-ssl profile and optional virtual server on F5, site on an nginx server), the renewal threshold, and optionally Automatic renewal (D-X), which renews the members and redeploys the whole group.
- Deploy the group. Rotate (redeploy) redeploys the current members without interruption.
The key of every member is generated by PKIFactor and pushed (custody push_both, full automation). See How deployment works.
Status per member: served, deferred, failed¶
The result lists each member with one of three statuses. PKIFactor never reports a member as served when the device cannot actually present it.
| Status | Meaning |
|---|---|
| served | Installed and presented on the serving object |
| deferred (not servable) | Not installed on the serving object, without error: typically an ML-DSA certificate on a device whose TLS stack cannot negotiate ML-DSA (OpenSSL older than 3.5). The detail says why; deployment of that member is deferred until the stack is upgraded |
| failed | The device refused the operation for that member; the other members are not affected |
Fewer served members than members is normal on such devices. A group deployment is a failure only when a member is in error or when no member is served.
| Device | Co-location | ML-DSA member |
|---|---|---|
| Linux server with nginx (SSH target) | One ssl_certificate / ssl_certificate_key pair per member in the same server block |
Served if the OpenSSL that nginx is built with is 3.5 or later (probed with nginx -V); deferred otherwise. If the version cannot be read, the member is installed but not reported as served |
| F5 BIG-IP | One certificate-key-chain per member on the same client-ssl profile | Deferred (TMOS TLS stack) |
| Fortinet FortiWeb | A server policy holds one certificate: one member is served (a classical one by preference), the others are reported as not co-located | Deferred |
| Check Point, Progress Kemp, Palo Alto Networks, Windows IIS | No specific co-location: each classical member is deployed on the object in turn; check what the device keeps | Deferred |
Pure post-quantum certificates¶
A profile can allow ML-DSA-44, ML-DSA-65 or ML-DSA-87 when its CA template offers them, on a CA that signs ML-DSA (for example a post-quantum ZetaCA CA). Both modes work: the requester brings an ML-DSA CSR, or PKIFactor generates the key (with OpenSSL 3.5). SLH-DSA cannot be requested in this version.
Post-quantum algorithms must be allowed explicitly on the profile: a profile with no algorithm list allows only the classical algorithms, except on a connector declared post-quantum (pki_family = pqc or composite in its provider_metadata), where ML-DSA-44, ML-DSA-65 and ML-DSA-87 are also allowed. ML-DSA is never offered on a public CA.
An ML-DSA certificate is useful only where both sides support it (mTLS between modern components, for example); browsers and most devices cannot use it yet. That is why the crypto-agile group, which keeps a classical certificate next to it, is the usual way to introduce it.
Composite and hybrid certificates¶
These approaches put classical and post-quantum material in one certificate, and need a CA that implements them; among the connectors, the ZetaCA preset does.
| Profile setting | Result |
|---|---|
Algorithm COMP-P256-ML-DSA-44, COMP-RSA3072-ML-DSA-44, COMP-P384-ML-DSA-65 or COMP-P521-ML-DSA-87 |
A composite certificate (one key combining a classical and an ML-DSA key, IETF composite signatures) |
| Enable Hybrid/PQC Mode, Hybrid Strategy = Hybrid (AltSignatureValue), Post-Quantum Algorithms | A classical certificate that also carries an ML-DSA signature in the X.509 alternative signature extensions |
The Hybrid / Post-Quantum block appears only when the CA template offers post-quantum algorithms. A composite algorithm is offered only when the CA can sign composite requests; on a CA that cannot, a composite request is refused ("L'autorité de certification de ce profil ne sait pas émettre de certificat composite"), it is never downgraded to a classical certificate. A hybrid strategy on a CA that does not offer hybrid issuance issues a classical certificate.
Dual Certificate (RFC 9763) is replaced
The Dual Certificate (RFC 9763) strategy, still listed in the form, no longer issues a second certificate: a profile set to it issues one classical certificate and logs a deprecation warning. Use a crypto-agile profile with two authorities instead. Existing dual profiles are converted to two-family crypto-agile profiles by the database migration.
License¶
Post-quantum, composite, hybrid and crypto-agile profiles are included with every license. The members of a crypto-agile family share one common name and count once (License).
Crypto catalogue¶
The Crypto catalogue holds the reference data that drive the crypto posture scores and the CBOM: the classification of algorithms, the posture rules and the posture profiles. It is updated through a signed pack, without rebuilding or restarting PKIFactor.
Open it in the Administration workspace, Infrastructure > Crypto catalogue (administrators only). The entry is shown only when the CBOM features are enabled on the installation (CBOM_ENABLED=true on the frontend).
| Block | Content |
|---|---|
| Active catalog | The three files of the catalogue (classification.yaml, policy_rules.yaml, policy_profiles.yaml) with their version, and whether the catalogue in use is the one embedded in the release (Embedded (release)) or one applied from a pack (Override (volume)). The directory and the verification key are shown underneath |
| Apply a signed pack | Pack (.tar.gz) and Signature (.sig), provided by ZetaCert, then Verify and apply |
| Previous version | Restore the previous version, when a backup of the previous catalogue exists |
Before activation, PKIFactor checks the signature of the pack (ECDSA P-256 against the verification key shipped with the product) and its content: exactly the three known files, valid YAML, each with a version: header. No outbound connection is made. The new catalogue takes effect without a restart; the previous one is kept as a backup for Restore the previous version.
A pack can be applied only when a catalogue volume is configured (CRYPTO_CATALOG_DIR on the backend); otherwise the page says so, since the embedded catalogue is read-only. Applying a pack (successful or refused) and restoring are recorded in the audit trail (CRYPTO_CATALOG_APPLY, CRYPTO_CATALOG_ROLLBACK).
Via the API
curl -s -b jar https://clm.example.com/api/v1/admin/crypto-catalog
curl -s -b jar -X POST https://clm.example.com/api/v1/admin/crypto-catalog/apply \
-F pack=@catalog-pack.tar.gz -F signature=@catalog-pack.tar.gz.sig
curl -s -b jar -X POST https://clm.example.com/api/v1/admin/crypto-catalog/rollback
422 with the reason.
Troubleshooting¶
| Symptom | Cause and fix |
|---|---|
| "Faux PQC refusé : la famille « … » est déclarée PQC mais sa clé feuille (…) est classique" | The family's algorithm resolves to a classical one: put an ML-DSA algorithm first in that family's profile, or set the family's key_algorithm (see the note above) |
| "Faux PQC refusé : … sous un intermédiaire dont la signature n'est pas quantum-résistante" | The issuing CA of that family is classical or could not be identified: check the connector's CA chain, or set pki_family |
| "Profil crypto-agile : le mode CSR (un CSR unique) n'est pas pris en charge" | Use Generate key pair |
| Group incomplete | One member was not issued (CA error, approval, DCV). The members already issued were revoked; fix the cause and request again |
| ML-DSA member always deferred | The device's TLS stack cannot negotiate ML-DSA; on nginx, upgrade to a build with OpenSSL 3.5 or later |
| Hybrid profile issues a plain classical certificate | The CA does not offer hybrid issuance; use a CA that does (ZetaCA) |
| "L'autorité de certification de ce profil ne sait pas émettre de certificat composite" | The profile's CA cannot sign composite requests; use a CA that does (ZetaCA) |