hardware

package
v0.2.2-develop Latest Latest
Warning

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

Go to latest
Published: Dec 23, 2025 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Overview

Package hardware provides hardware-backed certificate storage implementations for PKCS#11 HSMs and TPM2 devices.

Package hardware provides hardware-backed certificate storage implementations for PKCS#11 HSMs and TPM2 devices.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrCapacityExceeded indicates hardware storage is full
	ErrCapacityExceeded = errors.New("hardware certificate storage capacity exceeded")

	// ErrCertificateTooLarge indicates certificate exceeds maximum size
	ErrCertificateTooLarge = errors.New("certificate exceeds maximum size for hardware storage")

	// ErrNotSupported indicates hardware doesn't support the operation
	ErrNotSupported = errors.New("operation not supported by hardware")

	// ErrHardwareUnavailable indicates hardware storage is inaccessible
	ErrHardwareUnavailable = errors.New("hardware certificate storage unavailable")

	// ErrNVIndexUnavailable indicates TPM NV index conflicts with existing data
	ErrNVIndexUnavailable = errors.New("TPM NV index already in use")

	// ErrStorageClosed indicates storage has been closed
	ErrStorageClosed = errors.New("storage has been closed")

	// ErrInvalidCertificate indicates certificate is invalid or corrupted
	ErrInvalidCertificate = errors.New("invalid or corrupted certificate")

	// ErrTokenFull indicates PKCS#11 token has no free object slots
	ErrTokenFull = errors.New("PKCS#11 token is full")

	// ErrNilContext indicates a nil PKCS#11 context was provided
	ErrNilContext = errors.New("PKCS#11 context cannot be nil")

	// ErrInvalidSession indicates an invalid or closed PKCS#11 session
	ErrInvalidSession = errors.New("invalid or closed PKCS#11 session")

	// ErrNilTPM indicates a nil TPM connection was provided
	ErrNilTPM = errors.New("TPM connection cannot be nil")

	// ErrInvalidBaseIndex indicates TPM base index is out of valid range
	ErrInvalidBaseIndex = errors.New("TPM base index out of valid NV RAM range")

	// ErrInvalidCertSize indicates certificate size is outside acceptable limits
	ErrInvalidCertSize = errors.New("certificate size outside acceptable limits")

	// ErrNilStorage indicates a nil storage backend was provided
	ErrNilStorage = errors.New("storage backend cannot be nil")
)

Functions

func IsCapacityError

func IsCapacityError(err error) bool

IsCapacityError returns true if the error indicates a capacity-related issue (full storage or certificate too large).

func IsHardwareError

func IsHardwareError(err error) bool

IsHardwareError returns true if the error is hardware-related and suggests that the hardware backend may be unavailable or in an error state.

func NewHardwareBackendAdapter

func NewHardwareBackendAdapter(hardware HardwareCertStorage) storage.Backend

NewHardwareBackendAdapter creates a new adapter that wraps a HardwareCertStorage to implement the storage.Backend interface.

func NewOperationError

func NewOperationError(op string, err error) error

NewOperationError creates a new operation error

Types

type BackendCertStorageAdapter

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

BackendCertStorageAdapter wraps a storage.Backend to implement HardwareCertStorage interface. This adapter converts between the Backend's []byte interface and HardwareCertStorage's *x509.Certificate interface by encoding/decoding certificates as DER.

func (*BackendCertStorageAdapter) CertExists

func (a *BackendCertStorageAdapter) CertExists(id string) (bool, error)

CertExists checks if a certificate exists in the backend.

func (*BackendCertStorageAdapter) Close

func (a *BackendCertStorageAdapter) Close() error

Close closes the underlying backend.

func (*BackendCertStorageAdapter) Compact

func (a *BackendCertStorageAdapter) Compact() error

