scitt

package
v0.1.17 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// HeaderReceipt is the HTTP header for SCITT receipts.
	HeaderReceipt = "X-SCITT-Receipt"
	// HeaderStatusToken is the HTTP header for ANS status tokens.
	HeaderStatusToken = "X-ANS-Status-Token" //nolint:gosec // G101: not credentials, this is a header name constant

	// MaxBase64HeaderSize is the maximum allowed Base64-encoded header size.
	// Derived from MaxCoseInputSize defined in cose.go.
	MaxBase64HeaderSize = (MaxCoseInputSize + 2) / 3 * 4 //nolint:mnd // standard base64 encoding formula: ceil(n/3)*4
)
View Source
const (
	DefaultRefreshInterval  = 24 * time.Hour
	DefaultOnDemandCooldown = 5 * time.Minute
)

Default refresh configuration values.

View Source
const MaxCertArrayLen = 128

MaxCertArrayLen is the maximum number of entries allowed in cert arrays.

View Source
const MaxClockSkew = 10 * time.Minute

MaxClockSkew is the maximum clock-skew tolerance for status token expiry checks. Matches the cap in verify/options.go WithClockSkewTolerance.

View Source
const MaxCoseInputSize = 1 << 20

MaxCoseInputSize is the maximum allowed size for COSE_Sign1 input (1 MiB).

View Source
const MaxHashPathLen = 63

MaxHashPathLen is the maximum number of elements in a Merkle inclusion proof path. A SHA-256 Merkle tree can have at most 2^63 leaves, requiring at most 63 path nodes.

Variables

This section is empty.

Functions

func BuildSigStructure

func BuildSigStructure(protectedBytes, payload []byte) ([]byte, error)

BuildSigStructure constructs the COSE Sig_structure1 for signing/verification. The structure is: ["Signature1", protectedBytes, externalAad, payload]

func ComputeLeafHash

func ComputeLeafHash(data []byte) [32]byte

ComputeLeafHash computes SHA-256(0x00 || data) per RFC 9162 section 2.1.

func ComputeNodeHash

func ComputeNodeHash(left, right [32]byte) [32]byte

ComputeNodeHash computes SHA-256(0x01 || left || right) per RFC 9162 section 2.1.

func ComputeSigStructureDigest

func ComputeSigStructureDigest(protectedBytes, payload []byte) ([32]byte, error)

ComputeSigStructureDigest builds the Sig_structure1 and returns its SHA-256 digest.

func GenerateHeaders

func GenerateHeaders(receipt, statusToken []byte) http.Header

GenerateHeaders encodes receipt and statusToken as Base64 and returns them as HTTP headers. Nil or empty slices are omitted from the result.

func MatchesIdentityCert

func MatchesIdentityCert(payload *StatusTokenPayload, fingerprint [32]byte) bool

MatchesIdentityCert checks if any identity cert in the payload matches the given fingerprint. Uses constant-time comparison.

func MatchesServerCert

func MatchesServerCert(payload *StatusTokenPayload, fingerprint [32]byte) bool

MatchesServerCert checks if any server cert in the payload matches the given fingerprint. Uses constant-time comparison.

func VerifyMerkleInclusion

func VerifyMerkleInclusion(eventBytes []byte, leafIndex, treeSize uint64, hashPath [][32]byte, expectedRoot [32]byte) error

VerifyMerkleInclusion verifies an RFC 9162 Merkle inclusion proof by walking the path and comparing the computed root against the expected root using constant-time comparison.

func WalkInclusionPath

func WalkInclusionPath(eventBytes []byte, leafIndex, treeSize uint64, hashPath [][32]byte) ([32]byte, error)

WalkInclusionPath walks an RFC 9162 inclusion proof, computing the root hash from the event data, leaf index, tree size, and hash path.

Types

type AgentStatus

type AgentStatus string

AgentStatus represents an agent's operational status.

