sprints completion. new product advisories prepared
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
// Copyright © StellaOps. All rights reserved.
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Sprint: SPRINT_20260112_018_CRYPTO_key_escrow_shamir
|
||||
// Tasks: ESCROW-003, ESCROW-004
|
||||
|
||||
namespace StellaOps.Cryptography.KeyEscrow;
|
||||
|
||||
/// <summary>
|
||||
/// Service for key escrow operations using Shamir's Secret Sharing.
|
||||
/// </summary>
|
||||
public interface IKeyEscrowService
|
||||
{
|
||||
/// <summary>
|
||||
/// Escrow a key by splitting it into shares and distributing to agents.
|
||||
/// </summary>
|
||||
/// <param name="keyId">Identifier for the key being escrowed.</param>
|
||||
/// <param name="keyMaterial">The key material to escrow.</param>
|
||||
/// <param name="options">Escrow configuration options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Result containing share IDs and metadata.</returns>
|
||||
Task<KeyEscrowResult> EscrowKeyAsync(
|
||||
string keyId,
|
||||
byte[] keyMaterial,
|
||||
KeyEscrowOptions options,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Recover a key from escrow using collected shares.
|
||||
/// </summary>
|
||||
/// <param name="request">Recovery request with authorization details.</param>
|
||||
/// <param name="shares">Decrypted shares from custodians.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Result containing recovered key material.</returns>
|
||||
Task<KeyRecoveryResult> RecoverKeyAsync(
|
||||
KeyRecoveryRequest request,
|
||||
IReadOnlyList<KeyShare> shares,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get escrow status for a key.
|
||||
/// </summary>
|
||||
/// <param name="keyId">Key identifier.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Escrow status or null if not escrowed.</returns>
|
||||
Task<KeyEscrowStatus?> GetEscrowStatusAsync(
|
||||
string keyId,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// List all escrowed keys.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>List of escrowed key summaries.</returns>
|
||||
Task<IReadOnlyList<KeyEscrowSummary>> ListEscrowedKeysAsync(
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Revoke escrow for a key (delete all shares).
|
||||
/// </summary>
|
||||
/// <param name="keyId">Key identifier.</param>
|
||||
/// <param name="reason">Reason for revocation.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>True if revocation succeeded.</returns>
|
||||
Task<bool> RevokeEscrowAsync(
|
||||
string keyId,
|
||||
string reason,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Re-escrow a key with new shares (after recovery or rotation).
|
||||
/// Invalidates previous shares.
|
||||
/// </summary>
|
||||
/// <param name="keyId">Key identifier.</param>
|
||||
/// <param name="keyMaterial">Key material to re-escrow.</param>
|
||||
/// <param name="options">New escrow options (or null to use previous).</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Result containing new share IDs.</returns>
|
||||
Task<KeyEscrowResult> ReEscrowKeyAsync(
|
||||
string keyId,
|
||||
byte[] keyMaterial,
|
||||
KeyEscrowOptions? options = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for key escrow operations.
|
||||
/// </summary>
|
||||
public sealed record KeyEscrowOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum shares required for recovery (M in M-of-N).
|
||||
/// </summary>
|
||||
public required int Threshold { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total shares to create (N in M-of-N).
|
||||
/// </summary>
|
||||
public required int TotalShares { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Days until shares expire.
|
||||
/// </summary>
|
||||
public int ExpirationDays { get; init; } = 365;
|
||||
|
||||
/// <summary>
|
||||
/// IDs of agents to distribute shares to.
|
||||
/// Must have at least TotalShares agents.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string>? AgentIds { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to require dual-control ceremony for recovery.
|
||||
/// </summary>
|
||||
public bool RequireDualControl { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Metadata to attach to the escrow record.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status of a key's escrow.
|
||||
/// </summary>
|
||||
public sealed record KeyEscrowStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Key identifier.
|
||||
/// </summary>
|
||||
public required string KeyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the key is currently escrowed.
|
||||
/// </summary>
|
||||
public required bool IsEscrowed { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Threshold for recovery.
|
||||
/// </summary>
|
||||
public int Threshold { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total shares created.
|
||||
/// </summary>
|
||||
public int TotalShares { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of shares still valid (not expired or revoked).
|
||||
/// </summary>
|
||||
public int ValidShares { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the escrow was created.
|
||||
/// </summary>
|
||||
public DateTimeOffset? CreatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When shares expire.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether recovery is currently possible.
|
||||
/// </summary>
|
||||
public bool CanRecover => ValidShares >= Threshold;
|
||||
|
||||
/// <summary>
|
||||
/// Custodians holding shares.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string>? CustodianIds { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Summary of an escrowed key.
|
||||
/// </summary>
|
||||
public sealed record KeyEscrowSummary
|
||||
{
|
||||
/// <summary>
|
||||
/// Key identifier.
|
||||
/// </summary>
|
||||
public required string KeyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Threshold for recovery.
|
||||
/// </summary>
|
||||
public required int Threshold { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total shares.
|
||||
/// </summary>
|
||||
public required int TotalShares { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When escrowed.
|
||||
/// </summary>
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When shares expire.
|
||||
/// </summary>
|
||||
public required DateTimeOffset ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Escrow metadata.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user