ca

package
v1.0.126 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package ca implements Culvert's SSL-inspection Root CA — the MITM trust core (ADR-0002 extraction; engine was ca.go in package main). It owns the Root CA lifecycle (in-memory init, encrypted-bundle load/save, custom-CA import), on-the-fly leaf-cert signing with an LRU+TTL cache, dual-CA rotation with an overlap window, and the pluggable KeyProvider (HSM/KMS) seam.

The encrypted-bundle wire format is FROZEN: `caMagic` ("PSCA"), `caVersion`, and the PBKDF2-600k + AES-256-GCM layout are read from bundles already on operators' disks — changing any of them breaks load. See encryptBundle.

Observability crosses the boundary via publish-once package-level hooks (SignLatencyObserver, RotationObserver), wired once by package main to its Prometheus histogram / alert store / rotation counter — the obs/fileutil injection pattern (ADR-0003), so the engine never imports main. The auto-rotation LOOP (StartCAAutoRotation) and the cluster CA stay in main; this package exposes the per-tick primitives (RotateIfNeeded, CleanupSecondaryCA) the loop drives.

Index

Constants

View Source
const (
	CacheTTL      = certCacheTTL
	CacheMaxSize  = certCacheMaxSize
	BundleVersion = caVersion
)

Exported mirrors of internal tuning constants, for tests that assert cache behavior at the real bounds.

View Source
const RotationCheckInterval = caRotationCheckInterval

RotationCheckInterval is how often main's auto-rotation loop should tick.

Variables

View Source
var CAChangedObserver func()

CAChangedObserver is invoked (with mu NOT held) whenever the active Root CA key/cert changes at runtime — InitCA (fresh generation, incl. the manual force-rotate API and the InitCA inside RotateIfNeeded) and LoadCustomCA (admin-uploaded CA). Publish-once: package main wires it to flush the client-facing MITM session-ticket keys so a TLS 1.3 client cannot RESUME a session authenticated under the previous CA (the PSK path never re-runs GetCertificate). nil ⇒ no-op. Startup-time calls are harmless (no sessions exist yet). This is intentionally distinct from RotationObserver, which is dual-CA-overlap-specific and does not fire on InitCA/LoadCustomCA.

View Source
var RotationObserver func(oldExpiry, newExpiry time.Time)

RotationObserver is invoked after a successful RotateIfNeeded with the old and new CA expiry times when set. Publish-once: package main wires it to fire the cert-rotation alert and bump the rotation counter. nil ⇒ no-op.

View Source
var SignLatencyObserver func(seconds float64)

SignLatencyObserver receives each successful leaf-sign's latency in seconds when set. Publish-once: package main wires it to its Prometheus histogram at startup. nil ⇒ no-op (the engine never depends on metrics wiring).

Functions

func DecryptBundle

func DecryptBundle(data, passphrase []byte) ([]byte, error)

DecryptBundle opens a PSCA envelope produced by EncryptBundle, validating the magic, version, and minimum iteration count before AES-256-GCM decrypt. It returns a generic error on any failure without disclosing key material.

func EncryptBundle

func EncryptBundle(plaintext, passphrase []byte) ([]byte, error)

EncryptBundle seals plaintext into a PSCA envelope: a magic+version header, PBKDF2-SHA256 (600k iterations) key derivation over a random salt, and AES-256-GCM with a random nonce. The layout is FROZEN (see the package doc).

func HasBundleMagic

func HasBundleMagic(data []byte) bool

HasBundleMagic reports whether data begins with the PSCA envelope magic (i.e. is an encrypted bundle rather than plain PEM).

func Magic

func Magic() []byte

Magic returns a copy of the PSCA bundle magic header bytes.

Types

type KeyProvider

type KeyProvider interface {
	// SignCertificate creates and signs a certificate using the provider's key.
	SignCertificate(template, parent *x509.Certificate, pubKey any) ([]byte, error)
	// PublicKey returns the public key corresponding to the signing key.
	PublicKey() any
	// Name returns a human-readable provider name (e.g. "local", "aws-kms").
	Name() string
}

KeyProvider signs certificate data using an externally managed private key.

func NewLocalKeyProvider

func NewLocalKeyProvider(key *ecdsa.PrivateKey) KeyProvider

NewLocalKeyProvider returns the default in-memory KeyProvider backed by key.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages the Root CA used for SSL inspection (MITM). It generates leaf certificates on-the-fly and caches them with LRU eviction at certCacheMaxSize entries and TTL of certCacheTTL.

func New

func New() *Manager

New returns a ready-to-use Manager with an initialised (empty) leaf cache. Call InitCA / LoadOrInitCA / LoadCustomCA to install a Root CA.

func (*Manager) AgeCacheEntryForTest

func (cm *Manager) AgeCacheEntryForTest(host string, createdAt time.Time) bool

AgeCacheEntryForTest back-dates an existing entry's creation time (past the TTL when the delta exceeds certCacheTTL), for cache-expiry tests.

func (*Manager) CACertForTest

func (cm *Manager) CACertForTest() *x509.Certificate

CACertForTest returns the current Root CA certificate (nil if unset).

func (*Manager) CACertInfo

func (cm *Manager) CACertInfo() map[string]any