const (
	// StatusActive indicates the agent is active and fully operational.
	StatusActive AgentStatus = "ACTIVE"
	// StatusWarning indicates the agent has warnings but is still operational.
	StatusWarning AgentStatus = "WARNING"
	// StatusDeprecated indicates the agent is deprecated but still allows connections.
	StatusDeprecated AgentStatus = "DEPRECATED"
	// StatusExpired indicates the agent's registration has expired (terminal).
	StatusExpired AgentStatus = "EXPIRED"
	// StatusRevoked indicates the agent's registration has been revoked (terminal).
	StatusRevoked AgentStatus = "REVOKED"
)

func (AgentStatus) IsTerminal

func (s AgentStatus) IsTerminal() bool

IsTerminal returns true if the status is a terminal state (no recovery).

func (AgentStatus) IsValidForConnection

func (s AgentStatus) IsValidForConnection() bool

IsValidForConnection returns true if the status allows new connections.

type CertEntry

type CertEntry struct {
	Fingerprint [32]byte
	CertType    CertType
}

CertEntry is a certificate fingerprint with its type.

type CertType

type CertType string

CertType represents the type of certificate.

const (
	// CertTypeX509DVServer is a domain-validated server certificate.
	CertTypeX509DVServer CertType = "x509-dv-server"
	// CertTypeX509OVClient is an organization-validated client certificate.
	CertTypeX509OVClient CertType = "x509-ov-client"
)

type Client

type Client interface {
	FetchReceipt(ctx context.Context, agentID string) ([]byte, error)
	FetchStatusToken(ctx context.Context, agentID string) ([]byte, error)
	FetchRootKeys(ctx context.Context) ([]string, error)
}

Client defines the interface for fetching SCITT artifacts.

type ClockFunc

type ClockFunc func() time.Time

ClockFunc returns the current time. Default: time.Now. Override for deterministic tests.

type CoseError

type CoseError struct {
	Type    CoseErrorType
	Message string
	Cause   error
}

CoseError represents a COSE_Sign1 structure or parsing failure.

func (*CoseError) Error

func (e *CoseError) Error() string

Error implements the error interface.

func (*CoseError) Unwrap

func (e *CoseError) Unwrap() error

Unwrap returns the underlying cause.

type CoseErrorType

type CoseErrorType int

CoseErrorType represents the type of COSE_Sign1 parsing error.

const (
	// CoseErrOversizedInput indicates the input exceeds the maximum allowed size.
	CoseErrOversizedInput CoseErrorType = iota
	// CoseErrNotACoseSign1 indicates the data is not a valid COSE_Sign1 structure.
	CoseErrNotACoseSign1
	// CoseErrCborDecode indicates a CBOR decoding failure.
	CoseErrCborDecode
	// CoseErrInvalidArrayLength indicates the COSE_Sign1 array does not have exactly 4 elements.
	CoseErrInvalidArrayLength
	// CoseErrInvalidSignatureLength indicates the signature is not exactly 64 bytes (P1363).
	CoseErrInvalidSignatureLength
	// CoseErrInvalidProtectedHeader indicates the protected header is malformed.
	CoseErrInvalidProtectedHeader
	// CoseErrInvalidUnprotectedHeader indicates the unprotected header or VDP is malformed.
	CoseErrInvalidUnprotectedHeader
	// CoseErrUnsupportedAlgorithm indicates an unsupported COSE algorithm.
	CoseErrUnsupportedAlgorithm
	// CoseErrMissingKid indicates the key ID (kid) is missing from the protected header.
	CoseErrMissingKid
)

type HTTPClient

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

HTTPClient is an HTTP-based implementation of Client.

func NewHTTPClient

func NewHTTPClient(baseURL string, opts ...HTTPClientOption) (*HTTPClient, error)

NewHTTPClient creates a new HTTPClient. baseURL must use the https scheme unless WithAllowInsecureTransport is supplied. Returns an error if baseURL is malformed or uses a non-https scheme without the insecure opt-in.

func (*HTTPClient) FetchReceipt

func (c *HTTPClient) FetchReceipt(ctx context.Context, agentID string) ([]byte, error)

FetchReceipt retrieves the SCITT receipt for the given agent.

func (*HTTPClient) FetchRootKeys

