# Cosign Specification Alignment Check
## Official Cosign Specification (from sigstore/cosign)
### Algorithm & Cryptography
✅ **ECDSA P-256** - "cosign only generates ECDSA-P256 keys"
✅ **SHA256 hashing** - "uses SHA256 hashes"
✅ **Key Format**: PEM-encoded PKCS8 for private, SPKI for public - "Keys are stored in PEM format"
### Our Implementation in cosign-hash-provider.js
✅ Uses Node.js crypto with `prime256v1` (ECDSA P-256)
✅ Uses SHA256 for hashing: `crypto.createSign('sha256')`
✅ Generates keys with:
- Private: PKCS8 format (`type: 'pkcs8'`)
- Public: SPKI format (`type: 'spki'`)
---
## Critical Differences: Cosign vs Our Implementation
### 1. Cosign's Purpose: Container Image Registry Signing
- Cosign signs **container images stored in OCI registries**
- Stores signatures as artifacts in the same registry
- Signatures have a specific JSON payload format with metadata
### 2. Our Use Case: Plan & Audit Log Signing
- We sign **implementation plans** and **audit log entries**
- We store signatures **as file names** (plan signature is the filename)
- We store signatures **in audit log entries** (JSON lines format)
- We use raw ECDSA signatures, not cosign's payload format
---
## Signature Format Check
### Cosign's Payload Format (Red Hat Simple Signing)
```json
{
"critical" : {
"identity" : {
"docker-reference" : "image-name"
},
"image" : {
"Docker-manifest-digest" : "sha256:..."
},
"type" : "cosign container image signature"
},
"optional" : {
"creator" : "...",
"timestamp" : ...
}
}
```
### Our Signature Output
- **Raw ECDSA signature** in URL-safe Base64
- Format: `signature = crypto.createSign('sha256').sign(privateKey, 'base64')`
- Transformed to URL-safe: `+` → `-`, `/` → `_`, `=` removed
**This is CORRECT for our use case** - we don't need cosign's JSON payload wrapper for local plan/audit signing.
---
## URL-Safe Base64 Encoding
### Our Implementation
```javascript
// Convert to URL-safe base64
const urlSafe = signature
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
// Reverse for verification
const standardBase64 = signature
.replace(/-/g, '+')
.replace(/_/g, '/')
.padEnd(signature.length + (4 - (signature.length % 4)) % 4, '=');
```
✅ **CORRECT** - Standard approach for URL-safe Base64 (RFC 4648 urlsafe variant)
---
## Key Generation & Storage
### Our Implementation
```javascript
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'prime256v1',
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});
```
✅ **MATCHES COSIGN SPEC**
- ECDSA P-256 (prime256v1 is the same curve)
- SPKI for public key
- PKCS8 for private key
- PEM format
### Storage Location
- `.atlas-gate/.cosign-keys/public.pem`
- `.atlas-gate/.cosign-keys/private.pem`
✅ **GOOD** - Matches pattern from audit-system.js
---
## Verification Checklist
| Aspect | Cosign Spec | Our Impl | Status |
|--------|------------|---------|--------|
| Algorithm | ECDSA P-256 | Node.js crypto prime256v1 | ✅ Match |
| Hashing | SHA256 | crypto.createSign('sha256') | ✅ Match |
| Public Key Format | SPKI PEM | SPKI PEM | ✅ Match |
| Private Key Format | PKCS8 PEM | PKCS8 PEM | ✅ Match |
| Signature Encoding | Raw bytes (base64) | URL-safe Base64 | ✅ Match* |
| Key Generation | crypto methods | Node.js crypto | ✅ Match |
*URL-safe Base64 is appropriate for our filesystem/audit log storage
---
## Conclusion
**Our cosign implementation is CRYPTOGRAPHICALLY CORRECT** according to the official sigstore/cosign specification for:
- Key generation (ECDSA P-256)
- Key storage (SPKI/PKCS8 PEM format)
- Signing algorithm (SHA256 with ECDSA)
- Signature encoding (URL-safe Base64)
**Our use case differs from cosign's primary purpose** (container registry signing), but we use the same underlying cryptographic primitives correctly.
**Recent fixes ensure:**
- ✅ governance.js loads keyPair before signing
- ✅ audit-log.js loads keyPair before signing
- ✅ All signWithCosign calls pass (content, keyPair) correctly
- ✅ Signatures are deterministic and verifiable