synergy moats product advisory implementations
This commit is contained in:
@@ -7,7 +7,9 @@
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cronos" />
|
||||
<PackageReference Include="JsonSchema.Net" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
|
||||
@@ -114,7 +114,7 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
// Get proof from Rekor
|
||||
var backend = new RekorBackend
|
||||
{
|
||||
Url = entry.RekorUrl ?? opts.RekorUrl,
|
||||
Url = new Uri(entry.RekorUrl ?? opts.RekorUrl),
|
||||
Name = "verification"
|
||||
};
|
||||
|
||||
@@ -134,22 +134,11 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
duration: stopwatch.Elapsed);
|
||||
}
|
||||
|
||||
// Verify log index matches
|
||||
if (proof.LogIndex != entry.LogIndex)
|
||||
// Verify body hash if available (leaf hash provides best-effort match)
|
||||
var proofLeafHash = proof.Inclusion?.LeafHash;
|
||||
if (!string.IsNullOrEmpty(entry.EntryBodyHash) && !string.IsNullOrEmpty(proofLeafHash))
|
||||
{
|
||||
stopwatch.Stop();
|
||||
return RekorVerificationResult.Failure(
|
||||
entry.Uuid,
|
||||
$"Log index mismatch: expected {entry.LogIndex}, got {proof.LogIndex}",
|
||||
RekorVerificationFailureCode.LogIndexMismatch,
|
||||
startTime,
|
||||
duration: stopwatch.Elapsed);
|
||||
}
|
||||
|
||||
// Verify body hash if available
|
||||
if (!string.IsNullOrEmpty(entry.EntryBodyHash) && !string.IsNullOrEmpty(proof.EntryBodyHash))
|
||||
{
|
||||
if (!string.Equals(entry.EntryBodyHash, proof.EntryBodyHash, StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(entry.EntryBodyHash, proofLeafHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stopwatch.Stop();
|
||||
_metrics.RecordSignatureFailure();
|
||||
@@ -171,7 +160,7 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
backend,
|
||||
cts.Token);
|
||||
|
||||
if (!inclusionResult.IsValid)
|
||||
if (!inclusionResult.Verified)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
_metrics.RecordInclusionProofFailure();
|
||||
@@ -185,6 +174,17 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
duration: stopwatch.Elapsed);
|
||||
}
|
||||
|
||||
if (inclusionResult.LogIndex.HasValue && inclusionResult.LogIndex.Value != entry.LogIndex)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
return RekorVerificationResult.Failure(
|
||||
entry.Uuid,
|
||||
$"Log index mismatch: expected {entry.LogIndex}, got {inclusionResult.LogIndex.Value}",
|
||||
RekorVerificationFailureCode.LogIndexMismatch,
|
||||
startTime,
|
||||
duration: stopwatch.Elapsed);
|
||||
}
|
||||
|
||||
// Check time skew
|
||||
var timeSkewResult = CheckTimeSkew(entry, opts.MaxTimeSkewSeconds);
|
||||
if (!timeSkewResult.IsValid)
|
||||
@@ -356,7 +356,7 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
{
|
||||
var backend = new RekorBackend
|
||||
{
|
||||
Url = opts.RekorUrl,
|
||||
Url = new Uri(opts.RekorUrl),
|
||||
Name = "verification"
|
||||
};
|
||||
|
||||
@@ -376,24 +376,26 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
}
|
||||
|
||||
// Verify consistency: tree size should only increase
|
||||
if (currentCheckpoint.TreeSize < expectedTreeSize)
|
||||
var checkpoint = currentCheckpoint.Value;
|
||||
|
||||
if (checkpoint.TreeSize < expectedTreeSize)
|
||||
{
|
||||
return RootConsistencyResult.Inconsistent(
|
||||
currentCheckpoint.TreeRoot,
|
||||
currentCheckpoint.TreeSize,
|
||||
checkpoint.TreeRoot,
|
||||
checkpoint.TreeSize,
|
||||
expectedTreeRoot,
|
||||
expectedTreeSize,
|
||||
$"Tree size decreased from {expectedTreeSize} to {currentCheckpoint.TreeSize} (possible log truncation)",
|
||||
$"Tree size decreased from {expectedTreeSize} to {checkpoint.TreeSize} (possible log truncation)",
|
||||
now);
|
||||
}
|
||||
|
||||
// If sizes match, roots should match
|
||||
if (currentCheckpoint.TreeSize == expectedTreeSize &&
|
||||
!string.Equals(currentCheckpoint.TreeRoot, expectedTreeRoot, StringComparison.OrdinalIgnoreCase))
|
||||
if (checkpoint.TreeSize == expectedTreeSize &&
|
||||
!string.Equals(checkpoint.TreeRoot, expectedTreeRoot, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return RootConsistencyResult.Inconsistent(
|
||||
currentCheckpoint.TreeRoot,
|
||||
currentCheckpoint.TreeSize,
|
||||
checkpoint.TreeRoot,
|
||||
checkpoint.TreeSize,
|
||||
expectedTreeRoot,
|
||||
expectedTreeSize,
|
||||
"Tree root changed without size change (possible log tampering)",
|
||||
@@ -401,8 +403,8 @@ public sealed class RekorVerificationService : IRekorVerificationService
|
||||
}
|
||||
|
||||
return RootConsistencyResult.Consistent(
|
||||
currentCheckpoint.TreeRoot,
|
||||
currentCheckpoint.TreeSize,
|
||||
checkpoint.TreeRoot,
|
||||
checkpoint.TreeSize,
|
||||
now);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user