Table of Contents

Getting Started

Installation

Install the Sigstore NuGet package:

dotnet add package Sigstore

Verifying a Sigstore Bundle

The most common use case is verifying that an artifact was signed by an expected identity.

Basic Verification

using Sigstore;

// Create a verifier (downloads the Sigstore public-good trusted root on first use)
var verifier = new SigstoreVerifier();

// Load the bundle
var bundle = SigstoreBundle.Deserialize(File.ReadAllText("artifact.sigstore.json"));

// Define verification policy
var policy = new VerificationPolicy
{
    CertificateIdentity = new CertificateIdentity
    {
        SubjectAlternativeName = "user@example.com",
        Issuer = "https://accounts.google.com"
    }
};

// Verify
using var artifact = File.OpenRead("artifact.tar.gz");
var result = await verifier.VerifyStreamAsync(artifact, bundle, policy);

Console.WriteLine($"Signed by: {result.SignerIdentity!.SubjectAlternativeName}");
Console.WriteLine($"Issuer: {result.SignerIdentity.Issuer}");
Console.WriteLine($"Timestamps: {result.VerifiedTimestamps.Count}");

// Access rich build provenance from certificate extensions
if (result.SignerIdentity.Extensions is { } extensions)
{
    Console.WriteLine($"Source repo: {extensions.SourceRepositoryUri}");
    Console.WriteLine($"Build trigger: {extensions.BuildTrigger}");
}

// For DSSE/in-toto bundles, access the attestation statement
if (result.Statement is { } statement)
{
    Console.WriteLine($"Predicate type: {statement.PredicateType}");
    Console.WriteLine($"Subjects: {statement.Subject.Count}");
}

Verifying GitHub Actions Signatures

Use the convenience factory for GitHub Actions workflows:

var policy = new VerificationPolicy
{
    CertificateIdentity = CertificateIdentity.ForGitHubActions(
        owner: "owner",
        repository: "repo",
        workflowRef: "refs/heads/main")
};

Using a Custom Trust Root

For private Sigstore deployments or testing:

using Sigstore;

var trustRoot = TrustedRoot.Deserialize(File.ReadAllText("custom-trusted-root.json"));
var verifier = new SigstoreVerifier(new InMemoryTrustRootProvider(trustRoot));

Try-Pattern (No Exceptions)

If you prefer to handle failures without exceptions:

var (success, result) = await verifier.TryVerifyStreamAsync(artifact, bundle, policy);
if (success)
{
    Console.WriteLine($"Verified: {result!.SignerIdentity!.SubjectAlternativeName}");
}
else
{
    Console.WriteLine($"Failed: {result?.FailureReason}");
}

Verification Policy Options

Property Default Description
CertificateIdentity null Expected signer identity (SAN + OIDC issuer)
CertificateIdentity.Extensions null Expected Fulcio certificate extensions (source repo, runner, etc.)
RequireTransparencyLog true Require at least one verified tlog entry
TransparencyLogThreshold 1 Minimum number of verified tlog entries
RequireSignedTimestamps false Require RFC 3161 TSA timestamps
SignedTimestampThreshold 1 Minimum signed timestamps (when required)
RequireSignedCertificateTimestamps true Require SCT verification

Next Steps