- 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.
6.1 KiB
6.1 KiB
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:
- Auditability - Proof that a path was found at scan time
- Offline verification - Verify claims without re-running analysis
- Provenance - Links to the source graph and analysis context
- Transparency - Can be published to transparency logs
Schema Definition
PathWitness
{
"$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:
- Serialize the witness to canonical JSON (sorted keys, no whitespace)
- Exclude
witness_id,witness_hash, andcreated_atfields - Compute BLAKE3 hash of the canonical bytes
- Prefix with
blake3:and hex-encode
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):
{
"payloadType": "application/vnd.stellaops.witness.v1+json",
"payload": "<base64url-encoded witness JSON>",
"signatures": [
{
"keyid": "sha256:abcd1234...",
"sig": "<base64url-encoded signature>"
}
]
}
Verification
- Decode the payload from base64url
- Parse as PathWitness JSON
- Recompute witness_hash and compare
- Verify signature against known public key
- 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 |