Pre-release

v0.1.0-rc.1 is out. Until v1.0.0, any release may change fundamentally. Download v0.1.0-rc.1 Project status

Trust Center

CryptOS Security Review

Architecture, appliance design, boot chain, key custody and the fleet of a self-hosted PKI operating system, with the evidence behind each claim.

Document
Draft 1
Date
4 November 2026
Product version
v0.1.0-rc.1 (prerelease), and main where marked
Classification
Public

CryptOS holds no SOC 2 report, ISO 27001 certificate or other certification. This review describes only what is built, links the code and tests behind each claim so an independent reviewer can check it, and lists every known gap. Where a control depends on how you deploy CryptOS, it says so.

1. Scope and how to read this review

CryptOS is an immutable, API-driven PKI operating system. A node boots a signed kernel image into a read-only root, keeps its CA key in the TPM, and is managed only over a mutually authenticated gRPC API. FleetOS Manager is an optional console for many nodes. You run both yourself; the project operates no service and never receives your keys.

This review covers the v0.1.0 release train, currently at release candidate 1. Implemented means the code is on main, with the release it first shipped in. Partial means it is built with a named gap. Planned means it isn't built. Not planned means it is left out on purpose.

CryptOS is pre-1.0. Ceremonies are one person today, high-availability pairs and split-custody recovery aren't built, and a TPM-held CA key can't be backed up. They are described plainly in their sections and collected in Gaps and planned work.

2. Architecture and trust boundaries

A node is one Go program running as PID 1. It serves the management API, the enrolment protocols you turn on, revocation and time-stamping, and keeps its state in an embedded etcd on the encrypted state partition. There is no shell, no SSH server and no login.

CryptOS architecture and trust boundariesOff the boxcryptosctlyour admin certificateTLS 1.3, mTLSFleetOS Manageroptional; dials the nodewith the node's admin certEnrolment clientsACME, EST, SCEPTSA requestersRelying partiesfetch CRL, OCSPand the CA certificateCryptOS node: no shell, no SSH, no loginManagement APIgRPC, mTLS on :443, one addresstrusts only the pinned admin certBreak-glass socket/run/cryptos.sockon the box only, no networkProtocol listenersACME :8555 · EST :8443 (TLS)SCEP :80 · TSA :318on only if enabled; never on a RootRevocationCRL and OCSP over HTTP :80when a base URL is setCA engineprofiles, issuance, revocationRFC 5280 path lengthEmbedded etcd127.0.0.1 onlyon the encrypted state diskcryptos-consolelocal dashboardreads the socketTPM 2.0CA key made andused inside itsign
Figure 1. Architecture and trust boundaries. Everything off the box reaches the node only through the listeners on its edge; the break-glass socket and etcd never leave it. Solid arrows are calls; dashed arrows are reads and writes on the box.
SurfacePort and transportWho can reach it
Management API443, gRPC over TLS 1.3, client certificate requiredOnly the admin certificate pinned in the machine config: cryptosctl, or FleetOS Manager holding that node's credential
Break-glass socket/run/cryptos.sock, UNIX socket, no TLSSoftware on the box only: the local dashboard and cryptosctl run there
ACME8555, HTTPEnrolment clients, when ACME is on; never on a Root
EST8443, TLSEnrolment clients, when EST is on; never on a Root
SCEP80, HTTPEnrolment clients, when SCEP is on; never on a Root
Time-stamping318, HTTPRequesters, when the TSA is on; never on a Root
CRL, OCSP, CA certificate80, HTTPRelying parties, when a revocation base URL is set
Maintenance mode443, TLS, no client certificateOnly before install, to adopt or install the node

Trust domains: the node trusts one pinned admin certificate for management; its own CA chain for what it issues; and FleetOS Manager's operators are signed by a separate operator CA that the node never sees.

Controls: Architecture and trust boundaries

ControlStatusEvidence
ARC-1 No interactive access
A node has no SSH server, login prompt, shell or user accounts. The kernel is built without loadable modules and boots with lockdown=confidentiality.
Implemented in v0.1.0-rc.1cryptos-appliance/build/kernel/cryptos.config (CONFIG_MODULES unset, forced lockdown)cryptos-appliance/build/uki/assemble.sh (kernel command line)website/apps/docs/docs/concepts/immutable-no-login.md
ARC-2 Remote management is mutual TLS only
The management API is gRPC over TLS 1.3 with a client certificate required. A certificate that doesn't match the node's pinned admin is refused.
Implemented in v0.1.0-rc.1cryptos-node/internal/grpc/authz.gocryptos-node/internal/grpc/authz_test.go (TestAuthorizeAdmin_MismatchIsPermissionDenied)cryptos-node/internal/init/servertls.go
ARC-3 Break-glass socket on the box only
An unauthenticated UNIX socket serves the same API for on-box use only, with no network listener behind it. An unauthenticated reset works only there; over the network, reset needs the admin and the Root CA name typed back.
Implemented in v0.1.0-rc.1cryptos-node/internal/grpc/authz.gocryptos-node/internal/grpc/authz_test.go (TestAuthorizeAdmin_LocalNoPeer)website/apps/docs/docs/deep-dives/trust-from-zero.md
ARC-4 Embedded state store on loopback
The node's etcd listens on 127.0.0.1 only and keeps its data on the encrypted state partition.
Implemented in v0.1.0-rc.1cryptos-node/internal/storage/etcd/etcd.go
ARC-5 No web interface in the OS image
The node serves no web front end, compiled or otherwise. A web console exists only in FleetOS Manager, which runs off the node.
Why: Every web stack on the CA is more code that could be attacked. Nodes stay API-only by design.
Not plannedcryptos-node/README.md
ARC-6 No cross-signing between Roots
Each Root is its own trust domain. CryptOS doesn't cross-sign one Root with another.
Why: Siloed Roots keep a compromise of one hierarchy from reaching another. It stays out until a real need appears.
Not plannedwebsite/apps/docs/docs/concepts/ca-roles.md

Controls: Issuance and protocols

ControlStatusEvidence
ISS-1 RFC 5280 Root certificates
The Root certificate the node self-signs is checked by zlint in the test suite with no errors and no warnings.
Implemented in v0.1.0-rc.1cryptos-node/internal/ca/ca_test.go (TestSelfSignRoot_ZLintCleanRoot)
ISS-2 One profile engine for every issuance path
Every path to a certificate, the API and the ACME, EST and SCEP adapters included, goes through one profile engine that decides the extensions. A subordinate's path length is clamped to what its parent allows.
Implemented in v0.1.0-rc.1cryptos-node/internal/ca/profile.gocryptos-node/internal/node/signer.go (clampPathLen)
ISS-3 No arbitrary CSR signing in production builds
The raw SignCSR call is a stub in production builds; it exists only in a debug build tag.
Implemented in v0.1.0-rc.1cryptos-node/internal/grpc/signcsr_stub.gocryptos-node/internal/grpc/server_test.go (TestSignCSR_StubReturnsUnimplemented)
ISS-4 SCEP (RFC 8894)
SCEP enrolment, tested against the sscep client in CI.
Implemented in v0.1.0-rc.1cryptos-node/internal/scep/sscep_test.gocryptos-node/.github/workflows/ci-go.yml (Build sscep)
ISS-5 ACME (RFC 8555)
ACME with http-01 and External Account Binding, and a strict JWS algorithm allow-list. dns-01, wildcards, key change and account deactivation aren't built.
Partial in v0.1.0-rc.1cryptos-node/internal/acme/doc.gocryptos-node/internal/acme/jws_test.go (TestVerifyJWSAlgorithmConfusion)Open: cryptos-node#110 ACME HTTP-01/DNS-01 for cert-manager and native clients
ISS-6 EST (RFC 7030)
An EST enrolment adapter over TLS.
Implemented in v0.1.0-rc.1cryptos-node/internal/est/handlers.gocryptos-node/docs/est.md
ISS-7 Revocation: CRL and OCSP
The node publishes an RFC 5280 CRL and answers RFC 6960 OCSP requests when a revocation URL is set.
Implemented in v0.1.0-rc.1cryptos-node/internal/revocation/crl.gocryptos-node/internal/revocation/ocsp.gocryptos-node/internal/revocation/http_test.go
ISS-8 Time-stamping (RFC 3161)
A built-in time-stamp authority that refuses SHA-1 and MD5 message imprints.
Implemented in v0.1.0-rc.1cryptos-node/internal/tsa/responder.gocryptos-node/internal/tsa/responder_test.go
ISS-9 Root CAs serve no enrolment protocols
Config validation refuses ACME, EST, SCEP and the TSA on a Root, so a Root never answers enrolment requests.
Implemented in v0.1.0-rc.1cryptos-node/internal/config/protocols.go
ISS-10 Windows autoenrolment (MS-XCEP and WSTEP)
Native Windows autoenrolment through Group Policy isn't built.
PlannedOpen: cryptos-node#108 Native Windows autoenrolment via GPO (MS-XCEP/WSTEP)

3. The appliance

The image is a unified kernel image (UKI): systemd-stub, the Linux kernel, a command line with lockdown=confidentiality, and a small initrd that carries a SquashFS root, mounts it read-only and switches into it. The kernel has no loadable modules.

