- Implemented Attestation Chain API client with methods for verifying, fetching, and managing attestation chains. - Created models for Attestation Chain, including DSSE envelope structures and verification results. - Developed Triage Evidence API client for fetching finding evidence, including methods for evidence retrieval by CVE and component. - Added models for Triage Evidence, encapsulating evidence responses, entry points, boundary proofs, and VEX evidence. - Introduced mock implementations for both API clients to facilitate testing and development.
222 lines
6.1 KiB
Markdown
222 lines
6.1 KiB
Markdown
# Witness Schema v1 Contract
|
|
|
|
> **Version**: `stellaops.witness.v1`
|
|
> **Status**: Draft
|
|
> **Sprint**: `SPRINT_3700_0001_0001_witness_foundation`
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
A **witness** is a cryptographically-signed proof of a reachability path from an entrypoint to a vulnerable sink. Witnesses provide:
|
|
|
|
1. **Auditability** - Proof that a path was found at scan time
|
|
2. **Offline verification** - Verify claims without re-running analysis
|
|
3. **Provenance** - Links to the source graph and analysis context
|
|
4. **Transparency** - Can be published to transparency logs
|
|
|
|
---
|
|
|
|
## Schema Definition
|
|
|
|
### PathWitness
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://stellaops.org/schemas/witness-v1.json",
|
|
"schema_version": "stellaops.witness.v1",
|
|
"witness_id": "uuid",
|
|
"witness_hash": "blake3:abcd1234...",
|
|
"witness_type": "reachability_path",
|
|
"created_at": "2025-12-18T12:00:00Z",
|
|
|
|
"provenance": {
|
|
"graph_hash": "blake3:efgh5678...",
|
|
"scan_id": "uuid",
|
|
"run_id": "uuid",
|
|
"analyzer_version": "1.0.0",
|
|
"analysis_timestamp": "2025-12-18T11:59:00Z"
|
|
},
|
|
|
|
"path": {
|
|
"entrypoint": {
|
|
"fqn": "com.example.MyController.handleRequest",
|
|
"kind": "http_handler",
|
|
"location": {
|
|
"file": "src/main/java/com/example/MyController.java",
|
|
"line": 42
|
|
}
|
|
},
|
|
"sink": {
|
|
"fqn": "org.apache.log4j.Logger.log",
|
|
"cve": "CVE-2021-44228",
|
|
"package": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"
|
|
},
|
|
"steps": [
|
|
{
|
|
"index": 0,
|
|
"fqn": "com.example.MyController.handleRequest",
|
|
"call_site": "MyController.java:45",
|
|
"edge_type": "call"
|
|
},
|
|
{
|
|
"index": 1,
|
|
"fqn": "com.example.LoggingService.logMessage",
|
|
"call_site": "LoggingService.java:23",
|
|
"edge_type": "call"
|
|
},
|
|
{
|
|
"index": 2,
|
|
"fqn": "org.apache.log4j.Logger.log",
|
|
"call_site": "Logger.java:156",
|
|
"edge_type": "sink"
|
|
}
|
|
],
|
|
"hop_count": 3
|
|
},
|
|
|
|
"gates": [
|
|
{
|
|
"type": "auth_required",
|
|
"location": "MyController.java:40",
|
|
"description": "Requires authenticated user"
|
|
}
|
|
],
|
|
|
|
"evidence": {
|
|
"graph_fragment_hash": "blake3:ijkl9012...",
|
|
"path_hash": "blake3:mnop3456..."
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Field Definitions
|
|
|
|
### Root Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `schema_version` | string | Yes | Must be `stellaops.witness.v1` |
|
|
| `witness_id` | UUID | Yes | Unique identifier |
|
|
| `witness_hash` | string | Yes | BLAKE3 hash of canonical JSON |
|
|
| `witness_type` | enum | Yes | `reachability_path`, `gate_proof` |
|
|
| `created_at` | ISO8601 | Yes | Witness creation timestamp (UTC) |
|
|
|
|
### Provenance
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `graph_hash` | string | Yes | BLAKE3 hash of source rich graph |
|
|
| `scan_id` | UUID | No | Scan that produced the graph |
|
|
| `run_id` | UUID | No | Analysis run identifier |
|
|
| `analyzer_version` | string | Yes | Analyzer version |
|
|
| `analysis_timestamp` | ISO8601 | Yes | When analysis was performed |
|
|
|
|
### Path
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `entrypoint` | object | Yes | Entry point of the path |
|
|
| `sink` | object | Yes | Vulnerable sink at end of path |
|
|
| `steps` | array | Yes | Ordered list of path steps |
|
|
| `hop_count` | integer | Yes | Number of edges in path |
|
|
|
|
### Path Step
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `index` | integer | Yes | Position in path (0-indexed) |
|
|
| `fqn` | string | Yes | Fully qualified name of node |
|
|
| `call_site` | string | No | Source location of call |
|
|
| `edge_type` | enum | Yes | `call`, `virtual`, `static`, `sink` |
|
|
|
|
### Gates
|
|
|
|
Optional array of protective controls encountered along the path.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `type` | enum | Yes | `auth_required`, `feature_flag`, `admin_only`, `non_default_config` |
|
|
| `location` | string | No | Source location of gate |
|
|
| `description` | string | No | Human-readable description |
|
|
|
|
---
|
|
|
|
## Hash Computation
|
|
|
|
The `witness_hash` is computed as:
|
|
|
|
1. Serialize the witness to canonical JSON (sorted keys, no whitespace)
|
|
2. Exclude `witness_id`, `witness_hash`, and `created_at` fields
|
|
3. Compute BLAKE3 hash of the canonical bytes
|
|
4. Prefix with `blake3:` and hex-encode
|
|
|
|
```csharp
|
|
var canonical = JsonSerializer.Serialize(witness, canonicalOptions);
|
|
var hash = Blake3.Hasher.Hash(Encoding.UTF8.GetBytes(canonical));
|
|
var witnessHash = $"blake3:{Convert.ToHexString(hash.AsSpan()).ToLowerInvariant()}";
|
|
```
|
|
|
|
---
|
|
|
|
## DSSE Signing
|
|
|
|
Witnesses are signed using [DSSE (Dead Simple Signing Envelope)](https://github.com/secure-systems-lab/dsse):
|
|
|
|
```json
|
|
{
|
|
"payloadType": "application/vnd.stellaops.witness.v1+json",
|
|
"payload": "<base64url-encoded witness JSON>",
|
|
"signatures": [
|
|
{
|
|
"keyid": "sha256:abcd1234...",
|
|
"sig": "<base64url-encoded signature>"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Verification
|
|
|
|
1. Decode the payload from base64url
|
|
2. Parse as PathWitness JSON
|
|
3. Recompute witness_hash and compare
|
|
4. Verify signature against known public key
|
|
5. Optionally check transparency log for inclusion
|
|
|
|
---
|
|
|
|
## Storage
|
|
|
|
Witnesses are stored in `scanner.witnesses` table:
|
|
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| `witness_id` | UUID | Primary key |
|
|
| `witness_hash` | TEXT | BLAKE3 hash (unique) |
|
|
| `payload_json` | JSONB | Full witness JSON |
|
|
| `dsse_envelope` | JSONB | Signed envelope (nullable) |
|
|
| `graph_hash` | TEXT | Source graph reference |
|
|
| `sink_cve` | TEXT | CVE for quick lookup |
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| `GET` | `/api/v1/witnesses/{id}` | Get witness by ID |
|
|
| `GET` | `/api/v1/witnesses?cve={cve}` | List witnesses for CVE |
|
|
| `GET` | `/api/v1/witnesses?scan={scanId}` | List witnesses for scan |
|
|
| `POST` | `/api/v1/witnesses/{id}/verify` | Verify witness signature |
|
|
|
|
---
|
|
|
|
## Related Documents
|
|
|
|
- [Rich Graph Contract](richgraph-v1.md)
|
|
- [DSSE Specification](https://github.com/secure-systems-lab/dsse)
|
|
- [BLAKE3 Hash Function](https://github.com/BLAKE3-team/BLAKE3)
|