Skip to content

Add import-cert: register externally-issued certificates in the inventory#115

Open
bootc wants to merge 2 commits into
mainfrom
feature/import-certificate
Open

Add import-cert: register externally-issued certificates in the inventory#115
bootc wants to merge 2 commits into
mainfrom
feature/import-certificate

Conversation

@bootc

@bootc bootc commented Jul 12, 2026

Copy link
Copy Markdown
Member

Certificates issued outside this CA's normal Sign/Generate flow (e.g. migrated from a legacy CA sharing this CA's key) previously had no way to enter the inventory, so they were invisible to listing, expiry cleanup, and by-subject revocation, even though they were genuinely signed by this CA.

This adds PUT /certificate/{subject} (admin-only, sharing its path with the existing public GET /certificate/{subject}) and an openvox-ca-ctl import-cert --certname --cert-file CLI command to import such a certificate:

  • The certificate's signature must verify against this CA's certificate (a pure cryptographic check via CheckSignatureFrom, so an already-expired legacy certificate is still accepted for record-keeping).
  • The path {subject} must match the certificate's CN or one of its DNS SANs.
  • CA certificates (IsCA: true) are rejected — use openvox-ca-ctl import for CA bundle import instead.
  • Conflict handling, in priority order: (1) resubmitting the exact same certificate is an idempotent no-op; (2) a serial already tracked anywhere in the inventory is rejected (409); (3) an existing active certificate for the subject is rejected (409), or evicted if it's revoked.

Once imported, the certificate is tracked exactly like a normally-issued one: it shows up in listings, gets cleaned up by the expiry sweep, and can be revoked via the normal PUT /certificate_status/{subject} (desired_state: "revoked") mechanism.

Also hardens AppendInventory to reject a duplicate serial atomically on every storage backend — previously only the SQL backend enforced this, via its DB-level unique index; filesystem/etcd/redis backends had no equivalent check at all. This benefits normal certificate issuance too, not just the new import path, and is what the import feature's serial-conflict check ultimately relies on for race-safety (a separate best-effort pre-check exists only to get error precedence right in the common, non-racing case).

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

…tory

Certificates issued outside this CA's normal Sign/Generate flow (e.g.
migrated from a legacy CA sharing this CA's key) previously had no way
to enter the inventory, so they were invisible to listing, expiry
cleanup, and by-subject revocation even though they were genuinely
signed by this CA.

Adds PUT /certificate/{subject} (admin-only) and the openvox-ca-ctl
import-cert CLI command to import such a certificate: the signature
must verify against this CA's key, the certificate's CN or a DNS SAN
must match the path subject, and CA certificates are rejected. Import
is idempotent on an identical resubmission, rejects a serial already
tracked anywhere in the inventory, and rejects (or evicts, if revoked)
an existing active certificate for the subject.

Also hardens AppendInventory to reject a duplicate serial atomically
on every storage backend (previously only the SQL backend enforced
this via its unique index), closing a race the import feature's
conflict checks otherwise relied on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@bootc
bootc requested a review from trevor-vaughan July 12, 2026 14:26
AppendInventory now validates and enforces serial uniqueness on every
backend (see previous commit), which correctly rejects the "line 1" /
"line 2" placeholder strings this test previously relied on. Switch to
well-formed, distinct-serial canonical inventory lines, matching the
fix already applied to the equivalent Redis smoke test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant