[5.27.0] - 2026-09-05
🔒 Security
- SSRF via attacker-controlled CRL Distribution Points in KMIP
Validate/Import(COSMIAN-2026-021, GHSA-rwc8-xwm6-52xc): the CRL-fetch client used byValidateandImportnow rejects private/loopback/link-local IP ranges and internal hostnames before any network I/O, disables HTTP redirects, applies a 30-second timeout and a 10 MiB response cap, and no longer resolves filesystem-path orfile://CRL Distribution Point values in production builds (#987) Getgrant on wildcard uid*bypasses the Create/Import authorization gate (COSMIAN-2026-020):"*"is now a reserved object identifier rejected at the database layer for every backend, closing a path where aGetgrant on a colliding"*"object could be used to satisfy theCreate/Importprivileged-user/Crypto-Officer check (#909, #1151)
🚀 Features
PKI — CRL & OCSP (#987, #1164)
- Auto-inject a
crlDistributionPointsextension (RFC 5280 §4.2.1.13) into issued certificates, pointing at the KMS's own public CRL endpoint, whenkms_public_urlis configured GET /certificates/{issuer_id}/crl: X.509 v2 CRL generation (RFC 5280 §5);ckms certificates generate-crlCLI command; Web UI support (Certificates → Certs → Generate CRL)GET /public/certificates/{issuer_id}/crl: new unauthenticated, cached CRL Distribution Point endpoint for PKI relying parties- OCSP responder (RFC 6960, RFC 9654, RFC 5019, RFC 5280):
GET /ocsp/{base64url-DER}andPOST /ocsp/, configurable nonce policy, delegated responder signing key, CA key-compromise cascade, new--ocsp-*CLI flags /[ocsp]TOML section - KMIP
Validate: internal KMS-state cascade now also catches a compromised self-signed root CA, which has no CRL Distribution Point of its own - PQC key export (ML-KEM, ML-DSA, SLH-DSA) as
KeyFormatType::Rawvia on-the-fly PKCS#8→Raw conversion - Extended vendor-extension
RevocationReasonCodecoverage:CertificateHold,RemoveFromCRL,AaCompromise(KMIP 2.1 §11.48 8XXXXXXX range)
Split-Key Ceremony & Two-Role RBAC (#991, #1146)
- Two-role RBAC (
Operator/CryptoOfficer) replaces the flatprivileged_userslist, aligned with FIPS 140-3 / NIST SP 800-57 Pt 2 §4.8; unknown users default toOperator(fail-secure) CreateSplitKey/JoinSplitKeyKMIP 2.1 (and 1.4) operations implementing an XOR n-of-n secret-sharing ceremony, with optional AES-KW (RFC 5649) share wrapping- Self-revoke and peer-revocation endpoints for the active Crypto Officer, without a server restart (NIST SP 800-152 FR:6.119)
- CLI:
ckms access-rights crypto-officer status/disable, newcreate-split-keysubcommand - Web UI: Crypto Officer status dashboard, Split-Key/Join-Split-Key dialogs (XOR n-of-n only), refreshed dark/light theme palette for WCAG AA contrast
Web UI Internationalization (#1113, #1124)
- Bilingual English / Simplified Chinese UI via
react-i18next, plus a third French locale, covering the sidebar, layout, and every action form - Cryptographic algorithm/standard names (
RSA,AES,EC,PQC,Covercrypt,MAC,FPE,HSM,ML-KEM,ML-DSA,SLH-DSA, …) are kept untranslated across all locales; business/user-facing copy is translated localeRegistry.ts(#1119): single source of truth for per-locale configuration (label, Ant Design/dayjslocale, browser-language matcher, translation bundle), so adding a future locale is a single registry entry plus its JSON bundle
Authentication
- Web UI login page now supports multiple configured authentication methods at once: the highest-priority method is shown as the primary action and the rest as a secondary control; priority order is OIDC (JWT) > username/password (auth-verifier) > client certificate.
GET /ui/auth_methodgained an orderedauth_methodsarray; the existingauth_methodfield is kept for backward compatibility (#1117) ckms login approle: Vault-compatible AppRole login for automation/service accounts, exchanging arole_id(+ optionalsecret_id) for a token viaPOST /v1/auth/approle/loginckms login cosmian: Cosmian authentication-server login (POST /login?realm=<realm>with HTTP Basic credentials); server gained a matchingCosmianAuthbearer-token validation middleware and a/ui/login_asWeb UI login route using the same session-cookie (BFF) pattern as OIDC- BFF (Backend for Frontend) rework of the Web UI OIDC flow: discovery document and JWKS cached at server startup with refresh-on-miss; only
user_idis stored in the session cookie;id_tokennever reaches the browser;/ui/tokenrenamed to/ui/whoami
🐛 Bug Fixes
PKI / CRL
- CRL freshness (
nextUpdate, RFC 5280 §6.3/§5.1.2.5) now hard-enforced; HTTP(S) CRLs with an unverifiable signature are rejected instead of only warned about (#987) - Fixed revocation reason not being persisted in an object's own attributes when revoking a certificate or key (#987)
file://CRL Distribution Points were incorrectly treated as web URLs and skipped during validation (#987)- Fixed a KMIP 1.4
RevocationReasonTTLV deserialization failure caused by the post-serialization normalizer collapsing structuredAttributeValuenodes into scalars (#987) - CRL Number is now seeded from
max(unix_timestamp, highest stored CRL Number)across server restarts, restoring RFC 5280 §5.2.3 monotonicity (#987) generate_crl: the issuer'scRLSignkeyUsagebit is now enforced (RFC 5280 §4.2.1.3), since OpenSSL'sX509_CRL_sign()does not check it itself (#987)- MySQL
get_max_crl_numberno longer panics on an emptycrlstable (#987)
OCSP Responder (#1164)
- Hardening fixes from an internal STRIDE-A threat-model review, applied before release: unbounded batch requests capped at 128 queries; response cache now keyed on the actual per-request nonce presence (previously never activated under the documented default policy); cache bypassed immediately on CA compromise or certificate revocation; an independently-compromised delegated signing key is refused; delegated signer certificates now require
extKeyUsage: OCSPSigning; unsignedmalformedRequestreturned for oversized GET-encoded requests - Fixed the issuer-hash digest algorithm being hardcoded to SHA-256, rejecting valid requests using a different
hashAlgorithm(e.g. the standardopenssl ocspclient's SHA-1 default) - Fixed the nonce extension being triple-wrapped, breaking RFC 9654 nonce verification in standard clients
nonce_policy = requirednow returns a proper unsignedmalformedRequestOCSP response instead of a raw HTTP 500- Fixed an intermittent
unknownstatus for freshly-issued certificates caused by inconsistent leading-zero-byte handling between the database and crypto layers' serial-number hex extraction
PKCS#11 / OpenSSH
- Backend fallback when a private key referenced by
CKA_IDis not yet in the in-memory object store, fixing an OpenSSH "cannot find private key" regression left by the class-awareCKA_IDlookup fix in5.26.0(#1111, #1076, #1112)
Database
- Release PostgreSQL pool connections before retry back-off waits, instead of holding them idle (#1027, #1152)
- Fixed a
PgPoolstartup deadlock with a single-connection pool (max_connections = 1) and database clearing enabled (#1152) - PostgreSQL deadlock/serialization-failure retry detection now preserves the SQLSTATE code instead of collapsing every database error to a generic message (#1152)
Web UI / CORS
kms_public_urlis now automatically added to the in-RAM CORS allow-list whencors_allowed_originsis not explicitly configured, fixing the Web UI becoming inaccessible on upgrades where onlykms_public_urlwas set (#987)
Docker / Nix packaging (#1133)
- Added the missing
grepbinary to thekms/kms-fipsDocker images, fixing a silently-failing CA-bundle validity check (#1132) - Fixed
fakeRootCommandsfailing with "Permission denied" on Nix-store symlinked directories during Docker image packaging
🧪 Testing
- CRL/OCSP: end-to-end CRL validation lifecycle test; RFC 5280 §5 CRL compliance suite (partial revocation, cross-CA isolation, all revocation-reason codes, validity period, required extensions); black-box
mise run test:ocspandmise run test:pki-revocationcustomer-facing suites drivingckms/openssl ocsp/curldirectly, wired into CI for both FIPS and non-FIPS (#987, #1164) - Split-key / RBAC: ceremony vector tests (2-of-2, 3-of-3, failure scenarios), CLI RBAC permission-matrix tests, and Playwright RBAC-flow E2E smoke tests (#991)
- PQC export-as-Raw round-trip regression tests for ML-DSA-44, ML-KEM-768, SLH-DSA-SHA2-128s (#987)
♻️ Refactor
crate/cryptonow depends directly onforeign-typesinstead of the internalforeign-types-sharedsub-crate (#987)- CRL generation's Authority Key Identifier extension is now built manually per RFC 5280 §5.2.1 instead of via OpenSSL's
X509V3_EXT_nconf_nid, which fell back to a non-FIPS-approved SHA-1 EVP call when the issuer certificate lacked asubjectKeyIdentifier(#987) - Extracted
verify_cosmian_jwt_subject()so the bearer-tokenCosmianAuthmiddleware and the new/ui/login_ashandler share JWT/JWKS trust logic instead of duplicating it
⚙️ Build
- Bump the
authenticationgit submodule, picking up the authentication server's0.4.0release changelog; noauth_verifier-related KMS code changes were required (verified viacargo test -p cosmian_kms_server auth_verifier) - Windows CI: resolve
vcpkg/Ninja lookup failures on runners where Ninja is not onPATHby default, with a Chocolatey fallback (#991)
📚 Documentation
- PKI: documented CRL/OCSP configuration and status mapping, added a manual
openssl ocspverification runbook, and split "PKI Support" navigation into Introduction / Revocation & CRL Distribution / OCSP Responder pages (#1164) - Added Delta CRLs (RFC 5280 §5.4) to the documented "Not supported" PKI features (#987)
- Key ceremony guide (two-role RBAC, XOR n-of-n, NIST references) and an updated authorization/permission-evaluation reference (#991)
- Added a manual end-to-end test plan for the new Web UI Cosmian-authentication-server login flow, since there is no mock harness for a live external auth server in this repo
.github/instructions/rust.instructions.md: added a mandatory four-layer test-coverage rule (unit, DB persistence, functional, security/non-regression) for every new Rust feature, using the CRL test suite as the reference implementation