localtls

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 15, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

Local TLS

Machine-scoped TLS material lifecycle for localhost HTTPS on Windows.

local-tls owns the creation, persistence, verification, renewal, and exact cleanup of the TLS material used to serve localhost HTTPS on Windows. Its centerpiece is a self-signed local CA certificate and a CA-signed localhost server certificate, backed by machine-scoped CNG/KSP signing keys whose private material never leaves Windows CNG.

Scope

  • A Local TLS-owned self-signed CA certificate and a CA-signed localhost server certificate (ECDSA P-256).
  • Machine-scoped persisted CA and server signing keys via Windows CNG/KSP (Microsoft Software Key Storage Provider); private keys are non-exportable.
  • Persistence of public certificate DER only on the production machine (CNG) path — private keys stay in CNG.
  • Installation, verification, and exact removal of the local CA trust anchor in LocalMachine\Root.
  • Fail-closed provisioning, serving-startup, reload/renewal, and cleanup flows.

Non-goals

local-tls is not a general-purpose TLS/PKI framework, a certificate manager, or a trust-store framework. It does not own enterprise CA enrollment, enterprise-vs-local selection policy, low-level reusable CNG/KSP key custody, the long-lived HTTPS listener runtime, or unrelated application state.

Quick start

import "github.com/keppin-oss/local-tls"

The package is named localtls. Machine provisioning is performed once (elevated); ordinary HTTPS serving startup uses LoadServingMaterial. Complete compile-safe examples live under examples/:

Resources

Documentation

Index

Constants

View Source
const (

	// RenewalThreshold is how close to expiry we renew the server certificate.
	RenewalThreshold = 30 * 24 * time.Hour
)

Variables

View Source
var ErrKeyNotFound = errors.New("persisted CNG key not found")

ErrKeyNotFound indicates that the exact persisted CNG key does not exist. Cleanup treats this as an idempotent success, not a failure.

View Source
var ErrTrustAnchorNotFound = errors.New("trust anchor certificate not found in LocalMachine\\Root")

ErrTrustAnchorNotFound indicates that the exact CA trust anchor is not present in the machine trust store (i.e. it is already absent). Cleanup treats this as an idempotent success, not a failure.

Functions

func CleanupMachine

func CleanupMachine() error

CleanupMachine is not supported on non-Windows platforms.

func CleanupMachineBySHA256

func CleanupMachineBySHA256(fp [32]byte) error

CleanupMachineBySHA256 is not supported on non-Windows platforms.

func ComputeSHA256Fingerprint

func ComputeSHA256Fingerprint(der []byte) [32]byte

ComputeSHA256Fingerprint returns the SHA-256 fingerprint of a DER certificate.

func MachineAgentPath

func MachineAgentPath() (string, error)

MachineAgentPath returns an error on non-Windows platforms because machine-scoped state at %ProgramData% is a Windows-only concept.

func MachineTLSPath

func MachineTLSPath() (string, error)

MachineTLSPath returns an error on non-Windows platforms.

func ParseSHA256Fingerprint

func ParseSHA256Fingerprint(hexFP string) ([32]byte, error)

ParseSHA256Fingerprint parses a 64-character hex SHA-256 fingerprint into a [32]byte. It accepts surrounding whitespace and is case-insensitive.

Types

type MachineKeyDeleter

type MachineKeyDeleter interface {
	// DeleteCAKey deletes the exact persisted Local-TLS CA key.
	// Returns ErrKeyNotFound when the key does not exist.
	DeleteCAKey() error

	// DeleteServerKey deletes the exact persisted Local-TLS server key.
	// Returns ErrKeyNotFound when the key does not exist.
	DeleteServerKey() error
}

MachineKeyDeleter deletes exactly the Local-TLS-owned persisted machine keys. It must never delete keys that are not owned by this module, and it deletes only by exact persisted key name — never by wildcard or CN.

func PlatformKeyDeleter

func PlatformKeyDeleter() (MachineKeyDeleter, error)