func (c *HTTPClient) FetchRootKeys(ctx context.Context) ([]string, error)

FetchRootKeys retrieves the SCITT root signing keys (newline-delimited C2SP key strings).

func (*HTTPClient) FetchStatusToken

func (c *HTTPClient) FetchStatusToken(ctx context.Context, agentID string) ([]byte, error)

FetchStatusToken retrieves the status token for the given agent.

type HTTPClientOption

type HTTPClientOption func(*HTTPClient)

HTTPClientOption configures an HTTPClient.

func WithAllowInsecureTransport

func WithAllowInsecureTransport() HTTPClientOption

WithAllowInsecureTransport returns an option that permits a non-https baseURL. Use only for tests or loopback development — production must use https.

func WithHTTPClient

func WithHTTPClient(client *http.Client) HTTPClientOption

WithHTTPClient returns an option that supplies a custom *http.Client. If the client has zero Timeout, defaultTimeout (30s) is applied.

func WithHeader

func WithHeader(name, value string) HTTPClientOption

WithHeader returns an option that sets a single header (overwrites existing values for that name).

func WithHeaders

func WithHeaders(headers http.Header) HTTPClientOption

WithHeaders returns an option that merges the given headers (appends values).

func WithTimeout

func WithTimeout(d time.Duration) HTTPClientOption

WithTimeout returns an option that overrides the request timeout. Takes precedence over any timeout set on a WithHTTPClient client.

type HeaderSupplier

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

HeaderSupplier fetches, verifies, caches, and base64-encodes SCITT proof headers for agent-side HTTP requests. Thread-safe.

func NewHeaderSupplier

func NewHeaderSupplier(agentID string, client Client, keyStore *RefreshableKeyStore, opts ...HeaderSupplierOption) *HeaderSupplier

NewHeaderSupplier creates a HeaderSupplier backed by a RefreshableKeyStore.

func NewHeaderSupplierWithStaticKeys

func NewHeaderSupplierWithStaticKeys(agentID string, client Client, keyStore *KeyStore, opts ...HeaderSupplierOption) *HeaderSupplier

NewHeaderSupplierWithStaticKeys creates a HeaderSupplier using a plain KeyStore wrapped in a static (no-refresh) RefreshableKeyStore.

func (*HeaderSupplier) CurrentHeaders

func (s *HeaderSupplier) CurrentHeaders() *OutgoingHeaders

CurrentHeaders returns the current base64-encoded SCITT headers. On first call, triggers lazy initialization with a timeout. Returns empty headers if init fails or times out — never blocks indefinitely.

func (*HeaderSupplier) Healthy

func (s *HeaderSupplier) Healthy() bool

Healthy returns true if initialized and no recent errors.

func (*HeaderSupplier) LastError

func (s *HeaderSupplier) LastError() error

LastError returns the most recent fetch or verification error.

func (*HeaderSupplier) RefreshNow

func (s *HeaderSupplier) RefreshNow(ctx context.Context) error

RefreshNow forces an immediate re-fetch and verification of receipt and status token.

func (*HeaderSupplier) StartAutoRefresh

func (s *HeaderSupplier) StartAutoRefresh(ctx context.Context) context.CancelFunc

StartAutoRefresh spawns a background goroutine that refreshes at 50% of the remaining token TTL (min 10s) with ±10% jitter. Returns a cancel func.

type HeaderSupplierOption

type HeaderSupplierOption func(*HeaderSupplier)

HeaderSupplierOption configures a HeaderSupplier.

func WithInitTimeout

func WithInitTimeout(d time.Duration) HeaderSupplierOption

WithInitTimeout sets the timeout for the lazy initialization fetch.

func WithSupplierClock

func WithSupplierClock(clock ClockFunc) HeaderSupplierOption

WithSupplierClock sets the clock function.

func WithSupplierClockSkew

func WithSupplierClockSkew(d time.Duration) HeaderSupplierOption

WithSupplierClockSkew sets the clock skew tolerance for token verification. Negative values are clamped to 0. Values exceeding MaxClockSkew are clamped.

func WithSupplierLogger

func WithSupplierLogger(logger *slog.Logger) HeaderSupplierOption

WithSupplierLogger sets the logger.

type Headers

type Headers struct {
	Receipt     []byte
	StatusToken []byte
}

Headers holds the decoded SCITT-related HTTP headers.

func ExtractHeaders

func ExtractHeaders(h http.Header) (*Headers, error)

ExtractHeaders decodes SCITT-related headers from an HTTP response. Returns an empty Headers (not an error) when neither header is present.

func (*Headers) HasBoth

func (s *Headers) HasBoth() bool

HasBoth returns true when both Receipt and StatusToken are non-nil and non-empty.

func (*Headers) IsEmpty

func (s *Headers) IsEmpty() bool

IsEmpty returns true when both Receipt and StatusToken are nil or empty.

type KeyLookup

type KeyLookup interface {
	Get(kid [4]byte) (*TrustedKey, error)
}

KeyLookup retrieves a trusted key by its 4-byte key ID.

type KeyStore

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

KeyStore is an immutable store of trusted ECDSA P-256 keys keyed by kid.

func NewKeyStore

func NewKeyStore(keyStrings []string) (*KeyStore, error)

NewKeyStore parses a slice of C2SP key strings and returns an immutable key store. Returns an error if any key fails to parse or if duplicate key IDs are found.

func (*KeyStore) Get

func (s *KeyStore) Get(kid [4]byte) (*TrustedKey, error)

Get looks up a trusted key by its 4-byte key ID.

func (*KeyStore) IsEmpty

func (s *KeyStore) IsEmpty() bool

IsEmpty returns true if the store contains no keys.

func (*KeyStore) Len

func (s *KeyStore) Len() int

Len returns the number of keys in the store.

func (*KeyStore) MergeFrom

func (s *KeyStore) MergeFrom(keyStrings []string) (*KeyStore, MergeResult)

MergeFrom returns a new KeyStore containing all keys from s plus any successfully parsed keys from keyStrings. Existing keys (same kid) are preserved; duplicates and unparseable strings are skipped. The original store is never modified.

type MergeResult

type MergeResult struct {
	Added              int
	Skipped            int      // sum of SkippedUnparseable + SkippedDuplicate
	SkippedUnparseable int      // strings that failed ParseC2SPKey
	SkippedDuplicate   int      // well-formed keys whose kid already existed
	Collisions         []string // kid hex strings that collided with a different name
}

MergeResult reports the outcome of a MergeFrom operation.

SkippedUnparseable counts input strings that failed to parse as C2SP keys. A non-zero value indicates a potentially malformed key server response and warrants operator attention.

SkippedDuplicate counts well-formed keys that collided with an existing kid in the store. This is benign during a re-scan of the same key set.

Skipped is the sum of both counters, retained for backward compatibility.

type MerkleError

type MerkleError struct {
	Type    MerkleErrorType
	Message string
	Cause   error
}

MerkleError represents an RFC 9162 inclusion proof verification failure.

func (*MerkleError) Error

func (e *MerkleError) Error() string

Error implements the error interface.

func (*MerkleError) Unwrap

func (e *MerkleError) Unwrap() error

Unwrap returns the underlying cause.

type MerkleErrorType

type MerkleErrorType int

MerkleErrorType represents the type of Merkle proof verification error.

const (
	// MerkleErrInvalidProof indicates the inclusion proof is structurally invalid.
	MerkleErrInvalidProof MerkleErrorType = iota
	// MerkleErrRootMismatch indicates the computed root does not match the expected root.
	MerkleErrRootMismatch
)

type MockClient

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

MockClient is a mock implementation of Client for testing.

func NewMockClient

func NewMockClient() *MockClient

NewMockClient creates a new MockClient.

func (*MockClient) FetchReceipt

func (m *MockClient) FetchReceipt(_ context.Context, agentID string) ([]byte, error)

FetchReceipt returns the configured receipt or error for the given agent.

func (*MockClient) FetchRootKeys

func (m *MockClient) FetchRootKeys(_ context.Context) ([]string, error)

FetchRootKeys returns the configured root keys or error.

