Skip to content

Releases

Qertum 1.0.0

Choose a tag to compare

@tomgron tomgron released this 11 Nov 17:03
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0

The first stable release. From this version the
support and compatibility policy applies: it says what a
version number promises and which releases get security fixes. Qertum stays free software under the MIT licence,
provided as is; no support plan is sold.

Security

  • Automatic renewals revoke what they replace. ACME and EST renewals that are approved automatically now honour
    AutoRevokeOnRenewal, as manual approval already did: the replaced certificate is revoked with reason
    superseded.
  • Concurrent revocations keep the winning reason. Two revocation requests for the same certificate can no
    longer overwrite each other's reason or side effects.
  • CA keys at rest are always encrypted. Startup encrypts legacy plaintext CA key files, including per-issuer
    files, with the Data Protection key ring, replacing them atomically with owner-only permissions.
  • TPM wrapping keys never touch disk. Sealing and unsealing pass the wrapping key through process pipes instead
    of temporary files.
  • Multi container: CA hosts no longer see identity or web state. API, ACME, EST and the queue consumer see
    /data/identity and /data/web as empty; API and the queue consumer read only the identity audit logs.
  • Shorter access tokens. The built-in identity provider issues access tokens valid for 10 minutes instead of an
    hour (IdentityService__AccessTokenLifetimeMinutes, 1 to 60), so a disabled, deleted or demoted user loses API
    access within that time.
  • Permission changes reach every API instance. When the shared cache cannot be read, role permissions are read
    from the database instead of a cached copy.
  • The first settings save cannot weaken PQC enforcement. The PQC stage starts at Enforce and only an
    administrator changes it.
  • ACME http-01 never uses a proxy, so the challenge address policy checks the address actually connected to.
  • ACME renewals need an issued predecessor to qualify for the Pilot-stage classical-key exception.
  • Bulk operations without a stable creator are administrator-only.
  • Sign-in input is bounded: usernames up to 256 and passwords up to 1024 characters.
  • The web UI's localhost development addresses are registered with the built-in identity provider only in
    Development.
  • qca replaces terminal control characters in server text with ? and writes key files without following a
    symbolic link at the output path.
  • Logs name issuers by ID in the CRL supersession message, not by their user-controlled name.
  • Patched .NET runtime. Both images now build on ASP.NET Core 10.0.15, which fixes the November 2026
    ASP.NET Core advisories, among them an elevation of privilege in the connection layer that Blazor's web UI uses
    (CVE-2026-114146) and a denial of service (CVE-2026-114147). ASP.NET Core, EF Core and the cryptography packages
    move to 10.0.15 too.
  • Source builds: Aspire 13.6.5. The AppHost and its packages move to Aspire 13.6.5, which fixes a dashboard
    cookie leak to a linked container (CVE-2026-120006). The Aspire CLI must be 13.6.5 or newer too
    (CVE-2026-120778, CVE-2026-120792). This concerns local development only: the release images do not contain
    Aspire.

Changed

  • The cache is named Valkey throughout. The multi-container image reads the cache address from VALKEY_ADDRESS;
    the old REDIS_ADDRESS still works.
  • Step-up during onboarding. When step-up authentication is on, the onboarding pages ask for a fresh sign-in
    instead of failing.
  • Issue forms on GitHub. Bug reports and feature requests use forms, and questions go to the
    Q&A category of GitHub Discussions. Report a
    vulnerability by email as SECURITY.md describes, never in a
    public issue.

Verified for this release

  • Full test suite, local CodeQL (security and code quality) and the security scan of both layouts, with the browser
    check in Chromium, Firefox and WebKit.
  • Upgrade from 1.0.0-rc7 on the same data volume.
  • The post-quantum compatibility matrix on x86_64 as well as arm64: all 33 Linux cells give the same verdict on both
    architectures, and the .NET cell now has a Linux x64 run.
  • TPM secret storage on real hardware in both layouts, as a non-root user: one x86_64 firmware TPM 2.0 (Microsoft
    Pluton). Clearing or replacing a TPM was tested on software TPMs only. Discrete TPM chips, other firmware TPMs and
    arm64 are untested.
  • Step-up with Keycloak 26.8.1: the web UI's reauthentication works. The tested Keycloak device flow does not
    produce the required MFA level, so qca step-up against Keycloak is refused; see
    Identity Providers.

