attestation

package
v0.1.0-alpha.4 Latest Latest
Warning

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

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

Documentation

Overview

Package attestation provides a Verifier object that orchestrates loading, signature verification, and per-predicate-type semantic verification of in-toto attestations. The shape is one method per predicate family (VerifyVSA today, VerifyBuild / VerifySource to follow), each built on top of the same generic Load and VerifySignatures primitives.

Envelope and Statement are re-exported from github.com/carabiner-dev/attestation as type aliases so callers only need to import this package.

Index

Constants

This section is empty.

Variables

View Source
var ErrAmbiguousAttestation = errors.New("ambiguous attestation")

ErrAmbiguousAttestation is returned by Select when several envelopes in a file could be the one to verify and nothing tells them apart.

View Source
var ErrIdentityMismatch = errors.New("envelope signer does not match any expected identity")

ErrIdentityMismatch is returned by VerifyIdentity when none of the expected identities match the envelope's verified signers. Like ErrSignatureRequired, it's a verification outcome — callers should translate it to their "verification failed" exit path rather than treating it as an execution error.

View Source
var ErrNoApplicableAttestation = errors.New("no applicable attestation")

ErrNoApplicableAttestation is returned by Select when none of the envelopes in a file is one the caller can verify.

View Source
var ErrSignatureRequired = errors.New("envelope is unsigned and signatures are required")

ErrSignatureRequired is returned by VerifySignatures when the envelope is unsigned and SignatureOptions.Required is true. It is a verification outcome rather than an execution error — callers should translate it to their domain's "verification failed" exit path (e.g. exit code 1) rather than treating it as a setup problem.

View Source
var ErrSignatureUnverifiable = errors.New("envelope is signed but cannot be verified")

ErrSignatureUnverifiable is returned by VerifySignatures when the envelope carries signatures but the verifier had nothing to check them against: no --key for a DSSE envelope, or no configured verifier for the bundle's kind. The signature was neither confirmed nor refuted. Callers may treat it as a configuration problem rather than a verification failure.

View Source
var ErrSignatureUnverified = errors.New("envelope signature did not verify")

ErrSignatureUnverified is returned by VerifySignatures when the envelope carries signatures that were checked against the available key or trust material and did not verify. When the envelope records a reason, the returned error wraps this sentinel and carries it. Like ErrSignatureRequired it is a verification outcome, not an execution error.

View Source
var ErrVerifierUnbound = errors.New("verifier has no authorized signer")

ErrVerifierUnbound is returned by VerifyVSA when an accepted verifier has no authorized signer — neither its own nor a wildcard — and VSAOptions.AllowUnbound is false. A VSA's verifier.id is a claim written by whoever produced the document; without a signer bound to it, matching the id proves nothing about who issued the VSA.

Functions

This section is empty.

Types

type Envelope

type Envelope = cdattestation.Envelope

Envelope is an in-toto attestation envelope (bare statement, DSSE, or Sigstore bundle). Re-exported from the carabiner attestation package as a type alias so callers of this library don't need a separate import for the envelope abstraction.

func Select

func Select(envs []Envelope, sel *Selection) (Envelope, error)

Select picks the envelope a verification is about. A single envelope is returned as is, whatever it holds: the verification itself will say whether it applies. Among several, those of the selection's predicate types about its subjects remain; a preference breaks a tie between types, and what is left must be exactly one.

type Selection

type Selection struct {
	// Kind names what is being looked for, for messages ("build
	// provenance", "VSA").
	Kind string

	// PredicateTypes are the predicate types the caller verifies. Empty
	// accepts any.
	PredicateTypes []string

	// Subjects, when given, must all be subjects of the attestation.
	Subjects []*subject.Expected

	// NoGitDigestAliases matches subject digests by exact algorithm
	// name; see subject.WithGitDigestAliases.
	NoGitDigestAliases bool

	// Prefer breaks a tie among candidates of different predicate
	// types: the first type listed that any candidate has wins.
	Prefer []string
}

Selection says which of the attestations in a file a verification is about. Files often hold several: a commit's git note accumulates the source provenance, tag provenance and VSAs sourcetool pushes, and a release's attestations file may carry provenance next to other attestations.

type SignatureOptions