CryptOS appliance high-level designThe CAmanagement API :443 · protocol listeners · CA engine · embedded etcdsupervised by PID 1, with the local dashboard on the consoleRead-only root: SquashFS (xz), mounted read-only, never writteninitGo PID 1cryptos-nodecryptosctlon-box clientfor the socketcryptos-consolestatus screenon the consolecryptsetupstatic, LUKS2and disk toolsUnified kernel image (UKI)systemd-stub · Linux kernel · cmdline with lockdown=confidentialityinitrd shim that carries the SquashFS and switches root into itUEFI firmware, Secure Bootboots the UKI you signed with your own db keyHardware or VMx86-64, network and consoleTPM 2.0seals the disk key to PCR 7 + 11Disk (written by the installer)p1: EFI system partitionFAT, 512 MiBthe UKI and EFI/cryptos/machine.yamlp2: cryptos-stateLUKS2, aes-xts-plain64, argon2idext4 at /var/lib/cryptosconfig · etcd · auditInterfacesOne network interfacemanagement on its address, protocols on allLocal consoleread-only dashboard; no login promptNo SSH, no shellevery change goes through the API
Figure 2. The appliance, from firmware to the CA. Firmware boots the UKI you signed; the UKI mounts the read-only root; init runs the CA. The installer writes two partitions, and the TPM unseals the second.
PartWhat it isWritten
EFI system partition (p1)FAT, 512 MiB: the UKI and EFI/cryptos/machine.yamlBy the installer and by signed upgrades
Root filesystemSquashFS inside the UKI: init, cryptosctl, cryptos-console, cryptsetup and disk toolsNever; mounted read-only
State partition (p2)LUKS2, aes-xts-plain64, argon2id, ext4 at /var/lib/cryptos: config, etcd, auditBy the node, only after the TPM unseals it

There is one network interface: management binds its configured address, and the protocol listeners bind all addresses. The local console shows a read-only status screen and has no login prompt.

Controls: Appliance platform

ControlStatusEvidence
APP-1 Read-only root filesystem
The signed kernel image carries the Go PID 1 and a SquashFS root that is mounted read-only. Only the encrypted state partition is writable.
Implemented in v0.1.0-rc.1cryptos-appliance/build/squashfs/build.shcryptos-appliance/internal/switchroot/switchroot.go
APP-2 Secure Boot with your own key
Releases ship unsigned and the release pipeline checks they are. You sign the kernel image with your own Secure Boot key, so nothing in your chain of trust is signed by the project.
Implemented in v0.1.0-rc.1cryptos-appliance/build/uki/sign.shcryptos-appliance/build/release/check-unsigned.shcryptos-appliance/docs/secure-boot.md
APP-3 Signed in-place upgrades with rollback
An upgrade image is checked against a detached signature before anything is written to the boot partition, and the previous image is kept for one rollback.
Implemented in v0.1.0-rc.1cryptos-node/internal/imageupgrade/imageupgrade.gocryptos-node/internal/imageupgrade/imageupgrade_test.go (TestStage_RefusesASignatureOverOtherBytes)
APP-4 Remote attestation
Measured boot gates the state disk (KEY-2). A node proves its identity by signing a challenge with its CA key; a TPM quote of its boot measurements isn't offered yet.
Partial in v0.1.0-rc.1cryptos-node/internal/grpc/attest.go
APP-5 A guarded clock
A time floor and NTP sync keep certificate validity and time-stamps from going backwards.
Implemented in v0.1.0-rc.1cryptos-node/internal/timesync/floor.gowebsite/apps/docs/docs/deep-dives/clock-safety.md
APP-6 More platforms
Node images are amd64 for VMware today. Proxmox VE, bare-metal installs and an arm64 image are in progress.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.mdOpen: cryptos-appliance#38 Support Proxmox VE as a VM platformOpen: cryptos-appliance#54 A plain installer ISO for bare-metal serversOpen: cryptos-appliance#117 Build and prove an arm64 appliance image

4. Boot chain and TPM key custody

Boot chain and TPM key custodyBoot, in orderUEFI Secure Bootchecks the UKI against your db keysystemd-stubmeasures the UKI into PCR 11Kernel and initrd shimmounts the SquashFS read-onlyinit (PID 1)asks the TPM for the state keyLUKS2 state partitionopened at /var/lib/cryptosCA readykey blob loaded from etcd into the TPMTPM 2.0: nothing leaves it in the clearPCR 7Secure BootstatePCR 11the UKI(SHA-256)Storage root keyECC P-256, persistenthandle 0x81000001State disk keysealed under PolicyPCR 7 + 11blob in LUKS2 token 0CA private keymade in the TPM: P-384 or RSA 3072+wrapped blob kept in etcdWhat the TPM refusesa changed boot chain can't unseal the disk; an image updatepredicts the new PCR 11 and reseals first; CA key export is refusedpolicyparentunsealload, sign
Figure 3. Boot chain and TPM key custody. Firmware records Secure Boot state in PCR 7 and systemd-stub measures the UKI into PCR 11; the state key unseals only for those values. The CA key is made inside the TPM and only its wrapped blob is stored.
KeyAlgorithmWhere it lives
Storage root keyECC P-256Persistent in the TPM at 0x81000001
State disk keyLUKS2, aes-xts-plain64, 512-bitSealed in the TPM under PolicyPCR 7 + 11; blob in LUKS2 token 0
CA key (TPM mode)ECDSA P-384 with SHA-384, or RSA 3072+Created in the TPM under the SRK; wrapped blob in etcd; export refused
CA key (nodeid or kms mode)As aboveIn software on the encrypted partition, not hardware-protected
Ceremony manifest keyEd25519Derived on the node; signs the ceremony record
Secure Boot keyRSA, yoursOff the box: you sign the UKI with it
First boot to a Root
  1. The node boots in maintenance mode and installs to disk, staging the machine config on the EFI partition.
  2. The installed node encrypts its state partition and seals the key to PCR 7 and 11.
  3. Over the channel pinned to the admin certificate, the ceremony provisions the SRK and creates the CA key inside the TPM.
  4. The node self-signs the Root certificate, signs the ceremony manifest, and commits both to etcd in one step.

An image upgrade predicts the new PCR 11 and reseals the state key before anything is written, so a signed upgrade keeps the disk readable and a tampered one doesn't.

Controls: Keys and TPM custody

ControlStatusEvidence
KEY-1 CA keys are made and used inside the TPM
In TPM mode the CA key is created inside the TPM under its storage root key, only its wrapped blob is stored, and export is refused.
Implemented in v0.1.0-rc.1cryptos-node/internal/tpm/key.gocryptos-node/internal/init/escrow_test.go (TestExportRefusedWhenNotExportable)website/apps/docs/docs/deep-dives/keys-never-leave-tpm.md
KEY-2 The state disk is sealed to the boot chain
The LUKS2 state partition's key is sealed in the TPM to PCR 7 (Secure Boot) and PCR 11 (the signed kernel image). A changed boot chain can't unseal it.
Implemented in v0.1.0-rc.1cryptos-node/internal/tpm/seal.gocryptos-node/internal/tpm/seal_test.go (TestUnseal_FailsAfterPCRDrift)website/apps/docs/docs/concepts/tpm-sealed-keys.md
KEY-3 Sealing follows upgrades and rollbacks
Before an upgrade or rollback, the node predicts the new PCR 11 and reseals the state key for exactly the images it can boot, adding before it removes.
Implemented in v0.1.0-rc.1cryptos-node/internal/init/statekeyreseal.gocryptos-node/internal/init/statekeyreseal_test.go (TestReseal_KeyFollowsAnUpgradeAndItsRollback)
KEY-4 Strong CA key algorithms only
CA keys in the TPM are ECDSA P-384 with SHA-384, or RSA of at least 3072 bits. Anything smaller is refused.
Implemented in v0.1.0-rc.1cryptos-node/internal/tpm/key.go (MinRSAKeyBits)cryptos-node/internal/tpm/keyalg_test.go (TestPublicTemplateRSAFloor)
KEY-5 Software key modes are labelled as such
The nodeid (development) and kms modes keep the CA key in software on the encrypted partition, not in the TPM, and the code and docs say so plainly.
Partial in v0.1.0-rc.1cryptos-node/internal/init/softroot.gocryptos-node/internal/config/config.go
KEY-6 No network HSM for CA keys
CA keys live only in the node's own TPM; a network HSM or PKCS#11 device for CA keys is out of scope. The kms mode wraps only the state disk's key with an external KMS. Saying so plainly in the docs is planned.
PlannedOpen: website#42 Say that CA keys stay in the TPM and a network HSM is out of scope

Controls: Ceremonies and quorum

ControlStatusEvidence
CER-1 First-boot Root ceremony
A Root key and its self-signed certificate are made in a first-boot ceremony, authorised by the admin certificate pinned in the machine config.
Implemented in v0.1.0-rc.1cryptos-node/internal/ceremony/ceremony.gowebsite/apps/docs/docs/deep-dives/ceremony-walkthrough.md
CER-2 Signed ceremony manifest
The ceremony writes an Ed25519-signed manifest, and tampering with it is detected. The signing key is derived on the node; it isn't an operator's signature.
Implemented in v0.1.0-rc.1cryptos-node/internal/ceremony/ceremony.gocryptos-node/internal/ceremony/ceremony_test.go (TestVerifyManifest_Tamper)
CER-3 M-of-N quorum for Root operations
Ceremonies are one person today. Requiring M of N key holders for Root operations isn't built.
PlannedOpen: cryptos-node#371 Build M-of-N quorum ceremonies
CER-4 Guarded factory reset
A reset needs the Root CA name typed back, compared in constant time, and fails closed. A quorum and one-time-code gate on top of it is planned.
Partial in v0.1.0-rc.1cryptos-node/internal/reset/reset.gocryptos-node/internal/reset/reset_test.go (TestWipeEmptyRootCNFailsClosed)Open: cryptos-node#361 Require M-of-N quorum plus holder codes for a factory reset

