commit
This commit is contained in:
		
							
								
								
									
										13
									
								
								src/StellaOps.Vexer.Attestation/Dsse/DsseEnvelope.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/StellaOps.Vexer.Attestation/Dsse/DsseEnvelope.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace StellaOps.Vexer.Attestation.Dsse;
 | 
			
		||||
 | 
			
		||||
public sealed record DsseEnvelope(
 | 
			
		||||
    [property: JsonPropertyName("payload")] string Payload,
 | 
			
		||||
    [property: JsonPropertyName("payloadType")] string PayloadType,
 | 
			
		||||
    [property: JsonPropertyName("signatures")] IReadOnlyList<DsseSignature> Signatures);
 | 
			
		||||
 | 
			
		||||
public sealed record DsseSignature(
 | 
			
		||||
    [property: JsonPropertyName("sig")] string Signature,
 | 
			
		||||
    [property: JsonPropertyName("keyid")] string? KeyId);
 | 
			
		||||
							
								
								
									
										83
									
								
								src/StellaOps.Vexer.Attestation/Dsse/VexDsseBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/StellaOps.Vexer.Attestation/Dsse/VexDsseBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Security.Cryptography;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using StellaOps.Vexer.Attestation.Models;
 | 
			
		||||
using StellaOps.Vexer.Attestation.Signing;
 | 
			
		||||
using StellaOps.Vexer.Core;
 | 
			
		||||
 | 
			
		||||
namespace StellaOps.Vexer.Attestation.Dsse;
 | 
			
		||||
 | 
			
		||||
public sealed class VexDsseBuilder
 | 
			
		||||
{
 | 
			
		||||
    private const string PayloadType = "application/vnd.in-toto+json";
 | 
			
		||||
 | 
			
		||||
    private readonly IVexSigner _signer;
 | 
			
		||||
    private readonly ILogger<VexDsseBuilder> _logger;
 | 
			
		||||
    private readonly JsonSerializerOptions _serializerOptions;
 | 
			
		||||
 | 
			
		||||
    public VexDsseBuilder(IVexSigner signer, ILogger<VexDsseBuilder> logger)
 | 
			
		||||
    {
 | 
			
		||||
        _signer = signer ?? throw new ArgumentNullException(nameof(signer));
 | 
			
		||||
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 | 
			
		||||
        _serializerOptions = new JsonSerializerOptions
 | 
			
		||||
        {
 | 
			
		||||
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
 | 
			
		||||
            DefaultIgnoreCondition = JsonIgnoreCondition.Never,
 | 
			
		||||
            WriteIndented = false,
 | 
			
		||||
        };
 | 
			
		||||
        _serializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<DsseEnvelope> CreateEnvelopeAsync(
 | 
			
		||||
        VexAttestationRequest request,
 | 
			
		||||
        IReadOnlyDictionary<string, string>? metadata,
 | 
			
		||||
        CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        ArgumentNullException.ThrowIfNull(request);
 | 
			
		||||
 | 
			
		||||
        var predicate = VexAttestationPredicate.FromRequest(request, metadata);
 | 
			
		||||
        var subject = new VexInTotoSubject(
 | 
			
		||||
            request.ExportId,
 | 
			
		||||
            new Dictionary<string, string>(StringComparer.Ordinal)
 | 
			
		||||
            {
 | 
			
		||||
                { request.Artifact.Algorithm.ToLowerInvariant(), request.Artifact.Digest }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        var statement = new VexInTotoStatement(
 | 
			
		||||
            VexInTotoStatement.InTotoType,
 | 
			
		||||
            "https://stella-ops.org/attestations/vex-export",
 | 
			
		||||
            new[] { subject },
 | 
			
		||||
            predicate);
 | 
			
		||||
 | 
			
		||||
        var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement, _serializerOptions);
 | 
			
		||||
        var signatureResult = await _signer.SignAsync(payloadBytes, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
        var envelope = new DsseEnvelope(
 | 
			
		||||
            Convert.ToBase64String(payloadBytes),
 | 
			
		||||
            PayloadType,
 | 
			
		||||
            new[] { new DsseSignature(signatureResult.Signature, signatureResult.KeyId) });
 | 
			
		||||
 | 
			
		||||
        _logger.LogDebug("DSSE envelope created for export {ExportId}", request.ExportId);
 | 
			
		||||
        return envelope;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static string ComputeEnvelopeDigest(DsseEnvelope envelope)
 | 
			
		||||
    {
 | 
			
		||||
        ArgumentNullException.ThrowIfNull(envelope);
 | 
			
		||||
        var envelopeJson = JsonSerializer.Serialize(envelope, new JsonSerializerOptions
 | 
			
		||||
        {
 | 
			
		||||
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
 | 
			
		||||
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
 | 
			
		||||
        });
 | 
			
		||||
        var bytes = Encoding.UTF8.GetBytes(envelopeJson);
 | 
			
		||||
        var hash = SHA256.HashData(bytes);
 | 
			
		||||
        return "sha256:" + Convert.ToHexString(hash).ToLowerInvariant();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user