func (*MockClient) FetchStatusToken

func (m *MockClient) FetchStatusToken(_ context.Context, agentID string) ([]byte, error)

FetchStatusToken returns the configured status token or error for the given agent.

func (*MockClient) WithError

func (m *MockClient) WithError(key string, err error) *MockClient

WithError configures an error for the given key. Use agentID for receipt/token errors, "root-keys" for root key errors.

func (*MockClient) WithReceipt

func (m *MockClient) WithReceipt(agentID string, receipt []byte) *MockClient

WithReceipt configures a receipt for the given agent ID.

func (*MockClient) WithRootKeys

func (m *MockClient) WithRootKeys(keys []string) *MockClient

WithRootKeys configures the root keys response.

func (*MockClient) WithStatusToken

func (m *MockClient) WithStatusToken(agentID string, token []byte) *MockClient

WithStatusToken configures a status token for the given agent ID.

type OutgoingHeaders

type OutgoingHeaders struct {
	ReceiptBase64     string
	StatusTokenBase64 string
}

OutgoingHeaders holds base64-encoded SCITT proof headers ready for HTTP transport.

func (*OutgoingHeaders) IsEmpty

func (h *OutgoingHeaders) IsEmpty() bool

IsEmpty returns true when neither header has a value.

func (*OutgoingHeaders) String

func (h *OutgoingHeaders) String() string

String implements fmt.Stringer for logging.

func (*OutgoingHeaders) ToHTTPHeaders

func (h *OutgoingHeaders) ToHTTPHeaders() (http.Header, error)

ToHTTPHeaders converts to http.Header using GenerateHeaders. The raw bytes are reconstructed from the base64 strings — this round-trip is intentional to ensure consistency with the canonical GenerateHeaders encoding. Returns an error if either base64 field is malformed.

type ParsedCoseSign1

type ParsedCoseSign1 struct {
	ProtectedBytes []byte // verbatim, never re-encoded
	Protected      ProtectedHeader
	Unprotected    cbor.RawMessage
	Payload        []byte
	Signature      []byte // exactly 64 bytes P1363
}

ParsedCoseSign1 holds the decoded fields of a COSE_Sign1 structure.

func ParseCoseSign1

func ParseCoseSign1(data []byte) (*ParsedCoseSign1, error)

ParseCoseSign1 parses a CBOR-encoded COSE_Sign1 structure.

This is a hand-rolled parser rather than using veraison/go-cose because:

  • go-cose does not expose custom CBOR decode options (MaxNestedLevels, MaxArrayElements, MaxMapPairs) needed for DoS protection on untrusted input.
  • Custom header fields (vds=395, CWT claims) require manual parsing of RawProtected regardless, negating most of go-cose's value.
  • Verbatim ProtectedBytes must be preserved without re-encoding for correct ECDSA signature verification over the exact signed bytes.

type ProtectedHeader

type ProtectedHeader struct {
	Alg         int64
	Kid         [4]byte
	Vds         *int64
	ContentType *string
	CwtIss      *string
	CwtIat      *int64
}

ProtectedHeader holds the decoded COSE protected header fields.

type ReceiptCache

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

ReceiptCache is a thread-safe cache for verified SCITT receipts, keyed by agent ID. Eviction is FIFO on insertion order: the oldest inserted entries are dropped first when maxEntries is exceeded.

func NewReceiptCache

func NewReceiptCache(ttl time.Duration, maxEntries int, clock ClockFunc) *ReceiptCache

NewReceiptCache creates a new ReceiptCache with the given TTL, max entries, and clock function.

func NewReceiptCacheWithDefaults

func NewReceiptCacheWithDefaults() *ReceiptCache

NewReceiptCacheWithDefaults creates a new ReceiptCache with default settings (24h TTL, 1000 entries).

func (*ReceiptCache) Get

func (c *ReceiptCache) Get(agentID string) (*VerifiedReceipt, bool)

Get retrieves a cached receipt by agent ID. Returns nil, false if missing or expired.

func (*ReceiptCache) Insert

