v0.1.0 free early access — download on request

A certificate authority you can read.

One Go binary; the roles it plays are selected at start. Classical and post-quantum signatures are peers, not a bolt-on. The audit log is one you can prove, not merely read.

goca is a CA engine — the hardened core behind your RA/CLM, not a lifecycle portal.

Architecture

No externally reachable component can mint a certificate alone.

Issuance is split across four services with different authority. api-cert records your request and asks the RA. The RA decides against the template and signs its decision — with a key it doesn't hold. The issuer verifies that signature with a public key, builds the exact certificate bytes, lints them, and records a purpose-bound intent. Only then does the key service sign — after checking who's asking, what for, and whether an intent for exactly those bytes exists.

the issuance split: api-cert → ra → issuer → keysvc

What a compromise buys an attacker

Compromised component What the attacker gains What still blocks issuance
api-cert Request traffic and its scoped principal Cannot create an RA decision or call keysvc
ra The ability to authorize within RA policy Holds no signing key and no key-unwrapping secret; it can only ask keysvc to sign its decisions
issuer Certificate construction and intent creation Cannot forge the RA signature; keysvc enforces independent key policy
keysvc Use of the custody assigned to that instance Accepts only authenticated callers and recorded, purpose-bound intents; HSM/KMS policy can keep keys outside process memory

Supply chain

A supply chain you can audit over coffee.

Exactly two direct Go dependencies. No frameworks, no ORM, no gRPC, no vendor SDKs. When the code that mints your certificates fits in one review, "trust us" becomes "read it".

Written in-house

ASN.1/DER encoding, AWS SigV4, QR codes, Shamir secret sharing, SPIFFE identity (own implementation, not SPIRE), and a certificate linter — hand-rolled, in the repo, readable.

cgo: 3 files

Native code is confined to three files — the PKCS#11 and Windows CNG bridges. Everything else is pure Go, including the cloud KMS clients.

No moving targets

Two dependencies is a diff you can actually read on update day. A dependency tree that fits on one screen is a security control, not an aesthetic.

Post-quantum

PQC as a peer, not a preview.

ML-DSA, SLH-DSA, and composite signatures sit next to ECDSA and RSA as equals — same templates, same custody model, same audit trail. You choose the algorithm; nothing else changes.

ML-DSA

Lattice-based signatures for everyday issuance — root, issuing CA, and end-entity alike.

SLH-DSA

Hash-based, conservative-assumption signatures — a common choice for long-lived roots.

Composite

Classical and post-quantum in one signature, for relying parties that need both to agree.

Proof point

Strict-PKCS#11 ML-DSA — the private key never leaving the token — verified on real Utimaco Quantum Protect hardware, 2026-08-16. Not a simulator, not a software fallback.

Key custody

"HSM-backed" is a phrase that hides the difference.

A stored key's custody is one of three answers to a single question: where is the private key at the moment a signature happens? goca refuses to blur this — and so does this page.

Mode Where the key is when it signs Signing rate A stolen database gets an attacker
software In the service's process memory, unwrapped under the KEK derived from your master secret CPU speed Every CA key — if they also have the master secret
pkcs11-wrapped In keysvc process memory, unwrapped by the token, for the duration of the call CPU speed Nothing usable — the wrapping key is on the token and is not extractable
pkcs11 Inside the token. Every signature is one C_Sign Bounded by the appliance's signature rate Nothing usable

The ranking is pkcs11 > pkcs11-wrappedsoftware, and it will keep being stated that way.

An audited acceptance gate

Wrapped custody isn't a checkbox: a backend earns it through an audited acceptance gate, and a Save button is test-gated — a backend is saved because a test proved it, not because you clicked.

16 vendor presets, runtime-pinned

Presets for 16 PKCS#11 vendors, including YubiKey PIV verified on real hardware. A runtime-pin catches the library being swapped out underneath you.

Cloud KMS in pure Go

AWS KMS, Azure Key Vault, and Google Cloud KMS clients with no vendor SDKs — hand-written request signing you can read, in the same custody vocabulary.

Windows CNG — labeled honestly

A CNG bridge exists in source; its device half is Windows-unverified — the bridge has not been compiled and run in the shipped image, and we won't imply otherwise.

Security controls

Controls that fail in the safe direction.

Offline TOTP with a compiled floor

MFA works with no internet, the admin minimum is compiled into the binary, and factors are tamper-evident.

Break-glass Shamir cards

Emergency access is split across physical cards — a quorum reconstructs it, no single card does.

Four-eyes that can't be deleted off

Deleting the four-eyes approval state turns the control on, not off.

Merkle audit, no retention knob

The audit log is a Merkle tree with signed checkpoints — there is no retention setting, and never will be.

Distroless, no shell

The container image has no shell, runs non-root on a read-only root filesystem — there is nothing to drop into.

Interfaces & protocols

What works today, and what doesn't yet.

Version 0.1.0. Features the manual marks "designed, not built" are labeled Roadmap here — never described as working.

Interface Status Notes
REST API Available Console parity — everything the console does is a public REST call
ACME + ARI Available RFC 8555 issuance with renewal information
Admin console Available Docs embedded in the binary, served from the console
Notifications Available Expiry and lifecycle events
CRL distribution Available CRL-first revocation: issuance may stop; validation must not
Certificate templates Available 18 seeded, including eIDAS-profile templates (QWAC, QSeal, QSigC, PSD2)
External-parent CAs / adopt-existing-key Available Bring a CA signed elsewhere, or adopt a key that already exists
SPIFFE mesh identity Available Built in (own implementation); mTLS enforcement is staged — opt-in per listener, off by default, with a migration path
SCEP Roadmap No handler today
EST Roadmap No handler today
CMP Roadmap Listener shell only
OCSP Roadmap Designed; revocation is CRL-first today
Delta / sharded CRLs Roadmap Full CRLs today

Deployment

Three shapes today. More designed.

Built  Runs today

  • Docker Compose all-in-one — one host, segmented networks per edge of the call graph
  • Docker Compose distributed — the issuance split across containers and network segments
  • Linux standalone — one binary under systemd, external PostgreSQL

Roadmap  Designed, not built

  • Appliance image
  • Windows service / installer
  • Offline-root kit — today: externalParent: true or NGCA_MODE=root-ca
  • Kubernetes / Helm packaging
~57 MB container image
~19 MB RSS, all-in-one
15 min to a verified CA
PG 16 the one external service

Fifteen minutes to a verified CA.

goca is free during early access — download on request. Follow the quickstart, take the operator training, or ask the support assistant — it has read the entire manual and will tell you when the honest answer is "that isn't built yet".