docs consolidation
This commit is contained in:
239
docs/modules/attestor/bundle-format.md
Normal file
239
docs/modules/attestor/bundle-format.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# 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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"certificate": {
|
||||
"rawBytes": "<base64-DER-certificate>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Public Key (alternative to certificate)
|
||||
|
||||
```json
|
||||
{
|
||||
"publicKey": {
|
||||
"hint": "<optional-key-hint>",
|
||||
"rawBytes": "<base64-public-key>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Transparency Log Entry
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```json
|
||||
{
|
||||
"payloadType": "application/vnd.in-toto+json",
|
||||
"payload": "<base64-encoded-attestation>",
|
||||
"signatures": [
|
||||
{
|
||||
"sig": "<base64-signature>",
|
||||
"keyid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Building a Bundle
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
```csharp
|
||||
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:
|
||||
|
||||
```bash
|
||||
# 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](./cosign-verification-examples.md) for more details.
|
||||
|
||||
## References
|
||||
|
||||
- [Sigstore Bundle Specification](https://github.com/sigstore/cosign/blob/main/specs/BUNDLE_SPEC.md)
|
||||
- [Sigstore Protobuf Specs](https://github.com/sigstore/protobuf-specs)
|
||||
- [DSSE Specification](https://github.com/secure-systems-lab/dsse)
|
||||
- [RFC 6962 - Certificate Transparency](https://www.rfc-editor.org/rfc/rfc6962)
|
||||
Reference in New Issue
Block a user