5. FleetOS Manager and the fleet

FleetOS Manager is a Go service with the web console built in, on one HTTPS listener. Operators sign in with a client certificate from your own operator CA. The manager connects out to each node over mTLS on port 443 with that node's admin credential; nodes never call the manager.

FleetOS Manager and the fleetYour sideOperator CAyours, outside the fleetsigns operator certificatesOperatorsbrowser or cryptos-managerctlclient cert: viewer, operator, adminStorage you runPostgreSQL, or Valkey/Redis,or memory for a trialFleetOS Manager: holds no CA keyConsole and fleet APIone HTTPS listenerclient certificate checked per requestApprovalscertificate requests, link andsubordinate requests, agent step-upsInventory and auditevery node's certificateshash-chained audit logNode credentialseach node's admin credentialminted on adoption: P-256, clientAuthCarries, never signsCSRs to the node that holds the CA,signed certificates backThe fleetFresh node, in maintenanceadopt: an admin confirms its fingerprint, the managerinstalls, then confirms the Mgmt SHA-256 on its consoleRunning node, link requestedPENDING: the node signed a challenge with its CA keyand its key is pinned; waits for an adminRoot CA nodemanagedoperator surface read-onlyIssuing CA nodemanagedoperator surface read-onlyEach node keeps its own stateetcd and the CA key stay on the node,which keeps working without the managerLeaving the fleetdecommission wipes the node; remove only forgets itsignsmTLS :443, the manager dials outadmin approves
Figure 4. FleetOS Manager and the fleet. A fresh node is adopted once an admin confirms its fingerprint; a running node's link waits as pending until an admin approves it. The manager carries requests to the node that holds the CA and signs nothing for it.
Adopt a fresh node
  1. An admin points the manager at a node in maintenance mode and confirms the certificate fingerprint it presents.
  2. The manager mints a P-256 clientAuth admin credential for the node and installs CryptOS to the disk the node reports.
  3. After the reboot the adoption pauses until an admin matches the new management certificate against the Mgmt SHA-256 line on the node's console.
  4. The manager runs the first-boot ceremony and registers the node.
Link a running node
  1. An operator supplies the node's address, an admin credential and the CA its management certificate chains to.
  2. The manager refuses the node unless its certificate verifies, then has it sign a random challenge (SHA-384) with its CA key and pins that key.
  3. The link is recorded as PENDING.
  4. An admin approves; the manager checks the node against the pin again, and the node's own operator surface becomes read-only.
Storage modeSettingPersists
PostgreSQLdatabase_urlYes
Valkey or Redis (next release)storage.mode: kvYes, with AOF; refuses to start without persistence
Memorystorage.mode: memoryNo; one replica, health reports degraded

Controls: FleetOS Manager

ControlStatusEvidence
FLT-1 The manager holds no CA key
Certificates are issued and revoked on the node that holds the CA. The manager carries CSRs and signed certificates; the only certificates it makes are its own first-run TLS certificate and each node's admin credential.
Implemented in v0.1.0-rc.1cryptos-manager/internal/fleet/certs.gocryptos-manager/internal/fleet/adopt_bootstrap.gocryptos-manager/cmd/manager/selfsigned.go
FLT-2 A node is pinned before it is trusted
Adoption pauses until an admin confirms the node's certificate fingerprint against its console. A link request pins the node's CA key from a signed challenge and waits as pending until an admin approves it.
Implemented in v0.1.0-rc.1cryptos-manager/internal/fleet/enrollment.gocryptos-manager/internal/fleet/attest.gocryptos-manager/docs/node-trust.md
FLT-3 Both sides verify every connection
The node accepts only the admin credential the manager made for it, and the manager accepts only the node certificate it recorded. A node it can't verify is refused.
Implemented in v0.1.0-rc.1cryptos-manager/internal/nodeclient/servertrust.gocryptos-manager/docs/node-trust.md
FLT-4 Pending-link until managed credentials exist
Marking an adopted node pending-link until its managed credentials are provisioned isn't built.
PlannedOpen: cryptos-manager#54 Mark adopted nodes pending-link until managed credentials are provisioned
FLT-5 A minimal, non-root manager image
The manager image is distroless, runs as a non-root user, and its base images are pinned by digest.
Implemented in v0.1.0-rc.1cryptos-manager/Dockerfile

