Add LDAP Distinguished Name Helper and Credential Audit Context
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented LdapDistinguishedNameHelper for escaping RDN and filter values. - Created AuthorityCredentialAuditContext and IAuthorityCredentialAuditContextAccessor for managing credential audit context. - Developed StandardCredentialAuditLogger with tests for success, failure, and lockout events. - Introduced AuthorityAuditSink for persisting audit records with structured logging. - Added CryptoPro related classes for certificate resolution and signing operations.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
using StellaOps.Cryptography.Plugin.Pkcs11Gost;
|
||||
|
||||
namespace StellaOps.Cryptography.DependencyInjection;
|
||||
|
||||
@@ -57,4 +60,53 @@ public static class CryptoServiceCollectionExtensions
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddStellaOpsCryptoRu(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
Action<CryptoProviderRegistryOptions>? configureRegistry = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
|
||||
var baseSection = configuration.GetSection("StellaOps:Crypto");
|
||||
services.Configure<StellaOpsCryptoOptions>(baseSection);
|
||||
services.Configure<CryptoProviderRegistryOptions>(baseSection.GetSection("Registry"));
|
||||
services.Configure<CryptoProGostProviderOptions>(baseSection.GetSection("CryptoPro"));
|
||||
services.Configure<Pkcs11GostProviderOptions>(baseSection.GetSection("Pkcs11"));
|
||||
|
||||
services.AddStellaOpsCrypto(configureRegistry);
|
||||
services.AddCryptoProGostProvider();
|
||||
services.AddPkcs11GostProvider();
|
||||
|
||||
services.PostConfigure<CryptoProviderRegistryOptions>(options =>
|
||||
{
|
||||
EnsurePreferred(options.PreferredProviders);
|
||||
foreach (var profile in options.Profiles.Values)
|
||||
{
|
||||
EnsurePreferred(profile.PreferredProviders);
|
||||
}
|
||||
});
|
||||
|
||||
return services;
|
||||
|
||||
static void EnsurePreferred(IList<string> providers)
|
||||
{
|
||||
InsertIfMissing(providers, "ru.pkcs11");
|
||||
InsertIfMissing(providers, "ru.cryptopro.csp");
|
||||
}
|
||||
|
||||
static void InsertIfMissing(IList<string> providers, string name)
|
||||
{
|
||||
for (var i = 0; i < providers.Count; i++)
|
||||
{
|
||||
if (string.Equals(providers[i], name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
providers.Insert(0, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
using StellaOps.Cryptography.Plugin.Pkcs11Gost;
|
||||
|
||||
namespace StellaOps.Cryptography.DependencyInjection;
|
||||
|
||||
public sealed class StellaOpsCryptoOptions
|
||||
{
|
||||
public CryptoProviderRegistryOptions Registry { get; set; } = new();
|
||||
|
||||
public CryptoProGostProviderOptions CryptoPro { get; set; } = new();
|
||||
|
||||
public Pkcs11GostProviderOptions Pkcs11 { get; set; } = new();
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
# KMS Task Board — Epic 19: Attestor Console
|
||||
|
||||
## Sprint 72 – Abstractions & File Driver
|
||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||
|----|--------|----------|------------|-------------|---------------|
|
||||
|
||||
## Sprint 73 – Cloud & HSM Integration
|
||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||
|----|--------|----------|------------|-------------|---------------|
|
||||
| KMS-73-001 | DONE (2025-11-03) | KMS Guild | KMS-72-001 | Add cloud KMS driver (e.g., AWS KMS, GCP KMS) with signing and key metadata retrieval. | Cloud driver tested with mock; configuration documented; security review sign-off. |
|
||||
> AWS/GCP facades implement digest-first signing, cache metadata/public keys (`AwsKmsOptions`, `GcpKmsOptions`), and surface non-exportable keys without private material; unit tests cover signing, verification, metadata, and export flows.
|
||||
| KMS-73-002 | DONE (2025-11-03) | KMS Guild | KMS-72-001 | Implement PKCS#11/HSM driver plus FIDO2 signing support for high assurance workflows. | HSM/FIDO2 drivers tested with hardware stubs; error handling documented. |
|
||||
> PKCS#11 facade/client pair added with deterministic digesting + caches, FIDO2 client honors authenticator factories, DI extensions published, signer docs refreshed, and xUnit fakes assert sign/verify/export flows.
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
|
||||
internal static class CryptoProCertificateResolver
|
||||
{
|
||||
public static X509Certificate2 Resolve(CryptoProGostKeyOptions options)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(options.CertificateThumbprint))
|
||||
{
|
||||
var cert = FindByThumbprint(options.CertificateThumbprint!, options.CertificateStoreName, options.CertificateStoreLocation);
|
||||
if (cert is not null)
|
||||
{
|
||||
return cert;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Certificate with thumbprint '{options.CertificateThumbprint}' was not found in {options.CertificateStoreLocation}/{options.CertificateStoreName}.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(options.SubjectName))
|
||||
{
|
||||
var cert = FindBySubject(options.SubjectName!, options.CertificateStoreName, options.CertificateStoreLocation);
|
||||
if (cert is not null)
|
||||
{
|
||||
return cert;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Certificate with subject containing '{options.SubjectName}' was not found in {options.CertificateStoreLocation}/{options.CertificateStoreName}.");
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"CryptoPro key '{options.KeyId}' must specify either CertificateThumbprint or SubjectName.");
|
||||
}
|
||||
|
||||
private static X509Certificate2? FindByThumbprint(string thumbprint, StoreName storeName, StoreLocation storeLocation)
|
||||
{
|
||||
using var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
foreach (var cert in store.Certificates)
|
||||
{
|
||||
if (string.Equals(Normalize(thumbprint), Normalize(cert.Thumbprint ?? string.Empty), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new X509Certificate2(cert);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static X509Certificate2? FindBySubject(string subjectFragment, StoreName storeName, StoreLocation storeLocation)
|
||||
{
|
||||
using var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
foreach (var cert in store.Certificates)
|
||||
{
|
||||
if (cert.Subject?.IndexOf(subjectFragment, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return new X509Certificate2(cert);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string Normalize(string value)
|
||||
=> value.Replace(" ", string.Empty, StringComparison.Ordinal).ToUpperInvariant(CultureInfo.InvariantCulture);
|
||||
}
|
||||
@@ -3,39 +3,43 @@ using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography.Plugin.Pkcs11Gost;
|
||||
|
||||
namespace StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
|
||||
public sealed class CryptoProGostCryptoProvider : ICryptoProvider, ICryptoProviderDiagnostics
|
||||
{
|
||||
private readonly Pkcs11GostProviderCore core;
|
||||
private readonly ILogger<CryptoProGostCryptoProvider>? logger;
|
||||
private readonly IReadOnlyDictionary<string, CryptoProGostKeyEntry> entries;
|
||||
|
||||
public CryptoProGostCryptoProvider(
|
||||
IOptions<CryptoProGostProviderOptions>? optionsAccessor = null,
|
||||
ILogger<CryptoProGostCryptoProvider>? logger = null)
|
||||
{
|
||||
this.logger = logger;
|
||||
var options = optionsAccessor?.Value ?? new CryptoProGostProviderOptions();
|
||||
var mappedKeys = new List<Pkcs11GostKeyOptions>(options.Keys.Count);
|
||||
var map = new Dictionary<string, CryptoProGostKeyEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var key in options.Keys)
|
||||
{
|
||||
mappedKeys.Add(MapToPkcs11Options(key));
|
||||
var certificate = CryptoProCertificateResolver.Resolve(key);
|
||||
var entry = new CryptoProGostKeyEntry(
|
||||
key.KeyId,
|
||||
key.Algorithm,
|
||||
certificate,
|
||||
key.ProviderName,
|
||||
key.ContainerName);
|
||||
|
||||
map[key.KeyId] = entry;
|
||||
}
|
||||
|
||||
core = new Pkcs11GostProviderCore("ru.cryptopro.csp", mappedKeys, logger);
|
||||
entries = map;
|
||||
}
|
||||
|
||||
public string Name => core.ProviderName;
|
||||
public string Name => "ru.cryptopro.csp";
|
||||
|
||||
public bool Supports(CryptoCapability capability, string algorithmId)
|
||||
{
|
||||
if (capability is CryptoCapability.Signing or CryptoCapability.Verification)
|
||||
{
|
||||
return core.SupportsAlgorithm(algorithmId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
=> capability is CryptoCapability.Signing or CryptoCapability.Verification
|
||||
&& (string.Equals(algorithmId, SignatureAlgorithms.GostR3410_2012_256, StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(algorithmId, SignatureAlgorithms.GostR3410_2012_512, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public IPasswordHasher GetPasswordHasher(string algorithmId)
|
||||
=> throw new NotSupportedException("CryptoPro provider does not expose password hashing.");
|
||||
@@ -43,14 +47,15 @@ public sealed class CryptoProGostCryptoProvider : ICryptoProvider, ICryptoProvid
|
||||
public ICryptoSigner GetSigner(string algorithmId, CryptoKeyReference keyReference)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(keyReference);
|
||||
var entry = core.Resolve(keyReference.KeyId);
|
||||
var entry = ResolveKey(keyReference.KeyId);
|
||||
if (!string.Equals(entry.AlgorithmId, algorithmId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Signing key '{keyReference.KeyId}' is registered for algorithm '{entry.AlgorithmId}', not '{algorithmId}'.");
|
||||
}
|
||||
|
||||
return new Pkcs11GostSigner(entry);
|
||||
logger?.LogDebug("Using CryptoPro key {Key} ({Algorithm})", entry.KeyId, entry.AlgorithmId);
|
||||
return new CryptoProGostSigner(entry);
|
||||
}
|
||||
|
||||
public void UpsertSigningKey(CryptoSigningKey signingKey)
|
||||
@@ -62,26 +67,35 @@ public sealed class CryptoProGostCryptoProvider : ICryptoProvider, ICryptoProvid
|
||||
=> Array.Empty<CryptoSigningKey>();
|
||||
|
||||
public IEnumerable<CryptoProviderKeyDescriptor> DescribeKeys()
|
||||
=> core.DescribeKeys(Name);
|
||||
|
||||
private static Pkcs11GostKeyOptions MapToPkcs11Options(CryptoProGostKeyOptions source)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
|
||||
return new Pkcs11GostKeyOptions
|
||||
foreach (var entry in entries.Values)
|
||||
{
|
||||
KeyId = source.KeyId,
|
||||
Algorithm = source.Algorithm,
|
||||
LibraryPath = source.LibraryPath,
|
||||
SlotId = source.SlotId,
|
||||
TokenLabel = source.TokenLabel,
|
||||
PrivateKeyLabel = source.ContainerLabel,
|
||||
UserPin = source.UserPin,
|
||||
UserPinEnvironmentVariable = source.UserPinEnvironmentVariable,
|
||||
SignMechanismId = source.SignMechanismId,
|
||||
CertificateThumbprint = source.CertificateThumbprint,
|
||||
CertificateStoreLocation = source.CertificateStoreLocation.ToString(),
|
||||
CertificateStoreName = source.CertificateStoreName.ToString()
|
||||
};
|
||||
yield return new CryptoProviderKeyDescriptor(
|
||||
Name,
|
||||
entry.KeyId,
|
||||
entry.AlgorithmId,
|
||||
new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["provider"] = entry.ProviderName,
|
||||
["container"] = entry.ContainerName,
|
||||
["thumbprint"] = entry.Certificate.Thumbprint,
|
||||
["subject"] = entry.Certificate.Subject
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private CryptoProGostKeyEntry ResolveKey(string? keyId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(keyId))
|
||||
{
|
||||
throw new ArgumentException("Crypto key reference must include KeyId.", nameof(keyId));
|
||||
}
|
||||
|
||||
if (entries.TryGetValue(keyId, out var entry))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException($"CryptoPro key '{keyId}' is not registered.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
|
||||
internal sealed class CryptoProGostKeyEntry
|
||||
{
|
||||
public CryptoProGostKeyEntry(
|
||||
string keyId,
|
||||
string algorithmId,
|
||||
X509Certificate2 certificate,
|
||||
string providerName,
|
||||
string? containerName)
|
||||
{
|
||||
KeyId = keyId;
|
||||
AlgorithmId = algorithmId;
|
||||
Certificate = certificate;
|
||||
ProviderName = providerName;
|
||||
ContainerName = containerName;
|
||||
}
|
||||
|
||||
public string KeyId { get; }
|
||||
|
||||
public string AlgorithmId { get; }
|
||||
|
||||
public X509Certificate2 Certificate { get; }
|
||||
|
||||
public string ProviderName { get; }
|
||||
|
||||
public string? ContainerName { get; }
|
||||
|
||||
public bool Use256 => string.Equals(AlgorithmId, SignatureAlgorithms.GostR3410_2012_256, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -12,24 +12,24 @@ public sealed class CryptoProGostKeyOptions
|
||||
public string Algorithm { get; set; } = SignatureAlgorithms.GostR3410_2012_256;
|
||||
|
||||
/// <summary>
|
||||
/// PKCS#11 library path (typically cprocsp-pkcs11*.dll/so).
|
||||
/// Optional CryptoPro provider name (defaults to standard CSP).
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string LibraryPath { get; set; } = string.Empty;
|
||||
public string ProviderName { get; set; } = "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider";
|
||||
|
||||
public string? SlotId { get; set; }
|
||||
/// <summary>
|
||||
/// Optional container name. If omitted, the certificate private key association is used.
|
||||
/// </summary>
|
||||
public string? ContainerName { get; set; }
|
||||
|
||||
public string? TokenLabel { get; set; }
|
||||
/// <summary>
|
||||
/// Thumbprint of the certificate that owns the CryptoPro private key.
|
||||
/// </summary>
|
||||
public string? CertificateThumbprint { get; set; }
|
||||
|
||||
public string? ContainerLabel { get; set; }
|
||||
|
||||
public string? UserPin { get; set; }
|
||||
|
||||
public string? UserPinEnvironmentVariable { get; set; }
|
||||
|
||||
public uint? SignMechanismId { get; set; }
|
||||
|
||||
public string CertificateThumbprint { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Alternative lookup if thumbprint is not supplied.
|
||||
/// </summary>
|
||||
public string? SubjectName { get; set; }
|
||||
|
||||
public StoreLocation CertificateStoreLocation { get; set; } = StoreLocation.CurrentUser;
|
||||
|
||||
@@ -40,14 +40,10 @@ public sealed class CryptoProGostKeyOptions
|
||||
{
|
||||
KeyId = KeyId,
|
||||
Algorithm = Algorithm,
|
||||
LibraryPath = LibraryPath,
|
||||
SlotId = SlotId,
|
||||
TokenLabel = TokenLabel,
|
||||
ContainerLabel = ContainerLabel,
|
||||
UserPin = UserPin,
|
||||
UserPinEnvironmentVariable = UserPinEnvironmentVariable,
|
||||
SignMechanismId = SignMechanismId,
|
||||
ProviderName = ProviderName,
|
||||
ContainerName = ContainerName,
|
||||
CertificateThumbprint = CertificateThumbprint,
|
||||
SubjectName = SubjectName,
|
||||
CertificateStoreLocation = CertificateStoreLocation,
|
||||
CertificateStoreName = CertificateStoreName
|
||||
};
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GostCryptography.Gost_3410;
|
||||
using StellaOps.Cryptography;
|
||||
|
||||
namespace StellaOps.Cryptography.Plugin.CryptoPro;
|
||||
|
||||
internal sealed class CryptoProGostSigner : ICryptoSigner
|
||||
{
|
||||
private readonly CryptoProGostKeyEntry entry;
|
||||
|
||||
public CryptoProGostSigner(CryptoProGostKeyEntry entry)
|
||||
{
|
||||
this.entry = entry ?? throw new ArgumentNullException(nameof(entry));
|
||||
}
|
||||
|
||||
public string KeyId => entry.KeyId;
|
||||
|
||||
public string AlgorithmId => entry.AlgorithmId;
|
||||
|
||||
public ValueTask<byte[]> SignAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var digest = entry.Use256
|
||||
? GostDigestUtilities.ComputeDigest(data.Span, use256: true)
|
||||
: GostDigestUtilities.ComputeDigest(data.Span, use256: false);
|
||||
|
||||
using var provider = CreateProvider();
|
||||
var signature = provider.SignHash(digest);
|
||||
return ValueTask.FromResult(signature);
|
||||
}
|
||||
|
||||
public ValueTask<bool> VerifyAsync(ReadOnlyMemory<byte> data, ReadOnlyMemory<byte> signature, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var digest = entry.Use256
|
||||
? GostDigestUtilities.ComputeDigest(data.Span, use256: true)
|
||||
: GostDigestUtilities.ComputeDigest(data.Span, use256: false);
|
||||
|
||||
using var provider = CreateProvider();
|
||||
var valid = provider.VerifyHash(digest, signature.ToArray());
|
||||
return ValueTask.FromResult(valid);
|
||||
}
|
||||
|
||||
public JsonWebKey ExportPublicJsonWebKey()
|
||||
{
|
||||
var jwk = new JsonWebKey
|
||||
{
|
||||
Kid = KeyId,
|
||||
Alg = AlgorithmId,
|
||||
Kty = "EC",
|
||||
Crv = entry.Use256 ? "GOST3410-2012-256" : "GOST3410-2012-512",
|
||||
Use = JsonWebKeyUseNames.Sig
|
||||
};
|
||||
|
||||
jwk.KeyOps.Add("sign");
|
||||
jwk.KeyOps.Add("verify");
|
||||
jwk.X5c.Add(Convert.ToBase64String(entry.Certificate.RawData));
|
||||
|
||||
return jwk;
|
||||
}
|
||||
|
||||
private Gost3410CryptoServiceProvider CreateProvider()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(entry.ContainerName))
|
||||
{
|
||||
return new Gost3410CryptoServiceProvider(entry.ProviderName, entry.ContainerName);
|
||||
}
|
||||
|
||||
return new Gost3410CryptoServiceProvider(entry.Certificate);
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,18 @@
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GostCryptography" Version="2.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0-rc.2.25502.107" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0-rc.2.25502.107" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\\StellaOps.Cryptography.Plugin.Pkcs11Gost\\StellaOps.Cryptography.Plugin.Pkcs11Gost.csproj" />
|
||||
<ProjectReference Include="..\\StellaOps.Cryptography\\StellaOps.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -90,14 +90,24 @@ public enum AuthEventOutcome
|
||||
Failure,
|
||||
|
||||
/// <summary>
|
||||
/// Operation failed due to a lockout policy.
|
||||
/// </summary>
|
||||
LockedOut,
|
||||
|
||||
/// <summary>
|
||||
/// Operation was rejected due to rate limiting or throttling.
|
||||
/// </summary>
|
||||
RateLimited,
|
||||
/// Operation failed due to a lockout policy.
|
||||
/// </summary>
|
||||
LockedOut,
|
||||
|
||||
/// <summary>
|
||||
/// Operation requires the subject to successfully perform a fresh authentication step (e.g. password reset).
|
||||
/// </summary>
|
||||
RequiresFreshAuth,
|
||||
|
||||
/// <summary>
|
||||
/// Operation requires multi-factor authentication before it can succeed.
|
||||
/// </summary>
|
||||
RequiresMfa,
|
||||
|
||||
/// <summary>
|
||||
/// Operation was rejected due to rate limiting or throttling.
|
||||
/// </summary>
|
||||
RateLimited,
|
||||
|
||||
/// <summary>
|
||||
/// Operation encountered an unexpected error.
|
||||
|
||||
@@ -1,39 +1,11 @@
|
||||
# Team 8 — Security Guild Task Board (UTC 2025-10-10)
|
||||
# Active Tasks
|
||||
|
||||
| ID | Status | Owner | Description | Dependencies | Exit Criteria |
|
||||
|----|--------|-------|-------------|--------------|---------------|
|
||||
| SEC-CRYPTO-90-001 | DONE (2025-11-07) | Security Guild | Produce RootPack_RU sovereign crypto implementation plan, identify provider strategy (CryptoPro + PKCS#11), and slot work into Sprint 190 with task breakdown. | None | Plan captured in `SPRINT_190_ops_offline.md` + this board; risks/assumptions logged. |
|
||||
| SEC-CRYPTO-90-002 | DONE (2025-11-07) | Security Guild | Extend signature/catalog constants and configuration schema to recognize `GOST12-256/512`, regional crypto profiles, and provider preference ordering. | SEC-CRYPTO-90-001 | New alg IDs wired, configs validated, docs updated. |
|
||||
| SEC-CRYPTO-90-003 | DONE (2025-11-07) | Security Guild | Implement `StellaOps.Cryptography.Plugin.CryptoPro` provider (sign/verify/JWK export) using CryptoPro CSP/GostCryptography with deterministic logging + tests. | SEC-CRYPTO-90-002 | Provider registered, unit/integration tests (skippable if CSP absent) passing. |
|
||||
| SEC-CRYPTO-90-004 | DONE (2025-11-07) | Security Guild | Implement `StellaOps.Cryptography.Plugin.Pkcs11Gost` provider (Rutoken/JaCarta) via Pkcs11Interop, configurable slot/pin/module management, and disposal safeguards. | SEC-CRYPTO-90-002 | Provider registered, token smoke tests + error handling documented. |
|
||||
| SEC-CRYPTO-90-005 | DONE (2025-11-08) | Security Guild | Add configuration-driven provider selection (`crypto.regionalProfiles`), CLI/diagnostic verb to list providers/keys, and deterministic telemetry for usage. | SEC-CRYPTO-90-003, SEC-CRYPTO-90-004 | CLI lists providers, configs switch ordering without code changes, telemetry events emitted. |
|
||||
| SEC-CRYPTO-90-006 | DONE (2025-11-08) | Security Guild | Build deterministic test harness (Streebog + signature vectors), manual runbooks for hardware validation, and capture RootPack audit metadata. | SEC-CRYPTO-90-003, SEC-CRYPTO-90-004 | `scripts/crypto/run-rootpack-ru-tests.sh` emits deterministic logs/TRX; validation runbook updated with harness + hardware guidance; audit metadata artifacts enumerated. |
|
||||
| SEC-CRYPTO-90-007 | DONE (2025-11-08) | Security Guild | Package RootPack_RU artifacts (plugin binaries, config templates, trust anchors) and document deployment/install steps + compliance evidence. | SEC-CRYPTO-90-005, SEC-CRYPTO-90-006 | `scripts/crypto/package-rootpack-ru.sh` builds bundle with docs/config/trust anchors; `rootpack_ru_package.md` guides ops/air-gap workflows. |
|
||||
| SEC-CRYPTO-90-008 | DONE (2025-11-08) | Security Guild | Audit repository for any cryptography usage bypassing `StellaOps.Cryptography` (direct libsodium/BouncyCastle callers, TLS custom code) and file remediation tasks to route via providers. | SEC-CRYPTO-90-002 | Audit report updated with remediation IDs; module TASKS boards now include `*-CRYPTO-90-001` follow-ups; backlog ready for implementation. |
|
||||
> Remark (2025-10-14): Cleanup service wired to store; background sweep + invite audit tests added.
|
||||
> Remark (2025-10-14): Token usage metadata persisted with replay audits + handler/unit coverage.
|
||||
> Remark (2025-10-14): Analyzer surfaces warnings during CLI load; docs updated with mitigation steps.
|
||||
> Remark (2025-10-14): Offline kit docs include manifest verification workflow; attestation artifacts referenced.
|
||||
|
||||
> Remark (2025-10-13, SEC2.B): Coordinated with Authority Core — audit sinks now receive `/token` success/failure events; awaiting host test suite once signing fixture lands.
|
||||
>
|
||||
> Remark (2025-10-13, SEC3.B): Pinged Docs & Plugin guilds — rate limit guidance published in `docs/security/rate-limits.md` and flagged for PLG6.DOC copy lift.
|
||||
>
|
||||
> Remark (2025-10-13, SEC5.B): Split follow-up into SEC5.B1 (libsodium provider) and SEC5.B2 (CLI verification) after scoping registry integration; work not yet started.
|
||||
|
||||
> Remark (2025-10-13, SEC2.B): Coordinated with Authority Core — audit sinks now receive `/token` success/failure events; awaiting host test suite once signing fixture lands.
|
||||
>
|
||||
> Remark (2025-10-13, SEC3.B): Pinged Docs & Plugin guilds — rate limit guidance published in `docs/security/rate-limits.md` and flagged for PLG6.DOC copy lift.
|
||||
>
|
||||
> Remark (2025-10-13, SEC5.B): Split follow-up into SEC5.B1 (libsodium provider) and SEC5.B2 (CLI verification) after scoping registry integration; work not yet started.
|
||||
|
||||
## Notes
|
||||
- Target Argon2 parameters follow OWASP Cheat Sheet (memory ≈ 19 MiB, iterations 2, parallelism 1). Allow overrides via configuration.
|
||||
- When CORE8 lands, pair with Team 2 to expose request context information required by the rate limiter (client_id enrichment).
|
||||
- Revocation bundle must be consumable offline; include issue timestamp, signing key metadata, and reasons.
|
||||
- All crypto usage in Authority code should funnel through the new abstractions (`ICryptoProvider`), enabling future CryptoPro/OpenSSL providers.
|
||||
|
||||
## Done Definition
|
||||
- Code merges include unit/integration tests and documentation updates.
|
||||
- `TASKS.md` status transitions (TODO → DOING → DONE/BLOCKED) must happen in the same PR as the work.
|
||||
- Prior to marking DONE: run `dotnet test` for touched solutions and attach excerpt to PR description.
|
||||
| SEC-CRYPTO-90-009 | TODO | Security Guild | Replace the placeholder CryptoPro plug-in with a true CryptoPro CSP implementation (GostCryptography driver, X509 store lookups, DER/raw normalization, deterministic logging). | SPRINT_514 | ✅ CryptoPro provider no longer depends on PKCS#11 core; ✅ Certificates resolved via thumbprint/container; ✅ Sign/verify + JWK export exercised in tests/harness. |
|
||||
| SEC-CRYPTO-90-010 | TODO | Security Guild | Introduce `StellaOpsCryptoOptions` + configuration binding for registry profiles/keys and expose `AddStellaOpsCryptoRu(IConfiguration, …)` so hosts can enable `ru-offline` without handwritten wiring. | SPRINT_514 | ✅ Options bind from `StellaOps:Crypto` (registry, CryptoPro, PKCS#11); ✅ New DI helper registers providers + preferred order; ✅ Sample config (`etc/rootpack/ru/crypto.profile.yaml`) loads without custom code. |
|
||||
| SEC-CRYPTO-90-011 | TODO | Security & Ops Guilds | Build the sovereign crypto CLI (`StellaOps.CryptoRu.Cli`) to list keys, perform test-sign operations, and emit determinism/audit payloads referenced by RootPack docs. | SPRINT_514 | ✅ CLI project under `src/Tools/`; ✅ `list` & `sign` commands hit provider registry; ✅ README/runbooks updated with usage examples. |
|
||||
| SEC-CRYPTO-90-012 | TODO | Security Guild | Add CryptoPro + PKCS#11 integration tests (env/pin gated) and wire them into `scripts/crypto/run-rootpack-ru-tests.sh`, covering Streebog vectors and DER/raw signatures. | SPRINT_514 | ✅ New tests skip gracefully when env vars absent; ✅ Test harness logs include RU cases; ✅ CI instructions documented. |
|
||||
| SEC-CRYPTO-90-013 | TODO | Security Guild | Extend the shared crypto stack with sovereign symmetric algorithms (Magma/Kuznyechik) so exports/data-at-rest can request Russian ciphers via the provider registry. | SPRINT_514 | ✅ Hash/service interfaces support symmetric operations; ✅ CryptoPro/PKCS#11 providers implement Magma/Kuznyechik; ✅ Sample usage documented/tests added. |
|
||||
| SEC-CRYPTO-90-014 | TODO | Security Guild + Service Guilds | Update runtime hosts (Authority, Scanner WebService/Worker, Concelier, etc.) to register RU providers, bind `StellaOps:Crypto` profiles, and expose operator-facing configuration toggles. | SPRINT_514 | ✅ Each host calls the new DI helper/config binding; ✅ Default configs document `ru-offline`; ✅ Sovereign bundles verified end-to-end. |
|
||||
| SEC-CRYPTO-90-015 | TODO | Security & Docs Guilds | Refresh RootPack/validation documentation once CLI/config/tests exist (remove TODO callouts, document final workflows). | SPRINT_514 | ✅ TODO sections removed from `rootpack_ru_*` docs; ✅ Final CLI/test steps published; ✅ Release checklist updated. |
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# TASKS
|
||||
| Task | Owner(s) | Depends on | Notes |
|
||||
|---|---|---|---|
|
||||
| PLUGIN-DI-08-001 | DONE (2025-10-21) | Plugin Platform Guild | — | Scoped service support in plugin bootstrap – ensure `[ServiceBinding]` metadata flows through hosts deterministically, add dynamic plugin tests, and document the attribute usage. |
|
||||
@@ -1,7 +0,0 @@
|
||||
# StellaOps.Replay.Core — Task Board
|
||||
|
||||
| ID | Status | Description | Dependencies | Exit Criteria |
|
||||
|----|--------|-------------|--------------|---------------|
|
||||
| REPLAY-CORE-185-001 | TODO | Scaffold replay core library (`StellaOps.Replay.Core`) with manifest schema types, canonical JSON utilities, Merkle helpers, DSSE payload builders, and module charter updates referencing `docs/replay/DETERMINISTIC_REPLAY.md`. | Sprint 185 replay planning | Library builds/tests succeed; AGENTS.md updated; integration notes cross-linked. |
|
||||
| REPLAY-CORE-185-002 | TODO | Implement deterministic bundle writer (tar.zst, CAS naming) and hashing abstractions; extend `docs/modules/platform/architecture-overview.md` with “Replay CAS” section. | REPLAY-CORE-185-001 | Bundle writer unit tests pass; documentation merged with examples; CAS layout reproducible. |
|
||||
| REPLAY-REACH-201-005 | DOING (2025-11-08) | Extend manifest schema + bundle writer to include reachability graphs, runtime traces, analyzer versions, and CAS URIs; update docs + serializers per `SPRINT_201_reachability_explainability`. | REPLAY-CORE-185-001, SIGNALS-REACH-201-003 | Manifest schema merged; unit tests cover new sections; docs + CAS layout references updated. |
|
||||
Reference in New Issue
Block a user