Introduction to Sigstore
The supply chain problem
Every modern application depends on hundreds of upstream packages: NuGet packages, container base images, build artifacts, attestations from CI systems. A compromise anywhere in that chain — a stolen credential, a malicious dependency, a tampered release — can flow into production unnoticed.
Traditional code signing was the textbook answer: sign artifacts with a private key, distribute the public key out of band, verify on download. In practice it has gone unused in most ecosystems because:
- Key management is hard. Long-lived signing keys must be stored, rotated, revoked. Most teams skip the ceremony.
- Distribution is hard. Publishing public keys, building chains of trust, dealing with revocation lists — non-trivial work for every project.
- Identity is missing. A signature proves someone signed; it usually doesn't tell you who in a way you can verify.
Sigstore is a Linux Foundation project that fixes these. Its model:
- Keyless signing. Generate an ephemeral key pair right before signing. Use it once. Throw it away.
- OIDC-bound certificates. Prove your identity (GitHub Actions, Google, Microsoft, etc.) to a CA called Fulcio, which issues a short-lived X.509 certificate binding your OIDC subject to the ephemeral public key.
- Tamper-evident transparency log. Every signing event is recorded in a public Merkle log called Rekor. Anyone can audit. Tampering is detectable.
- Trust roots distributed via TUF. The set of trusted Fulcio CAs, Rekor keys, and CT log keys is published through TUF so clients can bootstrap trust without hard-coding anything.
The result: signing becomes a CI step that costs nothing, identities are real and verifiable, and any verifier can check a signature against the public infrastructure without operating their own PKI.
Why a managed .NET implementation
The Sigstore project ships first-class clients for Go, Java, and Python. Container image signing is handled by cosign. For .NET, the historical options were:
- Shell out to cosign. Works but adds an external binary dependency, complicates packaging, and leaves the .NET process dependent on a Go toolchain at runtime.
- Use sigstore-go via P/Invoke. Heavy, platform-specific, hard to audit, fights .NET's deployment story.
- Reimplement in .NET. What this library does.
sigstore-dotnet is a pure managed implementation that:
- Runs everywhere .NET 8 / 9 / 10 runs — Windows, Linux, macOS, ARM64, container, AOT-compatible.
- Has no native binaries. Cryptography is
System.Security.Cryptographyplus BouncyCastle.Cryptography for Ed25519. No P/Invoke, nounsafe. - Plays naturally with idiomatic .NET:
Task<T>/asynceverywhere, dependency injection viaMicrosoft.Extensions.DependencyInjection, configurable throughIOptions<T>, logging viaMicrosoft.Extensions.Logging.Abstractions. - Is cross-client interoperable. Bundles produced by sigstore-dotnet verify cleanly with cosign and sigstore-python, and vice versa. This is checked on every push by an interop workflow.
- Passes the full sigstore-conformance test suite — 132 tests, zero xfails — across all three target frameworks.
How it works
A signing operation runs through these steps:
- Obtain an OIDC identity token. The library ships providers for ambient detection on GitHub Actions, an explicit
SIGSTORE_ID_TOKENenv var, or any customIOidcTokenProvider. - Generate an ephemeral ECDSA P-256 keypair.
- Build a CSR binding the ephemeral public key.
- Submit the CSR + identity token to Fulcio. Fulcio verifies the OIDC token, and issues a short-lived (typically 10-minute) X.509 certificate whose Subject Alternative Name carries the OIDC subject. The certificate is logged to a Certificate Transparency log, producing an SCT.
- Sign the artifact (or its DSSE pre-authentication encoding for in-toto attestations).
- Submit the entry to Rekor. Rekor returns a transparency log entry with an inclusion proof and a Signed Entry Timestamp (SET).
- Optionally request an RFC 3161 timestamp from a Timestamp Authority, when configured.
- Assemble a Sigstore protobuf bundle carrying the certificate, signature, log entry, and any timestamps.
A verification operation runs the inverse pipeline. See the Architecture article for the full step-by-step flow with the typed exception that each step throws on failure.
Bundle formats
The library reads and writes the Sigstore bundle format v0.1, v0.2, and v0.3. Both MessageSignature and DSSE envelope payloads are supported. In-toto statements carried inside DSSE envelopes are validated against the artifact digest using the standard subject-list scheme.
Trust model
Trusted Fulcio CAs, Rekor keys, CT log keys, and Timestamp Authority chains are loaded from a TrustedRoot JSON document. By default, the library bootstraps this from the Sigstore Public Good Instance's TUF repository on first use. For air-gapped environments, custom trusted roots can be supplied directly. A staging preset (SigstoreSigningOptions.Staging()) is included for testing against the Sigstore staging environment.
Conformance and interop testing
Cryptographic libraries are easy to write and hard to write correctly. sigstore-dotnet treats correctness as a first-class concern:
- Conformance. sigstore-conformance v0.0.25 is the official cross-client test suite. The project's Conformance workflow runs the suite on every push to
mainagainst .NET 8, 9, and 10. Current state: 132 passed, 0 xfailed. - Interop. A separate Interop workflow signs an artifact with sigstore-dotnet and verifies with sigstore-python and cosign, then signs with each of those clients and verifies with sigstore-dotnet. Both
message_signatureand DSSE in-toto attestations are exercised in both directions, plus negative cases (tampered signatures, wrong identity, wrong issuer). 15 cases total. - Unit tests. 82 tests across the core types: bundle parsing, DSSE pre-authentication encoding, certificate identity matchers, signed-note parsing, signature algorithms (ECDSA, RSA, Ed25519), and the dependency injection extensions.
The whole thing builds and tests in under three minutes per framework.
Where to next
- Getting Started — install, set up DI, sign and verify your first artifact.
- Cosign Integration — workflow for container image signatures via cosign.
- Architecture — the verification and signing pipelines step-by-step.
- API Reference — auto-generated from XML doc comments.