91 lines
3.3 KiB
C#
91 lines
3.3 KiB
C#
using System.Net.Http.Json;
|
|
|
|
namespace StellaOps.Cryptography.Plugin.SmRemote;
|
|
|
|
public sealed class SmRemoteHttpClient
|
|
{
|
|
private readonly HttpClient client;
|
|
|
|
public SmRemoteHttpClient(HttpClient client)
|
|
{
|
|
this.client = client ?? throw new ArgumentNullException(nameof(client));
|
|
}
|
|
|
|
public async Task<SmRemoteStatus> GetStatusAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var response = await client.GetAsync("/status", cancellationToken).ConfigureAwait(false);
|
|
response.EnsureSuccessStatusCode();
|
|
var status = await response.Content.ReadFromJsonAsync<SmRemoteStatus>(cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
return status ?? new SmRemoteStatus { IsAvailable = false, Error = "empty response" };
|
|
}
|
|
|
|
public async Task<string> SignAsync(string keyId, string algorithmId, byte[] pae, CancellationToken cancellationToken = default)
|
|
{
|
|
var request = new SmRemoteSignRequest
|
|
{
|
|
KeyId = keyId,
|
|
AlgorithmId = algorithmId,
|
|
PayloadBase64 = Convert.ToBase64String(pae)
|
|
};
|
|
|
|
var response = await client.PostAsJsonAsync("/sign", request, cancellationToken).ConfigureAwait(false);
|
|
response.EnsureSuccessStatusCode();
|
|
var envelope = await response.Content.ReadFromJsonAsync<SmRemoteSignResponse>(cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
if (envelope is null || string.IsNullOrWhiteSpace(envelope.Signature))
|
|
{
|
|
throw new InvalidOperationException("SM remote sign response was empty.");
|
|
}
|
|
|
|
return envelope.Signature;
|
|
}
|
|
|
|
public async Task<bool> VerifyAsync(string keyId, string algorithmId, byte[] pae, string signatureBase64, CancellationToken cancellationToken = default)
|
|
{
|
|
var request = new SmRemoteVerifyRequest
|
|
{
|
|
KeyId = keyId,
|
|
AlgorithmId = algorithmId,
|
|
PayloadBase64 = Convert.ToBase64String(pae),
|
|
Signature = signatureBase64
|
|
};
|
|
|
|
var response = await client.PostAsJsonAsync("/verify", request, cancellationToken).ConfigureAwait(false);
|
|
response.EnsureSuccessStatusCode();
|
|
var result = await response.Content.ReadFromJsonAsync<SmRemoteVerifyResponse>(cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
return result?.Valid == true;
|
|
}
|
|
}
|
|
|
|
internal sealed class SmRemoteSignRequest
|
|
{
|
|
public string KeyId { get; set; } = string.Empty;
|
|
public string AlgorithmId { get; set; } = string.Empty;
|
|
public string PayloadBase64 { get; set; } = string.Empty;
|
|
}
|
|
|
|
public sealed class SmRemoteSignResponse
|
|
{
|
|
public string Signature { get; set; } = string.Empty;
|
|
}
|
|
|
|
public sealed class SmRemoteVerifyRequest
|
|
{
|
|
public string KeyId { get; set; } = string.Empty;
|
|
public string AlgorithmId { get; set; } = string.Empty;
|
|
public string PayloadBase64 { get; set; } = string.Empty;
|
|
public string Signature { get; set; } = string.Empty;
|
|
}
|
|
|
|
public sealed class SmRemoteVerifyResponse
|
|
{
|
|
public bool Valid { get; set; }
|
|
}
|
|
|
|
public sealed class SmRemoteStatus
|
|
{
|
|
public bool IsAvailable { get; set; }
|
|
public string? ProviderName { get; set; }
|
|
public string[] SupportedAlgorithms { get; set; } = Array.Empty<string>();
|
|
public string? Error { get; set; }
|
|
}
|