PlatformKeyDeleter returns the platform-appropriate MachineKeyDeleter. On Windows this deletes the exact persisted CNG keys via the Microsoft Software Key Storage Provider. On other platforms it returns an error.

type MachineKeyStore

type MachineKeyStore interface {
	// LoadOrCreateCAKey returns a signer for the local TLS CA key.
	// If the key does not exist it is created as a persistent,
	// non-exportable machine-scoped key.
	LoadOrCreateCAKey() (crypto.Signer, error)

	// LoadOrCreateServerKey returns a signer for the local TLS server key.
	// If the key does not exist it is created as a persistent,
	// non-exportable machine-scoped key.
	LoadOrCreateServerKey() (crypto.Signer, error)
}

MachineKeyStore provides machine-scoped persistent signing keys. On Windows this is backed by CNG/KSP; on other platforms it is unsupported.

The production implementation never returns private-key bytes. Keys are identified by stable names and persist across process restarts.

func PlatformKeyStore

func PlatformKeyStore() (MachineKeyStore, error)

PlatformKeyStore returns the platform-appropriate MachineKeyStore. On Windows this uses CNG/KSP with the Microsoft Software Key Storage Provider. On other platforms it returns an error — machine-scoped key storage is not supported outside Windows.

type Material

type Material struct {
	Certificate         tls.Certificate
	CACertificate       *x509.Certificate
	ServerCertificate   *x509.Certificate
	CAFingerprintSHA256 [32]byte
}

Material contains the provisioned local TLS material.

func LoadServingMaterial

func LoadServingMaterial() (Material, error)

LoadServingMaterial is not supported on non-Windows platforms.

func Provision

func Provision(dataDir string, protector Protector, trustStore TrustStore, now func() time.Time) (Material, error)

Provision provisions local TLS using a Protector. This is kept for backwards-compatible tests that use exported private keys.

func ProvisionMachine

func ProvisionMachine() (Material, error)

ProvisionMachine is not supported on non-Windows platforms.

func ProvisionWithKeyStore

func ProvisionWithKeyStore(dataDir string, keyStore MachineKeyStore, trustStore TrustStore, now func() time.Time) (Material, error)

ProvisionWithKeyStore provisions local TLS using a MachineKeyStore for persistent signing keys. Only public certificate DERs are written to disk; private keys remain in the machine-scoped key store.

func ReloadMachine

func ReloadMachine() (Material, error)

ReloadMachine is not supported on non-Windows platforms.

func (*Material) Close

func (m *Material) Close() error

Close releases the process-local native CNG handle backing the serving signer. It never deletes the persisted CNG key, never removes certificates or trust anchors, and never triggers CleanupMachine or CleanupMachineBySHA256. Lifecycle release is distinct from persisted-key deletion and from Local TLS uninstall/cleanup.

Close is safe to call after a successful production machine operation. It is idempotent in effect: the underlying CNG signer's Close is safe to call repeatedly and reports no error. After Close, the serving certificate must not be used for new TLS handshakes.

Material is single-owner: do not copy it by value and then reuse the copy after Close, since both copies reference the same underlying signer.

type Protector

type Protector interface {
	Protect(plaintext []byte) ([]byte, error)
	Unprotect(ciphertext []byte) ([]byte, error)
}

Protector transforms sensitive material for at-rest persistence on the legacy exported-key provisioning path. The production machine path does not use Protector: it keeps private keys in CNG/KSP and persists only public certificate DER. Protector is a seam — this package does not define which implementation (if any) actually encrypts the bytes it receives.

func PlatformProtector

func PlatformProtector() (Protector, error)

PlatformProtector returns the platform-appropriate Protector. Machine-scoped key protection is not configured: the production machine path uses CNG/KSP key custody rather than the protector-based path, so this function returns an error.

type TrustProvisioner