func (c *ReceiptCache) Insert(agentID string, receipt *VerifiedReceipt)

Insert adds a receipt to the cache. Overwrites any existing entry for the same agent ID. Evicts entries in FIFO order if the cache exceeds maxEntries.

func (*ReceiptCache) Invalidate

func (c *ReceiptCache) Invalidate(agentID string)

Invalidate removes a specific entry from the cache.

func (*ReceiptCache) Len

func (c *ReceiptCache) Len() int

Len returns the number of entries in the cache.

type RefreshableKeyStore

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

RefreshableKeyStore wraps a KeyStore with snapshot-based reads, on-demand refresh gated by cooldown, and optional background refresh. It implements KeyLookup and is a drop-in replacement for *KeyStore.

func NewRefreshableKeyStore

func NewRefreshableKeyStore(initial *KeyStore, client Client, opts ...RefreshableKeyStoreOption) *RefreshableKeyStore

NewRefreshableKeyStore creates a new RefreshableKeyStore wrapping the given initial KeyStore. If client is nil, the store operates in static mode where all refresh operations are no-ops.

func (*RefreshableKeyStore) CurrentSnapshot

func (r *RefreshableKeyStore) CurrentSnapshot() *KeyStore

CurrentSnapshot returns the current immutable KeyStore snapshot.

func (*RefreshableKeyStore) DoRefresh

func (r *RefreshableKeyStore) DoRefresh(ctx context.Context) error

DoRefresh fetches root keys from the client and merges them into the current snapshot. In static mode (client == nil) this is a no-op. Network errors do not update lastRefreshed and the existing snapshot is preserved.

func (*RefreshableKeyStore) Get

func (r *RefreshableKeyStore) Get(kid [4]byte) (*TrustedKey, error)

Get looks up a trusted key by kid from the current snapshot. Implements KeyLookup.

func (*RefreshableKeyStore) IsEmpty

func (r *RefreshableKeyStore) IsEmpty() bool

IsEmpty returns true if the current snapshot has no keys.

func (*RefreshableKeyStore) LastRefreshed

func (r *RefreshableKeyStore) LastRefreshed() *time.Time

LastRefreshed returns when the last successful refresh occurred, or nil if never.

func (*RefreshableKeyStore) Len

func (r *RefreshableKeyStore) Len() int

Len returns the number of keys in the current snapshot.

func (*RefreshableKeyStore) RefreshIfCooldownElapsed

func (r *RefreshableKeyStore) RefreshIfCooldownElapsed(ctx context.Context) (bool, error)

RefreshIfCooldownElapsed performs an on-demand refresh only if enough time has elapsed since the last refresh. Concurrent callers are serialized by refreshGate — only the first caller fetches, others wait and get the updated snapshot. Returns true if a refresh was actually performed.

func (*RefreshableKeyStore) StartBackgroundRefresh

func (r *RefreshableKeyStore) StartBackgroundRefresh(ctx context.Context, interval time.Duration) context.CancelFunc

StartBackgroundRefresh spawns a goroutine that periodically calls DoRefresh. Returns a cancel function to stop the background goroutine.

func (*RefreshableKeyStore) StartBackgroundRefreshDefault

func (r *RefreshableKeyStore) StartBackgroundRefreshDefault(ctx context.Context) context.CancelFunc

StartBackgroundRefreshDefault starts background refresh with DefaultRefreshInterval (24h).

type RefreshableKeyStoreOption

type RefreshableKeyStoreOption func(*RefreshableKeyStore)

RefreshableKeyStoreOption configures a RefreshableKeyStore.

func WithCooldown

func WithCooldown(d time.Duration) RefreshableKeyStoreOption

WithCooldown sets the minimum interval between on-demand refreshes.

func WithRefreshClock

func WithRefreshClock(clock ClockFunc) RefreshableKeyStoreOption

WithRefreshClock sets the clock function for the refreshable key store.

func WithRefreshLogger

func WithRefreshLogger(logger *slog.Logger) RefreshableKeyStoreOption

WithRefreshLogger sets the logger for refresh operations.

type SignatureError