type SignatureOptions struct {
	// Keys is the set of public-key providers used to verify DSSE
	// signatures on the envelope. Sigstore bundles verify against an
	// embedded trust root regardless and do not require entries here.
	Keys []key.PublicKeyProvider

	// RekorVerification enables verifying keyless DSSE envelopes — ones
	// carrying a Sigstore certificate on their signatures — against the
	// Rekor transparency log at RekorURL (the signer's default instance
	// when empty). An unreachable log records the envelope as
	// unverifiable rather than failing the call.
	RekorVerification bool

	// RekorURL is the transparency log to query; empty means the
	// signer's default.
	RekorURL string

	// Required, when true, makes VerifySignatures return
	// ErrSignatureRequired if the envelope carries zero signatures,
	// ErrSignatureUnverifiable if it carries signatures the verifier
	// had no material to check, and ErrSignatureUnverified if the
	// signatures were checked and did not verify. Use this to enforce
	// a "must be signed and verified" policy.
	Required bool
}

SignatureOptions parameterizes VerifySignatures. Keys are passed to the envelope's Verify implementation; Required toggles the "unsigned → error" policy independent of any keys.

type Statement

type Statement = cdattestation.Statement

Statement is an in-toto statement (subject + predicate). Re-exported from the carabiner attestation package.

type VSACheck

type VSACheck struct {
	// Name is a human-readable description of what was checked
	// (e.g. `Verifier == "https://verify.example.com"`).
	Name string

	// Pass reports whether the check succeeded.
	Pass bool

	// Message is populated on failure with the observed value
	// (e.g. `verifier.id = "..."`). Empty when Pass is true.
	Message string
}

VSACheck is the result of one hardcoded VSA check.

type VSAOptions

type VSAOptions struct {
	Verifiers    []VerifierBinding
	Signers      []*sapi.Identity
	AllowUnbound bool
	// Registry binds verifier ids to their signers, for accepted
	// verifiers given without one; see verifiers.Registry.
	Registry           *verifiers.Registry
	Subjects           []*subject.Expected
	NoGitDigestAliases bool
	Levels             []string
	Resource           string
	Policy             string
	Dependencies       []string
}

VSAOptions configures the hardcoded checks VerifyVSA runs against an attestation's normalized VSA representation.

Field semantics:

  • Verifiers lists the accepted verifiers, OR-matched on ID against VSA.Verifier.ID. At least one is required; a VSA with no asserted verifier identity carries very weak trust value.
  • Signers are wildcard identities authorized to sign for every accepted verifier. A verifier's own Signers add to them.
  • The signer check binds the matched verifier to who actually signed the envelope: the envelope's verified signature must match one of the identities authorized for that verifier. It runs whenever the matched verifier has any authorized signer.
  • Registry supplies the signer of an accepted verifier given without one, when it knows the id, along with the ref policy that signer must satisfy.
  • AllowUnbound permits verifiers with no authorized signer at all, in which case only the ID is matched. Off by default, VerifyVSA returns ErrVerifierUnbound instead.
  • Subjects are the artifacts the caller holds and expects the VSA to be about. Every one must match a VSA subject (sharing at least one digest algorithm and agreeing on every shared one) or the result fails; each outcome is reported in VSAResult.Subjects. Empty binds the VSA to nothing. By default a sha1 or sha256 digest meets a git object digest of the same hash; NoGitDigestAliases requires the exact algorithm names (see subject.WithGitDigestAliases).
  • Levels is OR-matched against VSA.VerifiedLevels — at least one listed level must be satisfied. For canonical SLSA level strings (e.g. SLSA_BUILD_LEVEL_3) the match is "at-or-above": a VSA verifiedLevel of SLSA_BUILD_LEVEL_4 satisfies a want of SLSA_BUILD_LEVEL_3 within the same track. Non-canonical strings only match exactly. Skipped when empty.
  • Resource and Policy are exact-match against ResourceURI and Policy.URI respectively. Skipped when empty.
  • Dependencies is AND-matched: every key must appear in VSA.DependencyLevels (count values are not consulted). Skipped when empty.

type VSAResult

type VSAResult struct {
	// VSA is the normalized VSA predicate parsed from the envelope.
	// Available to callers that want to display additional fields
	// (e.g. dependency-level counts) alongside the check results.
	VSA *vsa.VSA

	// Checks is the per-check outcome. Always includes the always-on
	// checks (result, verifier); optional checks appear when the
	// corresponding VSAOptions field is non-empty.
	Checks []VSACheck

	// Signers lists the principals of the envelope's verified signers,
	// when the envelope records them, for display alongside the
	// verifier it vouched for. Empty for unsigned or unverified
	// envelopes.
	Signers []string

	// Subjects holds the outcome of binding the VSA to the artifacts
	// the caller holds, one entry per VSAOptions.Subjects entry in
	// order. Empty when none were expected.
	Subjects []subject.Match
}

VSAResult is what VerifyVSA returns. VSA is the normalized version-neutral predicate; Checks is the per-check outcome in display order — exactly the entries needed to render a result table for the user.

func (*VSAResult) Pass