Controls: Identity, access and approvals

ControlStatusEvidence
ACC-1 One pinned admin per node
A node trusts exactly one admin certificate, pinned in its machine config. There are no roles or accounts on the node itself.
Implemented in v0.1.0-rc.1cryptos-node/internal/bootstrap/bootstrap.gocryptos-node/internal/grpc/authz.go
ACC-2 Certificate-based roles in FleetOS Manager
Operators sign in with a client certificate from your own operator CA. Viewer, operator and admin levels travel in the certificate. No passwords are stored.
Implemented in v0.1.0-rc.1cryptos-manager/internal/authz/level.gocryptos-manager/internal/authz/level_test.go (TestLevelFromCertificate)cryptos-manager/docs/operator-ca.md
ACC-3 Operator certificates are re-checked for revocation
Every request re-checks the operator's certificate against the manager's denylist, the CA's CRL and, where set, its OCSP responder.
Implemented in v0.1.0-rc.1cryptos-manager/internal/operatorca/crl.gocryptos-manager/internal/operatorca/ocsp.go
ACC-4 No self-approval
Certificate requests wait for an operator or admin, the requester can't approve their own, and both identities are audited.
Implemented in v0.1.0-rc.1cryptos-manager/internal/approval/approval.go (ErrSelfApproval)website/apps/docs/docs/fleet-manager/approvals.md
ACC-5 Agents go through the same checks
AI agents on the optional MCP endpoint get keys through an OAuth login that needs the operator's client certificate, and sensitive tools need a person's step-up approval.
Implemented in v0.1.0-rc.1cryptos-manager/internal/mcpserver/stepup.gocryptos-manager/docs/mcp.md

6. Audit, availability and recovery

Each node keeps a SHA-256 hash-chained audit log, signed with a key kept apart from the CA key, which cryptosctl can verify. FleetOS Manager keeps its own hash-chained log with the acting operator and any approver.

A node is a single machine today. A TPM-held CA key can't leave the TPM, so it can't be escrowed; losing that node's TPM loses that CA. Software keys can be escrowed in a passphrase envelope. An encrypted backup of a node's state and export of the audit log to a SIEM are planned, and pairs with failover and split-custody recovery are on the roadmap.

Controls: Audit trail

ControlStatusEvidence
AUD-1 Signed, hash-chained node audit log
Every node operation is appended to a SHA-256 hash chain, signed with a key kept apart from the CA key, on the encrypted partition.
Implemented in v0.1.0-rc.1cryptos-node/internal/audit/doc.gocryptos-node/internal/audit/audit_test.go (TestVerifyChain_DetectsSignatureTamper)website/apps/docs/docs/deep-dives/audit-integrity.md
AUD-2 Operators can verify the log
cryptosctl lists the audit log and verifies its chain and signatures.
Implemented in v0.1.0-rc.1cryptos-node/cmd/cryptosctl/audit.gowebsite/apps/docs/docs/using/audit-log.md
AUD-3 Hash-chained manager audit log
FleetOS Manager records every change with the acting operator, and the approval and approver where there is one, in a hash chain.
Implemented in v0.1.0-rc.1cryptos-manager/internal/auditlog/auditlog.go
AUD-4 Audit retention with a signed checkpoint
The node log grows without a retention policy today. Trimming it behind a signed checkpoint isn't built.
PlannedOpen: cryptos-node#327 Audit retention with a signed checkpoint
AUD-5 Audit export to a SIEM
Each node keeps its own signed, hash-chained log, which cryptosctl reads and verifies on the node. Shipping it to a SIEM isn't built.
PlannedOpen: cryptos-node#408 Export the audit log to a SIEM

Controls: Availability and recovery

ControlStatusEvidence
REC-1 CA key escrow for software keys
A software CA key can be exported and imported in a passphrase envelope (Argon2id and AES-256-GCM). A TPM key can't be exported, so it can't be escrowed.
Partial in v0.1.0-rc.1cryptos-node/internal/backup/doc.gocryptos-node/internal/init/escrow.go
REC-2 Two-node pairs with failover
Active and passive pairs with a shared address and lease-gated signing aren't built.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.md (Phase 3: high-availability pairs)
REC-3 Split custody for Root recovery
Recovering a Root through split custody (for example Shamir shares or smart cards) isn't built.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.md (Phase 3: disaster recovery)
REC-4 A changed boot chain means a rebuild
In TPM mode, if the PCR values drift outside an upgrade the state disk can't be unsealed and the node must be set up again. This is a stated limit, not a recovery path.
Partial in v0.1.0-rc.1cryptos-node/internal/init/statekey.go
REC-5 Encrypted backup of node state
There is no backup of a node's etcd state today; only a software CA key can be escrowed (REC-1). An encrypted snapshot and restore isn't built.
PlannedOpen: cryptos-node#407 Encrypted backup and restore of a node's etcd state

