notify doctors work, audit work, new product advisory sprints
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
# Rekor Verification Technical Design
|
||||
|
||||
**Document ID**: DOCS-ATTEST-REKOR-001
|
||||
**Version**: 1.0
|
||||
**Last Updated**: 2025-12-14
|
||||
**Version**: 2.0
|
||||
**Last Updated**: 2026-01-13
|
||||
**Status**: Draft
|
||||
|
||||
---
|
||||
|
||||
## 1. OVERVIEW
|
||||
|
||||
This document provides the comprehensive technical design for Rekor transparency log verification in StellaOps. It covers three key capabilities:
|
||||
This document provides the comprehensive technical design for Rekor transparency log verification in StellaOps. It covers four key capabilities:
|
||||
|
||||
1. **Merkle Proof Verification** - Cryptographic verification of inclusion proofs
|
||||
2. **Durable Retry Queue** - Reliable submission with failure recovery
|
||||
3. **Time Skew Validation** - Replay protection via timestamp validation
|
||||
4. **Tile-Based Verification (v2)** - Support for Rekor v2 Sunlight format
|
||||
|
||||
### Related Sprints
|
||||
|
||||
@@ -22,6 +23,7 @@ This document provides the comprehensive technical design for Rekor transparency
|
||||
| SPRINT_3000_0001_0001 | P0 | Merkle Proof Verification |
|
||||
| SPRINT_3000_0001_0002 | P1 | Rekor Retry Queue & Metrics |
|
||||
| SPRINT_3000_0001_0003 | P2 | Time Skew Validation |
|
||||
| SPRINT_3000_0001_0004 | P1 | Rekor v2 Tile-Based Verification |
|
||||
|
||||
---
|
||||
|
||||
@@ -405,6 +407,225 @@ public TimeSkewResult Validate(DateTimeOffset integratedTime, DateTimeOffset loc
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 Tile-Based Verification (Rekor v2)
|
||||
|
||||
Rekor v2 introduces a tile-based log structure following the Sunlight/C2SP `tlog-tiles` specification. This enables offline-capable verification and more efficient proof computation.
|
||||
|
||||
#### 3.4.1 Architecture Overview
|
||||
|
||||
In tile-based logs, the Merkle tree is stored in fixed-size chunks (tiles) of 256 entries each:
|
||||
|
||||
```
|
||||
Tile Structure (256 entries/tile)
|
||||
───────────────────────────────────────────────────────────
|
||||
Level 2 (root)
|
||||
[Tile]
|
||||
/ \
|
||||
Level 1 (intermediate)
|
||||
[Tile 0] [Tile 1] ...
|
||||
/ \
|
||||
Level 0 (leaves)
|
||||
[Tile 0] [Tile 1] [Tile 2] [Tile 3] ...
|
||||
|
||||
Each tile contains up to 256 hashes (32 bytes each = 8KB max)
|
||||
```
|
||||
|
||||
#### 3.4.2 Log Version Configuration
|
||||
|
||||
StellaOps supports automatic version detection and explicit version selection:
|
||||
|
||||
```csharp
|
||||
public enum RekorLogVersion
|
||||
{
|
||||
Auto = 0, // Auto-detect based on endpoint availability
|
||||
V1 = 1, // Traditional Trillian-based Rekor (API proofs)
|
||||
V2 = 2 // Tile-based Sunlight format
|
||||
}
|
||||
```
|
||||
|
||||
**Version Selection Logic:**
|
||||
|
||||
| Version | PreferTileProofs | Result |
|
||||
|---------|------------------|--------|
|
||||
| V2 | (any) | Always use tile proofs |
|
||||
| V1 | (any) | Always use API proofs |
|
||||
| Auto | true | Prefer tile proofs if available |
|
||||
| Auto | false | Use API proofs (default) |
|
||||
|
||||
#### 3.4.3 Checkpoint Format
|
||||
|
||||
V2 checkpoints follow the `c2sp.org/tlog-tiles` format:
|
||||
|
||||
```
|
||||
rekor.sigstore.dev - 2605736670972794746
|
||||
<tree_size>
|
||||
<root_hash_base64>
|
||||
|
||||
- rekor.sigstore.dev <signature_base64>
|
||||
```
|
||||
|
||||
**Checkpoint Components:**
|
||||
- **Line 1**: Origin identifier (log name + instance)
|
||||
- **Line 2**: Tree size (number of leaves)
|
||||
- **Line 3**: Root hash (base64-encoded SHA-256)
|
||||
- **Blank line**: Separator
|
||||
- **Signature lines**: One or more `- <origin> <signature>` lines
|
||||
|
||||
#### 3.4.4 Tile Path Calculation
|
||||
|
||||
Tiles are fetched via URL paths following the scheme:
|
||||
|
||||
```
|
||||
GET {tile_base_url}/tile/{level}/{index:03d}[.p/{partial_width}]
|
||||
|
||||
Examples:
|
||||
- /tile/0/000 # Level 0, tile 0 (entries 0-255)
|
||||
- /tile/0/001 # Level 0, tile 1 (entries 256-511)
|
||||
- /tile/1/000 # Level 1, tile 0 (intermediate hashes)
|
||||
- /tile/0/042.p/128 # Partial tile with 128 entries
|
||||
```
|
||||
|
||||
#### 3.4.5 Implementation Classes
|
||||
|
||||
**IRekorTileClient Interface:**
|
||||
|
||||
```csharp
|
||||
public interface IRekorTileClient
|
||||
{
|
||||
Task<RekorTileCheckpoint?> GetCheckpointAsync(
|
||||
RekorBackend backend,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RekorTileData?> GetTileAsync(
|
||||
RekorBackend backend,
|
||||
int level,
|
||||
long index,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RekorTileEntry?> GetEntryAsync(
|
||||
RekorBackend backend,
|
||||
long logIndex,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RekorTileInclusionProof?> ComputeInclusionProofAsync(
|
||||
RekorBackend backend,
|
||||
long logIndex,
|
||||
long treeSize,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
```
|
||||
|
||||
**RekorTileData Model:**
|
||||
|
||||
```csharp
|
||||
public sealed class RekorTileData
|
||||
{
|
||||
public required int Level { get; init; }
|
||||
public required long Index { get; init; }
|
||||
public required int Width { get; init; } // Number of hashes (max 256)
|
||||
public required byte[] Hashes { get; init; } // Width * 32 bytes
|
||||
|
||||
public byte[] GetHash(int position)
|
||||
{
|
||||
if (position < 0 || position >= Width)
|
||||
throw new ArgumentOutOfRangeException(nameof(position));
|
||||
|
||||
var result = new byte[32];
|
||||
Array.Copy(Hashes, position * 32, result, 0, 32);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.4.6 Proof Computation Algorithm
|
||||
|
||||
Computing an inclusion proof from tiles:
|
||||
|
||||
```python
|
||||
def compute_inclusion_proof(log_index, tree_size, tile_client):
|
||||
"""Compute inclusion proof by fetching necessary tiles."""
|
||||
proof_path = []
|
||||
level = 0
|
||||
index = log_index
|
||||
size = tree_size
|
||||
|
||||
while size > 1:
|
||||
tile_index = index // 256
|
||||
position_in_tile = index % 256
|
||||
|
||||
# Determine sibling position
|
||||
if index % 2 == 1:
|
||||
sibling_pos = position_in_tile - 1
|
||||
else:
|
||||
sibling_pos = position_in_tile + 1 if position_in_tile + 1 < size else None
|
||||
|
||||
if sibling_pos is not None:
|
||||
tile = tile_client.get_tile(level, tile_index)
|
||||
proof_path.append(tile.get_hash(sibling_pos))
|
||||
|
||||
index = index // 2
|
||||
size = (size + 1) // 2
|
||||
level += 1
|
||||
|
||||
return proof_path
|
||||
```
|
||||
|
||||
#### 3.4.7 Configuration
|
||||
|
||||
```yaml
|
||||
attestor:
|
||||
rekor:
|
||||
primary:
|
||||
url: https://rekor.sigstore.dev
|
||||
# Version: Auto, V1, or V2
|
||||
version: Auto
|
||||
# Custom tile base URL (optional, defaults to {url}/tile/)
|
||||
tile_base_url: ""
|
||||
# Log ID for multi-log environments (hex-encoded SHA-256)
|
||||
log_id: "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"
|
||||
# Prefer tile proofs when version is Auto
|
||||
prefer_tile_proofs: false
|
||||
```
|
||||
|
||||
**Environment Variables:**
|
||||
|
||||
```bash
|
||||
# Rekor v2 Configuration
|
||||
REKOR_SERVER_URL=https://rekor.sigstore.dev
|
||||
REKOR_VERSION=Auto # Auto, V1, or V2
|
||||
REKOR_TILE_BASE_URL= # Optional custom tile endpoint
|
||||
REKOR_LOG_ID=c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
|
||||
REKOR_PREFER_TILE_PROOFS=false
|
||||
```
|
||||
|
||||
#### 3.4.8 Offline Verification Benefits
|
||||
|
||||
Tile-based verification enables true offline capability:
|
||||
|
||||
1. **Pre-fetch tiles**: Download all necessary tiles during online phase
|
||||
2. **Bundle checkpoint**: Include signed checkpoint with offline kit
|
||||
3. **Local proof computation**: Compute proofs entirely from local tile data
|
||||
4. **No API dependency**: Verification works without Rekor connectivity
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Offline Verification │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Checkpoint │────►│ Tile Cache │────►│ Proof │ │
|
||||
│ │ (signed) │ │ (local) │ │ Verifier │ │
|
||||
│ └─────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │
|
||||
│ Advantages: │
|
||||
│ - No network round-trips for proof fetching │
|
||||
│ - Deterministic verification (same tiles = same proof) │
|
||||
│ - Caching efficiency (tiles are immutable) │
|
||||
│ - Air-gap compatible │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. DATA FLOW
|
||||
@@ -688,4 +909,7 @@ attestor:
|
||||
- [RFC 6962: Certificate Transparency](https://datatracker.ietf.org/doc/html/rfc6962)
|
||||
- [Sigstore Rekor](https://github.com/sigstore/rekor)
|
||||
- [Transparency.dev Checkpoint Format](https://github.com/transparency-dev/formats)
|
||||
- [C2SP tlog-tiles Specification](https://c2sp.org/tlog-tiles) - Tile-based transparency log format
|
||||
- [Sunlight CT Log](https://github.com/FiloSottile/sunlight) - Reference implementation for tile-based logs
|
||||
- [Sigstore Rekor v2 Announcement](https://blog.sigstore.dev/) - Official Rekor v2 migration information
|
||||
- [Advisory: Rekor Integration Technical Reference](../../../product/advisories/14-Dec-2025%20-%20Rekor%20Integration%20Technical%20Reference.md)
|
||||
|
||||
Reference in New Issue
Block a user