save progress
This commit is contained in:
@@ -48,7 +48,27 @@ public static class DsseEnvelopeExtensions
|
||||
ArgumentNullException.ThrowIfNull(signatures);
|
||||
|
||||
var payloadBytes = Convert.FromBase64String(payloadBase64);
|
||||
var dsseSignatures = signatures.Select(s => new DsseSignature(s.SignatureBase64, s.KeyId));
|
||||
var dsseSignatures = new List<DsseSignature>();
|
||||
var index = 0;
|
||||
foreach (var signature in signatures)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(signature.SignatureBase64))
|
||||
{
|
||||
throw new ArgumentException("Signature must be provided.", nameof(signatures));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Convert.FromBase64String(signature.SignatureBase64);
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
throw new ArgumentException($"Signature at index {index} must be base64-encoded.", nameof(signatures), ex);
|
||||
}
|
||||
|
||||
dsseSignatures.Add(new DsseSignature(signature.SignatureBase64, signature.KeyId));
|
||||
index++;
|
||||
}
|
||||
|
||||
return new DsseEnvelope(payloadType, payloadBytes, dsseSignatures);
|
||||
}
|
||||
|
||||
@@ -10,33 +10,42 @@ namespace StellaOps.Attestation;
|
||||
|
||||
public static class DsseHelper
|
||||
{
|
||||
private const string DefaultPayloadType = "https://in-toto.io/Statement/v1";
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
public static byte[] PreAuthenticationEncoding(string payloadType, ReadOnlySpan<byte> payload)
|
||||
{
|
||||
static byte[] Cat(params byte[][] parts)
|
||||
{
|
||||
var len = 0;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
len += part.Length;
|
||||
}
|
||||
|
||||
var buf = new byte[len];
|
||||
var offset = 0;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
Buffer.BlockCopy(part, 0, buf, offset, part.Length);
|
||||
offset += part.Length;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
var header = Encoding.UTF8.GetBytes("DSSEv1");
|
||||
var pt = Encoding.UTF8.GetBytes(payloadType);
|
||||
var lenPt = Encoding.UTF8.GetBytes(pt.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var lenPayload = Encoding.UTF8.GetBytes(payload.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var space = Encoding.UTF8.GetBytes(" ");
|
||||
|
||||
return Cat(header, space, lenPt, space, pt, space, lenPayload, space, payload.ToArray());
|
||||
var totalLength = header.Length + space.Length + lenPt.Length + space.Length + pt.Length +
|
||||
space.Length + lenPayload.Length + space.Length + payload.Length;
|
||||
var buffer = new byte[totalLength];
|
||||
var offset = 0;
|
||||
|
||||
static void CopyBytes(byte[] source, byte[] destination, ref int index)
|
||||
{
|
||||
Buffer.BlockCopy(source, 0, destination, index, source.Length);
|
||||
index += source.Length;
|
||||
}
|
||||
|
||||
CopyBytes(header, buffer, ref offset);
|
||||
CopyBytes(space, buffer, ref offset);
|
||||
CopyBytes(lenPt, buffer, ref offset);
|
||||
CopyBytes(space, buffer, ref offset);
|
||||
CopyBytes(pt, buffer, ref offset);
|
||||
CopyBytes(space, buffer, ref offset);
|
||||
CopyBytes(lenPayload, buffer, ref offset);
|
||||
CopyBytes(space, buffer, ref offset);
|
||||
payload.CopyTo(buffer.AsSpan(offset));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static async Task<DsseEnvelope> WrapAsync(InTotoStatement statement, IAuthoritySigner signer, CancellationToken cancellationToken = default)
|
||||
@@ -44,13 +53,13 @@ public static class DsseHelper
|
||||
ArgumentNullException.ThrowIfNull(statement);
|
||||
ArgumentNullException.ThrowIfNull(signer);
|
||||
|
||||
var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement, statement.GetType());
|
||||
var pae = PreAuthenticationEncoding(statement.Type ?? string.Empty, payloadBytes);
|
||||
var payloadType = string.IsNullOrWhiteSpace(statement.Type) ? DefaultPayloadType : statement.Type;
|
||||
var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement, SerializerOptions);
|
||||
var pae = PreAuthenticationEncoding(payloadType, payloadBytes);
|
||||
var signatureBytes = await signer.SignAsync(pae, cancellationToken).ConfigureAwait(false);
|
||||
var keyId = await signer.GetKeyIdAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var dsseSignature = DsseSignature.FromBytes(signatureBytes, keyId);
|
||||
var payloadType = statement.Type ?? "https://in-toto.io/Statement/v1";
|
||||
return new DsseEnvelope(payloadType, payloadBytes, new[] { dsseSignature });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0043-M | DONE | Maintainability audit for StellaOps.Attestation. |
|
||||
| AUDIT-0043-T | DONE | Test coverage audit for StellaOps.Attestation. |
|
||||
| AUDIT-0043-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0043-A | DONE | Applied DSSE payloadType alignment and base64 validation with tests. |
|
||||
|
||||
Reference in New Issue
Block a user