Upgrading

  • Back up /data first. This release adds no database migration over 1.0.0-rc7.
  • Multi container: refresh your copy of deploy/multi-container/ from this release before
    docker compose up -d. The data initializer is now the container qertum-data-init, and the backup and restore
    wrappers take the volume from it. With the bind override, refresh docker-compose.bind.yml too.
  • Access tokens of the built-in identity provider now last 10 minutes; the web UI and qca renew them on their own.
  • Every change is listed in Upgrading.

Qertum 1.0.0-rc7

Qertum 1.0.0-rc7 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 06 Nov 15:27
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc7

Security

  • CA certificates cannot be relabelled as leaf certificates. A request's certificate type can now
    change only while the request is Pending or Rejected. Attempts to change the type later return HTTP 409.
    This closes a path that could otherwise bypass the permission required to revoke a CA certificate.
  • CRL publication is safe under concurrency. Full and delta CRLs coordinate publication with revocation
    writes, reserve distinct CRL numbers and prevent an older snapshot from replacing a newer one. A partial
    cache failure cannot cause an already published CRL number to be reused.
  • Public CRL endpoints are protected from repeated cache misses. Full and delta CRLs use the same
    per-caller API rate limit as certificate requests and OCSP. Concurrent misses for the same CRL share one
    build. Anonymous callers are identified by their client address.
  • Certificate request sizes are bounded. REST create and update accept at most 100 subject alternative
    names in total and 65,536 characters in propertiesJson. EST CSRs accept at most 100 DNS names.

Changed

  • Release-matched architecture diagram. The README and wiki include a complete SVG overview of the
    services, integrations, key protection and manual CA trust hierarchy. Each release's wiki snapshot keeps
    the matching diagram.
  • Dependencies and base images refreshed. OpenIddict, Scalar, StackExchange.Redis, OpenTelemetry
    instrumentation and the Aspire development SDK are updated. The container base-image digests are refreshed;
    the .NET runtime remains on the 10.0 servicing line.

Upgrading

  • Back up /data before upgrading. This release adds no database migration over 1.0.0-rc6.
  • CRL and OCSP fetches now share the certificate-request quota: by default, 100 requests per caller per
    60 seconds, with a queue of 10. Fetchers that poll frequently can receive HTTP 429; review their frequency
    and your configured rate limit before upgrading.
  • Certificate request type changes and input sizes are subject to the limits above. Existing issued
    certificates are not modified by the upgrade.

Qertum 1.0.0-rc6

Qertum 1.0.0-rc6 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 05 Nov 20:34
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc6

Security

  • A CA certificate is issued only when it was approved as one. Approval checks the certificates.ca
    permission and the independent-approver rule when the request's template can sign certificates, but the
    issuing worker used the template as it was at signing time. Someone allowed to edit templates could add
    KeyCertSign to the template of an already approved leaf request and have a subordinate CA certificate
    issued that nobody with the CA permission approved. Approval now records whether a request was approved as a
    CA certificate, and the worker refuses to sign a CA-capable template for a request that was not, rejecting
    it without retry. Automatic approvals (ACME, EST, auto-renewal) never count as a CA approval.

New

  • Releases are signed. The container images on Docker Hub, Quay and GHCR carry a cosign signature, and
    SHA256SUMS is signed in SHA256SUMS.sigstore.json, which covers the deploy bundle, the qca binaries, the
    SBOMs and the third-party notices. The keys live in YubiKeys and cannot be exported; the public keys are in
    signing/ of the source. Signatures are recorded in the public Sigstore transparency log. See the wiki page
    Verify a Release:

    cosign verify --key signing/qertum-release-primary.pub qertum/qertum:1.0.0-rc6
    cosign verify-blob --key signing/qertum-release-primary.pub --bundle SHA256SUMS.sigstore.json SHA256SUMS
    

    Earlier releases are not signed.

  • Compliance documentation for operators. A new wiki page lists the personal data Qertum keeps and for how
    long, how to handle erasure requests given the tamper-evident audit log, and gives a record-of-processing
    template and notes on DPIA, NIS2, eIDAS and the Cyber Resilience Act. The Configuration Reference has a new
    Retention table.

