v2.194
What's Changed
Fixed
- CSR SKI/AKI injection — Subject Key Identifier and Authority Key Identifier from a client CSR are no longer copied into the issued certificate. SKI is always derived from the subject public key; AKI always from the issuing CA's SKI (public-key fallback). Prevents enrollee-controlled key-identifier spoofing (RFC 5280 §4.2.1.1 / §4.2.1.2).
- EE and intermediate AKI — end-entity and intermediate certificates set AKI from the issuer certificate's SKI when present, matching CRL AKI behaviour.
- CA AIA caIssuers — intermediate CA certificates now include AIA
caIssuers(and OCSP) from the parent CA when configured, mirroring the end-entity path (RFC 5280 §4.2.2.1). - CRL invalidityDate — optional
invalidity_at/ APIinvalidity_dateon revoke is emitted as CRL entry extension §5.3.2 (migration 058). - Unhold + delta CRL — lifting
certificateHoldemits a delta CRL entry with reasonremoveFromCRLwhen delta CRL is enabled, then regenerates the full CRL (§5.3.1). - CRL Authority Key Identifier (RFC 5280 §5.2.1) — full and delta CRLs now set AKI from the issuing CA's Subject Key Identifier (with public-key fallback if SKI is absent), instead of copying the CA certificate's AKI (which points at the parent for intermediates). Clients that match CRL AKI to the signing CA SKI no longer reject intermediate CRLs. (#202)
- CRL RFC 5280 profile follow-up — omit
IssuingDistributionPointon delta CRLs so base+delta both omit IDP (§5.2.4); guardFreshestCRLso missing CDP no longer raises (§5.2.6); omitunspecifiedreasonCode and restrictremoveFromCRLto delta CRLs (§5.3.1); shared AKI helper; accuraterevoked_count.
Tests
- Regression coverage for #202: intermediate full/delta CRL AKI≠parent, root CRL, SKI-missing fallback, and unauthenticated regenerate gates.
- RFC 5280 CRL profile suite: IDP parity, FreshestCRL, reasonCode, AKI smoke, auth gates, openssl lab text dump.
- Cert/CRL profile gaps suite: CSR SKI/AKI overwrite, CA AIA caIssuers, invalidityDate, unhold removeFromCRL, auth gates, openssl lab.
- Lab scripts:
scripts/lab_crl_openssl_verify.py,scripts/lab_rfc5280_cert_crl_profile.py.
Docs
- ADMIN_GUIDE / SECURITY / TESTING / API_REFERENCE updated for CRL profile, CSR SKI/AKI policy, and optional
invalidity_date.
📜 Recent release history (last 2 versions)
[2.193] - 2026-07-17
Changed
- WinRM admin channel dependencies bundled —
pywinrmandrequests-ntlmare now part of the default requirements (pure-python wheels), so the Microsoft CA admin channel (revoke/unrevoke, CRL publish, inventory sync) works out of the box on Docker, DEB and RPM without a manualpip install— previously impossible in policy-restricted or air-gapped deployments.requests-kerberosstays optional (C-extension dependencies). (#159)
Added
- ACME preferred certificate chain — per-account
preferred_chain(trust-anchor CN, e.g.ISRG Root X1) selects an RFC 8555Link: rel="alternate"chain during certificate download in the ACME client and proxy; matches last cert subject or issuer CN; alternate issuer chains are rebuilt with the primary leaf when intermediates differ; UI field on the multi-CA account manager. (#197)
Fixed
- SoftHSM token persistence in Docker Compose —
docker-compose.ymlanddocker-compose.simple.ymlnow mountucm-hsm-tokens:/var/lib/softhsm/tokenslikedocker-compose.hsm.ymlalready did. Without it, the token auto-initialized by the entrypoint was lost on container re-creation, orphaning theSoftHSM-Defaultprovider row and any keys stored under it. (#195) - PKCS#11 config key normalization (#198) — migration 057 rewrites legacy
library_path/pinrows tomodule_path/user_pin; startup repair for existing SoftHSM-Default; runtime alias acceptance inPKCS11Provider. Extends #194.
Security
- ACME proxy post-directory SSRF — upstream directory, nonce, and signed POST-as-GET calls now use DNS-pinned
safe_request_get/safe_request_head/safe_request_postwithvalidate_url_not_cloud_metadata(), matching the hardened ACME client path.
[2.192] - 2026-07-11
Security
/api/v2/auth/methodstrusted-proxy gate — the unauthenticated auth-method discovery endpoint re-parsed reverse-proxyX-SSL-Client-*headers without checkingis_request_from_trusted_proxy(), so a remote caller who knew an enrolled certificate serial could learn the mapped UCM username (mtls_user) without a session. The endpoint now applies the same trusted-proxy gate aslogin_mtls(). (GHSA-p4hj-mmxv-xh65)- Legacy settings webhook test DNS rebinding —
POST /api/v2/settings/webhooks/<id>/testvalidated the URL once then called barerequests.post(), which re-resolved DNS and could reach cloud metadata or loopback despite the check. The test path now uses DNS-pinnedsafe_request_post(), matching the hardened/api/v2/webhooksdelivery path. (GHSA-q7j8-h9jm-qxw8) - ACME multi-CA account directory SSRF — creating or registering an external ACME CA account accepted any
https://directory_urland fetched it with an unpinned HTTP client, allowing loopback/cloud-metadata targets despite the narrow SSRF guard used elsewhere. Account create/register now validates withvalidate_url_not_cloud_metadata()(RFC1918 internal CAs remain allowed) and directory fetch uses DNS-pinnedsafe_request_get()with the configuredacme.client.verify_sslsetting preserved. (GHSA-5p92-5vpr-2x5w) - Smart import / OPNsense CA import permission gate — CA (and private-key) ingestion now requires
write:cas, matchingPOST /api/v2/cas/import. Smart import gates on parsed CA presence in the content (cert-only imports still work withwrite:certificatesalone). (GHSA-rgcp-9wxj-6896) - Smart import CA gate bypass for legacy CA certs without BasicConstraints — the
write:casgate classified CA material byBasicConstraints CA:truealone, so a legacy root that assertskeyCertSignin Key Usage but omits BasicConstraints was treated as a leaf and could be imported (and routed into the CA store) withwrite:certificatesonly. Import now treats a certificate as CA material when it has eitherBasicConstraints CA:trueorkeyCertSign, both for the permission gate and for CA-vs-leaf routing. - SAML IdP metadata fetch DNS rebinding —
POST /api/v2/sso/saml/metadata/fetchnow uses DNS-pinnedsafe_request_get()instead of a barerequests.get()after one-shot SSRF validation. (GHSA-9crx-4487-wvxc) - Global search user PII scope —
GET /api/v2/searchreturns user email/role only when the caller holdsread:users, aligning with/api/v2/users. (GHSA-4v84-cxgw-8g4g) /api/v2/auth/methodsusername enumeration — pre-authentication responses no longer expose per-usermtls_certificatescounts that leak valid usernames (distinct from GHSA-p4hj header-forgery). (GHSA-xxhm-683g-fjj5)- ACME proxy EAB gate on new-order — when
acme_eab_requiredwas enabled,POST /acme/proxy/new-orderrequired bothjwkandkidin the protected header, but RFC 8555 §6.2 makes them mutually exclusive, so every request was rejected (kid-authenticated orders failed with "Missing JWK"). The gate now requireskid(registered account) only. - ACME proxy concurrent cert/order mis-binding —
get_certificate()picked the newest pending proxy order instead of matching the upstreamcertificateURL, so concurrent orders could return the wrong certificate. Certificate download now resolves the order via upstreamcertificateURL; finalize also binds the requester JWK thumbprint when stored on the order. - ACME client post-directory SSRF — after the initial directory fetch was pinned (GHSA-5p92),
_get_nonce()and_post()still used unpinnedsession.head()/session.post()for URLs embedded in directory JSON, allowing DNS rebinding to loopback or cloud metadata. All ACME client outbound calls now validate withvalidate_url_not_cloud_metadata()and use DNS-pinnedsafe_request_head()/safe_request_post().
Added
- Certificate list: filter by source — the Certificates page has a new Source filter (multi-select) alongside status and issuer, to narrow the list by issuance origin: Manual, Import, Local ACME, Let's Encrypt, SCEP, EST, and Microsoft AD CS. Backed by
GET /api/v2/certificates?source=<...>(repeatable for multi-select); legacy rows with no recorded source are matched under "Manual". - Public endpoints GUI — admin, protocol HTTP, and ACME vhost — Settings → General → Endpoints publics to configure canonical admin URL (
base_url), protocol HTTP base (protocol_base_url), and ACME public vhost with effective ports fromHTTPS_PORT/HTTP_PROTOCOL_PORT. Includes dynamic CORS origins, Utiliser l'URL du navigateur, and Vérifier DNS et TLS preflight (local, corporate/internal viaUCM_CORPORATE_DNS_SERVERS, and public resolvers) plus TCP/TLS reachability checks. Host middleware soft-redirects IP/alias hosts to the canonical admin origin, serves ACME paths on the split vhost only, and rejects untrustedX-Forwarded-Hostwhen ProxyFix is enabled. API:GET/PATCH/POST /api/v2/settings/public-endpoints. Docs:docs/testing/PUBLIC-ENDPOINTS.md. (#186) - Microsoft AD CS: CA control panel — approve/deny pending requests and CA health (admin channel) — the connection now surfaces a control panel (over the WinRM admin channel) to manage requests that are awaiting CA manager approval: list pending requests, approve them (
certutil -resubmit, with the issued certificate imported into UCM automatically), or deny them (certutil -deny). It also shows a CA health snapshot — CA service status, CA certificate expiry, CRL next-update, and pending-request count — assembled from locale-neutral sources so it works regardless of the CA's display language. Pending listing and health needread:certificates; approve/deny needadmin:system. Completes the CA management surface for #185; verified end-to-end against a Windows Server 2025 AD CS (approve → issued → imported, deny → request marked denied on the CA). (#185) - Microsoft AD CS: CA inventory sync — import certificates issued directly on the CA (opt-in) — building on the WinRM admin channel, UCM can now import certificates that were issued on the Windows CA outside UCM (native tools, autoenrollment, or before UCM was deployed), so it can track the whole certificate lifecycle rather than only what it issued itself. The sync reads the CA database with
certutil -view, imports certificates UCM doesn't already have (deduplicated by serial), and is incremental by request id (with a full-rescan option). A reconciliation view lists certificates present on the CA but not in UCM, and UCM certificates for that connection absent from the CA. Runs every 6 hours for opted-in connections plus an on-demand "Import from CA" action; import needsadmin:system, reconciliation needsread:certificates. Completes the CA inventory sync requested in #185; verified end-to-end against a Windows Server 2025 AD CS. (#185) - Microsoft AD CS: WinRM admin channel — revoke, unrevoke and publish CRL on the CA (opt-in) — a Microsoft CA connection can now carry an optional WinRM administration channel so UCM performs real management operations on the Windows CA (which AD CS Web Enrollment cannot do). Revoking an MS-CA-issued certificate in UCM now propagates the revocation to the CA (
certutil -revoke+ CRL publish); lifting a certificateHold propagates the unrevoke; and a "Publish CRL" action forces the CA to issue a fresh CRL. Auth is NTLM or Kerberos over HTTP/HTTPS (Kerberos+HTTPS recommended); credentials default to the connection's own, with optional override fields for a dedicated least-privilege "Issue and Manage Certificates" account (required for mTLS-enrolled connections, which have no reusable WinRM credential). Serial numbers are validated as hex and no user-supplied string reaches the remote shell.pywinrmis an optional dependency (lazy-imported; the rest of UCM and installs without AD CS never require it). Management operations requireadmin:system. Verified end-to-end against a Windows Server 2025 AD CS (revocation in UCM confirmed as disposition "Revoked" in the CA database). (#185) - Microsoft AD CS: CRL-based revocation sync (opt-in) — a Microsoft CA connection can now periodically fetch the CA's CRL and mark certificates revoked on the CA as revoked in UCM (strictly one-way, CA → UCM; certificates revoked locally in UCM are never un-revoked). The CRL URL is taken from the connection settings or auto-detected from the CRL Distribution Point of certificates issued by that CA, the CRL signature is verified against the CA certificate before anything is applied, and the revocation date/reason are taken from the CRL entry. Runs hourly for opted-in connections, plus a "Sync CRL now" button and
POST /api/v2/microsoft-cas/<id>/sync-crl. First step of the CA inventory sync discussed in #185; verified end-to-end against a Windows Server 2025 AD CS (revocation done withcertutil -revokeon the CA propagated to UCM by the scheduled sync). (#185)
Fixed
- Microsoft AD CS: pending requests are now recognized on non-English CAs — the
certsrvclient only matches the English "Certificate Pending" enrollment page, so against a localized AD CS (e.g. a French-language CA) a genuinely pending request was misreported as denied — signing returned a 400 — and polling a still-pending request failed with a 500. UCM now classifies the AD CS response using the locale-independent HTML markers certsrv itself emits (thelocInfoReqIDelement id, and the numeric request disposition code where 5 = under submission and 2 = denied) instead of the translated text, so submit returns a proper "pending" status and polling keeps returning "pending" until the CA manager acts. Verified end-to-end against a French Windows Server 2025 AD CS. (#159) - Renewing a certificate issued by a Microsoft AD CS connection now goes through the connector — renewal previously used the local re-sign path, which failed with "Issuing CA not found" (or "CA private key not available") because the issuing CA's key lives on the Windows CA. UCM now resubmits the certificate's original CSR (same key, subject and SANs) to the AD CS connection and template that issued it, and updates the certificate in place; if the CA holds the request for manager approval, the renewal is tracked like any pending MS CA request. EOBO-issued certificates require the same elevated permission to renew as to issue. Reported in #159. Verified end-to-end against a Windows Server 2025 AD CS.
Changed
- Revoking a Microsoft-CA-issued certificate now states that the revocation is local to UCM — AD CS Web Enrollment has no revocation endpoint, so UCM cannot propagate the revocation to the Windows CA. The API response and the revoke confirmation dialog now say so explicitly (
meta.msca_local_onlyfor API consumers) and remind you to revoke the certificate on the CA itself. Reported in #159.
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.194
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.194
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.194Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.194/ucm_2.194_all.deb
sudo dpkg -i ucm_2.194_all.deb
sudo apt-get install -fFedora/RHEL
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.194/ucm-2.194-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.194-1.fc43.noarch.rpmSilent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.194_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!