Binary Evidence Alignment with SBOM/VEX Outputs (SC6)

Status: Draft · Date: 2025-12-04 Scope: Define how binary-level evidence (build-id, symbols, patch oracle) aligns with SBOM/VEX outputs to feed policy engines and VEX decisioning.

Objectives

Evidence Types

Build Identity Evidence

Evidence TypeSourceSBOM FieldVEX FieldPolicy Input
Build IDELF .note.gnu.build-idcomponent.properties[evidence:build-id]statement.products[].identifiers.buildIdbinary.buildId
Go Build Inforuntime.BuildInfocomponent.properties[evidence:go-build]n/abinary.goBuildInfo
PE VersionPE resource sectioncomponent.properties[evidence:pe-version]n/abinary.peVersion
Mach-O UUIDLC_UUID commandcomponent.properties[evidence:macho-uuid]n/abinary.machoUuid

Symbol Evidence

Evidence TypeSourceSBOM FieldVEX FieldPolicy Input
Exported SymbolsELF .dynsym / PE exportscomponent.properties[evidence:symbols-hash]n/abinary.symbolsHash
Debug SymbolsDWARF / PDBcomponent.properties[evidence:debug-hash]n/abinary.debugHash
Function NamesSymbol tablecomponent.properties[evidence:functions]statement.justification.functionsbinary.functions[]

Patch Oracle Evidence

Evidence TypeSourceSBOM FieldVEX FieldPolicy Input
Patch SignatureFunction hash diffcomponent.properties[evidence:patch-sig]statement.justification.patchSignaturepatch.signature
CVE Fix CommitCommit mappingcomponent.properties[evidence:fix-commit]statement.justification.fixCommitpatch.fixCommit
Binary Diffobjdiff hashcomponent.properties[evidence:binary-diff]n/apatch.binaryDiffHash

Evidence Chain

Binary → SBOM Component → VEX Statement → Policy Evaluation
   │          │                │                │
   │          │                │                └── policy://input/component/{purl}
   │          │                └── vex://statement/{cve}/{product}
   │          └── sbom://component/{purl}
   └── binary://evidence/{hash}

Join Keys

SourceTargetJoin FieldRequired
BinarySBOM Componentevidence:hashcomponent.hashes[]Yes
SBOM ComponentVEX Productcomponent.purlstatement.products[].purlYes
VEX StatementPolicy Inputstatement.cvepolicy.advisoryIdYes
Binary EvidenceVEX Justificationevidence:patch-sigjustification.patchSignatureNo

Required SBOM Evidence Properties

For binary evidence to flow through the pipeline, components MUST include:

{
  "type": "library",
  "name": "openssl",
  "version": "3.0.0",
  "purl": "pkg:generic/openssl@3.0.0",
  "hashes": [
    {"alg": "SHA-256", "content": "..."}
  ],
  "properties": [
    {"name": "evidence:hash", "value": "b3:..."},
    {"name": "evidence:source", "value": "scanner:binary-analyzer:v1.0.0"},
    {"name": "evidence:build-id", "value": "abc123..."},
    {"name": "evidence:symbols-hash", "value": "b3:..."},
    {"name": "evidence:patch-sig", "value": "b3:..."},
    {"name": "evidence:confidence", "value": "0.95"}
  ]
}

VEX Integration

VEX statements can reference binary evidence for justification:

{
  "vulnerability": "CVE-2025-0001",
  "products": [
    {
      "purl": "pkg:generic/openssl@3.0.0",
      "identifiers": {
        "buildId": "abc123...",
        "evidenceHash": "b3:..."
      }
    }
  ],
  "status": "not_affected",
  "justification": {
    "category": "vulnerable_code_not_present",
    "patchSignature": "b3:...",
    "fixCommit": "deadbeef...",
    "functions": ["EVP_EncryptUpdate", "EVP_DecryptUpdate"],
    "evidenceRef": "cas://evidence/openssl/3.0.0/binary-analysis.json"
  }
}

Policy Engine Integration

Policy rules can reference binary evidence fields:

# policy/scanner/binary-evidence.rego
package scanner.binary

import rego.v1

# Require build-id for high-severity vulns
deny contains msg if {
    input.vulnerability.severity == "critical"
    not input.component.properties["evidence:build-id"]
    msg := sprintf("Critical vuln %s requires build-id evidence", [input.vulnerability.id])
}

# Accept patch oracle evidence as mitigation
allow contains decision if {
    input.component.properties["evidence:patch-sig"]
    input.vex.status == "not_affected"
    input.vex.justification.patchSignature == input.component.properties["evidence:patch-sig"]
    decision := {
        "action": "accept",
        "reason": "Patch signature verified",
        "confidence": input.component.properties["evidence:confidence"]
    }
}

# Confidence threshold for binary analysis
warn contains msg if {
    conf := to_number(input.component.properties["evidence:confidence"])
    conf < 0.8
    msg := sprintf("Low confidence (%v) binary evidence for %s", [conf, input.component.purl])
}

Evidence Fields by Binary Format

ELF (Linux)

SectionEvidence ExtractedDeterministic
.note.gnu.build-idBuild ID (SHA1/UUID)Yes
.gnu.hashSymbol hash tableYes
.dynsymDynamic symbolsYes
.debug_infoDWARF debug symbolsYes
.rodataString literalsYes

PE (Windows)

SectionEvidence ExtractedDeterministic
PE HeaderTimestamp, Machine typePartial*
ResourceVersion info, Product nameYes
Export TableExported functionsYes
Import TableDependenciesYes
Debug DirectoryPDB path, GUIDYes

*PE timestamp may be zeroed for reproducible builds

Mach-O (macOS)

CommandEvidence ExtractedDeterministic
LC_UUIDBinary UUIDYes
LC_VERSION_MINMin OS versionYes
LC_BUILD_VERSIONBuild versionYes
LC_CODE_SIGNATURECode signatureYes
SYMTABSymbol tableYes

Determinism Requirements

  1. Stable ordering: Evidence properties sorted by name
  2. Hash computation: BLAKE3-256 over canonical JSON
  3. Confidence scores: 4 decimal places, MidpointRounding.ToZero
  4. Function lists: Sorted lexicographically, deduplicated
  5. Symbol hashes: Computed over sorted symbol names

CAS Storage

Binary evidence artifacts stored in CAS:

cas://evidence/{component}/{version}/
├── binary-analysis.json      # Full analysis result
├── symbols.txt               # Extracted symbols (sorted)
├── functions.txt             # Extracted functions (sorted)
└── patch-signatures.json     # Patch oracle signatures