Fixed

  • Single container: the web UI reaches the API when the API port is remapped. With the API published on
    another host port (for example -p 9082:8082 -e API_PORT=9082), every page answered
    Unable to load dashboard. Connection refused. The web UI now calls the API on the port it listens on inside
    the container.
  • Images include Ubuntu's latest security updates. The .NET base image still carried apt 3.2.0
    (CVE-2026-109518); the images now apply pending Ubuntu updates when they are built.
  • Issuers page: row actions stay on the page. At smaller window widths the actions of an issuer ran past the
    right edge; they now wrap.

Changed

  • Support is provided as is. Qertum is free open-source software under the MIT licence with no paid support.
    SECURITY.md and SUPPORT.md now say that security fixes are made on a best-effort basis, with no guaranteed
    response or fix time.

Upgrading

  • One database migration is added. The API service applies it at start. Back up the data volume first.
  • A CA certificate request (a subordinate CA template) that is approved but not yet signed when you upgrade is
    rejected after the upgrade, because it carries no record of a CA approval. File it again and have it approved.
    Requests that are already issued are not affected.

Qertum 1.0.0-rc5

Qertum 1.0.0-rc5 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 04 Nov 23:00
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc5

Breaking changes

  • Browser, identity and API ports bind to host loopback in both compose layouts. Use a TLS proxy for remote
    access. Multi-container plain HTTP additionally requires an explicit QERTUM_ALLOW_INSECURE_HTTP=true lab
    opt-in; see the TLS proxy setup before recreating containers.
  • Multi-container web and identity now mount only their own state. Keep the existing named volume/project;
    existing bind installations must add docker-compose.bind.yml. No data is moved or deleted. Named subpaths
    require Docker 26+ and Compose 2.35+; the bind override requires Compose 2.24.4+.
  • qca est credentials create --password and -p are refused. Use the hidden terminal prompt or pipe a password
    from a secret manager with --password-stdin.
  • EST certificate-based re-enrollment requires an active certificate issued through EST with explicit TLS client
    authentication and signing usage. The default WebServer template has serverAuth only: configure a dedicated
    client-authentication EST template and bootstrap older devices again with credential-based /simpleenroll.
  • Public ACME catch-all CIDRs no longer admit internal addresses. Add explicit internal ranges for intended
    private enrollment. Metadata/link-local addresses remain blocked unconditionally.

Fixed

  • Identity password hashes and client secrets are readable by the file owner only on Unix. The identity
    service creates temporary files with mode 0600 before writing hashes or OIDC client secrets, then replaces stores
    atomically. It uses a new, exclusively created temporary path for every write, so a pre-existing
    symbolic link cannot redirect the write. Startup repairs permissions on existing users.json, clients.json
    and one-time API secret files without replacing users, passwords or client secrets.

  • Anonymous OCSP requests have a caller quota. GET and POST on both OCSP aliases share the existing
    certificate-request rate limit; excess requests receive 429 before parsing, lookup or response signing.

  • Interactive navigation enforces page permissions. The web router now evaluates declared role and policy
    requirements inside an existing circuit and after permission changes.

  • EST re-enrollment requires an enrollment credential certificate. Other CA certificates and certificates
    pending revocation cannot bypass enrollment credentials. The presented certificate must match the stored EST
    certificate, permit client authentication, chain to a trusted issuer, and have Good revocation status.

  • ACME public validation cannot implicitly probe private hosts. Broad CIDRs require an additional explicit
    internal range before a private or loopback address can be reached.

  • Web and identity containers cannot read CA state. Each mounts only its own state subdirectory; the CA
    hosts retain their shared signing/database state and backups retain the existing layout.

  • Web and identity sessions use separate cookie names. Signing in to one service no longer replaces the
    other service's cookie when both use the same host on different ports.

  • Sign-in over plain HTTP on a LAN address works. The web UI no longer forces a Secure session cookie on
    an HTTP deployment.

  • Licence notices ship with the product. Every image carries LICENSE and THIRD-PARTY-NOTICES.txt in
    /usr/share/doc/qertum/; the qca Linux archives carry both beside qca, and the release has
    THIRD-PARTY-NOTICES.txt as an asset of its own. The notices list every bundled .NET package, web asset, font and
    the .NET runtime with their licences.

  • The shared cache is Valkey instead of Redis. Redis 8 is offered only under RSALv2, SSPLv1 or AGPLv3, which
    does not fit an MIT-licensed product image. Valkey 9.1 (BSD-3-Clause) is Redis-compatible and holds the same
    regenerable data (published CRLs, ACME nonces). The single container runs valkey-server; the multi-container
    cache service uses the valkey/valkey image. Nothing is migrated: the cache is not persisted and refills on
    first use.

  • The browser tab shows the Qertum icon everywhere. A 32x32 icon sits beside the SVG one for browsers that do
    not use an SVG icon.

