Add tests for SBOM generation determinism across multiple formats

- Created `StellaOps.TestKit.Tests` project for unit tests related to determinism.
- Implemented `DeterminismManifestTests` to validate deterministic output for canonical bytes and strings, file read/write operations, and error handling for invalid schema versions.
- Added `SbomDeterminismTests` to ensure identical inputs produce consistent SBOMs across SPDX 3.0.1 and CycloneDX 1.6/1.7 formats, including parallel execution tests.
- Updated project references in `StellaOps.Integration.Determinism` to include the new determinism testing library.
This commit is contained in:
master
2025-12-23 18:56:12 +02:00
committed by StellaOps Bot
parent 7ac70ece71
commit 491e883653
409 changed files with 23797 additions and 17779 deletions

View File

@@ -1,319 +1,598 @@
# Offline Verification Crypto Provider
# Offline Verification Crypto Provider - Security Guide
**Provider ID:** `offline-verification`
**Version:** 1.0
**Status:** Production
**Last Updated:** 2025-12-23
**Sprint:** SPRINT_1000_0007_0002
**Document Version**: 1.0
**Last Updated**: 2025-12-23
**Status**: Active
**Audience**: Security Engineers, Platform Operators, DevOps Teams
**Sprint**: SPRINT_1000_0007_0002
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Security Model](#security-model)
4. [Algorithm Support](#algorithm-support)
5. [Deployment Scenarios](#deployment-scenarios)
6. [API Reference](#api-reference)
7. [Trust Establishment](#trust-establishment)
8. [Threat Model](#threat-model)
9. [Compliance](#compliance)
10. [Best Practices](#best-practices)
11. [Troubleshooting](#troubleshooting)
---
## Overview
The **OfflineVerificationCryptoProvider** is a cryptographic provider designed for offline and air-gapped environments. It wraps .NET BCL cryptography (`System.Security.Cryptography`) within the `ICryptoProvider` abstraction, enabling configuration-driven crypto while maintaining offline verification capabilities.
The **OfflineVerificationCryptoProvider** is a cryptographic abstraction layer that wraps .NET BCL (`System.Security.Cryptography`) to enable **configuration-driven cryptography** in offline, air-gapped, and sovereignty-constrained environments.
This provider is particularly useful for:
- **Air-gapped deployments** where hardware security modules (HSMs) are unavailable
- **Offline bundle verification** in disconnected environments
- **Development and testing** environments
- **Fallback scenarios** when regional crypto providers are unavailable
### Purpose
## When to Use This Provider
- **Offline Operations**: Function without network access to external cryptographic services
- **Deterministic Behavior**: Reproducible signatures and hashes for compliance auditing
- **Zero External Dependencies**: No cloud KMS, HSMs, or online certificate authorities required
- **Regional Neutrality**: NIST-approved algorithms without regional compliance constraints
### ✅ Recommended Use Cases
### Key Features
1. **Air-Gapped Bundle Verification**
- Verifying DSSE-signed evidence bundles in disconnected environments
- Validating attestations without external connectivity
- Offline policy verification
- ECDSA (ES256/384/512) and RSA (RS256/384/512, PS256/384/512) signing/verification
- SHA-2 family hashing (SHA-256/384/512)
- Ephemeral verification for public-key-only scenarios (DSSE, JWT, JWS)
- Configuration-driven plugin architecture with priority-based selection
- Zero-cost abstraction over .NET BCL primitives
2. **Development & Testing**
- Local development without HSM dependencies
- CI/CD pipelines for automated testing
- Integration test environments
---
3. **Fallback Provider**
- When regional providers (GOST, SM, eIDAS) are unavailable
- Default offline verification path
## Architecture
### ❌ NOT Recommended For
### Component Hierarchy
1. **Production Signing Operations** - Use HSM-backed providers instead
2. **Compliance-Critical Scenarios** - Use certified providers (FIPS, eIDAS, etc.)
3. **High-Value Key Storage** - Use hardware-backed key storage
```
┌─────────────────────────────────────────────────────────┐
│ Production Code (AirGap, Scanner, Attestor) │
│ ├── Uses: ICryptoProvider abstraction │
│ └── Never touches: System.Security.Cryptography │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ StellaOps.Cryptography (Core Abstraction) │
│ ├── ICryptoProvider interface │
│ ├── ICryptoSigner interface │
│ ├── ICryptoHasher interface │
│ └── CryptoProviderRegistry │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ OfflineVerificationCryptoProvider (Plugin) │
│ ├── BclHasher (SHA-256/384/512) │
│ ├── EcdsaSigner (ES256/384/512) │
│ ├── RsaSigner (RS/PS 256/384/512) │
│ ├── EcdsaEphemeralVerifier (public-key-only) │
│ └── RsaEphemeralVerifier (public-key-only) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ System.Security.Cryptography (.NET BCL) │
│ ├── ECDsa (NIST P-256/384/521) │
│ ├── RSA (2048/3072/4096-bit) │
│ └── SHA256/SHA384/SHA512 │
└─────────────────────────────────────────────────────────┘
```
## Supported Algorithms
### Isolation Boundaries
**Crypto Operations Allowed**:
- ✅ Inside `StellaOps.Cryptography.Plugin.*` projects
- ✅ Inside unit test projects (`__Tests/**`)
-**NEVER** in production application code
**Enforcement Mechanisms**:
1. **Static Analysis**: `scripts/audit-crypto-usage.ps1`
2. **CI Validation**: `.gitea/workflows/crypto-compliance.yml`
3. **Code Review**: Automated checks on pull requests
---
## Security Model
### Threat Categories
| Threat | Likelihood | Impact | Mitigation |
|--------|------------|--------|------------|
| **Key Extraction** | Medium | High | In-memory keys only, minimize key lifetime |
| **Side-Channel (Timing)** | Low | Medium | .NET BCL uses constant-time primitives |
| **Algorithm Downgrade** | Very Low | Critical | Compile-time algorithm allowlist |
| **Public Key Substitution** | Medium | Critical | Fingerprint verification, out-of-band trust |
| **Replay Attack** | Medium | Medium | Include timestamps in signed payloads |
| **Man-in-the-Middle** | Low (offline) | N/A | Physical media transport |
### Trust Boundaries
```
┌────────────────────────────────────────────────────────┐
│ Trusted Computing Base (TCB) │
│ ├── .NET Runtime (Microsoft-signed) │
│ ├── OfflineVerificationCryptoProvider (AGPL-3.0) │
│ └── Pre-distributed Public Key Fingerprints │
└────────────────────────────────────────────────────────┘
│ Trust Anchor
┌────────────────────────────────────────────────────────┐
│ Untrusted Zone │
│ ├── Container Images (to be verified) │
│ ├── SBOMs (to be verified) │
│ └── VEX Documents (to be verified) │
└────────────────────────────────────────────────────────┘
```
**Trust Establishment**:
1. **Pre-distribution**: Public key fingerprints embedded in airgap bundle
2. **Out-of-Band Verification**: Manual verification via secure channel
3. **Chain of Trust**: Each signature verified against trusted fingerprints
---
## Algorithm Support
### Signing & Verification
| Algorithm | Curve/Key Size | Hash | Padding | Notes |
|-----------|----------------|------|---------|-------|
| ES256 | NIST P-256 | SHA-256 | N/A | ECDSA with SHA-256 |
| ES384 | NIST P-384 | SHA-384 | N/A | ECDSA with SHA-384 |
| ES512 | NIST P-521 | SHA-512 | N/A | ECDSA with SHA-512 |
| RS256 | RSA 2048+ | SHA-256 | PKCS1 | RSA with PKCS#1 v1.5 padding |
| RS384 | RSA 2048+ | SHA-384 | PKCS1 | RSA with PKCS#1 v1.5 padding |
| RS512 | RSA 2048+ | SHA-512 | PKCS1 | RSA with PKCS#1 v1.5 padding |
| PS256 | RSA 2048+ | SHA-256 | PSS | RSA-PSS with SHA-256 |
| PS384 | RSA 2048+ | SHA-384 | PSS | RSA-PSS with SHA-384 |
| PS512 | RSA 2048+ | SHA-512 | PSS | RSA-PSS with SHA-512 |
| Algorithm | Curve/Key Size | Hash | Padding | Use Case |
|-----------|----------------|------|---------|----------|
| **ES256** | NIST P-256 | SHA-256 | N/A | DSSE envelopes, in-toto attestations |
| **ES384** | NIST P-384 | SHA-384 | N/A | High-security SBOM signatures |
| **ES512** | NIST P-521 | SHA-512 | N/A | Long-term archival signatures |
| **RS256** | 2048+ bits | SHA-256 | PKCS1 | Legacy compatibility |
| **RS384** | 2048+ bits | SHA-384 | PKCS1 | Legacy compatibility |
| **RS512** | 2048+ bits | SHA-512 | PKCS1 | Legacy compatibility |
| **PS256** | 2048+ bits | SHA-256 | PSS | Recommended RSA (FIPS 186-4) |
| **PS384** | 2048+ bits | SHA-384 | PSS | Recommended RSA (FIPS 186-4) |
| **PS512** | 2048+ bits | SHA-512 | PSS | Recommended RSA (FIPS 186-4) |
### Content Hashing
| Algorithm | Output Size | Aliases |
|-----------|-------------|---------|
| SHA-256 | 32 bytes | SHA256 |
| SHA-384 | 48 bytes | SHA384 |
| SHA-512 | 64 bytes | SHA512 |
| Algorithm | Output Size | Performance | Use Case |
|-----------|-------------|-------------|----------|
| **SHA-256** | 256 bits | Fast | Default for most use cases |
| **SHA-384** | 384 bits | Medium | Medium-security requirements |
| **SHA-512** | 512 bits | Medium | High-security requirements |
**Normalization**: Both `SHA-256` and `SHA256` formats accepted, normalized to `SHA-256`.
### Password Hashing
**Not Supported.** The offline verification provider does not implement password hashing. Use dedicated password hashers:
**Not Supported.** Use dedicated password hashers:
- `Argon2idPasswordHasher` for modern password hashing
- `Pbkdf2PasswordHasher` for legacy compatibility
## API Reference
---
### Basic Usage
## Deployment Scenarios
```csharp
using StellaOps.Cryptography;
using StellaOps.Cryptography.Plugin.OfflineVerification;
### Scenario 1: Air-Gapped Container Scanning
// Create provider instance
var provider = new OfflineVerificationCryptoProvider();
**Environment**: Offline network segment, no internet access
// Check algorithm support
bool supportsES256 = provider.Supports(CryptoCapability.Signing, "ES256");
// Returns: true
// Get a hasher
var hasher = provider.GetHasher("SHA-256");
var hash = hasher.ComputeHash(dataBytes);
// Get a signer (requires key reference)
var keyRef = new CryptoKeyReference("my-signing-key");
var signer = provider.GetSigner("ES256", keyRef);
var signature = await signer.SignAsync(dataBytes);
```
### Ephemeral Verification (New in v1.0)
For verification-only scenarios where you have raw public key bytes (e.g., DSSE verification):
```csharp
// Create ephemeral verifier from SubjectPublicKeyInfo bytes
byte[] publicKeyBytes = LoadPublicKeyFromDsse();
var verifier = provider.CreateEphemeralVerifier("ES256", publicKeyBytes);
// Verify signature (no private key required)
var isValid = await verifier.VerifyAsync(dataBytes, signatureBytes);
```
**When to use ephemeral verification:**
- DSSE envelope verification with inline public keys
- One-time verification operations
- No need to persist keys in provider's key store
### Dependency Injection Setup
```csharp
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Cryptography;
using StellaOps.Cryptography.Plugin.OfflineVerification;
// Add to DI container
services.AddSingleton<ICryptoProvider, OfflineVerificationCryptoProvider>();
// Or use with crypto provider registry
services.AddSingleton<ICryptoProviderRegistry>(sp =>
**Configuration**:
```json
{
var registry = new CryptoProviderRegistry();
registry.RegisterProvider(new OfflineVerificationCryptoProvider());
return registry;
});
```
### Air-Gapped Bundle Verification Example
```csharp
using StellaOps.Cryptography;
using StellaOps.Cryptography.Plugin.OfflineVerification;
using StellaOps.AirGap.Importer.Validation;
// Initialize provider
var cryptoRegistry = new CryptoProviderRegistry([
new OfflineVerificationCryptoProvider()
]);
// Create DSSE verifier with crypto provider
var dsseVerifier = new DsseVerifier(cryptoRegistry);
// Verify bundle signature
var trustRoots = new TrustRootConfig
{
PublicKeys = new Dictionary<string, byte[]>
{
["airgap-signer"] = LoadPublicKeyBytes()
},
TrustedKeyFingerprints = new HashSet<string>
{
ComputeFingerprint(LoadPublicKeyBytes())
}
};
var result = dsseVerifier.Verify(dsseEnvelope, trustRoots);
if (result.IsSuccess)
{
Console.WriteLine("Bundle signature verified successfully!");
"cryptoProvider": "offline-verification",
"algorithms": {
"signing": "ES256",
"hashing": "SHA-256"
},
"trustRoots": {
"fingerprints": [
"sha256:a1b2c3d4e5f6....",
"sha256:f6e5d4c3b2a1...."
]
}
}
```
## Configuration
**Trust Establishment**:
1. Pre-distribute trust bundle via USB/DVD: `offline-kit.tar.gz`
2. Bundle contains:
- Public key fingerprints (`trust-anchors.json`)
- Root CA certificates (if applicable)
- Offline crypto provider plugin
3. Operator verifies bundle signature using out-of-band channel
### crypto-plugins-manifest.json
**Workflow**:
```
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Scan │──▶│ Generate │──▶│ Sign │──▶│ Verify │
│ Container│ │ SBOM │ │ with ES256│ │ Signature│
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
OfflineVerificationCryptoProvider
```
The offline verification provider is typically enabled by default:
### Scenario 2: Sovereign Cloud Deployment
**Environment**: National cloud with data residency requirements
**Configuration**:
```json
{
"cryptoProvider": "offline-verification",
"jurisdiction": "world",
"compliance": ["NIST", "offline-airgap"],
"keyRotation": {
"enabled": true,
"intervalDays": 90
}
}
```
**Key Considerations**:
- Keys generated and stored within sovereign boundary
- No external KMS dependencies
- Audit trail for all cryptographic operations
- Compliance with local data protection laws
### Scenario 3: CI/CD Pipeline with Reproducible Builds
**Environment**: Build server with deterministic signing
**Configuration**:
```json
{
"cryptoProvider": "offline-verification",
"deterministicSigning": true,
"algorithms": {
"signing": "ES256",
"hashing": "SHA-256"
}
}
```
**Workflow**:
1. Build produces identical artifact hash
2. Offline provider signs with deterministic ECDSA (RFC 6979)
3. CI stores signature alongside artifact
4. Downstream consumers verify signature before deployment
---
## API Reference
### ICryptoProvider.CreateEphemeralVerifier (New in v1.0)
**Signature**:
```csharp
ICryptoSigner CreateEphemeralVerifier(
string algorithmId,
ReadOnlySpan<byte> publicKeyBytes)
```
**Purpose**: Create a verification-only signer from raw public key bytes, without key persistence or management overhead.
**Parameters**:
- `algorithmId`: Algorithm identifier (ES256, RS256, PS256, etc.)
- `publicKeyBytes`: Public key in **SubjectPublicKeyInfo** (SPKI) format, DER-encoded
**Returns**: `ICryptoSigner` instance with:
- `VerifyAsync(data, signature)` - Returns `true` if signature valid
- `SignAsync(data)` - Throws `NotSupportedException`
- `KeyId` - Returns `"ephemeral"`
- `AlgorithmId` - Returns the specified algorithm
**Throws**:
- `NotSupportedException`: Algorithm not supported or public key format invalid
- `CryptographicException`: Public key parsing failed
**Usage Example**:
```csharp
// DSSE envelope verification
var envelope = DsseEnvelope.Parse(envelopeJson);
var trustRoots = LoadTrustRoots();
foreach (var signature in envelope.Signatures)
{
// Get public key from trust store
if (!trustRoots.PublicKeys.TryGetValue(signature.KeyId, out var publicKeyBytes))
continue;
// Verify fingerprint
var fingerprint = ComputeFingerprint(publicKeyBytes);
if (!trustRoots.TrustedFingerprints.Contains(fingerprint))
continue;
// Create ephemeral verifier
var verifier = cryptoProvider.CreateEphemeralVerifier("PS256", publicKeyBytes);
// Build pre-authentication encoding (PAE)
var pae = BuildPAE(envelope.PayloadType, envelope.Payload);
// Verify signature
var isValid = await verifier.VerifyAsync(pae, Convert.FromBase64String(signature.Signature));
if (isValid)
return ValidationResult.Success();
}
return ValidationResult.Failure("No valid signature found");
```
### ICryptoHasher.ComputeHash
**Signature**:
```csharp
byte[] ComputeHash(ReadOnlySpan<byte> data)
```
**Usage Example**:
```csharp
var hasher = cryptoProvider.GetHasher("SHA-256");
var hash = hasher.ComputeHash(fileBytes);
var hex = Convert.ToHexString(hash).ToLowerInvariant();
```
### ICryptoSigner.SignAsync / VerifyAsync
**Signatures**:
```csharp
ValueTask<byte[]> SignAsync(ReadOnlyMemory<byte> data, CancellationToken ct = default)
ValueTask<bool> VerifyAsync(ReadOnlyMemory<byte> data, ReadOnlyMemory<byte> signature, CancellationToken ct = default)
```
**Usage Example**:
```csharp
// Signing
var signingKey = new CryptoSigningKey(
reference: new CryptoKeyReference("my-key"),
algorithmId: "ES256",
privateParameters: ecParameters,
createdAt: DateTimeOffset.UtcNow);
cryptoProvider.UpsertSigningKey(signingKey);
var signer = cryptoProvider.GetSigner("ES256", new CryptoKeyReference("my-key"));
var signature = await signer.SignAsync(data);
// Verification
var isValid = await signer.VerifyAsync(data, signature);
```
---
## Trust Establishment
### Offline Trust Bundle Structure
```
offline-kit.tar.gz
├── trust-anchors.json # Public key fingerprints
├── public-keys/ # Public keys in SPKI format
│ ├── scanner-key-001.pub
│ ├── scanner-key-002.pub
│ └── attestor-key-001.pub
├── metadata/
│ ├── bundle-manifest.json # Bundle metadata
│ └── bundle-signature.sig # Bundle self-signature
└── crypto-plugins/
└── StellaOps.Cryptography.Plugin.OfflineVerification.dll
```
### trust-anchors.json Format
```json
{
"plugins": [
"version": "1.0",
"createdAt": "2025-12-23T00:00:00Z",
"expiresAt": "2026-12-23T00:00:00Z",
"trustAnchors": [
{
"name": "offline-verification",
"assembly": "StellaOps.Cryptography.Plugin.OfflineVerification.dll",
"type": "StellaOps.Cryptography.Plugin.OfflineVerification.OfflineVerificationCryptoProvider",
"enabled": true,
"priority": 45,
"config": {}
"keyId": "scanner-key-001",
"algorithmId": "ES256",
"fingerprint": "sha256:a1b2c3d4e5f6...",
"purpose": "container-scanning",
"notBefore": "2025-01-01T00:00:00Z",
"notAfter": "2026-01-01T00:00:00Z"
}
]
],
"bundleSignature": {
"keyId": "bundle-signing-key",
"algorithmId": "ES256",
"signature": "base64encodedSignature=="
}
}
```
**Priority:** `45` - Higher than default (50), lower than regional providers (10-40)
### Fingerprint Computation
### Environment Variables
No environment variables required. The provider is self-contained.
## Security Considerations
### ✅ Safe for Verification
The offline verification provider is **safe for verification operations** in offline environments:
- Public key verification
- Signature validation
- Hash computation
- Bundle integrity checks
### ⚠️ Signing Key Protection
**Private keys used with this provider MUST be protected:**
1. **Key Storage:**
- Use encrypted key files with strong passphrases
- Store in secure filesystem locations with restricted permissions
- Consider using OS-level key storage (Windows DPAPI, macOS Keychain)
2. **Key Rotation:**
- Rotate signing keys periodically
- Maintain key version tracking for bundle verification
3. **Access Control:**
- Limit file system permissions on private keys (chmod 600 on Unix)
- Use separate keys for dev/test/prod environments
### Deterministic Operations
The provider ensures deterministic operations where required:
- **Hash computation:** SHA-256/384/512 are deterministic
- **Signature verification:** Deterministic for given signature and public key
- **ECDSA signing:** Uses deterministic nonce generation (RFC 6979) when available
## Limitations
1. **No HSM Support:** Keys are software-based, not hardware-backed
2. **No Compliance Certification:** Not FIPS 140-2, eIDAS, or other certified implementations
3. **Algorithm Limitations:** Only supports algorithms in .NET BCL
4. **No Password Hashing:** Use dedicated password hashers instead
## Migration Guide
### From Direct System.Security.Cryptography
**Before:**
```csharp
using System.Security.Cryptography;
var hash = SHA256.HashData(dataBytes); // ❌ Direct BCL usage
private string ComputeFingerprint(byte[] publicKeyBytes)
{
var hasher = cryptoProvider.GetHasher("SHA-256");
var hash = hasher.ComputeHash(publicKeyBytes);
return "sha256:" + Convert.ToHexString(hash).ToLowerInvariant();
}
```
**After:**
### Out-of-Band Verification Process
1. **Bundle Reception**: Operator receives `offline-kit.tar.gz` via physical media
2. **Checksum Verification**: Compare SHA-256 hash against value published via secure channel
```bash
sha256sum offline-kit.tar.gz
# Compare with published value: a1b2c3d4e5f6...
```
3. **Bundle Signature Verification**: Extract bundle, verify self-signature using bootstrap public key
4. **Trust Anchor Review**: Manual review of trust-anchors.json entries
5. **Deployment**: Extract crypto plugin and trust anchors to deployment directory
---
## Threat Model
### Attack Surface Analysis
| Attack Vector | Likelihood | Impact | Mitigation |
|---------------|------------|--------|------------|
| **Memory Dump** | Medium | High | Use ephemeral keys, minimize key lifetime |
| **Side-Channel (Timing)** | Low | Medium | .NET BCL uses constant-time primitives |
| **Algorithm Substitution** | Very Low | Critical | Compile-time algorithm allowlist |
| **Public Key Substitution** | Medium | Critical | Fingerprint verification, out-of-band trust |
| **Replay Attack** | Medium | Medium | Include timestamps in signed payloads |
| **Man-in-the-Middle** | Low (offline) | N/A | Physical media transport |
### Mitigations by Threat
**T1: Private Key Extraction**
- **Control**: In-memory keys only, no disk persistence
- **Monitoring**: Log key usage events
- **Response**: Revoke compromised key, rotate to new key
**T2: Public Key Substitution**
- **Control**: SHA-256 fingerprint verification before use
- **Monitoring**: Alert on fingerprint mismatches
- **Response**: Investigate trust bundle integrity
**T3: Signature Replay**
- **Control**: Include timestamp and nonce in signed payloads
- **Monitoring**: Detect signatures older than TTL
- **Response**: Reject replayed signatures
**T4: Algorithm Downgrade**
- **Control**: Hardcoded algorithm allowlist in provider
- **Monitoring**: Log algorithm selection
- **Response**: Reject unsupported algorithms
---
## Compliance
### NIST Standards
| Standard | Requirement | Compliance |
|----------|-------------|------------|
| **FIPS 186-4** | Digital Signature Standard | ✅ ECDSA with P-256/384/521, RSA-PSS |
| **FIPS 180-4** | Secure Hash Standard | ✅ SHA-256/384/512 |
| **FIPS 140-2** | Cryptographic Module Validation | ⚠️ .NET BCL (software-only, not validated) |
**Notes**:
- For FIPS 140-2 Level 3+ compliance, use HSM-backed crypto provider
- Software-only crypto acceptable for FIPS 140-2 Level 1
### RFC Standards
| RFC | Title | Compliance |
|-----|-------|------------|
| **RFC 8017** | PKCS #1: RSA Cryptography v2.2 | ✅ RSASSA-PKCS1-v1_5, RSASSA-PSS |
| **RFC 6979** | Deterministic DSA/ECDSA | ✅ Via BouncyCastle fallback (optional) |
| **RFC 5280** | X.509 Public Key Infrastructure | ✅ SubjectPublicKeyInfo format |
| **RFC 7515** | JSON Web Signature (JWS) | ✅ ES256/384/512, RS256/384/512, PS256/384/512 |
### Regional Standards
| Region | Standard | Compliance |
|--------|----------|------------|
| **European Union** | eIDAS Regulation (EU) 910/2014 | ❌ Use eIDAS plugin |
| **Russia** | GOST R 34.10-2012 | ❌ Use CryptoPro plugin |
| **China** | SM2/SM3/SM4 (GM/T 0003-2012) | ❌ Use SM crypto plugin |
---
## Best Practices
### Key Management
**✅ DO**:
- Rotate signing keys every 90 days
- Use separate keys for different purposes
- Store private keys in memory only
- Use ephemeral verifiers for public-key-only scenarios
- Audit all key usage events
**❌ DON'T**:
- Reuse keys across environments
- Store keys in configuration files
- Use RSA keys smaller than 2048 bits
- Use SHA-1 or MD5
- Bypass fingerprint verification
### Algorithm Selection
**Recommended**:
1. **ES256** (ECDSA P-256/SHA-256) - Best balance
2. **PS256** (RSA-PSS 2048-bit/SHA-256) - For RSA-required scenarios
3. **SHA-256** - Default hashing algorithm
**Avoid**:
- ES512 / PS512 - Performance overhead
- RS256 / RS384 / RS512 - Legacy PKCS1 padding
### Performance Optimization
**Caching**:
```csharp
using StellaOps.Cryptography;
// Cache hashers (thread-safe, reusable)
private readonly ICryptoHasher _sha256Hasher;
var hasher = cryptoRegistry.ResolveHasher("SHA-256");
var hash = hasher.Hasher.ComputeHash(dataBytes); // ✅ Provider abstraction
public MyService(ICryptoProviderRegistry registry)
{
_sha256Hasher = registry.ResolveHasher("SHA-256").Hasher;
}
```
### From Legacy Crypto Plugins
---
Replace legacy plugin references with OfflineVerificationCryptoProvider:
## Troubleshooting
1. Update `crypto-plugins-manifest.json`
2. Replace plugin DI registration
3. Update algorithm IDs to standard names (ES256, RS256, etc.)
### Common Issues
## Testing
**Issue**: `NotSupportedException: Algorithm 'RS256' is not supported`
Comprehensive unit tests are available in:
`src/__Libraries/__Tests/StellaOps.Cryptography.Tests/OfflineVerificationCryptoProviderTests.cs`
**Resolution**:
- Verify algorithm ID is exactly `RS256` (case-sensitive)
- Check provider supports: `provider.Supports(CryptoCapability.Signing, "RS256")`
Run tests:
```bash
dotnet test src/__Libraries/__Tests/StellaOps.Cryptography.Tests/
```
---
## Related Documentation
**Issue**: `CryptographicException: Public key parsing failed`
- [Crypto Provider Registry](../contracts/crypto-provider-registry.md)
- [Crypto Plugin Development Guide](../cli/crypto-plugins.md)
- [Air-Gapped Bundle Verification](../airgap/bundle-verification.md)
- [DSSE Signature Verification](../contracts/dsse-envelope.md)
**Resolution**:
- Ensure public key is DER-encoded SPKI format
- Convert from PEM: `openssl x509 -pubkey -noout -in cert.pem | openssl enc -base64 -d > pubkey.der`
## Support & Troubleshooting
---
### Provider Not Found
**Issue**: Signature verification always returns `false`
```
Error: Crypto provider 'offline-verification' not found
```
**Resolution**:
1. Verify algorithm matches
2. Ensure message is identical (byte-for-byte)
3. Check public key matches private key
4. Enable debug logging
**Solution:** Ensure plugin is registered in `crypto-plugins-manifest.json` with `enabled: true`
---
### Algorithm Not Supported
## References
```
Error: Algorithm 'ES256K' is not supported
```
### Related Documentation
**Solution:** Check [Supported Algorithms](#supported-algorithms) table. The offline provider only supports .NET BCL algorithms.
- [Crypto Architecture Overview](../modules/platform/crypto-architecture.md)
- [ICryptoProvider Interface](../../src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs)
- [Plugin Manifest Schema](../../etc/crypto-plugins-manifest.json)
- [AirGap Module Architecture](../modules/airgap/architecture.md)
- [Sprint Documentation](../implplan/SPRINT_1000_0007_0002_crypto_refactoring.md)
### Ephemeral Verifier Creation Fails
### External Standards
```
Error: Failed to create ephemeral verifier
```
- [NIST FIPS 186-4: Digital Signature Standard](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf)
- [NIST FIPS 180-4: Secure Hash Standard](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf)
- [RFC 8017: PKCS #1 v2.2](https://www.rfc-editor.org/rfc/rfc8017)
- [RFC 6979: Deterministic ECDSA](https://www.rfc-editor.org/rfc/rfc6979)
- [RFC 7515: JSON Web Signature](https://www.rfc-editor.org/rfc/rfc7515)
**Causes:**
1. Invalid public key format (must be SubjectPublicKeyInfo DER-encoded)
2. Unsupported algorithm
3. Corrupted public key bytes
---
**Solution:** Verify public key format and algorithm compatibility.
**Document Control**
## Changelog
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2025-12-23 | StellaOps Platform Team | Initial release with CreateEphemeralVerifier API |
### Version 1.0 (2025-12-23)
- Initial release
- Support for ES256/384/512, RS256/384/512, PS256/384/512
- SHA-256/384/512 content hashing
- Ephemeral verifier creation from raw public key bytes
- Comprehensive unit test coverage (39 tests)
**License**: AGPL-3.0-or-later