consolidation of some of the modules, localization fixes, product advisories work, qa work

This commit is contained in:
master
2026-03-05 03:54:22 +02:00
parent 7bafcc3eef
commit 8e1cb9448d
3878 changed files with 72600 additions and 46861 deletions

View File

@@ -4,6 +4,9 @@
using Microsoft.Extensions.Logging;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Security;
using System.Collections.Immutable;
using System.Security.Cryptography;
using System.Text;
@@ -133,24 +136,21 @@ public sealed class DsseVerifier : IDsseVerifier
try
{
var signatureBytes = Convert.FromBase64String(sig.Sig);
if (VerifySignature(pae, signatureBytes, publicKeyPem))
var verification = VerifySignature(pae, signatureBytes, publicKeyPem);
if (verification.IsValid)
{
verifiedKeyIds.Add(sig.KeyId ?? "unknown");
_logger.LogDebug("DSSE signature verified for keyId: {KeyId}", sig.KeyId ?? "unknown");
}
else
{
issues.Add($"signature_invalid_{sig.KeyId ?? "unknown"}");
issues.Add($"signature_invalid_{sig.KeyId ?? "unknown"}:{verification.ReasonCode}");
}
}
catch (FormatException)
{
issues.Add($"signature_invalid_base64_{sig.KeyId ?? "unknown"}");
}
catch (CryptographicException ex)
{
issues.Add($"signature_crypto_error_{sig.KeyId ?? "unknown"}: {ex.Message}");
}
}
// Compute payload hash for result
@@ -236,49 +236,164 @@ public sealed class DsseVerifier : IDsseVerifier
/// <summary>
/// Verifies a signature against PAE using the provided public key.
/// Supports ECDSA P-256 and RSA keys.
/// Supports ECDSA, RSA, and Ed25519 keys.
/// </summary>
private bool VerifySignature(byte[] pae, byte[] signature, string publicKeyPem)
private SignatureVerificationResult VerifySignature(byte[] pae, byte[] signature, string publicKeyPem)
{
if (!TryExtractPublicKeyDer(publicKeyPem, out var publicKeyDer))
{
return SignatureVerificationResult.Invalid("invalid_public_key_material");
}
if (TryVerifyWithEcdsa(pae, signature, publicKeyDer, out var ecdsaResult))
{
return ecdsaResult;
}
if (TryVerifyWithRsa(pae, signature, publicKeyDer, out var rsaResult))
{
return rsaResult;
}
if (TryVerifyWithEd25519(pae, signature, publicKeyDer, out var ed25519Result))
{
return ed25519Result;
}
return SignatureVerificationResult.Invalid("unsupported_public_key_type");
}
private static bool TryVerifyWithEcdsa(
byte[] pae,
byte[] signature,
byte[] publicKeyDer,
out SignatureVerificationResult result)
{
// Try ECDSA first (most common for Sigstore/Fulcio)
try
{
using var ecdsa = ECDsa.Create();
ecdsa.ImportFromPem(publicKeyPem);
return ecdsa.VerifyData(pae, signature, HashAlgorithmName.SHA256);
ecdsa.ImportSubjectPublicKeyInfo(publicKeyDer, out _);
var isValid = ecdsa.VerifyData(pae, signature, HashAlgorithmName.SHA256);
result = isValid
? SignatureVerificationResult.Valid
: SignatureVerificationResult.Invalid("signature_mismatch");
return true;
}
catch (CryptographicException)
{
// Not an ECDSA key, try RSA
result = SignatureVerificationResult.NotApplicable;
return false;
}
}
// Try RSA
private static bool TryVerifyWithRsa(
byte[] pae,
byte[] signature,
byte[] publicKeyDer,
out SignatureVerificationResult result)
{
try
{
using var rsa = RSA.Create();
rsa.ImportFromPem(publicKeyPem);
return rsa.VerifyData(pae, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
rsa.ImportSubjectPublicKeyInfo(publicKeyDer, out _);
var isValid = rsa.VerifyData(pae, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
result = isValid
? SignatureVerificationResult.Valid
: SignatureVerificationResult.Invalid("signature_mismatch");
return true;
}
catch (CryptographicException)
{
// Not an RSA key either
}
// Try Ed25519 if available (.NET 9+)
try
{
// Ed25519 support via System.Security.Cryptography
// Note: Ed25519 verification requires different handling
// For now, we log and return false - can be extended later
_logger.LogDebug("Ed25519 signature verification not yet implemented");
result = SignatureVerificationResult.NotApplicable;
return false;
}
catch
}
private static bool TryVerifyWithEd25519(
byte[] pae,
byte[] signature,
byte[] publicKeyDer,
out SignatureVerificationResult result)
{
try
{
// Ed25519 not available
var key = PublicKeyFactory.CreateKey(publicKeyDer);
if (key is not Ed25519PublicKeyParameters ed25519PublicKey)
{
result = SignatureVerificationResult.NotApplicable;
return false;
}
var verifier = new Ed25519Signer();
verifier.Init(false, ed25519PublicKey);
verifier.BlockUpdate(pae, 0, pae.Length);
var isValid = verifier.VerifySignature(signature);
result = isValid
? SignatureVerificationResult.Valid
: SignatureVerificationResult.Invalid("signature_mismatch");
return true;
}
catch (Exception ex) when (ex is InvalidOperationException or ArgumentException)
{
result = SignatureVerificationResult.Invalid("invalid_public_key_material");
return true;
}
}
private static bool TryExtractPublicKeyDer(string publicKeyPem, out byte[] publicKeyDer)
{
publicKeyDer = Array.Empty<byte>();
if (string.IsNullOrWhiteSpace(publicKeyPem))
{
return false;
}
return false;
var beginMarker = "-----BEGIN PUBLIC KEY-----";
var endMarker = "-----END PUBLIC KEY-----";
var beginIndex = publicKeyPem.IndexOf(beginMarker, StringComparison.Ordinal);
var endIndex = publicKeyPem.IndexOf(endMarker, StringComparison.Ordinal);
if (beginIndex < 0 || endIndex <= beginIndex)
{
return false;
}
var bodyStart = beginIndex + beginMarker.Length;
var body = publicKeyPem[bodyStart..endIndex];
var normalized = new string(body.Where(static ch => !char.IsWhiteSpace(ch)).ToArray());
if (string.IsNullOrWhiteSpace(normalized))
{
return false;
}
try
{
publicKeyDer = Convert.FromBase64String(normalized);
return publicKeyDer.Length > 0;
}
catch (FormatException)
{
return false;
}
}
private readonly struct SignatureVerificationResult
{
public static SignatureVerificationResult Valid => new(true, "none");
public static SignatureVerificationResult NotApplicable => new(false, "not_applicable");
public bool IsValid { get; }
public string ReasonCode { get; }
private SignatureVerificationResult(bool isValid, string reasonCode)
{
IsValid = isValid;
ReasonCode = reasonCode;
}
public static SignatureVerificationResult Invalid(string reasonCode) => new(false, reasonCode);
}
/// <summary>

View File

@@ -5,6 +5,7 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
| Task ID | Status | Notes |
| --- | --- | --- |
| ATTESTOR-225-001 | DOING | Sprint 225: implement Ed25519 DSSE verification with deterministic failure reasons and vectors. |
| AUDIT-0043-M | DONE | Revalidated maintainability for StellaOps.Attestation (2026-01-06). |
| AUDIT-0043-T | DONE | Revalidated test coverage for StellaOps.Attestation (2026-01-06). |
| AUDIT-0043-A | TODO | Open findings from revalidation (canonical JSON for DSSE payloads). |