Upgrading

  • No database migration is added by these fixes. Back up the data volume before upgrading.
  • Run the identity service as the owner of its data files, so it can repair Unix permissions. Windows continues
    to use the data directory's inherited ACLs. Earlier copies and backups retain their old permissions.
  • The session-cookie names changed; sign in again after upgrading.
  • Protect the one-time password output from qca est credentials create, including JSON output.
  • Email and UPN policy restrictions introduced in rc4.3 limit domains, not individual user identities. Approvers
    must still verify that the requester may use each requested identity.

Scan follow-up

The earlier root-renewal, email/UPN policy and logout reports were checked against rc4.3 and retain their existing
fixes. A fresh scan of that snapshot reported eight additional issues; the changes above address those paths with
focused regression coverage. A new AI Scan of the released source is still needed to confirm the service's results.

Qertum 1.0.0-rc4.3

Qertum 1.0.0-rc4.3 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 03 Nov 22:32
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc4.3

An interim release with fixes for findings from code scanning of the rc4.2 source. Two database migrations add
columns at start; a few things behave differently, listed under Upgrading.

Breaking changes

  • Multi container with QERTUM_SCHEME=https: the identity service refuses plain HTTP on its own port. Through
    the TLS proxy nothing changes. Before, the published identity port also accepted plain HTTP in https mode, so
    passwords and tokens could cross the network unencrypted. To keep the old behaviour set
    IdentityService__DisableTransportSecurity=true.
  • CA certificates issued from a template have a path length of 0. A certificate from a template that can sign
    certificates (for example SubordinateCA) signs end-entity certificates only. For a CA that issues further CAs,
    use the issuer ceremony (qca issuers create-intermediate), which also sets name constraints. Certificates issued
    before are unchanged.

Fixed

  • A CA renewal needs a second person. Renewing the root skipped the independent-approver rule, and a renewal
    keeps the original requester as its owner, so whoever filed a CA renewal could approve it alone. The renewer is now
    recorded and cannot approve, for the root and for subordinate CAs.
  • Policies can restrict email and UPN entries. New rules list allowed email domains and allowed UPN suffixes.
    Before, a template that issues them (the built-in ClientAuth) took any UPN typed, and a client-authentication
    certificate with someone else's UPN signs in as them. Requests must also give both as local@domain.
  • Account changes by an administrator are no longer undone by the user. A profile or password change, or the
    sign-in that upgrades a stored password hash, could put back a user an administrator had just deleted, disabled,
    changed roles for or reset.
  • Sign-in has a limit per client address, 100 failed attempts in 15 minutes across all user names, so trying a
    new user name every time is no longer unlimited. Successful sign-ins do not count.
  • Signing out of the identity service needs the user's intent. /connect/logout signs out at once only with
    the signed-in user's own ID token as a hint (which the web UI sends), otherwise it asks.
  • qca root init writes the root key readable by its owner only, in a folder only the owner can open.
  • qca root sign cannot be made to overwrite the root certificate. It refuses a request named root or
    chain, never overwrites an earlier certificate file, and shows the file it will write before asking.

Upgrading

  • Back up /data first, then pull the new tag. The upgrade from rc4.2 was tested. The two migrations add columns;
    existing policies keep issuing as before (the new rules start empty, which means unrestricted).
  • Read Breaking changes above if you run the multi container behind a TLS proxy or issue CA certificates from
    a template.
  • Renewing the root through the shared renew route now needs a second approver unless an administrator has waived
    the rule (qca ca approval set waived).
  • An application other than the Qertum web UI that sends users to /connect/logout without an id_token_hint now
    shows them a confirmation page.
  • Coming from rc4.1 or earlier: read the rc4.2, rc4.1 and rc4 notes too (rc4 has two breaking changes).