7. Supply chain and development

Release images are built twice and compared byte for byte, and ship with SHA256SUMS and a build manifest. They ship unsigned on purpose: you sign the UKI with your own Secure Boot key, so no project key sits in your chain of trust.

Every change goes through a pull request with CI: Go formatting, lint, vet and tests with a software TPM, interop tests against standard clients, and secret scanning. Scanning for known vulnerabilities with govulncheck and gosec is planned.

Controls: Supply chain and development

ControlStatusEvidence
SUP-1 Reproducible release images
The release pipeline builds the image twice and compares the outputs byte for byte. Releases carry SHA256SUMS and a build manifest.
Implemented in v0.1.0-rc.1cryptos-appliance/build/release/reproducible.shcryptos-appliance/docs/release.md
SUP-2 No project signature on releases
The project doesn't sign the images you boot. You verify the checksums and sign with your own key (APP-2).
Why: A project key in your boot chain would make the project a party to your trust. You hold the keys, not us.
Not plannedcryptos-appliance/docs/secure-boot.md
SUP-3 SBOM and build provenance
Release images carry no SBOM or provenance attestation; the image build sets them off.
Why: Reproducible builds and published checksums are the check today; an SBOM isn't scheduled.
Not plannedcryptos-manager/.github/workflows/job-release-image.yaml
SUP-4 Secret scanning
Gitleaks runs in CI on every code repository.
Implemented in v0.1.0-rc.1cryptos-node/.github/workflows/job-gitleaks.yamlcryptos-appliance/.github/workflows/job-gitleaks.yaml
SUP-5 Tests gate every change
Go code is formatted, linted, vetted and tested in CI, with a software TPM and interop tests, before it can merge.
Implemented in v0.1.0-rc.1cryptos-node/.github/workflows/ci-go.yml
SUP-6 Pinned CI actions
Third-party GitHub Actions are pinned by commit SHA. A few org and tool references still float.
Partialcryptos-node/.github/workflows/ci-go.yml
SUP-7 Standard library crypto on the certificate path
Key generation, signing and X.509 use only the Go standard library and golang.org/x/crypto. It is a written rule; no linter enforces it yet.
Partial in v0.1.0-rc.1cryptos-node/internal/ca/doc.go
SUP-8 Private vulnerability reporting
Vulnerabilities are reported privately through GitHub security advisories; the latest 0.x release gets fixes.
Implemented.github/SECURITY.md
SUP-9 Vulnerability scanning in CI
CI scans for secrets and runs the linters and tests, but no workflow checks for known vulnerabilities with govulncheck or runs gosec yet.
PlannedOpen: cryptos-node#406 Run govulncheck and gosec in the Go repos' CI

Gaps and planned work

Every control that is partial or planned, with the open issue or roadmap entry that tracks it. Nothing here is promised for a date.