func (r *VSAResult) Pass() bool

Pass reports whether every check passed and every expected subject was found.

type Verifier

type Verifier struct{}

Verifier orchestrates attestation verification. Methods on the Verifier split into two groups:

  • Generic primitives — Load, VerifySignatures, VerifyIdentity — reusable across every supported attestation type.
  • Per-predicate-family checks — VerifyVSA (and, in time, VerifyBuild / VerifySource) — run the semantic checks for that family against an already-loaded, signature-verified envelope.

The zero value is not usable; construct with New.

func New

func New() *Verifier

New returns a Verifier ready to load and verify attestations. It takes no required arguments; per-call inputs (keys, expected identities, VSA fields, …) flow in via the method-specific Options arguments instead of constructor options.

func (*Verifier) Fetch

func (*Verifier) Fetch(ctx context.Context, path string) ([]Envelope, error)

Fetch loads the attestations at path, in order: every attestation file under a directory, one attestation per line of a JSON lines file (.jsonl, as a commit's git note or a release's attestations file are written), or the single bundle, DSSE envelope or bare statement any other file holds. The collector's drivers do the reading: the JSON lines one is not reached by its format detection, so it is chosen here by extension.

func (*Verifier) Load

func (v *Verifier) Load(path string) (Envelope, error)

Load parses a single attestation envelope from path. Format auto-detection covers bare in-toto statements, DSSE envelopes, and Sigstore bundles; the returned Envelope already has its predicate parsed by the SLSA / VSA parser registry the package wires up via init().

Returns an error if the file produces zero envelopes or more than one; see Fetch and Select for files holding several.

func (*Verifier) VerifyIdentity

func (*Verifier) VerifyIdentity(env Envelope, expected []*sapi.Identity) error

VerifyIdentity confirms that the envelope was signed by at least one identity in expected (OR semantics: any match is sufficient). The check is meaningful only for envelopes whose Verification implementation supports identity matching — primarily Sigstore bundles, where signing certificates carry subject identities.

Returns ErrIdentityMismatch if no expected identity matches. If expected is empty, returns nil (no-op).

Call VerifySignatures first: identity matching reads from the envelope's verified-signature material, which the envelope only populates once cryptographic verification has succeeded.

func (*Verifier) VerifySignatures

func (*Verifier) VerifySignatures(env Envelope, opts SignatureOptions) error

VerifySignatures runs the envelope's cryptographic signature verification and, when opts.Required is set, also enforces that the envelope is signed and that the signature verified. The checks are kept in one method because callers nearly always want both: running verification on whatever signatures are present, and demanding a verified signature when policy requires it.

A missing signal is not an error on its own: an unsigned envelope, or a signed one with no key material to check it against, passes when opts.Required is false. Errors from the envelope's Verify implementation (signature/key mismatches, trust-root failures for Sigstore bundles) always propagate.

With opts.Required set, the verdict is read from the Verification the envelope recorded rather than from the presence of signatures, since envelope implementations record a failed verification as a result instead of returning an error from Verify. It returns ErrSignatureRequired when the envelope carries no signatures, ErrSignatureUnverifiable when it carries signatures the verifier had no key or trust material to check, and ErrSignatureUnverified — with the recorded reason, when there is one — when they were checked and did not verify.

func (*Verifier) VerifyVSA

func (*Verifier) VerifyVSA(_ context.Context, env Envelope, opts *VSAOptions) (*VSAResult, error)

VerifyVSA extracts the VSA predicate from env (which must already have been signature-verified by the caller — see VerifySignatures), converts it to the normalized representation via pkg/slsa/vsa, and runs the hardcoded checks selected by opts.

Returns vsa.ErrNotVSA wrapped with the offending predicate type when env carries a non-VSA predicate, and ErrVerifierUnbound when an accepted verifier has no authorized signer and opts.AllowUnbound is false. Always-on checks (verificationResult == PASSED and the verifier match) always appear in the result; the signer check appears when the matched verifier has authorized signers, and the optional checks only when the corresponding VSAOptions field is set.

ctx is accepted for future cancellation/deadline plumbing; the current check set is purely in-memory and ignores it.

type VerifierBinding

type VerifierBinding struct {
	// ID is matched exactly against VSA.Verifier.ID.
	ID string

	// Signers are identities allowed to sign VSAs from this verifier,
	// on top of any wildcard signers in VSAOptions.Signers. A verifier
	// with neither is unbound: see VSAOptions.AllowUnbound.
	Signers []*sapi.Identity
}

VerifierBinding names an accepted verifier and the signer identities authorized to issue VSAs on its behalf.

Jump to

Keyboard shortcuts

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