signer

package module
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: Apache-2.0 Imports: 21 Imported by: 4

README

Carabiner Signer Library

Easy digital signing library with support for sigstore bundles, DSSE envelopes and support for easy signing with key pairs. The library handles ECDSA, RSA, ed25519 and GPG/OpenPGP keys.

Signing and Creating Sigstore Bundles

Signing data with sigstore and bundling it is super easy. The library takes care of producing the signing key pair and fulcio certificate for you. Once the signing operation is done, the Carabiner signer registers it in the Rekor transparency log.

Sigstore Example
package main

import (
	"fmt"
	"os"

	"github.com/carabiner-dev/signer"
)

func main() {
    // Create a signer:
    s := signer.NewSigner()

	// Sign a string as a sigstore bundle.
    //
    // This call triggers the sigstore flow if ambient
    // credentials are not available.
	bundle, err := s.SignMessage([]byte("My signed data"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	// Output the bundle to STDOUT
	if err := s.WriteBundle(bundle, os.Stdout); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
}

Dead Simple Signing Envelope (DSSE)

Initial support for DSSE has been implemented since v0.2.0. The library can sign and verify envelopes signed with arbitrary keys.

DSSE Example
package main

import (
	"fmt"
	"os"

	"github.com/carabiner-dev/signer"
	"github.com/carabiner-dev/signer/options"
	"github.com/carabiner-dev/signer/key"
)

func main() {
	// Start with a message
	myMessage := []byte("Hello world")

	// Generate a Key Pair to sign
	privateKey, err := key.NewGenerator().GenerateKeyPair()

	// Create a new signer
	s := signer.NewSigner()

	// Wrap the message in a new envelope and sign it with the key:
	envelope, err := s.SignMessageToDSSE(
		myMessage,
		options.WithKey(privateKey),
		options.WithPayloadType("text/plain"),
	)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// DSEE Envelope Verification
	v := signer.NewVerifier()
	res, err := v.VerifyParsedDSSE(envelope, []key.PublicKeyProvider{
		privateKey, // Private keys are public key providers
	})
	if err != nil {
		fmt.Printf("Error verifying: %v\n", err)
		os.Exit(1)
	}

	if res.Verified {
		fmt.Println("DSSE envelope verified!")
	} else {
		fmt.Println("DSSE envelope failed verification.")
	}
}

Key Pair Handling

The key package will handle all aspects with keys. The package provides a key Generator and a key Parser. It also defines the public and private key abstractions used throughout the package.

Most verifying operations take a key.PublicKeyProvider. This interface masks any object that can provide a public key object for use in cryptographic operations. The key.Public object is the most basic PublicKeyProvider but we may implement more complex providers such as cache interfaces and key management systems clients. For GPG/OpenPGP keys, the key.GPGPublic provider preserves full key metadata (key IDs, subkeys, and fingerprints) required for PGP signature verification.

Signing operations take a key.PrivateKeyProvider. This abstraction handles key pairs. You can generate keys using the key.Generator object. The library supports ECDSA, RSA, ed25519, and GPG/OpenPGP key formats.

Status

The library has simple signing functions to sign and verify attestations and arbitrary data into sigstore bundles. The current functionality is considered stable but the library is still under active feature development.

Full DSSE signature verification is now implemented in the signer module. The main verifier exposes functions to sign and verify DSSE envelopes and their payloads.

The library also includes a key package that handles public key parsing and signature verification. GPG/OpenPGP key blocks are supported for both parsing and DSSE envelope verification.

Key identity matching (via MatchesKeyIdentity) compares identities using their key ID and type. Identities defined with only raw key material (including GPG key blocks) are automatically normalized — the key data is parsed to extract the ID and type before matching.

Upcoming Features

Some of the features we are working on that will soon show up in this module include:

  • Support for signing with supplied plain key pairs.
  • DSSE (non bundle) output
  • More keypair providers
  • Certificate/identity cache (gitsign credential cache style).

Code Examples

We have examples that demonstrate features of the library:

This library is made with <3 and Copyright by Carabiner Systems, Inc and released under the Apache-2.0 license. Feel free to send patches and open issues or just tell us if you are using it. We love feedback on all our projects.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArtifactKind added in v0.5.0

type ArtifactKind string

ArtifactKind is the format of a SignedArtifact.

const (
	// ArtifactKindBundle is a sigstore bundle (cert chain + DSSE
	// envelope + optional Rekor/TSA), produced by the sigstore and
	// SPIFFE signing backends.
	ArtifactKindBundle ArtifactKind = "sigstore"

	// ArtifactKindEnvelope is a bare DSSE envelope produced by the
	// key signing backend.
	ArtifactKindEnvelope ArtifactKind = "dsse"
)

type Backend added in v0.5.0

type Backend interface {
	// Name reports which backend this is.
	Name() options.Backend

	// SignStatement signs an in-toto attestation. Bundle backends
	// produce *BundleArtifact; the key backend produces
	// *EnvelopeArtifact.
	SignStatement(data []byte, funcs ...options.SignOptFn) (SignedArtifact, error)

	// SignMessage signs a raw payload. Bundle backends wrap it in a
	// sigstore bundle; the key backend wraps it in a DSSE envelope
	// (caller must supply options.WithPayloadType).
	SignMessage(data []byte, funcs ...options.SignOptFn) (SignedArtifact, error)
}

Backend is one of the three signing implementations the Signer dispatches to. Real implementations are constructed by Signer.resolveBackend based on Signer.Options.Backend (or per-call options.WithKey overrides). A counterfeiter-generated fake lives at signerfakes.FakeBackend.

Backends are self-contained: they hold the state they need (credentials, bundle/dsse signers, configured keys) and the per-instance caches that make repeated Sign calls cheap (one OIDC flow + one Fulcio cert request shared across calls).

type BundleArtifact added in v0.5.0

type BundleArtifact struct {
	Bundle *sbundle.Bundle
}

BundleArtifact is the SignedArtifact wrapper for sigstore bundles. Produced by the sigstore and SPIFFE signing backends.

func (*BundleArtifact) Kind added in v0.5.0

func (b *BundleArtifact) Kind() ArtifactKind

Kind returns ArtifactKindBundle.

func (*BundleArtifact) MediaType added in v0.5.0

func (b *BundleArtifact) MediaType() string

MediaType returns the bundle's media type, falling back to the generic sigstore-bundle JSON content type when unset.

func (*BundleArtifact) WriteTo added in v0.5.0

func (b *BundleArtifact) WriteTo(w io.Writer) (int64, error)

WriteTo marshals the bundle as protojson and writes it to w.

type EnvelopeArtifact added in v0.5.0

type EnvelopeArtifact struct {
	Envelope *sdsse.Envelope
}

EnvelopeArtifact is the SignedArtifact wrapper for DSSE envelopes. This is produced by the key signing backend.

func (*EnvelopeArtifact) Kind added in v0.5.0

func (e *EnvelopeArtifact) Kind() ArtifactKind

Kind returns ArtifactKindEnvelope.

func (*EnvelopeArtifact) MediaType added in v0.5.0

func (e *EnvelopeArtifact) MediaType() string

func (*EnvelopeArtifact) WriteTo added in v0.5.0

func (e *EnvelopeArtifact) WriteTo(w io.Writer) (int64, error)

WriteTo marshals the envelope as multiline-indented protojson and writes it to w. Indented output matches the existing Signer.WriteDSSEEnvelope convention.

type SignedArtifact added in v0.5.0

type SignedArtifact interface {
	// Kind reports the canonical format of this artifact.
	Kind() ArtifactKind

	// MediaType returns an IANA-like media type for the canonical
	// serialization form.
	MediaType() string

	// WriteTo serializes the artifact to its canonical JSON form.
	WriteTo(w io.Writer) (int64, error)
}

SignedArtifact is the polymorphic result of a signing operation. It abstracts sigstore bundles, DSSE envelopes, and any future signed formats. Callers serialize the artifact via WriteTo and branch on Kind only when the underlying format matters.

type Signer

type Signer struct {
	Options options.Signer

	// Credentials supplies the keypair and certificate material for the
	// bundle backends (sigstore / SPIFFE). Pre-set for SPIFFE; for
	// sigstore the backend will lazily build a sigstore.CredentialProvider
	// from Options if this is nil.
	//
	// The Signer carries no per-instance signing-key state. To sign with
	// raw private keys, either configure Options.Backend = BackendKey +
	// Options.Keys, or pass options.WithKey(...) at the call site.
	Credentials bundle.CredentialProvider
	// contains filtered or unexported fields
}

Signer is a thin orchestrator. It owns the configuration (Options + Credentials + bundle/dsse signers) and resolves the concrete Backend that does the actual signing on each call. The signing logic lives entirely in the Backend implementations (sigstoreBackend / spiffeBackend / keyBackend in backend.go).

func NewSigner

func NewSigner() *Signer

NewSigner creates a new signer and initializes it with the default sigstore roots embedded in the package.

func NewSignerFromSet added in v0.5.0

func NewSignerFromSet(set *options.SignerSet) (*Signer, error)

NewSignerFromSet builds a fully-armed *Signer from a SignerSet. Equivalent to: BuildSigner + BuildCredentialProvider + NewSigner + field assignment, in one call. Lives in this package (not options/) because options/ cannot import signer/ — see the package-level comments on SignerSet for the import-cycle reasoning.

The caller is responsible for closing the returned Signer when done (via Signer.Close) so any Workload API stream lazily opened by the SPIFFE backend is released.

func (*Signer) Close added in v0.5.0

func (s *Signer) Close() error

Close releases resources held by the Signer's credentials. It's a no-op when Credentials is nil or doesn't hold any closeable resources; today only the SPIFFE credential provider has anything to release (the Workload API stream lazily opened on first sign). Safe to call multiple times.

func (*Signer) SignEnvelope added in v0.2.0

func (s *Signer) SignEnvelope(envelope *sdsse.Envelope, funcs ...options.SignOptFn) error

SignEnvelope signs an existing DSSE envelope. Key resolution mirrors the polymorphic Sign methods:

  • Per-call options.WithKey(...) wins → those keys sign this envelope (the configured backend is disregarded for this call).
  • Otherwise, if Signer.Options.Backend == BackendKey, the configured Signer.Options.Keys are used.
  • Otherwise → error. Sigstore/SPIFFE backends produce bundles end-to-end; they don't sign pre-existing standalone envelopes.

func (*Signer) SignMessage

func (s *Signer) SignMessage(data []byte, funcs ...options.SignOptFn) (SignedArtifact, error)

SignMessage signs a payload and returns a polymorphic SignedArtifact. Backend resolution follows the same rules as SignStatement. The DSSE path requires options.WithPayloadType.

func (*Signer) SignMessageBundle added in v0.5.0

func (s *Signer) SignMessageBundle(data []byte, funcs ...options.SignOptFn) (*sbundle.Bundle, error)

SignMessageBundle signs a payload and returns a sigstore bundle. Same dispatch rules as SignStatementBundle.

func (*Signer) SignMessageToDSSE added in v0.2.0

func (s *Signer) SignMessageToDSSE(data []byte, funcs ...options.SignOptFn) (*sdsse.Envelope, error)

SignMessageToDSSE signs a payload as a bare DSSE envelope. Requires keys from per-call options.WithKey or Signer.Options.Keys (when Backend=BackendKey).

func (*Signer) SignStatement

func (s *Signer) SignStatement(data []byte, funcs ...options.SignOptFn) (SignedArtifact, error)

SignStatement signs an in-toto attestation and returns a polymorphic SignedArtifact. Resolution rules:

  1. Per-call options.WithKey(...) → transient key backend using the per-call keys (Signer.Options.Keys ignored for this invocation).
  2. Otherwise the persistent backend (lazily built from Signer.Options.Backend on first call) signs: BackendSigstore (default) / BackendSpiffe → *BundleArtifact; BackendKey → *EnvelopeArtifact signed with Signer.Options.Keys.

Errors out before signing when the resolved backend's configuration is incomplete (e.g. BackendKey selected but no keys available).

func (*Signer) SignStatementBundle added in v0.5.0

func (s *Signer) SignStatementBundle(data []byte, funcs ...options.SignOptFn) (*sbundle.Bundle, error)

SignStatementBundle signs an in-toto attestation and returns a sigstore bundle. Resolves the persistent backend (sigstore or SPIFFE) and unwraps its artifact. Errors when the configured backend is BackendKey — keys can't produce a bundle.

Use the polymorphic SignStatement when you want format-agnostic dispatch.

func (*Signer) SignStatementToDSSE added in v0.2.0

func (s *Signer) SignStatementToDSSE(data []byte, funcs ...options.SignOptFn) (*sdsse.Envelope, error)

SignStatementToDSSE signs an in-toto statement as a bare DSSE envelope. Constructs a transient keyBackend from per-call keys (or Signer.Options.Keys when Backend=BackendKey). Errors when no keys are available.

func (*Signer) WriteBundle

func (s *Signer) WriteBundle(bndl *sbundle.Bundle, w io.Writer) error

WriteBundle marshals a sigstore bundle to JSON and writes it to w.

func (*Signer) WriteDSSEEnvelope added in v0.2.0

func (s *Signer) WriteDSSEEnvelope(env *sdsse.Envelope, w io.Writer) error

WriteDSSEEnvelope marshals a DSSE envelope to JSON and writes it to an io.Writer.

type Verifier

type Verifier struct {
	Options options.Verifier
	// contains filtered or unexported fields
}

func NewVerifier

func NewVerifier(fnOpts ...options.VerifierOptFunc) *Verifier

NewVerifier creates a new verifier with default options and verifiers

func NewVerifierFromSet added in v0.5.0

func NewVerifierFromSet(set *options.VerifierSet) (*Verifier, error)

NewVerifierFromSet builds a *Verifier from a VerifierSet. Equivalent to BuildVerifier + NewVerifier with the resolved options applied, in one call. Lives in this package (not options/) because options/ cannot import signer/.

func (*Verifier) VerifyBundle

func (v *Verifier) VerifyBundle(bundlePath string, fnOpts ...options.VerificationOptFunc) (*verify.VerificationResult, error)

VerifyBundle verifies a signed bundle containing a dsse envelope

func (*Verifier) VerifyDSSE added in v0.2.0

func (v *Verifier) VerifyDSSE(path string, keys []key.PublicKeyProvider, fnOpts ...options.VerificationOptFunc) (*key.VerificationResult, error)

VerifyDSSE parses a DSSE envelope from a file and returns it

func (*Verifier) VerifyInlineBundle

func (v *Verifier) VerifyInlineBundle(bundleContents []byte, fnOpts ...options.VerificationOptFunc) (*verify.VerificationResult, error)

VerifyBundle verifies a signed bundle containing a dsse envelope

func (*Verifier) VerifyParsedBundle

func (v *Verifier) VerifyParsedBundle(bndl *sbundle.Bundle, fnOpts ...options.VerificationOptFunc) (*verify.VerificationResult, error)

VerifyParsedBundle verifies a sigstore bundle with the provided options

func (*Verifier) VerifyParsedDSSE added in v0.2.0

func (v *Verifier) VerifyParsedDSSE(env *sdsse.Envelope, keys []key.PublicKeyProvider, fnOpts ...options.VerificationOptFunc) (*key.VerificationResult, error)

VerifyParsedDSSE verifies an already parsed DSSE envelope

Directories

Path Synopsis
_examples
attestation command
dsse-sign command
dsse-verify command
message command
spiffe command
Sign an in-toto attestation with an X.509 SVID obtained from the SPIFFE Workload API, then verify it against a pinned SPIRE upstream root and apply a SPIFFE identity policy via the api/v1 layer.
Sign an in-toto attestation with an X.509 SVID obtained from the SPIFFE Workload API, then verify it against a pinned SPIRE upstream root and apply a SPIFFE identity policy via the api/v1 layer.
api
v1
bundlefakes
Code generated by counterfeiter.
Code generated by counterfeiter.
dssefakes
Code generated by counterfeiter.
Code generated by counterfeiter.
internal
tuf
Code generated by counterfeiter.
Code generated by counterfeiter.
verifier
Package verifier validates SPIFFE-signed bundles against a pinned SPIRE trust root and enforces SPIFFE identity matchers on the SVID leaf.
Package verifier validates SPIFFE-signed bundles against a pinned SPIRE trust root and enforces SPIFFE identity matchers on the SVID leaf.
sts
providers/github
Package github implements a client to requesta short lived token from github actions.
Package github implements a client to requesta short lived token from github actions.
providers/gitlab
Package gitlab implements a client to read OIDC tokens from GitLab CI using the SIGSTORE_ID_TOKEN environment variable.
Package gitlab implements a client to read OIDC tokens from GitLab CI using the SIGSTORE_ID_TOKEN environment variable.

Jump to

Keyboard shortcuts

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