type SignatureError struct {
	Type    SignatureErrorType
	Message string
	Kid     [4]byte
	Cause   error
}

SignatureError represents an ECDSA verification or key management failure.

func (*SignatureError) Error

func (e *SignatureError) Error() string

Error implements the error interface.

func (*SignatureError) Unwrap

func (e *SignatureError) Unwrap() error

Unwrap returns the underlying cause.

type SignatureErrorType

type SignatureErrorType int

SignatureErrorType represents the type of signature verification error.

const (
	// SigErrSignatureInvalid indicates ECDSA signature verification failed.
	SigErrSignatureInvalid SignatureErrorType = iota
	// SigErrUnknownKeyID indicates the key ID was not found in the key store.
	SigErrUnknownKeyID
	// SigErrIssuerMismatch indicates the issuer claim does not match the key.
	SigErrIssuerMismatch
	// SigErrInvalidKeyFormat indicates the key material is not in the expected format.
	SigErrInvalidKeyFormat
	// SigErrKeyHashMismatch indicates the key ID does not match the key's SHA-256 prefix.
	SigErrKeyHashMismatch
	// SigErrInvalidPublicKey indicates the public key is invalid.
	SigErrInvalidPublicKey
	// SigErrUntrustedKeyDomain indicates a domain-restricted key was used outside its trust boundary.
	SigErrUntrustedKeyDomain
)

type StatusTokenCache

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

StatusTokenCache is a thread-safe cache for verified status tokens, keyed by agent ID. Expiration is per-entry, derived from the token's Payload.Exp claim. Eviction is FIFO on insertion order: the oldest inserted entries are dropped first when maxEntries is exceeded.

func NewStatusTokenCache

func NewStatusTokenCache(maxEntries int, clock ClockFunc) *StatusTokenCache

NewStatusTokenCache creates a new StatusTokenCache with the given max entries and clock function.

func NewStatusTokenCacheWithDefaults

func NewStatusTokenCacheWithDefaults() *StatusTokenCache

NewStatusTokenCacheWithDefaults creates a new StatusTokenCache with default settings (1000 entries).

func (*StatusTokenCache) Get

func (c *StatusTokenCache) Get(agentID string) (*VerifiedStatusToken, bool)

Get retrieves a cached status token by agent ID. Returns nil, false if missing or expired.

func (*StatusTokenCache) Insert

func (c *StatusTokenCache) Insert(agentID string, token *VerifiedStatusToken)

Insert adds a status token to the cache. Expiration is derived from token.Payload.Exp. Overwrites any existing entry for the same agent ID. Evicts entries in FIFO order if the cache exceeds maxEntries.

func (*StatusTokenCache) Invalidate

func (c *StatusTokenCache) Invalidate(agentID string)

Invalidate removes a specific entry from the cache.

func (*StatusTokenCache) Len

func (c *StatusTokenCache) Len() int

Len returns the number of entries in the cache.

type StatusTokenPayload

type StatusTokenPayload struct {
	AgentID            string
	AnsName            string
	Status             AgentStatus
	Iat                int64
	Exp                int64
	ValidIdentityCerts []CertEntry
	ValidServerCerts   []CertEntry
	MetadataHashes     map[string]string
}

StatusTokenPayload is the decoded payload of a verified status token.

type TokenError

type TokenError struct {
	Type    TokenErrorType
	Message string
	Status  AgentStatus
	Exp     int64
	Now     int64
	Cause   error
}

TokenError represents a status token payload or lifecycle failure.

func (*TokenError) Error

func (e *TokenError) Error() string

Error implements the error interface.

func (*TokenError) Unwrap

func (e *TokenError) Unwrap() error

Unwrap returns the underlying cause.

type TokenErrorType

type TokenErrorType int

TokenErrorType represents the type of status token error.

const (
	// TokenErrExpired indicates the status token has expired.
	TokenErrExpired TokenErrorType = iota
	// TokenErrMissingField indicates a required field is missing from the token payload.
	TokenErrMissingField
	// TokenErrPayloadInvalid indicates the token payload structure is invalid.
	TokenErrPayloadInvalid
	// TokenErrTerminalStatus indicates the agent has a terminal status.
	TokenErrTerminalStatus
	// TokenErrPayloadEmpty indicates the token payload is empty.
	TokenErrPayloadEmpty
)