Known limits

  • The images and the qca files are not signed yet. Signing and build provenance come with the next release;
    every release already carries a CycloneDX SBOM per image and checksums.
  • qca for Windows was run on Windows x64 (--version); sign-in and API commands were exercised on Linux only.
    Windows on Arm and macOS have no build of their own.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only.
  • Composite ML-DSA follows an IETF draft and may change.

Qertum 1.0.0-rc4.2

Qertum 1.0.0-rc4.2 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 03 Nov 18:57
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc4.2

An interim release with twelve fixes for findings from code scanning of the rc4.1 source. No migration and no new
configuration; a few things behave differently, listed under Upgrading.

Fixed

  • CA certificates are guarded on every route that reaches them. The routes every certificate shares reached CA
    certificates with only the ordinary permissions: an operator could approve any request by editing its status,
    renew and approve the root (which replaces the trust anchor), or revoke a CA certificate (which retires the
    issuer and, by default, everything below it). Now a request's status changes only through approve, reject and
    revoke; revoking a CA certificate and renewing the root need certificates.ca; bulk operations leave CA
    certificates out; and automatic renewal never renews the root.
  • Publishing a policy publishes exactly the reviewed draft. An edit saved at the moment of publishing could
    become the published policy, unreviewed, under the publisher's name.
  • ACME account keys meet the key-size rule of certificate requests: RSA account keys under 2048 bits are refused.
  • Sign-in can no longer be blocked for someone else. Failed attempts count per user name and client address,
    with a looser per-user limit across addresses.
  • Unknown user names take as long as wrong passwords at sign-in and EST enrollment, so timing no longer shows
    which user names exist.
  • qca writes downloaded private keys and PFX files readable by their owner only.
  • Signing out needs a form post from the web UI, so another site cannot sign you out with a link.

Upgrading

  • Back up /data first, then pull the new tag. The upgrade from rc4.1 was tested.
  • PUT /v1/certificate-requests/{id} ignores a status in the body; use approve, reject and revoke.
  • Revoking a CA certificate and renewing the root need certificates.ca. Bulk operations leave CA certificates out,
    so after an issuer compromise revoke each subordinate CA on its own.
  • An ACME client registered with an RSA account key under 2048 bits must register a new account.
  • Signing out of the web UI is a form post; a link or bookmark to /signout no longer signs out.
  • Coming from rc4 or earlier: read the rc4.1 and rc4 notes too (rc4 has two breaking changes).

Known limits

  • The images and the qca files are not signed yet. Signing and build provenance come with the next release;
    every release already carries a CycloneDX SBOM per image and checksums.
  • qca for Windows was run on Windows x64 (--version); sign-in and API commands were exercised on Linux only.
    Windows on Arm and macOS have no build of their own.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only.
  • Composite ML-DSA follows an IETF draft and may change.

Qertum 1.0.0-rc4.1

Qertum 1.0.0-rc4.1 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 03 Nov 16:47
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc4.1

An interim release with four fixes for findings from code scanning of the rc4 source. No new features, no
configuration change, no migration.

Fixed

  • Backup archives are readable only by their owner. backup.sh and backup.ps1 wrote the archive, which holds
    the CA key, readable by every local user (mode 0644). It is now mode 0600 and owned by the user who ran the
    script. Archives taken before rc4.1 keep their old mode: run chmod 600 on them (or on the folder that holds
    them) once.
  • One ACME external account key binds one account, also under load. Registrations sent at the same moment with
    the same external account key could each get an account; now exactly one does and the others are refused with
    unauthorized.
  • TPM storage never leaves the plain key readable. While sealing a new key, the TPM provider briefly wrote it to
    a file other local users could read; secret files are now created readable by their owner only.
  • The standalone identity example listens on localhost only, matching its plain-http localhost address. To
    serve other machines, put a TLS proxy in front of it.

Upgrading

  • Back up /data first, then pull the new tag. Nothing else changes; the upgrade from rc4 was tested.
  • Run chmod 600 on backup archives taken before this release.
  • Coming from rc3 or earlier: read the rc4 notes first (two breaking changes: API clients must request the
    qertum-api scope, and QERTUM_TRUSTED_PROXIES is required behind a TLS proxy).

Known limits

  • The images and the qca files are not signed yet. Signing and build provenance come with the next release;
    every release already carries a CycloneDX SBOM per image and checksums.
  • qca for Windows was run on Windows x64 (--version); sign-in and API commands were exercised on Linux only.
    Windows on Arm and macOS have no build of their own.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only.
  • Composite ML-DSA follows an IETF draft and may change.

