This commit is contained in:
StellaOps Bot
2025-12-07 22:49:53 +02:00
parent 11597679ed
commit 7c24ed96ee
204 changed files with 23313 additions and 1430 deletions

View File

@@ -235,6 +235,10 @@ internal sealed class AttestorSigningKeyRegistry : IDisposable
}
var privateKeyBytes = LoadSm2KeyBytes(key);
var metadata = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
{
["source"] = "config"
};
var signingKey = new CryptoSigningKey(
new CryptoKeyReference(providerKeyId, providerName),
normalizedAlgorithm,

View File

@@ -120,6 +120,95 @@ public sealed class AttestorVerificationServiceTests
Assert.Equal("missing", verifyResult.Report.Transparency.WitnessStatus);
}
[Fact]
public async Task VerifyAsync_KmsBundle_Passes_WhenTwoSignaturesRequired()
{
var options = Options.Create(new AttestorOptions
{
Redis = new AttestorOptions.RedisOptions { Url = string.Empty },
Rekor = new AttestorOptions.RekorOptions
{
Primary = new AttestorOptions.RekorBackendOptions
{
Url = "https://rekor.stellaops.test",
ProofTimeoutMs = 1000,
PollIntervalMs = 50,
MaxAttempts = 2
}
},
Security = new AttestorOptions.SecurityOptions
{
SignerIdentity = new AttestorOptions.SignerIdentityOptions
{
Mode = { "kms" },
KmsKeys = { HmacSecretBase64 }
}
},
Verification = new AttestorOptions.VerificationOptions
{
MinimumSignatures = 2,
PolicyId = "policy/dual-sign"
}
});
using var metrics = new AttestorMetrics();
using var activitySource = new AttestorActivitySource();
var canonicalizer = new DefaultDsseCanonicalizer();
var engine = new AttestorVerificationEngine(canonicalizer, new TestCryptoHash(), options, NullLogger<AttestorVerificationEngine>.Instance);
var repository = new InMemoryAttestorEntryRepository();
var dedupeStore = new InMemoryAttestorDedupeStore();
var rekorClient = new StubRekorClient(new NullLogger<StubRekorClient>());
var archiveStore = new NullAttestorArchiveStore(new NullLogger<NullAttestorArchiveStore>());
var auditSink = new InMemoryAttestorAuditSink();
var submissionService = new AttestorSubmissionService(
new AttestorSubmissionValidator(canonicalizer),
repository,
dedupeStore,
rekorClient,
new NullTransparencyWitnessClient(),
archiveStore,
auditSink,
new NullVerificationCache(),
options,
new NullLogger<AttestorSubmissionService>(),
TimeProvider.System,
metrics);
var submission = CreateSubmissionRequestWithTwoSignatures(canonicalizer, HmacSecret);
var context = new SubmissionContext
{
CallerSubject = "urn:stellaops:signer",
CallerAudience = "attestor",
CallerClientId = "signer-service",
CallerTenant = "default"
};
var response = await submissionService.SubmitAsync(submission, context);
var verificationService = new AttestorVerificationService(
repository,
canonicalizer,
rekorClient,
new NullTransparencyWitnessClient(),
engine,
options,
new NullLogger<AttestorVerificationService>(),
metrics,
activitySource,
TimeProvider.System);
var verifyResult = await verificationService.VerifyAsync(new AttestorVerificationRequest
{
Uuid = response.Uuid,
Bundle = submission.Bundle
});
Assert.True(verifyResult.Ok);
Assert.Equal(VerificationSectionStatus.Pass, verifyResult.Report!.Signatures.Status);
Assert.Equal(2, verifyResult.Report.Signatures.VerifiedSignatures);
Assert.Equal(2, verifyResult.Report.Signatures.RequiredSignatures);
}
[Fact]
public async Task VerifyAsync_FlagsTamperedBundle()
{
@@ -262,6 +351,32 @@ public sealed class AttestorVerificationServiceTests
return request;
}
private static AttestorSubmissionRequest CreateSubmissionRequestWithTwoSignatures(DefaultDsseCanonicalizer canonicalizer, byte[] hmacSecret)
{
var request = CreateSubmissionRequest(canonicalizer, hmacSecret);
// Recompute signature and append a second copy to satisfy multi-signature verification
if (!TryDecodeBase64(request.Bundle.Dsse.PayloadBase64, out var payload))
{
throw new InvalidOperationException("Test payload failed to decode.");
}
var preAuth = ComputePreAuthEncodingForTests(request.Bundle.Dsse.PayloadType, payload);
using (var hmac = new HMACSHA256(hmacSecret))
{
var signature = hmac.ComputeHash(preAuth);
request.Bundle.Dsse.Signatures.Add(new AttestorSubmissionRequest.DsseSignature
{
KeyId = "kms-test-2",
Signature = Convert.ToBase64String(signature)
});
}
var canonical = canonicalizer.CanonicalizeAsync(request).GetAwaiter().GetResult();
request.Meta.BundleSha256 = Convert.ToHexString(SHA256.HashData(canonical)).ToLowerInvariant();
return request;
}
private static AttestorSubmissionRequest.SubmissionBundle CloneBundle(AttestorSubmissionRequest.SubmissionBundle source)
{
var clone = new AttestorSubmissionRequest.SubmissionBundle