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:
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user