type TrustProvisioner interface {
	// InstallTrust installs the CA certificate DER into the machine
	// trust store. It is idempotent: if the exact same certificate
	// (matched by SHA-256 fingerprint) already exists, the call
	// succeeds without creating a duplicate.
	InstallTrust(certificateDER []byte) error

	// RemoveTrust removes the exact CA certificate identified by DER
	// from the machine trust store. Only the exact certificate
	// (matched by SHA-256 fingerprint) is removed.
	// Returns ErrTrustAnchorNotFound when the certificate is not present.
	RemoveTrust(certificateDER []byte) error

	// RemoveTrustBySHA256 removes the exact CA certificate identified by
	// its SHA-256 fingerprint from the machine trust store. This is used
	// when the original DER is no longer available (e.g. the state
	// directory was already removed).
	//
	// Removal is by exact 32-byte SHA-256 identity only; no subject/CN
	// matching is performed. Returns ErrTrustAnchorNotFound when the
	// certificate is not present.
	RemoveTrustBySHA256(fp [32]byte) error
}

TrustProvisioner performs elevated certificate trust operations. Mutating operations MUST only be called from an elevated context (installer, provisioning, repair). Normal runtime MUST NOT use this.

type TrustState

type TrustState int

TrustState describes the result of a runtime trust verification.

const (
	// TrustHealthy means the expected CA certificate is present exactly once
	// in the machine trust store.
	TrustHealthy TrustState = iota

	// TrustAbsent means the expected CA certificate is not present in the
	// machine trust store. Repair (elevated provisioning) is required.
	TrustAbsent

	// TrustConflict means a certificate with a matching subject name but a
	// different fingerprint exists. Manual resolution is required.
	TrustConflict

	// TrustError means the verification itself failed (store access, etc.).
	TrustError
)

func (TrustState) String

func (s TrustState) String() string

String returns a human-readable representation of the trust state.

type TrustStore

type TrustStore interface {
	TrustProvisioner
	TrustVerifier

	// EnsureTrusted installs the CA certificate DER into the trust store
	// if it is not already present.
	// Deprecated: use TrustProvisioner.InstallTrust for elevated operations,
	// and TrustVerifier.VerifyTrust for runtime checks.
	EnsureTrusted(certificateDER []byte) error
}

TrustStore is the combined interface for backward compatibility. New code should use TrustProvisioner and TrustVerifier separately.

func PlatformTrustStore

func PlatformTrustStore() (TrustStore, error)

PlatformTrustStore returns the platform-appropriate TrustStore. Machine-scoped trust deployment targets LocalMachine\Root on Windows.

type TrustVerifier

type TrustVerifier interface {
	// VerifyTrust checks whether the given CA certificate DER is
	// trusted in the machine trust store. It returns the trust state
	// and, when TrustError, an error describing the failure.
	VerifyTrust(certificateDER []byte) (TrustState, error)

	// IsTrustedSHA256 reports whether a certificate with the given
	// SHA-256 fingerprint is present in the trust store.
	IsTrustedSHA256(fingerprint [32]byte) (bool, error)
}

TrustVerifier performs read-only trust verification. It is safe for normal (non-elevated) runtime use.

Directories

Path Synopsis
cmd
verify command
Command verify performs manual verification for the Local TLS module.
Command verify performs manual verification for the Local TLS module.
examples
fingerprint command
Command fingerprint demonstrates the non-destructive fingerprint / cleanup handoff utilities of Local TLS.
Command fingerprint demonstrates the non-destructive fingerprint / cleanup handoff utilities of Local TLS.
provision command
Command provision demonstrates the elevated first-install/repair flow using ProvisionMachine.
Command provision demonstrates the elevated first-install/repair flow using ProvisionMachine.
serving command
Command serving demonstrates the preferred production HTTPS serving startup flow using LoadServingMaterial.
Command serving demonstrates the preferred production HTTPS serving startup flow using LoadServingMaterial.
internal
identity
Package identity centralises the product-branding constants used by the Local TLS module.
Package identity centralises the product-branding constants used by the Local TLS module.

Jump to

Keyboard shortcuts

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