Qertum 1.0.0-rc4

Qertum 1.0.0-rc4 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 03 Nov 14:56
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc4

The fourth release candidate. These are the changes since 1.0.0-rc3: two security fixes found by code scanning of
the rc3 source, both of which change how a deployment is set up (see Breaking changes), the encryption key ring
now actually encrypted on disk (found while testing TPM storage), console log hardening, and code-quality work with
no change in behaviour.

Breaking changes

  • The API accepts only tokens issued for it. An access token from the built-in identity provider now carries the
    API audience (qertum-api) only when the client requested the qertum-api scope. Before, every token carried it,
    so a client that asked only for the user's profile (openid profile) could still call the API with the user's
    roles. A client that calls the API without requesting the scope now gets 401 Unauthorized: add
    scope=qertum-api to its token request and make sure its clients.json entry permits that scope. The web UI,
    qca and the automation snippets in the web UI already request it, so they need no change. Tokens issued before
    the upgrade stay valid until they expire (about an hour); a refresh token issued without the scope keeps
    returning tokens without the audience, so sign in again. Another OpenID Connect provider is not affected: its
    audience comes from its own settings.
  • Behind a TLS proxy, name the proxy. With QERTUM_PUBLIC_SCHEME=https (single container) or QERTUM_SCHEME=https
    (multi container), set QERTUM_TRUSTED_PROXIES to the proxy's IP address or network, comma-separated for several,
    for example the subnet of the Docker network it shares with Qertum. Web, identity and API accept
    X-Forwarded-Proto and X-Forwarded-For from those addresses only; before, a client that reached their ports
    directly could claim https (and pass the identity provider's https check) or another address (and escape the
    per-address rate limit). Without the variable the container, or the web, identity and API containers, stop at
    start (exit 64) with a message that names it. Plain http deployments are not affected. The standalone identity
    image applies the headers only when QERTUM_TRUSTED_PROXIES is set.

Fixed

  • The encryption key ring is now encrypted on disk. The key ring in /data/DataProtection-Keys, which protects
    the CA key, stored private keys and webhook secrets, was written unencrypted by every earlier release: the local
    file key or TPM chosen under Secret Storage was never applied to it, so a copy of /data was enough to decrypt the
    CA key. The first start of rc4 encrypts the existing files. Two faults that this had hidden are fixed with it: a
    migration to another secret storage (for example to the TPM) built its new key in a folder it then deleted, and the
    services of the single container, starting at the same moment, could each make a key of their own. Tested on a real
    TPM 2.0: a CA on the file key, migrated to the TPM and restarted, keeps every key readable, and its data cannot be
    opened without that TPM.
  • Console log forging. Text from requests (a common name, an issuer or policy name, a webhook URL, an ACME
    identifier) reached the console log unescaped, so a line break in it could forge a second log line. Every
    service now escapes control characters and Unicode line separators in logged values. The audit log was not
    affected.
  • The README picture of the dashboard shows the loaded data instead of the loading spinner.
  • Code quality. Every warning of the CodeQL code-quality analysis is fixed, mostly resource disposal and null
    handling, with no change in behaviour. For code that uses the API client library:
    CertificateRequestsApiClient is now IDisposable and disposes the HttpClient it was given; pass
    disposeHttpClient: false when that HttpClient is shared.

Upgrading

  • Back up /data first. rc4 adds no migration; the upgrade from rc3 was tested with certificates of every key kind,
    a revoked certificate, pending and rejected requests: everything carries over, the audit hash chains continue,
    and the offline restore check passes.
  • Backups taken before rc4 hold the encryption key ring in plain text, so they decrypt the CA key without the
    file key or the TPM. Keep them as safe as the CA key itself, or take a new backup after the upgrade and delete the
    old ones.
  • Check the two breaking changes above: API clients that request no qertum-api scope, and
    QERTUM_TRUSTED_PROXIES behind a TLS proxy. The wiki page "Upgrading" has both.

Known limits

  • The images and the qca files are not signed yet. Signing and build provenance come with 1.0.0; every
    release already carries a CycloneDX SBOM per image and checksums.
  • qca for Windows was run on Windows x64 (--version); sign-in and API commands were exercised on Linux only.
    Windows on Arm and macOS have no build of their own.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only (single container, again for rc4).
  • Composite ML-DSA follows an IETF draft and may change.

Qertum 1.0.0-rc3

Qertum 1.0.0-rc3 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 31 Oct 23:03
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc3

The third release candidate. These are the changes since 1.0.0-rc2: security fixes found by code scanning of the
rc2 source, the qca command line as a download, and a few fixes.

New

  • qca as a download. Every release now carries the command line client as a single file that needs no .NET
    install: qca.exe for Windows x64, and qca-linux-x64.tar.gz and qca-linux-arm64.tar.gz, each holding the executable
    qca, all listed in SHA256SUMS.
    qca --version prints the release and its source commit. The files are not signed with a code-signing
    certificate, so Windows SmartScreen may warn the first time; check the file against SHA256SUMS and choose
    More info, then Run anyway. macOS builds are not published yet. Download and install steps are on the
    wiki page "Using the CLI".

Fixed

  • Security fixes from code scanning of the rc2 source:
    • the private key of the second certificate of a paired request (hybrid, or signing + encryption) was stored
      unencrypted in the database; it is now encrypted like every other private key, and the first start of rc3
      encrypts the ones already stored;
    • a certificate template with the type key RootCA let a requester file a root CA request through the ordinary
      request route, without the permission, step-up or independent approval that creating a CA needs; the type is
      now reserved;
    • a common name in an EST request could add extra subject fields (for example O=) to the issued certificate;
      the subject is now built field by field;
    • ACME and EST accepted RSA keys of any size; keys shorter than 2048 bits, or with a public exponent below
      65537, are refused;
    • the webhook list returned each webhook's signing secret; the secret is now write-only (the list says whether
      one is set);
    • the public OCSP endpoint read request bodies of any size into memory; bodies over 64 KiB are refused;
    • the device sign-in confirmation page (qca auth login) could be submitted from another page on the same site,
      and did not encode the user name and code it shows;
    • qca stored its session tokens in a file other local users could often read; on Linux and macOS it is now
      readable by its owner only, and qca auth login opens only web addresses;
    • an unexpected server error returned the internal error text; it now returns a fixed message and the
      correlation id.
  • Certificate templates are checked when they are saved: key usages, extended key usages, name types and custom
    extensions must be valid. A template saved earlier through the API with a value that cannot be read used to
    issue certificates without that extension; its requests are now rejected with a reason that names the field.
  • Saving a template in the web UI no longer erases its custom extensions.
  • GET /v1/certificate-requests/{id}/private-key and .../certificate work without ?pqc=, as documented.
  • Issuers: row actions confirm in a dialog, and their buttons are spaced. Policies: a refused publish shows
    its reason beside the button.

Upgrading

  • Back up /data first. rc3 adds no migration. Its first start encrypts the stored private keys of paired
    certificates (the API log says how many); downloads return the same keys as before.
  • Backups taken before rc3 still hold those keys unencrypted. Keep them as safe as the keys themselves, or take
    a new backup after the upgrade and delete the old ones.
  • A template with the type key RootCA (only possible through the REST API or qca) no longer accepts requests;
    create one under another type key. CSRs with RSA keys under 2048 bits are refused. Webhook listings no longer
    return signing secrets.

Known limits

  • The images and the qca files are not signed yet. Signing and build provenance come with 1.0.0; every
    release already carries a CycloneDX SBOM per image and checksums.
  • qca for Windows was run on Windows x64 (--version); sign-in and API commands were exercised on Linux only.
    Windows on Arm and macOS have no build of their own.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only.
  • Composite ML-DSA follows an IETF draft and may change.

Qertum 1.0.0-rc2

Qertum 1.0.0-rc2 Pre-release
Pre-release

Choose a tag to compare

@tomgron tomgron released this 30 Oct 17:46
Immutable release. Only release title and notes can be modified.

Qertum 1.0.0-rc2

The second release candidate. These are the changes since 1.0.0-rc1.1.

New

  • Renew an intermediate CA. Issuers, Renew (or qca issuers renew <id>, POST /v1/issuers/{id}/renew)
    gives an active or revoked intermediate a new key under the same name, subject, algorithm, constraints and
    parent. The renewal takes the old intermediate's place: the default seat and every template pinned to it. A
    live old intermediate is retired, not destroyed, so its CRL and OCSP keep answering. When Qertum holds the
    parent's key it finishes at once; under an offline root or an external CA it goes through the same request file
    and install as creating an intermediate. An imported intermediate's renewal must be signed by the CA that
    issued the old one. After a root renewal, renewing an intermediate signs it under the new root.
  • Renewing a root CA gives it a new key and makes it the default as soon as the renewal is signed; a live old
    root is retired, never destroyed. Before, approving a root renewal handed back the old certificate. Renewal is
    also the way back after the root certificate was revoked. A renewed CA keeps its name; serial, thumbprint and
    dates tell the two apart.
  • Show only valid certificates. All Certificates and Issuers hide, by default, what can no longer be used:
    expired, revoked or revoking certificates, anything signed under a CA whose certificate is revoked or expired,
    and archived or destroyed CAs. A renewed certificate stays until it expires, so the overlap with its renewal is
    visible. The API takes validOnly=true; without it the lists are unchanged.
  • A new look. The web UI and the sign-in pages use the Qertum brand: dark, flat surfaces, a mint accent,
    Space Grotesk headings and monospace labels. Fonts and icons are served by Qertum itself, so the UI makes no
    request to another site and works offline.
  • https public URLs behind a TLS proxy (QERTUM_PUBLIC_SCHEME=https for the single container,
    QERTUM_SCHEME=https for the multi-container layout). Plain http stays the default and now logs a warning
    at every start, because sign-in, tokens and the admin password then cross the network unencrypted.
  • After a revoked CA certificate the web UI stays usable. An administrator is no longer forced into
    onboarding; a banner offers Renew it (the root's certificate page, or the Issuers page for an intermediate)
    and Set up a new CA. Revoking a CA certificate, root or intermediate, warns first what it stops.

Fixed

  • Sign-in behind a TLS proxy never worked in either image: the identity service saw the proxy's plain-http hop
    and refused every request. In https mode the web UI, identity service and API now honour the proxy's
    X-Forwarded-* headers; ACME and EST never do. Expose those three ports to the proxy only.
  • Security fixes from a security scan and from code scanning:
    • malformed or unsigned ACME requests answered 500 with the .NET exception text; they now answer 400 with an
      ACME error type, and server errors no longer echo internal messages;
    • every service now sends X-Content-Type-Options, Referrer-Policy, X-Frame-Options and a
      Content-Security-Policy (the web UI and sign-in pages allow scripts from Qertum itself only);
    • the API rate limit was one window shared by every caller; it is now one window per caller;
    • the sign-in redirect no longer announces the identity library's version;
    • audit entries are written one line per value, so a name taken from a request cannot forge a log line;
    • the EST HTTPS requirement now checks the connection's own TLS handshake;
    • a TPM tool call broke on a data path containing a space;
    • the bootstrap password is no longer written to the log.

Upgrading

  • Back up /data first. Starting 1.0.0-rc2 on an rc1.1 volume applies two migrations: issuer names are no longer
    unique (a renewed CA keeps its name) and issuers record which issuer they renew. There is no downgrade; the
    rollback is the backup restored with the previous image. Existing CAs, certificates, the CRL, sign-in and the
    audit log carry over unchanged, and the audit hash chains continue across the upgrade.
  • Set QERTUM_HOST to the public address, exactly as users type it in the browser, with no NAT, DNS alias or
    proxy name in between: sign-in accepts only that address. Behind a TLS proxy, also set
    QERTUM_PUBLIC_SCHEME=https (or QERTUM_SCHEME=https).

Known limits

  • The images are not signed yet. Signing and build provenance come with 1.0.0; every release already carries
    a CycloneDX SBOM per image and checksums.
  • With QERTUM_HOST=localhost and remapped host ports, the single container's API refuses every token; use a
    host name or IP address, or keep the published ports at 8080-8083 (see Troubleshooting in the wiki).
  • A root CA that was imported, rather than generated in Qertum, cannot be renewed in Qertum.
  • Step-up authentication has been tested against Keycloak and a claim-mock server only. The web UI is tested in
    Chromium, Firefox and WebKit; Safari itself is untested.
  • TPM-backed secret storage has been run on one x86_64 TPM 2.0 only.
  • Composite ML-DSA follows an IETF draft and may change.