Files
git.stella-ops.org/src/__Libraries/StellaOps.AuditPack/Services/AuditBundleSigner.Sign.cs

98 lines
3.1 KiB
C#

using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace StellaOps.AuditPack.Services;
public sealed partial class AuditBundleSigner
{
/// <summary>
/// Signs a manifest with DSSE envelope.
/// </summary>
public async Task<AuditBundleSigningResult> SignAsync(
AuditBundleSigningRequest request,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(request.ManifestBytes);
try
{
AsymmetricAlgorithm key;
string keyId;
string algorithm;
if (!string.IsNullOrEmpty(request.KeyFilePath))
{
(key, keyId, algorithm) = await LoadKeyFromFileAsync(
request.KeyFilePath,
request.KeyPassword,
cancellationToken)
.ConfigureAwait(false);
}
else
{
var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
key = ecdsa;
keyId = $"ephemeral:{ComputeKeyId(ecdsa)}";
algorithm = "ES256";
}
using (key)
{
var pae = CreatePae(PayloadType, request.ManifestBytes);
byte[] signature;
if (key is ECDsa ecdsa)
{
signature = ecdsa.SignData(pae, HashAlgorithmName.SHA256);
}
else if (key is RSA rsa)
{
signature = rsa.SignData(pae, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
algorithm = "RS256";
}
else
{
return AuditBundleSigningResult.Failed($"Unsupported key type: {key.GetType().Name}");
}
var envelope = new DsseEnvelope
{
PayloadType = PayloadType,
Payload = Convert.ToBase64String(request.ManifestBytes),
Signatures =
[
new DsseSignature
{
KeyId = keyId,
Sig = Convert.ToBase64String(signature)
}
]
};
var envelopeBytes = JsonSerializer.SerializeToUtf8Bytes(envelope, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
var payloadDigest = ComputeSha256(request.ManifestBytes);
return new AuditBundleSigningResult
{
Success = true,
Envelope = envelopeBytes,
KeyId = keyId,
Algorithm = algorithm,
PayloadDigest = payloadDigest
};
}
}
catch (Exception ex)
{
return AuditBundleSigningResult.Failed($"Signing failed: {ex.Message}");
}
}
}