Documentation
¶
Index ¶
- Constants
- func BuildSigStructure(protectedBytes, payload []byte) ([]byte, error)
- func ComputeLeafHash(data []byte) [32]byte
- func ComputeNodeHash(left, right [32]byte) [32]byte
- func ComputeSigStructureDigest(protectedBytes, payload []byte) ([32]byte, error)
- func GenerateHeaders(receipt, statusToken []byte) http.Header
- func MatchesIdentityCert(payload *StatusTokenPayload, fingerprint [32]byte) bool
- func MatchesServerCert(payload *StatusTokenPayload, fingerprint [32]byte) bool
- func VerifyMerkleInclusion(eventBytes []byte, leafIndex, treeSize uint64, hashPath [][32]byte, ...) error
- func WalkInclusionPath(eventBytes []byte, leafIndex, treeSize uint64, hashPath [][32]byte) ([32]byte, error)
- type AgentStatus
- type CertEntry
- type CertType
- type Client
- type ClockFunc
- type CoseError
- type CoseErrorType
- type HTTPClient
- type HTTPClientOption
- type HeaderSupplier
- type HeaderSupplierOption
- type Headers
- type KeyLookup
- type KeyStore
- type MergeResult
- type MerkleError
- type MerkleErrorType
- type MockClient
- func (m *MockClient) FetchReceipt(_ context.Context, agentID string) ([]byte, error)
- func (m *MockClient) FetchRootKeys(_ context.Context) ([]string, error)
- func (m *MockClient) FetchStatusToken(_ context.Context, agentID string) ([]byte, error)
- func (m *MockClient) WithError(key string, err error) *MockClient
- func (m *MockClient) WithReceipt(agentID string, receipt []byte) *MockClient
- func (m *MockClient) WithRootKeys(keys []string) *MockClient
- func (m *MockClient) WithStatusToken(agentID string, token []byte) *MockClient
- type OutgoingHeaders
- type ParsedCoseSign1
- type ProtectedHeader
- type ReceiptCache
- type RefreshableKeyStore
- func (r *RefreshableKeyStore) CurrentSnapshot() *KeyStore
- func (r *RefreshableKeyStore) DoRefresh(ctx context.Context) error
- func (r *RefreshableKeyStore) Get(kid [4]byte) (*TrustedKey, error)
- func (r *RefreshableKeyStore) IsEmpty() bool
- func (r *RefreshableKeyStore) LastRefreshed() *time.Time
- func (r *RefreshableKeyStore) Len() int
- func (r *RefreshableKeyStore) RefreshIfCooldownElapsed(ctx context.Context) (bool, error)
- func (r *RefreshableKeyStore) StartBackgroundRefresh(ctx context.Context, interval time.Duration) context.CancelFunc
- func (r *RefreshableKeyStore) StartBackgroundRefreshDefault(ctx context.Context) context.CancelFunc
- type RefreshableKeyStoreOption
- type SignatureError
- type SignatureErrorType
- type StatusTokenCache
- type StatusTokenPayload
- type TokenError
- type TokenErrorType
- type TransportError
- type TransportErrorType
- type TrustedKey
- type VerifiedReceipt
- type VerifiedStatusToken
Constants ¶
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 )
const ( DefaultRefreshInterval = 24 * time.Hour DefaultOnDemandCooldown = 5 * time.Minute )
Default refresh configuration values.
const MaxCertArrayLen = 128
MaxCertArrayLen is the maximum number of entries allowed in cert arrays.
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.
const MaxCoseInputSize = 1 << 20
MaxCoseInputSize is the maximum allowed size for COSE_Sign1 input (1 MiB).
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 ¶
BuildSigStructure constructs the COSE Sig_structure1 for signing/verification. The structure is: ["Signature1", protectedBytes, externalAad, payload]
func ComputeLeafHash ¶
ComputeLeafHash computes SHA-256(0x00 || data) per RFC 9162 section 2.1.
func ComputeNodeHash ¶
ComputeNodeHash computes SHA-256(0x01 || left || right) per RFC 9162 section 2.1.
func ComputeSigStructureDigest ¶
ComputeSigStructureDigest builds the Sig_structure1 and returns its SHA-256 digest.
func GenerateHeaders ¶
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.
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 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 ¶
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.
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 ¶
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 ¶
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 ¶
Headers holds the decoded SCITT-related HTTP headers.
func ExtractHeaders ¶
ExtractHeaders decodes SCITT-related headers from an HTTP response. Returns an empty Headers (not an error) when neither header is present.
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 ¶
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) 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 (*MockClient) FetchReceipt ¶
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 ¶
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 ¶
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 ¶
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:
- Parse COSE_Sign1 structure
- Validate vds == 1 (RFC 9162)
- Look up signing key by kid
- Verify ECDSA signature (before any issuer check)
- Verify issuer binding (after signature verification)
- Extract VDP (Verifiable Data Proofs) from unprotected header
- 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.