# Binary Micro-Witness Verification Script # Sprint: SPRINT_0128_001_BinaryIndex_binary_micro_witness # Usage: .\verify.ps1 [-WitnessPath ] [-VerboseOutput] [CmdletBinding()] param( [Parameter(Position=0)] [string]$WitnessPath, [switch]$All, [switch]$VerboseOutput ) $ErrorActionPreference = "Stop" $Script:PassCount = 0 $Script:FailCount = 0 function Write-Status { param([string]$Status, [string]$Message, [string]$Color = "White") $symbol = switch ($Status) { "PASS" { "[OK]"; $Color = "Green" } "FAIL" { "[FAIL]"; $Color = "Red" } "SKIP" { "[SKIP]"; $Color = "Yellow" } "INFO" { "[INFO]"; $Color = "Cyan" } default { "[-]" } } Write-Host "$symbol " -ForegroundColor $Color -NoNewline Write-Host $Message } function Verify-Witness { param([string]$Path) Write-Host "`n=== Verifying: $Path ===" -ForegroundColor Cyan if (-not (Test-Path $Path)) { Write-Status "FAIL" "Witness file not found: $Path" $Script:FailCount++ return } try { $witness = Get-Content $Path -Raw | ConvertFrom-Json } catch { Write-Status "FAIL" "Failed to parse witness JSON: $_" $Script:FailCount++ return } # Handle both standalone predicate and in-toto statement formats $predicate = if ($witness.predicate) { $witness.predicate } else { $witness } # Verify required fields $requiredFields = @("schemaVersion", "binary", "cve", "verdict", "confidence", "tooling", "computedAt") $missingFields = @() foreach ($field in $requiredFields) { if (-not $predicate.$field) { $missingFields += $field } } if ($missingFields.Count -gt 0) { Write-Status "FAIL" "Missing required fields: $($missingFields -join ', ')" $Script:FailCount++ return } Write-Status "PASS" "All required fields present" # Display witness details Write-Host "`nWitness Details:" -ForegroundColor White Write-Host " Binary Digest: $($predicate.binary.digest)" Write-Host " Binary File: $($predicate.binary.filename)" Write-Host " CVE: $($predicate.cve.id)" Write-Host " Verdict: $($predicate.verdict)" Write-Host " Confidence: $([math]::Round($predicate.confidence * 100, 1))%" Write-Host " Computed At: $($predicate.computedAt)" # Verify schema version if ($predicate.schemaVersion -eq "1.0.0") { Write-Status "PASS" "Schema version: $($predicate.schemaVersion)" } else { Write-Status "SKIP" "Unknown schema version: $($predicate.schemaVersion)" } # Verify binary digest format if ($predicate.binary.digest -match "^sha256:[a-fA-F0-9]{64}$") { Write-Status "PASS" "Binary digest format valid" } else { Write-Status "FAIL" "Invalid binary digest format" $Script:FailCount++ return } # Verify CVE ID format if ($predicate.cve.id -match "^CVE-\d{4}-\d{4,}$") { Write-Status "PASS" "CVE ID format valid" } else { Write-Status "SKIP" "Non-standard vulnerability ID: $($predicate.cve.id)" } # Verify verdict $validVerdicts = @("patched", "vulnerable", "inconclusive", "partial") if ($predicate.verdict -in $validVerdicts) { $verdictColor = switch ($predicate.verdict) { "patched" { "Green" } "vulnerable" { "Red" } "inconclusive" { "Yellow" } "partial" { "Yellow" } } Write-Status "PASS" "Verdict: $($predicate.verdict)" -Color $verdictColor } else { Write-Status "FAIL" "Invalid verdict: $($predicate.verdict)" $Script:FailCount++ return } # Verify confidence range if ($predicate.confidence -ge 0 -and $predicate.confidence -le 1) { Write-Status "PASS" "Confidence in valid range" } else { Write-Status "FAIL" "Confidence out of range: $($predicate.confidence)" $Script:FailCount++ return } # Check evidence if ($predicate.evidence -and $predicate.evidence.Count -gt 0) { Write-Status "PASS" "Evidence present: $($predicate.evidence.Count) function(s)" if ($VerboseOutput) { Write-Host "`nFunction Evidence:" -ForegroundColor White foreach ($ev in $predicate.evidence) { $stateColor = switch ($ev.state) { "patched" { "Green" } "vulnerable" { "Red" } "modified" { "Yellow" } "unchanged" { "Gray" } default { "White" } } Write-Host " - $($ev.function): " -NoNewline Write-Host "$($ev.state)" -ForegroundColor $stateColor -NoNewline Write-Host " (score: $([math]::Round($ev.score * 100, 1))%, method: $($ev.method))" } } } else { Write-Status "SKIP" "No function-level evidence provided" } # Check tooling Write-Status "INFO" "Tooling: BinaryIndex $($predicate.tooling.binaryIndexVersion), Lifter: $($predicate.tooling.lifter)" # TODO: Signature verification (not yet implemented) Write-Status "SKIP" "Signature verification (not yet implemented)" # TODO: Rekor proof verification (not yet implemented) Write-Status "SKIP" "Rekor inclusion proof (not yet implemented)" $Script:PassCount++ Write-Host "`nResult: " -NoNewline Write-Host "VERIFIED" -ForegroundColor Green } # Main Write-Host "Binary Micro-Witness Verification" -ForegroundColor Cyan Write-Host "==================================" -ForegroundColor Cyan Write-Host "Sprint: SPRINT_0128_001_BinaryIndex_binary_micro_witness" Write-Host "" if ($All) { $witnessDir = Join-Path $PSScriptRoot "witnesses" $witnesses = Get-ChildItem -Path $witnessDir -Filter "*.json" -ErrorAction SilentlyContinue if ($witnesses.Count -eq 0) { Write-Host "No witness files found in $witnessDir" -ForegroundColor Yellow exit 1 } foreach ($w in $witnesses) { Verify-Witness -Path $w.FullName } } elseif ($WitnessPath) { Verify-Witness -Path $WitnessPath } else { # Default: verify all witnesses $witnessDir = Join-Path $PSScriptRoot "witnesses" $witnesses = Get-ChildItem -Path $witnessDir -Filter "*.json" -ErrorAction SilentlyContinue if ($witnesses.Count -eq 0) { Write-Host "Usage: .\verify.ps1 [-WitnessPath ] [-All] [-Verbose]" -ForegroundColor Yellow Write-Host "" Write-Host "Examples:" Write-Host " .\verify.ps1 witnesses\openssl-cve-2024-0567.json" Write-Host " .\verify.ps1 -All -Verbose" exit 1 } foreach ($w in $witnesses) { Verify-Witness -Path $w.FullName } } Write-Host "`n==================================" -ForegroundColor Cyan Write-Host "Summary: $Script:PassCount passed, $Script:FailCount failed" -ForegroundColor $(if ($Script:FailCount -eq 0) { "Green" } else { "Red" }) exit $Script:FailCount