CACertInfo returns metadata about the current Root CA for the UI dashboard.

func (*Manager) CACertPEM

func (cm *Manager) CACertPEM() []byte

CACertPEM returns the Root CA certificate encoded as PEM (for browser import).

func (*Manager) CAExpiry

func (cm *Manager) CAExpiry() time.Time

CAExpiry returns the CA certificate NotAfter time, or zero if CA is not ready.

func (*Manager) CacheStats

func (cm *Manager) CacheStats() (hits, misses int64, size int)

CacheStats returns (hits, misses, currentSize) for the leaf-cert cache (CA-2). Hits/misses are lock-free atomics; size is read under the cache lock.

func (*Manager) CertCacheLen

func (cm *Manager) CertCacheLen() int

CertCacheLen returns the current number of cached leaf certificates (testing).

func (*Manager) CleanupSecondaryCA

func (cm *Manager) CleanupSecondaryCA()

CleanupSecondaryCA removes the secondary CA when its overlap window expires. Driven per-tick by main's StartCAAutoRotation loop.

func (*Manager) ClearCache

func (cm *Manager) ClearCache()

ClearCache removes all cached leaf certificates.

func (*Manager) GetCert

func (cm *Manager) GetCert(hello *tls.ClientHelloInfo) (*tls.Certificate, error)

GetCert is a tls.Config.GetCertificate callback that returns a dynamically signed certificate for the requested ServerName. Results are cached with TTL-based expiry and LRU eviction at certCacheMaxSize entries.

func (*Manager) HasKeyProviderForTest

func (cm *Manager) HasKeyProviderForTest() bool

HasKeyProviderForTest reports whether a key provider has been installed.

func (*Manager) ImportBundle

func (cm *Manager) ImportBundle(data []byte) error

ImportBundle parses a PEM bundle (CERTIFICATE + EC PRIVATE KEY blocks) and installs the CA into the Manager, clearing the leaf cache.

func (*Manager) InitCA

func (cm *Manager) InitCA() error

InitCA generates a fresh in-memory Root CA key pair. Call once at startup when no persisted CA is available.

func (*Manager) KeyProviderName

func (cm *Manager) KeyProviderName() string

KeyProviderName returns the name of the active key provider.

func (*Manager) LoadCA

func (cm *Manager) LoadCA(path, passphrase string) error

LoadCA reads and decrypts a CA bundle previously written by SaveCA. If passphrase is empty the file is treated as plain PEM.

func (*Manager) LoadCustomCA

func (cm *Manager) LoadCustomCA(certPEM, keyPEM []byte) error

LoadCustomCA loads a PEM-encoded CA certificate and private key supplied by the user (e.g. an enterprise intermediate CA). Private key is never stored in cleartext memory beyond the parsing step.

func (*Manager) LoadOrInitCA

func (cm *Manager) LoadOrInitCA(path, passphrase string) error

LoadOrInitCA loads an existing CA bundle from path (decrypting with passphrase) or, if the file does not exist, generates a fresh CA and saves it. An empty passphrase disables encryption (development/testing only).

The env var CULVERT_CA_PASSPHRASE is the recommended way to supply the passphrase so it never appears in CLI history or process listings.

func (*Manager) ParseTLSPair

func (cm *Manager) ParseTLSPair(certPEM, keyPEM []byte) (*tls.Certificate, error)

ParseTLSPair validates a PEM cert+key pair without storing it.

func (*Manager) Ready

func (cm *Manager) Ready() bool

Ready returns true once the Root CA has been initialised.

func (*Manager) RotateIfNeeded

func (cm *Manager) RotateIfNeeded(caPath, passphrase string) bool

RotateIfNeeded checks whether the CA cert is nearing expiry and generates a new one with dual-CA overlap: the old CA is kept as secondary for the remaining lifetime of its certificate, so leaf certs signed by either CA remain valid during the transition. Returns true if rotation occurred.

func (*Manager) SaveCA

func (cm *Manager) SaveCA(path, passphrase string) error

SaveCA encrypts (AES-256-GCM, key derived via PBKDF2-SHA256) and writes the current Root CA key+cert to path. If passphrase is empty the bundle is written in plain PEM — only suitable for development/testing environments.

func (*Manager) SecondaryCAActive

func (cm *Manager) SecondaryCAActive() bool

SecondaryCAActive returns whether a secondary (old) CA is still in the overlap window.

func (*Manager) SecondaryCAInfo

func (cm *Manager) SecondaryCAInfo() map[string]any

SecondaryCAInfo returns info about the secondary CA, or nil if inactive.

func (*Manager) SeedCacheEntryForTest

func (cm *Manager) SeedCacheEntryForTest(host string, cert *tls.Certificate, createdAt time.Time)

SeedCacheEntryForTest inserts a leaf-cache entry with an explicit creation time so cache TTL / LRU-eviction behavior can be exercised deterministically.

func (*Manager) SetCAForTest

func (cm *Manager) SetCAForTest(cert *x509.Certificate, key *ecdsa.PrivateKey)

SetCAForTest installs a Root CA cert+key directly, bypassing generation.

func (*Manager) SetKeyProvider

func (cm *Manager) SetKeyProvider(kp KeyProvider)

SetKeyProvider allows an external key provider (HSM/KMS) to be registered.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL