Files
git.stella-ops.org/docs/modules/attestor/bundle-format.md
2025-12-25 12:16:13 +02:00

6.0 KiB

Sigstore Bundle Format

This document describes the Sigstore Bundle v0.3 format implementation in StellaOps for offline DSSE envelope verification.

Overview

A Sigstore bundle is a self-contained package that includes all verification material needed to verify a DSSE envelope without network access. This enables offline verification scenarios critical for air-gapped environments.

Bundle Structure

{
  "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
  "verificationMaterial": {
    "certificate": { ... },
    "tlogEntries": [ ... ],
    "timestampVerificationData": { ... }
  },
  "dsseEnvelope": {
    "payloadType": "application/vnd.in-toto+json",
    "payload": "<base64-encoded-payload>",
    "signatures": [
      {
        "sig": "<base64-encoded-signature>",
        "keyid": "<optional-key-id>"
      }
    ]
  }
}

Components

Media Type

  • v0.3: application/vnd.dev.sigstore.bundle.v0.3+json (current)
  • v0.2: application/vnd.dev.sigstore.bundle.v0.2+json (legacy)

Verification Material

Contains cryptographic material for verification:

Field Type Description
certificate Object X.509 signing certificate (keyless signing)
publicKey Object Public key (keyful signing, alternative to certificate)
tlogEntries Array Transparency log entries from Rekor
timestampVerificationData Object RFC 3161 timestamps

Certificate

{
  "certificate": {
    "rawBytes": "<base64-DER-certificate>"
  }
}

Public Key (alternative to certificate)

{
  "publicKey": {
    "hint": "<optional-key-hint>",
    "rawBytes": "<base64-public-key>"
  }
}

Transparency Log Entry

{
  "logIndex": "12345",
  "logId": {
    "keyId": "<base64-log-key-id>"
  },
  "kindVersion": {
    "kind": "dsse",
    "version": "0.0.1"
  },
  "integratedTime": "1703500000",
  "inclusionPromise": {
    "signedEntryTimestamp": "<base64-SET>"
  },
  "inclusionProof": {
    "logIndex": "12345",
    "rootHash": "<base64-merkle-root>",
    "treeSize": "100000",
    "hashes": ["<base64-hash>", ...],
    "checkpoint": {
      "envelope": "<checkpoint-note>"
    }
  },
  "canonicalizedBody": "<base64-canonical-body>"
}

DSSE Envelope

Standard DSSE envelope format:

{
  "payloadType": "application/vnd.in-toto+json",
  "payload": "<base64-encoded-attestation>",
  "signatures": [
    {
      "sig": "<base64-signature>",
      "keyid": ""
    }
  ]
}

Usage

Building a Bundle

using StellaOps.Attestor.Bundle.Builder;
using StellaOps.Attestor.Bundle.Models;

var bundle = new SigstoreBundleBuilder()
    .WithDsseEnvelope(payloadType, payload, signatures)
    .WithCertificate(certificateBytes)
    .WithRekorEntry(
        logIndex: "12345",
        logIdKeyId: logKeyId,
        integratedTime: "1703500000",
        canonicalizedBody: body)
    .WithInclusionProof(inclusionProof)
    .Build();

// Serialize to JSON
var json = bundle.BuildJson();
File.WriteAllText("attestation.bundle", json);

Deserializing a Bundle

using StellaOps.Attestor.Bundle.Serialization;

var json = File.ReadAllText("attestation.bundle");
var bundle = SigstoreBundleSerializer.Deserialize(json);

// Or with error handling
if (SigstoreBundleSerializer.TryDeserialize(json, out var bundle))
{
    // Use bundle
}

Verifying a Bundle

using StellaOps.Attestor.Bundle.Verification;

var verifier = new SigstoreBundleVerifier();
var result = await verifier.VerifyAsync(bundle);

if (result.IsValid)
{
    Console.WriteLine("Bundle verified successfully");
    Console.WriteLine($"DSSE Signature: {result.Checks.DsseSignature}");
    Console.WriteLine($"Certificate Chain: {result.Checks.CertificateChain}");
    Console.WriteLine($"Inclusion Proof: {result.Checks.InclusionProof}");
}
else
{
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error: {error.Code} - {error.Message}");
    }
}

Verification Options

var options = new BundleVerificationOptions
{
    VerifyInclusionProof = true,
    VerifyTimestamps = false,
    VerificationTime = DateTimeOffset.UtcNow,
    TrustedRoots = trustedCertificates
};

var result = await verifier.VerifyAsync(bundle, options);

Verification Checks

Check Description
DsseSignature Verifies DSSE signature using PAE encoding
CertificateChain Validates certificate validity period
InclusionProof Verifies Merkle inclusion proof (RFC 6962)
TransparencyLog Validates transparency log entry
Timestamp Verifies RFC 3161 timestamps (optional)

Error Codes

Code Description
InvalidBundleStructure Bundle JSON structure is invalid
MissingDsseEnvelope DSSE envelope is required
DsseSignatureInvalid Signature verification failed
MissingCertificate No certificate or public key
CertificateChainInvalid Certificate chain validation failed
CertificateExpired Certificate has expired
CertificateNotYetValid Certificate not yet valid
InclusionProofInvalid Merkle proof verification failed
RootHashMismatch Computed root doesn't match expected

Cosign Compatibility

Bundles created by StellaOps are compatible with cosign verification:

# Verify bundle with cosign
cosign verify-attestation \
    --bundle attestation.bundle \
    --certificate-identity="subject@example.com" \
    --certificate-oidc-issuer="https://issuer.example.com" \
    --type=slsaprovenance \
    registry.example.com/image:tag

See Cosign Verification Examples for more details.

References