6.0 KiB
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.