type TransportError

type TransportError struct {
	Type       TransportErrorType
	Message    string
	StatusCode int
	Cause      error
}

TransportError represents an HTTP client or endpoint failure.

func (*TransportError) Error

func (e *TransportError) Error() string

Error implements the error interface.

func (*TransportError) ShouldFallbackToBadge

func (e *TransportError) ShouldFallbackToBadge() bool

ShouldFallbackToBadge returns true if this transport error is eligible for fallback to badge-based verification. Only transient/infrastructure errors are eligible — terminal agent states and decode errors are not.

func (*TransportError) Unwrap

func (e *TransportError) Unwrap() error

Unwrap returns the underlying cause.

type TransportErrorType

type TransportErrorType int

TransportErrorType represents the type of HTTP transport error.

const (
	// TransportErrNotFound indicates the endpoint returned 404.
	TransportErrNotFound TransportErrorType = iota
	// TransportErrAgentTerminal indicates the agent is in a terminal state (410).
	TransportErrAgentTerminal
	// TransportErrNotSupported indicates SCITT is not supported (501).
	TransportErrNotSupported
	// TransportErrHTTPError indicates a generic HTTP error.
	TransportErrHTTPError
	// TransportErrBase64Decode indicates Base64 decoding of a response failed.
	TransportErrBase64Decode
)

type TrustedKey

type TrustedKey struct {
	Name string
	Kid  [4]byte
	Key  *ecdsa.PublicKey
}

TrustedKey holds a named ECDSA P-256 public key with its 4-byte key ID.

func ParseC2SPKey

func ParseC2SPKey(s string) (*TrustedKey, error)

ParseC2SPKey parses a C2SP-formatted key string: "name+hex_kid+base64_spki_der".

type VerifiedReceipt

type VerifiedReceipt struct {
	TreeSize  uint64
	LeafIndex uint64
	// RootHash is the Merkle tree root computed from walking the inclusion path.
	// IMPORTANT: This value is NOT verified against any trusted tree head.
	// Callers requiring tree-head attestation MUST compare this hash to a root
	// obtained out-of-band (e.g., from a witness or monitor). The ECDSA signature
	// over the leaf is authoritative for leaf-level trust; the walked root alone
	// does not prove inclusion in any particular published tree.
	RootHash   [32]byte
	EventBytes []byte
	KeyID      [4]byte
	Iss        *string
	Iat        *int64
}

VerifiedReceipt holds the verified fields extracted from a SCITT receipt.

func VerifyReceipt

func VerifyReceipt(receiptBytes []byte, keys KeyLookup) (*VerifiedReceipt, error)

VerifyReceipt parses and verifies a COSE_Sign1 SCITT receipt.

Verification order:

  1. Parse COSE_Sign1 structure
  2. Validate vds == 1 (RFC 9162)
  3. Look up signing key by kid
  4. Verify ECDSA signature (before any issuer check)
  5. Verify issuer binding (after signature verification)
  6. Extract VDP (Verifiable Data Proofs) from unprotected header
  7. Walk Merkle inclusion path

type VerifiedStatusToken

type VerifiedStatusToken struct {
	Payload StatusTokenPayload
	KeyID   [4]byte
}

VerifiedStatusToken holds the decoded payload and key ID of a verified status token.

func VerifyStatusToken

func VerifyStatusToken(tokenBytes []byte, keys KeyLookup, clockSkew time.Duration) (*VerifiedStatusToken, error)

VerifyStatusToken verifies a COSE_Sign1 status token using the current time.

func VerifyStatusTokenAt

func VerifyStatusTokenAt(tokenBytes []byte, keys KeyLookup, clockSkew time.Duration, now int64) (*VerifiedStatusToken, error)

VerifyStatusTokenAt verifies a COSE_Sign1 status token at the given unix timestamp.

Jump to

Keyboard shortcuts

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