Compact returns ErrNotSupported (external storage doesn't need compaction).

func (*BackendCertStorageAdapter) DeleteCert

func (a *BackendCertStorageAdapter) DeleteCert(id string) error

DeleteCert removes a certificate from the backend.

func (*BackendCertStorageAdapter) GetCapacity

func (a *BackendCertStorageAdapter) GetCapacity() (total int, available int, err error)

GetCapacity returns ErrNotSupported (external storage has no capacity limits).

func (*BackendCertStorageAdapter) GetCert

GetCert retrieves and parses a certificate from the backend.

func (*BackendCertStorageAdapter) GetCertChain

func (a *BackendCertStorageAdapter) GetCertChain(id string) ([]*x509.Certificate, error)

GetCertChain retrieves and parses a certificate chain from the backend.

func (*BackendCertStorageAdapter) IsHardwareBacked

func (a *BackendCertStorageAdapter) IsHardwareBacked() bool

IsHardwareBacked returns false (this is external storage).

func (*BackendCertStorageAdapter) ListCerts

func (a *BackendCertStorageAdapter) ListCerts() ([]string, error)

ListCerts returns all certificate IDs from the backend.

func (*BackendCertStorageAdapter) SaveCert

func (a *BackendCertStorageAdapter) SaveCert(id string, cert *x509.Certificate) error

SaveCert stores a certificate by encoding it as DER and saving to the backend.

func (*BackendCertStorageAdapter) SaveCertChain

func (a *BackendCertStorageAdapter) SaveCertChain(id string, chain []*x509.Certificate) error

SaveCertChain stores a certificate chain by concatenating DER-encoded certificates.

func (*BackendCertStorageAdapter) SupportsChains

func (a *BackendCertStorageAdapter) SupportsChains() bool

SupportsChains returns true (external storage supports chains).

type CertStorageMode

type CertStorageMode string

CertStorageMode defines where certificates are stored

const (
	// CertStorageModeExternal stores all certificates in external storage (default)
	CertStorageModeExternal CertStorageMode = "external"

	// CertStorageModeHardware stores all certificates in hardware
	CertStorageModeHardware CertStorageMode = "hardware"

	// CertStorageModeHybrid stores new certificates in hardware, reads from both
	CertStorageModeHybrid CertStorageMode = "hybrid"
)

type HardwareBackendAdapter

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

HardwareBackendAdapter wraps a HardwareCertStorage to implement storage.Backend. This allows hardware certificate storage to be used wherever storage.Backend is expected, by converting between byte-based storage operations and certificate-specific operations.

Key Mapping:

  • "certs/{id}.pem" -> SaveCert/GetCert
  • "certs/{id}-chain.pem" -> SaveCertChain/GetCertChain

This adapter allows HardwareCertStorage implementations (PKCS#11, TPM2) to be used as generic storage backends while maintaining certificate-specific semantics.

func (*HardwareBackendAdapter) Close

func (a *HardwareBackendAdapter) Close() error

Close closes the underlying hardware storage.

func (*HardwareBackendAdapter) Delete

func (a *HardwareBackendAdapter) Delete(key string) error

Delete removes a certificate by key.

func (*HardwareBackendAdapter) Exists

func (a *HardwareBackendAdapter) Exists(key string) (bool, error)

Exists checks if a certificate exists by key.

func (*HardwareBackendAdapter) Get

func (a *HardwareBackendAdapter) Get(key string) ([]byte, error)

Get retrieves certificate data by key. Supports keys: "certs/{id}.pem" and "certs/{id}-chain.pem"

func (*HardwareBackendAdapter) GetHardwareStorage

func (a *HardwareBackendAdapter) GetHardwareStorage() HardwareCertStorage

GetHardwareStorage returns the underlying HardwareCertStorage. This allows callers to access hardware-specific methods if needed.

func (*HardwareBackendAdapter) List

func (a *HardwareBackendAdapter) List(prefix string) ([]string, error)

List returns all certificate keys with the given prefix.

func (*HardwareBackendAdapter) Put

func (a *HardwareBackendAdapter) Put(key string, value []byte, opts *storage.Options) error

Put stores certificate data by key. Supports keys: "certs/{id}.pem" and "certs/{id}-chain.pem"

type HardwareCertStorage

type HardwareCertStorage interface {
	// SaveCert stores a certificate by ID.
	// If a certificate with the same ID exists, it will be overwritten.
	SaveCert(id string, cert *x509.Certificate) error

	// GetCert retrieves a certificate by ID.
	// Returns ErrNotFound if the certificate does not exist.
	GetCert(id string) (*x509.Certificate, error)

	// DeleteCert removes a certificate by ID.
	// Returns ErrNotFound if the certificate does not exist.
	DeleteCert(id string) error

	// SaveCertChain stores a certificate chain by ID.
	// If a chain with the same ID exists, it will be overwritten.
	SaveCertChain(id string, chain []*x509.Certificate) error

	// GetCertChain retrieves a certificate chain by ID.
	// Returns ErrNotFound if the chain does not exist.
	GetCertChain(id string) ([]*x509.Certificate, error)

	// ListCerts returns all certificate IDs stored.
	ListCerts() ([]string, error)

	// CertExists checks if a certificate exists by ID.
	CertExists(id string) (bool, error)

	// Close releases any resources held by the storage backend.
	Close() error

	// GetCapacity returns the total and available certificate storage capacity.
	// For PKCS#11, this queries token info. For TPM2, this queries NV RAM.
	// Returns (total slots, available slots, error).
	// Returns ErrNotSupported if the hardware doesn't report capacity.
	GetCapacity() (total int, available int, err error)

	// SupportsChains returns true if the hardware supports storing certificate chains.
	// PKCS#11 typically stores individual certificates with relationships.
	// TPM2 stores chains as serialized blobs in NV RAM.
	SupportsChains() bool

	// IsHardwareBacked returns true to distinguish from external storage.
	// This allows runtime type checking without reflection.
	IsHardwareBacked() bool

	// Compact performs storage optimization if supported by hardware.
	// For PKCS#11, this is a no-op. For TPM2, this may defragment NV RAM.
	// Returns ErrNotSupported if compaction is not available.
	Compact() error
}

HardwareCertStorage defines the interface for hardware-backed certificate storage. This interface is implemented by PKCS#11 and TPM2 certificate storage backends.

Implementations MUST be thread-safe.

func NewBackendCertStorageAdapter

func NewBackendCertStorageAdapter(backend storage.Backend) HardwareCertStorage

NewBackendCertStorageAdapter creates a new adapter that wraps a storage.Backend.

func NewHybridCertStorage

func NewHybridCertStorage(
	hardware HardwareCertStorage,
	external HardwareCertStorage,
) (HardwareCertStorage, error)

NewHybridCertStorage creates a new hybrid certificate storage that combines hardware and external storage backends.

The hybrid storage provides automatic failover:

  • Writes prioritize hardware storage but fall back to external on capacity errors
  • Reads check hardware first, then external
  • Deletes remove from both backends

Parameters:

  • hardware: Hardware certificate storage implementation (PKCS#11, TPM2)
  • external: External certificate storage implementation (file, memory, etc.)

Returns an error if either storage is nil.

func NewHybridCertStorageFromBackend

func NewHybridCertStorageFromBackend(
	hardware HardwareCertStorage,
	externalBackend storage.Backend,
) (HardwareCertStorage, error)

NewHybridCertStorageFromBackend creates a hybrid storage using a storage.Backend for external storage. The backend is automatically wrapped with an adapter.

func NewTPM2CertStorage

func NewTPM2CertStorage(
	tpm transport.TPMCloser,
	config *TPM2CertStorageConfig,
) (HardwareCertStorage, error)

NewTPM2CertStorage creates a new TPM2 certificate storage instance.

Parameters:

  • tpm: Open TPM device connection
  • config: Storage configuration

Returns an error if NV RAM is inaccessible or config is invalid.

type HybridCertStorage

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

HybridCertStorage provides a hybrid storage strategy combining hardware and external storage for maximum flexibility and reliability.

Storage Strategy:

  • SaveCert: Always tries hardware first, falls back to external on capacity/error
  • GetCert: Tries hardware first, falls back to external if not found
  • DeleteCert: Deletes from both hardware and external (idempotent)
  • ListCerts: Merges IDs from both storages (deduplicated)

Use Cases:

  • Migration from external to hardware storage
  • Overflow handling when hardware capacity is exhausted
  • High-availability with redundant storage
  • Gradual rollout of hardware certificate storage

Thread Safety: This implementation is thread-safe. All operations are protected by a read-write mutex. The underlying hardware and external storage backends are also expected to be thread-safe.

func (*HybridCertStorage) CertExists

func (h *HybridCertStorage) CertExists(id string) (bool, error)

CertExists checks if a certificate exists in either hardware or external storage.

Returns:

  • true if the certificate exists in at least one storage backend
  • false if not found in either storage
  • error if both storages fail to check existence

func (*HybridCertStorage) Close

func (h *HybridCertStorage) Close() error

Close closes both hardware and external storage backends. After calling Close, all operations will return ErrStorageClosed.

This is idempotent - calling Close multiple times is safe.

Returns:

  • nil if both storages close successfully
  • error if either storage fails to close

func (*HybridCertStorage) Compact

func (h *HybridCertStorage) Compact() error

Compact performs compaction on the hardware storage backend.

func (*HybridCertStorage) DeleteCert

func (h *HybridCertStorage) DeleteCert(id string) error

DeleteCert removes a certificate from both hardware and external storage. This is idempotent - it succeeds if the certificate is removed from at least one storage backend or doesn't exist in either.

Returns:

  • nil if deleted from at least one storage or not found in both
  • error if both storages fail with non-NotFound errors

func (*HybridCertStorage) GetCapacity

func (h *HybridCertStorage) GetCapacity() (total int, available int, err error)

GetCapacity returns the hardware storage capacity. It only reports on the hardware backend capacity.

func (*HybridCertStorage) GetCert

func (h *HybridCertStorage) GetCert(id string) (*x509.Certificate, error)

GetCert retrieves a certificate by trying hardware storage first, then falling back to external storage if not found.

This allows transparent migration where certificates can exist in either storage backend.

Returns:

  • Certificate if found in either storage
  • ErrNotFound if not in either storage
  • Other errors if retrieval fails

func (*HybridCertStorage) GetCertChain

func (h *HybridCertStorage) GetCertChain(id string) ([]*x509.Certificate, error)

GetCertChain retrieves a certificate chain by trying hardware storage first, then falling back to external storage if not found.

Returns:

  • Certificate chain if found in either storage
  • ErrNotFound if not in either storage
  • Other errors if retrieval fails

func (*HybridCertStorage) IsHardwareBacked

func (h *HybridCertStorage) IsHardwareBacked() bool

IsHardwareBacked returns true (hybrid includes hardware backing).

func (*HybridCertStorage) ListCerts

func (h *HybridCertStorage) ListCerts() ([]string, error)

ListCerts returns a deduplicated list of all certificate IDs from both hardware and external storage.

This provides a unified view of all available certificates regardless of which storage backend they're in.

Returns:

  • Merged list of certificate IDs (deduplicated)
  • error if both storages fail to list certificates

func (*HybridCertStorage) SaveCert

func (h *HybridCertStorage) SaveCert(id string, cert *x509.Certificate) error

SaveCert attempts to save the certificate to hardware storage first. If hardware storage fails due to capacity or availability issues, it automatically falls back to external storage.

This provides transparent overflow handling and ensures certificates are never lost due to hardware limitations.

Returns:

  • nil if saved to either storage
  • error if both storage backends fail

func (*HybridCertStorage) SaveCertChain

func (h *HybridCertStorage) SaveCertChain(id string, chain []*x509.Certificate) error

SaveCertChain saves a certificate chain by trying hardware storage first, then falling back to external storage on capacity or availability issues.

This follows the same strategy as SaveCert for transparent overflow handling.

Returns:

  • nil if saved to either storage
  • error if both storage backends fail

func (*HybridCertStorage) SupportsChains

func (h *HybridCertStorage) SupportsChains() bool

SupportsChains returns true if hardware storage supports chains.

type OperationError

type OperationError struct {
	Op  string // Operation name (e.g., "create certificate object", "delete NV index")
	Err error  // Underlying error
}

OperationError wraps an error with operation context

func (*OperationError) Error

func (e *OperationError) Error() string

func (*OperationError) Unwrap

func (e *OperationError) Unwrap() error

type TPM2CertStorage

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

TPM2CertStorage implements HardwareCertStorage for TPM 2.0 devices. Certificates are stored in TPM NV (Non-Volatile) RAM.

Thread Safety: All operations are protected by a read-write mutex for concurrent access.

Certificate Storage:

  • Each certificate is stored in a dedicated NV index
  • NV indices are derived from a base index + hash(ID)
  • Certificates are stored as PEM-encoded data
  • NV index attributes provide access control

NV Index Layout:

Base Index: 0x01800000 (TPM_NV_INDEX_FIRST)
Cert Index: Base + (FNV-1a hash of ID % 0x003FFFFF)

Limitations:

  • Limited NV RAM capacity (typically 2KB-8KB total)
  • Each certificate consumes ~2KB (including overhead)
  • Practical limit: 2-4 certificates per TPM
  • No built-in chain support (stored as single blob)

func (*TPM2CertStorage) CertExists

func (t *TPM2CertStorage) CertExists(id string) (bool, error)

CertExists checks if an NV index exists for the certificate.

func (*TPM2CertStorage) Close

func (t *TPM2CertStorage) Close() error

Close releases TPM resources (NV handles are persistent, no cleanup needed).

func (*TPM2CertStorage) Compact

func (t *TPM2CertStorage) Compact() error

Compact defragments TPM NV RAM if supported (TPM 2.0 spec optional). Most TPMs don't support this, so we return ErrNotSupported.

func (*TPM2CertStorage) DeleteCert

func (t *TPM2CertStorage) DeleteCert(id string) error

DeleteCert removes a certificate by undefining its NV index.

func (*TPM2CertStorage) GetCapacity

func (t *TPM2CertStorage) GetCapacity() (total int, available int, err error)

GetCapacity queries TPM NV RAM capacity and usage. Note: This is an approximation based on max cert size and available space.

func (*TPM2CertStorage) GetCert

func (t *TPM2CertStorage) GetCert(id string) (*x509.Certificate, error)

GetCert retrieves a certificate from TPM NV RAM.

func (*TPM2CertStorage) GetCertChain

func (t *TPM2CertStorage) GetCertChain(id string) ([]*x509.Certificate, error)

GetCertChain retrieves and parses a certificate chain bundle.

func (*TPM2CertStorage) IsHardwareBacked

func (t *TPM2CertStorage) IsHardwareBacked() bool

IsHardwareBacked returns true.

func (*TPM2CertStorage) ListCerts

func (t *TPM2CertStorage) ListCerts() ([]string, error)

ListCerts returns certificate IDs by scanning defined NV indices. Note: This is expensive as it requires querying TPM capabilities.

func (*TPM2CertStorage) SaveCert

func (t *TPM2CertStorage) SaveCert(id string, cert *x509.Certificate) error

SaveCert stores a certificate in TPM NV RAM. The certificate is PEM-encoded and written to a dedicated NV index.

NV Index Attributes:

  • TPMA_NV_AUTHWRITE: Requires authorization to write
  • TPMA_NV_AUTHREAD: Requires authorization to read
  • TPMA_NV_NO_DA: Not subject to dictionary attack protection
  • TPMA_NV_OWNERWRITE: Owner hierarchy can write
  • TPMA_NV_OWNERREAD: Owner hierarchy can read

func (*TPM2CertStorage) SaveCertChain

func (t *TPM2CertStorage) SaveCertChain(id string, chain []*x509.Certificate) error

SaveCertChain stores a certificate chain as a PEM-encoded bundle. All certificates are concatenated and stored in a single NV index.

func (*TPM2CertStorage) SupportsChains

func (t *TPM2CertStorage) SupportsChains() bool

SupportsChains returns true (chains stored as concatenated PEM).

type TPM2CertStorageConfig

type TPM2CertStorageConfig struct {
	// BaseIndex is the starting NV index for certificate storage
	// Default: 0x01800000 (TPM_NV_INDEX_FIRST)
	BaseIndex uint32

	// MaxCertSize is the maximum certificate size in bytes
	// Default: 2048 bytes
	MaxCertSize int

	// OwnerAuth is the owner hierarchy password
	// Required for creating/deleting NV indices
	OwnerAuth []byte
}

TPM2CertStorageConfig configures TPM2 certificate storage

func DefaultTPM2CertStorageConfig

func DefaultTPM2CertStorageConfig() *TPM2CertStorageConfig

DefaultTPM2CertStorageConfig returns safe defaults for TPM2 certificate storage

Jump to

Keyboard shortcuts

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