Add signal contracts for reachability, exploitability, trust, and unknown symbols
- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties. - Implemented JSON serialization attributes for proper data interchange. - Created project files for the new signal contracts library and corresponding test projects. - Added deterministic test fixtures for micro-interaction testing. - Included cryptographic keys for secure operations with cosign.
This commit is contained in:
255
docs/modules/scanner/design/competitor-signature-verification.md
Normal file
255
docs/modules/scanner/design/competitor-signature-verification.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# Competitor SBOM/Scan Signature Verification (CM2)
|
||||
|
||||
Status: Draft · Date: 2025-12-04
|
||||
Scope: Specify signature and provenance verification requirements for accepting external SBOM and scan outputs, including rejection/flag policies.
|
||||
|
||||
## Objectives
|
||||
|
||||
- Define acceptable signature algorithms and formats.
|
||||
- Establish trust root management for external signers.
|
||||
- Specify verification workflow and failure modes.
|
||||
- Enable offline verification with bundled trust roots.
|
||||
|
||||
## Acceptable Signatures
|
||||
|
||||
### Signature Formats
|
||||
|
||||
| Format | Algorithm | Key Type | Status |
|
||||
|--------|-----------|----------|--------|
|
||||
| DSSE | Ed25519 | Asymmetric | Preferred |
|
||||
| DSSE | ECDSA P-256 | Asymmetric | Accepted |
|
||||
| DSSE | RSA-2048+ | Asymmetric | Accepted |
|
||||
| COSE | EdDSA | Asymmetric | Accepted |
|
||||
| JWS | ES256 | Asymmetric | Accepted |
|
||||
| JWS | RS256 | Asymmetric | Deprecated |
|
||||
|
||||
### Hash Algorithms
|
||||
|
||||
| Algorithm | Usage | Status |
|
||||
|-----------|-------|--------|
|
||||
| SHA-256 | Primary | Required |
|
||||
| BLAKE3-256 | Secondary | Preferred |
|
||||
| SHA-384 | Alternative | Accepted |
|
||||
| SHA-512 | Alternative | Accepted |
|
||||
| SHA-1 | Legacy | Rejected |
|
||||
| MD5 | Legacy | Rejected |
|
||||
|
||||
## Trust Root Management
|
||||
|
||||
### Bundled Trust Roots
|
||||
|
||||
```
|
||||
out/offline/competitor-ingest-kit-v1/trust/
|
||||
├── root-ca.pem # CA for signed SBOMs
|
||||
├── keyring.json # Known signing keys
|
||||
├── cosign-keys/ # Cosign public keys
|
||||
│ ├── syft-release.pub
|
||||
│ ├── trivy-release.pub
|
||||
│ └── clair-release.pub
|
||||
└── fulcio-root.pem # Sigstore Fulcio CA
|
||||
```
|
||||
|
||||
### Keyring Format
|
||||
|
||||
```json
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"id": "syft-release-2025",
|
||||
"type": "ecdsa-p256",
|
||||
"publicKey": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
|
||||
"issuer": "https://github.com/anchore/syft",
|
||||
"validFrom": "2025-01-01T00:00:00Z",
|
||||
"validTo": "2026-01-01T00:00:00Z",
|
||||
"purposes": ["sbom-signing", "attestation-signing"]
|
||||
}
|
||||
],
|
||||
"trustedIssuers": [
|
||||
"https://github.com/anchore/syft",
|
||||
"https://github.com/aquasecurity/trivy",
|
||||
"https://github.com/quay/clair"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Verification Workflow
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Receive │
|
||||
│ SBOM │
|
||||
└─────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Has DSSE? │──No─► Has JWS? │──No─► Unsigned
|
||||
└─────────────┘ └─────────────┘ │
|
||||
│ │ │
|
||||
Yes Yes │
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Verify DSSE │ │ Verify JWS │ │ Apply CM6 │
|
||||
│ Signature │ │ Signature │ │ Fallback │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Valid? │ │ Valid? │ │ Provenance: │
|
||||
└─────────────┘ └─────────────┘ │ unknown │
|
||||
│ │ │ │ └─────────────┘
|
||||
Yes No Yes No
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
Accept Reject Accept Reject
|
||||
```
|
||||
|
||||
### Verification Steps
|
||||
|
||||
1. **Format Detection**
|
||||
- Check for DSSE envelope wrapper
|
||||
- Check for detached signature file (`.sig`)
|
||||
- Check for inline JWS header
|
||||
|
||||
2. **Signature Extraction**
|
||||
- Parse envelope/signature structure
|
||||
- Extract signer key ID and algorithm
|
||||
|
||||
3. **Key Lookup**
|
||||
- Search bundled keyring for key ID
|
||||
- Verify key is within validity period
|
||||
- Check key purpose matches usage
|
||||
|
||||
4. **Cryptographic Verification**
|
||||
- Verify signature over payload
|
||||
- Verify hash matches content
|
||||
- Check for signature expiry
|
||||
|
||||
5. **Provenance Validation**
|
||||
- Extract signer identity
|
||||
- Verify issuer is trusted
|
||||
- Check build metadata if present
|
||||
|
||||
## Failure Modes
|
||||
|
||||
### Rejection Reasons
|
||||
|
||||
| Code | Reason | Action |
|
||||
|------|--------|--------|
|
||||
| `sig_missing` | No signature present | Apply fallback (CM6) |
|
||||
| `sig_invalid` | Signature verification failed | Reject |
|
||||
| `sig_expired` | Signature validity period exceeded | Reject |
|
||||
| `key_unknown` | Signing key not in keyring | Reject |
|
||||
| `key_expired` | Signing key validity exceeded | Reject |
|
||||
| `key_revoked` | Signing key has been revoked | Reject |
|
||||
| `issuer_untrusted` | Issuer not in trusted list | Reject |
|
||||
| `alg_unsupported` | Algorithm not acceptable | Reject |
|
||||
| `hash_mismatch` | Content hash doesn't match | Reject |
|
||||
|
||||
### Flag Policy
|
||||
|
||||
When `--allow-unsigned` is set:
|
||||
|
||||
| Condition | Behavior |
|
||||
|-----------|----------|
|
||||
| Signature missing | Accept with `provenance=unknown`, emit warning |
|
||||
| Signature invalid | Reject (flag doesn't override invalid) |
|
||||
| Key unknown | Accept with `provenance=unverified`, emit warning |
|
||||
|
||||
## Verification API
|
||||
|
||||
### Endpoint
|
||||
|
||||
```http
|
||||
POST /api/v1/ingest/verify
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sbom": "<base64-encoded-sbom>",
|
||||
"signature": "<base64-encoded-signature>",
|
||||
"options": {
|
||||
"allowUnsigned": false,
|
||||
"requireProvenance": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"verification": {
|
||||
"status": "valid",
|
||||
"signature": {
|
||||
"format": "dsse",
|
||||
"algorithm": "ecdsa-p256",
|
||||
"keyId": "syft-release-2025",
|
||||
"signedAt": "2025-12-04T00:00:00Z"
|
||||
},
|
||||
"provenance": {
|
||||
"issuer": "https://github.com/anchore/syft",
|
||||
"buildId": "build-12345",
|
||||
"sourceRepo": "https://github.com/example/app"
|
||||
},
|
||||
"hash": {
|
||||
"algorithm": "sha256",
|
||||
"value": "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Offline Verification
|
||||
|
||||
### Requirements
|
||||
|
||||
- All trust roots bundled in offline kit
|
||||
- No network calls during verification
|
||||
- Keyring includes all expected signers
|
||||
- CRL/OCSP checks disabled (use bundled revocation lists)
|
||||
|
||||
### Revocation List Format
|
||||
|
||||
```json
|
||||
{
|
||||
"revoked": [
|
||||
{
|
||||
"keyId": "compromised-key-2024",
|
||||
"revokedAt": "2024-12-01T00:00:00Z",
|
||||
"reason": "Key compromise"
|
||||
}
|
||||
],
|
||||
"lastUpdated": "2025-12-04T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with Normalization (CM1)
|
||||
|
||||
After successful verification:
|
||||
|
||||
1. Extract tool metadata from signature/provenance
|
||||
2. Pass to normalization adapter
|
||||
3. Include verification result in normalized output
|
||||
|
||||
```json
|
||||
{
|
||||
"source": {
|
||||
"tool": "syft",
|
||||
"version": "1.0.0",
|
||||
"hash": "sha256:..."
|
||||
},
|
||||
"verification": {
|
||||
"status": "verified",
|
||||
"keyId": "syft-release-2025",
|
||||
"signedAt": "2025-12-04T00:00:00Z"
|
||||
},
|
||||
"components": [...],
|
||||
"normalized_hash": "blake3:..."
|
||||
}
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- Sprint: `docs/implplan/SPRINT_0186_0001_0001_record_deterministic_execution.md` (CM2)
|
||||
- Normalization: `docs/modules/scanner/design/competitor-ingest-normalization.md` (CM1)
|
||||
- Fallback: See CM6 in this document series
|
||||
Reference in New Issue
Block a user