Add support for ГОСТ Р 34.10 digital signatures

- Implemented the GostKeyValue class for handling public key parameters in ГОСТ Р 34.10 digital signatures.
- Created the GostSignedXml class to manage XML signatures using ГОСТ 34.10, including methods for computing and checking signatures.
- Developed the GostSignedXmlImpl class to encapsulate the signature computation logic and public key retrieval.
- Added specific key value classes for ГОСТ Р 34.10-2001, ГОСТ Р 34.10-2012/256, and ГОСТ Р 34.10-2012/512 to support different signature algorithms.
- Ensured compatibility with existing XML signature standards while integrating ГОСТ cryptography.
This commit is contained in:
master
2025-11-09 21:59:57 +02:00
parent 75c2bcafce
commit cef4cb2c5a
486 changed files with 32952 additions and 801 deletions

View File

@@ -354,6 +354,111 @@ public class StellaOpsScopeAuthorizationHandlerTests
Assert.Equal("INC-741", GetPropertyValue(record, "backfill.ticket"));
}
[Fact]
public async Task HandleRequirement_Fails_WhenPackApprovalMetadataMissing()
{
var optionsMonitor = CreateOptionsMonitor(options =>
{
options.Authority = "https://authority.example";
options.RequiredTenants.Add("tenant-alpha");
options.Validate();
});
var (handler, accessor, sink) = CreateHandler(optionsMonitor, IPAddress.Parse("203.0.113.10"));
var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.PacksApprove });
var now = DateTimeOffset.Parse("2025-11-09T12:00:00Z", CultureInfo.InvariantCulture);
var principal = new StellaOpsPrincipalBuilder()
.WithSubject("approver")
.WithTenant("tenant-alpha")
.WithScopes(new[] { StellaOpsScopes.PacksApprove })
.AddClaim(OpenIddictConstants.Claims.AuthenticationTime, now.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture))
.Build();
var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext);
await handler.HandleAsync(context);
Assert.False(context.HasSucceeded);
var record = Assert.Single(sink.Records);
Assert.Equal("packs.approve tokens require pack_run_id claim.", record.Reason);
Assert.Equal("false", GetPropertyValue(record, "pack.approval_metadata_satisfied"));
Assert.Equal(StellaOpsScopes.PacksApprove, Assert.Single(record.Scopes));
}
[Fact]
public async Task HandleRequirement_Fails_WhenPackApprovalFreshAuthStale()
{
var optionsMonitor = CreateOptionsMonitor(options =>
{
options.Authority = "https://authority.example";
options.RequiredTenants.Add("tenant-alpha");
options.Validate();
});
var fakeTime = new FakeTimeProvider(DateTimeOffset.Parse("2025-11-09T14:00:00Z", CultureInfo.InvariantCulture));
var (handler, accessor, sink) = CreateHandler(optionsMonitor, IPAddress.Parse("203.0.113.11"), fakeTime);
var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.PacksApprove });
var staleAuthTime = fakeTime.GetUtcNow().AddMinutes(-10);
var principal = new StellaOpsPrincipalBuilder()
.WithSubject("approver")
.WithTenant("tenant-alpha")
.WithScopes(new[] { StellaOpsScopes.PacksApprove })
.AddClaim(StellaOpsClaimTypes.PackRunId, "run-123")
.AddClaim(StellaOpsClaimTypes.PackGateId, "security-review")
.AddClaim(StellaOpsClaimTypes.PackPlanHash, new string(a, 64))
.AddClaim(OpenIddictConstants.Claims.AuthenticationTime, staleAuthTime.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture))
.Build();
var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext);
await handler.HandleAsync(context);
Assert.False(context.HasSucceeded);
var record = Assert.Single(sink.Records);
Assert.Equal("packs.approve tokens require fresh authentication.", record.Reason);
Assert.Equal("false", GetPropertyValue(record, "pack.fresh_auth_satisfied"));
Assert.Equal("true", GetPropertyValue(record, "pack.approval_metadata_satisfied"));
Assert.Equal(StellaOpsScopes.PacksApprove, Assert.Single(record.Scopes));
}
[Fact]
public async Task HandleRequirement_Succeeds_WhenPackApprovalMetadataPresent()
{
var optionsMonitor = CreateOptionsMonitor(options =>
{
options.Authority = "https://authority.example";
options.RequiredTenants.Add("tenant-alpha");
options.Validate();
});
var fakeTime = new FakeTimeProvider(DateTimeOffset.Parse("2025-11-09T14:30:00Z", CultureInfo.InvariantCulture));
var (handler, accessor, sink) = CreateHandler(optionsMonitor, IPAddress.Parse("203.0.113.12"), fakeTime);
var requirement = new StellaOpsScopeRequirement(new[] { StellaOpsScopes.PacksApprove });
var freshAuthTime = fakeTime.GetUtcNow().AddMinutes(-2);
var principal = new StellaOpsPrincipalBuilder()
.WithSubject("approver")
.WithTenant("tenant-alpha")
.WithScopes(new[] { StellaOpsScopes.PacksApprove })
.AddClaim(StellaOpsClaimTypes.PackRunId, "run-456")
.AddClaim(StellaOpsClaimTypes.PackGateId, "security-review")
.AddClaim(StellaOpsClaimTypes.PackPlanHash, new string(b, 64))
.AddClaim(OpenIddictConstants.Claims.AuthenticationTime, freshAuthTime.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture))
.Build();
var context = new AuthorizationHandlerContext(new[] { requirement }, principal, accessor.HttpContext);
await handler.HandleAsync(context);
Assert.True(context.HasSucceeded);
var record = Assert.Single(sink.Records);
Assert.Equal(AuthEventOutcome.Success, record.Outcome);
Assert.Equal("true", GetPropertyValue(record, "pack.approval_metadata_satisfied"));
Assert.Equal("true", GetPropertyValue(record, "pack.fresh_auth_satisfied"));
Assert.Equal("run-456", GetPropertyValue(record, "pack.run_id"));
Assert.Equal("security-review", GetPropertyValue(record, "pack.gate_id"));
Assert.Equal(new string(b, 64), GetPropertyValue(record, "pack.plan_hash"));
}
private static (StellaOpsScopeAuthorizationHandler Handler, IHttpContextAccessor Accessor, RecordingAuthEventSink Sink) CreateHandler(IOptionsMonitor<StellaOpsResourceServerOptions> optionsMonitor, IPAddress remoteAddress, TimeProvider? timeProvider = null)
{
var accessor = new HttpContextAccessor();