ControlStatusEvidence
KEY-5 Software key modes are labelled as such
The nodeid (development) and kms modes keep the CA key in software on the encrypted partition, not in the TPM, and the code and docs say so plainly.
Partial in v0.1.0-rc.1cryptos-node/internal/init/softroot.gocryptos-node/internal/config/config.go
KEY-6 No network HSM for CA keys
CA keys live only in the node's own TPM; a network HSM or PKCS#11 device for CA keys is out of scope. The kms mode wraps only the state disk's key with an external KMS. Saying so plainly in the docs is planned.
PlannedOpen: website#42 Say that CA keys stay in the TPM and a network HSM is out of scope
CER-3 M-of-N quorum for Root operations
Ceremonies are one person today. Requiring M of N key holders for Root operations isn't built.
PlannedOpen: cryptos-node#371 Build M-of-N quorum ceremonies
CER-4 Guarded factory reset
A reset needs the Root CA name typed back, compared in constant time, and fails closed. A quorum and one-time-code gate on top of it is planned.
Partial in v0.1.0-rc.1cryptos-node/internal/reset/reset.gocryptos-node/internal/reset/reset_test.go (TestWipeEmptyRootCNFailsClosed)Open: cryptos-node#361 Require M-of-N quorum plus holder codes for a factory reset
ISS-5 ACME (RFC 8555)
ACME with http-01 and External Account Binding, and a strict JWS algorithm allow-list. dns-01, wildcards, key change and account deactivation aren't built.
Partial in v0.1.0-rc.1cryptos-node/internal/acme/doc.gocryptos-node/internal/acme/jws_test.go (TestVerifyJWSAlgorithmConfusion)Open: cryptos-node#110 ACME HTTP-01/DNS-01 for cert-manager and native clients
ISS-10 Windows autoenrolment (MS-XCEP and WSTEP)
Native Windows autoenrolment through Group Policy isn't built.
PlannedOpen: cryptos-node#108 Native Windows autoenrolment via GPO (MS-XCEP/WSTEP)
AUD-4 Audit retention with a signed checkpoint
The node log grows without a retention policy today. Trimming it behind a signed checkpoint isn't built.
PlannedOpen: cryptos-node#327 Audit retention with a signed checkpoint
AUD-5 Audit export to a SIEM
Each node keeps its own signed, hash-chained log, which cryptosctl reads and verifies on the node. Shipping it to a SIEM isn't built.
PlannedOpen: cryptos-node#408 Export the audit log to a SIEM
APP-4 Remote attestation
Measured boot gates the state disk (KEY-2). A node proves its identity by signing a challenge with its CA key; a TPM quote of its boot measurements isn't offered yet.
Partial in v0.1.0-rc.1cryptos-node/internal/grpc/attest.go
APP-6 More platforms
Node images are amd64 for VMware today. Proxmox VE, bare-metal installs and an arm64 image are in progress.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.mdOpen: cryptos-appliance#38 Support Proxmox VE as a VM platformOpen: cryptos-appliance#54 A plain installer ISO for bare-metal serversOpen: cryptos-appliance#117 Build and prove an arm64 appliance image
FLT-4 Pending-link until managed credentials exist
Marking an adopted node pending-link until its managed credentials are provisioned isn't built.
PlannedOpen: cryptos-manager#54 Mark adopted nodes pending-link until managed credentials are provisioned
REC-1 CA key escrow for software keys
A software CA key can be exported and imported in a passphrase envelope (Argon2id and AES-256-GCM). A TPM key can't be exported, so it can't be escrowed.
Partial in v0.1.0-rc.1cryptos-node/internal/backup/doc.gocryptos-node/internal/init/escrow.go
REC-2 Two-node pairs with failover
Active and passive pairs with a shared address and lease-gated signing aren't built.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.md (Phase 3: high-availability pairs)
REC-3 Split custody for Root recovery
Recovering a Root through split custody (for example Shamir shares or smart cards) isn't built.
Plannedwebsite/apps/docs/docs/introduction/status-roadmap.md (Phase 3: disaster recovery)
REC-4 A changed boot chain means a rebuild
In TPM mode, if the PCR values drift outside an upgrade the state disk can't be unsealed and the node must be set up again. This is a stated limit, not a recovery path.
Partial in v0.1.0-rc.1cryptos-node/internal/init/statekey.go
REC-5 Encrypted backup of node state
There is no backup of a node's etcd state today; only a software CA key can be escrowed (REC-1). An encrypted snapshot and restore isn't built.
PlannedOpen: cryptos-node#407 Encrypted backup and restore of a node's etcd state
SUP-6 Pinned CI actions
Third-party GitHub Actions are pinned by commit SHA. A few org and tool references still float.
Partialcryptos-node/.github/workflows/ci-go.yml
SUP-7 Standard library crypto on the certificate path
Key generation, signing and X.509 use only the Go standard library and golang.org/x/crypto. It is a written rule; no linter enforces it yet.
Partial in v0.1.0-rc.1cryptos-node/internal/ca/doc.go
SUP-9 Vulnerability scanning in CI
CI scans for secrets and runs the linters and tests, but no workflow checks for known vulnerabilities with govulncheck or runs gosec yet.
PlannedOpen: cryptos-node#406 Run govulncheck and gosec in the Go repos' CI

Left out on purpose

What CryptOS leaves out on purpose, and why. These aren't gaps waiting for a fix.

ControlStatusEvidence
ARC-5 No web interface in the OS image
The node serves no web front end, compiled or otherwise. A web console exists only in FleetOS Manager, which runs off the node.
Why: Every web stack on the CA is more code that could be attacked. Nodes stay API-only by design.
Not plannedcryptos-node/README.md
ARC-6 No cross-signing between Roots
Each Root is its own trust domain. CryptOS doesn't cross-sign one Root with another.
Why: Siloed Roots keep a compromise of one hierarchy from reaching another. It stays out until a real need appears.
Not plannedwebsite/apps/docs/docs/concepts/ca-roles.md
SUP-2 No project signature on releases
The project doesn't sign the images you boot. You verify the checksums and sign with your own key (APP-2).
Why: A project key in your boot chain would make the project a party to your trust. You hold the keys, not us.
Not plannedcryptos-appliance/docs/secure-boot.md
SUP-3 SBOM and build provenance
Release images carry no SBOM or provenance attestation; the image build sets them off.
Why: Reproducible builds and published checksums are the check today; an SBOM isn't scheduled.
Not plannedcryptos-manager/.github/workflows/job-release-image.yaml