sprints work.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// CertificateStatusOptions.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Configuration options for certificate status checking.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Options for certificate revocation status checking.
|
||||
/// </summary>
|
||||
public sealed record CertificateStatusOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether to prefer OCSP over CRL.
|
||||
/// </summary>
|
||||
public bool PreferOcsp { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether revocation checking is required.
|
||||
/// </summary>
|
||||
public bool RequireRevocationCheck { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to only accept stapled/cached responses (offline mode).
|
||||
/// </summary>
|
||||
public bool OfflineOnly { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to allow unknown status to pass.
|
||||
/// </summary>
|
||||
public bool AllowUnknownStatus { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum age for OCSP responses.
|
||||
/// </summary>
|
||||
public TimeSpan MaxOcspAge { get; init; } = TimeSpan.FromDays(7);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum age for CRL responses.
|
||||
/// </summary>
|
||||
public TimeSpan MaxCrlAge { get; init; } = TimeSpan.FromDays(30);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timeout for online requests.
|
||||
/// </summary>
|
||||
public TimeSpan RequestTimeout { get; init; } = TimeSpan.FromSeconds(10);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to include OCSP nonce for replay protection.
|
||||
/// </summary>
|
||||
public bool IncludeOcspNonce { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to cache responses.
|
||||
/// </summary>
|
||||
public bool EnableCaching { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to check the entire certificate chain.
|
||||
/// </summary>
|
||||
public bool CheckFullChain { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether to skip root certificate revocation check.
|
||||
/// </summary>
|
||||
public bool SkipRootCheck { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default options.
|
||||
/// </summary>
|
||||
public static CertificateStatusOptions Default { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets strict options (all checks required, short validity).
|
||||
/// </summary>
|
||||
public static CertificateStatusOptions Strict { get; } = new()
|
||||
{
|
||||
PreferOcsp = true,
|
||||
RequireRevocationCheck = true,
|
||||
AllowUnknownStatus = false,
|
||||
MaxOcspAge = TimeSpan.FromDays(1),
|
||||
MaxCrlAge = TimeSpan.FromDays(7),
|
||||
IncludeOcspNonce = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets offline-only options (stapled/cached responses only).
|
||||
/// </summary>
|
||||
public static CertificateStatusOptions OfflineOnlyMode { get; } = new()
|
||||
{
|
||||
OfflineOnly = true,
|
||||
RequireRevocationCheck = true,
|
||||
EnableCaching = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets permissive options (revocation check optional).
|
||||
/// </summary>
|
||||
public static CertificateStatusOptions Permissive { get; } = new()
|
||||
{
|
||||
RequireRevocationCheck = false,
|
||||
AllowUnknownStatus = true
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// CertificateStatusRequest.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Request model for certificate status checking.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Request for checking certificate revocation status.
|
||||
/// </summary>
|
||||
public sealed record CertificateStatusRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the certificate to check.
|
||||
/// </summary>
|
||||
public required X509Certificate2 Certificate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the issuer certificate (required for OCSP).
|
||||
/// </summary>
|
||||
public X509Certificate2? Issuer { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status check options.
|
||||
/// </summary>
|
||||
public CertificateStatusOptions Options { get; init; } = CertificateStatusOptions.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets pre-fetched stapled revocation data (for offline verification).
|
||||
/// </summary>
|
||||
public StapledRevocationData? StapledData { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the validation time (for historical validation).
|
||||
/// </summary>
|
||||
public DateTimeOffset? ValidationTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a request for a certificate with its issuer.
|
||||
/// </summary>
|
||||
public static CertificateStatusRequest Create(
|
||||
X509Certificate2 certificate,
|
||||
X509Certificate2? issuer = null,
|
||||
CertificateStatusOptions? options = null) => new()
|
||||
{
|
||||
Certificate = certificate,
|
||||
Issuer = issuer,
|
||||
Options = options ?? CertificateStatusOptions.Default
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a request for offline verification using stapled data.
|
||||
/// </summary>
|
||||
public static CertificateStatusRequest CreateOffline(
|
||||
X509Certificate2 certificate,
|
||||
StapledRevocationData stapledData,
|
||||
DateTimeOffset? validationTime = null) => new()
|
||||
{
|
||||
Certificate = certificate,
|
||||
StapledData = stapledData,
|
||||
ValidationTime = validationTime,
|
||||
Options = CertificateStatusOptions.OfflineOnlyMode
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// CertificateStatusResult.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Result model for certificate status checking.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Result of a certificate revocation status check.
|
||||
/// </summary>
|
||||
public sealed record CertificateStatusResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the revocation status.
|
||||
/// </summary>
|
||||
public required RevocationStatus Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source of the revocation information.
|
||||
/// </summary>
|
||||
public required RevocationSource Source { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time the status was produced.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ProducedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when this status information was last updated.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ThisUpdate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when this status information will next be updated.
|
||||
/// </summary>
|
||||
public DateTimeOffset? NextUpdate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the revocation time if the certificate is revoked.
|
||||
/// </summary>
|
||||
public DateTimeOffset? RevocationTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the revocation reason if the certificate is revoked.
|
||||
/// </summary>
|
||||
public RevocationReason? RevocationReason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw OCSP response if available.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte>? RawOcspResponse { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw CRL if available.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte>? RawCrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets error details if the check failed.
|
||||
/// </summary>
|
||||
public string? Error { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the responder URL that was used.
|
||||
/// </summary>
|
||||
public string? ResponderUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the status is considered valid.
|
||||
/// </summary>
|
||||
public bool IsValid => Status == RevocationStatus.Good;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the response is still fresh.
|
||||
/// </summary>
|
||||
public bool IsFresh => NextUpdate.HasValue && NextUpdate.Value > DateTimeOffset.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a result indicating the certificate is good.
|
||||
/// </summary>
|
||||
public static CertificateStatusResult Good(
|
||||
RevocationSource source,
|
||||
DateTimeOffset? thisUpdate = null,
|
||||
DateTimeOffset? nextUpdate = null,
|
||||
ReadOnlyMemory<byte>? rawResponse = null) => new()
|
||||
{
|
||||
Status = RevocationStatus.Good,
|
||||
Source = source,
|
||||
ProducedAt = DateTimeOffset.UtcNow,
|
||||
ThisUpdate = thisUpdate,
|
||||
NextUpdate = nextUpdate,
|
||||
RawOcspResponse = source is RevocationSource.Ocsp or RevocationSource.OcspStapled ? rawResponse : null,
|
||||
RawCrl = source is RevocationSource.Crl or RevocationSource.CrlCached ? rawResponse : null
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a result indicating the certificate is revoked.
|
||||
/// </summary>
|
||||
public static CertificateStatusResult Revoked(
|
||||
RevocationSource source,
|
||||
DateTimeOffset revocationTime,
|
||||
RevocationReason reason = Abstractions.RevocationReason.Unspecified) => new()
|
||||
{
|
||||
Status = RevocationStatus.Revoked,
|
||||
Source = source,
|
||||
ProducedAt = DateTimeOffset.UtcNow,
|
||||
RevocationTime = revocationTime,
|
||||
RevocationReason = reason
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a result indicating the status is unknown.
|
||||
/// </summary>
|
||||
public static CertificateStatusResult Unknown(RevocationSource source, string? error = null) => new()
|
||||
{
|
||||
Status = RevocationStatus.Unknown,
|
||||
Source = source,
|
||||
ProducedAt = DateTimeOffset.UtcNow,
|
||||
Error = error
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a result indicating the check is unavailable.
|
||||
/// </summary>
|
||||
public static CertificateStatusResult Unavailable(string error) => new()
|
||||
{
|
||||
Status = RevocationStatus.Unavailable,
|
||||
Source = RevocationSource.None,
|
||||
ProducedAt = DateTimeOffset.UtcNow,
|
||||
Error = error
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of checking an entire certificate chain.
|
||||
/// </summary>
|
||||
public sealed record ChainStatusResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether the entire chain is valid.
|
||||
/// </summary>
|
||||
public bool IsValid => CertificateResults.All(r => r.Status == RevocationStatus.Good);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status results for each certificate in the chain.
|
||||
/// </summary>
|
||||
public required IReadOnlyList<CertificateStatusResult> CertificateResults { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the overall chain status.
|
||||
/// </summary>
|
||||
public RevocationStatus OverallStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CertificateResults.Any(r => r.Status == RevocationStatus.Revoked))
|
||||
return RevocationStatus.Revoked;
|
||||
if (CertificateResults.Any(r => r.Status == RevocationStatus.Unknown))
|
||||
return RevocationStatus.Unknown;
|
||||
if (CertificateResults.Any(r => r.Status == RevocationStatus.Unavailable))
|
||||
return RevocationStatus.Unavailable;
|
||||
return RevocationStatus.Good;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first revoked certificate result if any.
|
||||
/// </summary>
|
||||
public CertificateStatusResult? FirstRevoked =>
|
||||
CertificateResults.FirstOrDefault(r => r.Status == RevocationStatus.Revoked);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// ICertificateStatusProvider.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Main interface for certificate revocation checking.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides certificate revocation status checking via OCSP, CRL, or stapled responses.
|
||||
/// </summary>
|
||||
public interface ICertificateStatusProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks the revocation status of a certificate.
|
||||
/// </summary>
|
||||
/// <param name="request">The status check request.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The certificate status result.</returns>
|
||||
Task<CertificateStatusResult> CheckStatusAsync(
|
||||
CertificateStatusRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Checks the revocation status of a certificate chain.
|
||||
/// </summary>
|
||||
/// <param name="chain">The certificate chain to check.</param>
|
||||
/// <param name="options">Status check options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Status results for each certificate in the chain.</returns>
|
||||
Task<ChainStatusResult> CheckChainStatusAsync(
|
||||
X509Chain chain,
|
||||
CertificateStatusOptions? options = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches revocation data for stapling (OCSP response and/or CRL).
|
||||
/// </summary>
|
||||
/// <param name="certificate">The certificate to get revocation data for.</param>
|
||||
/// <param name="issuer">The issuer certificate.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Stapled revocation data for bundling.</returns>
|
||||
Task<StapledRevocationData?> FetchRevocationDataAsync(
|
||||
X509Certificate2 certificate,
|
||||
X509Certificate2 issuer,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// RevocationEnums.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Enumerations for revocation status and sources.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Certificate revocation status.
|
||||
/// </summary>
|
||||
public enum RevocationStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The certificate is not revoked.
|
||||
/// </summary>
|
||||
Good,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate has been revoked.
|
||||
/// </summary>
|
||||
Revoked,
|
||||
|
||||
/// <summary>
|
||||
/// The revocation status could not be determined.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// Revocation checking is not available.
|
||||
/// </summary>
|
||||
Unavailable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Source of revocation information.
|
||||
/// </summary>
|
||||
public enum RevocationSource
|
||||
{
|
||||
/// <summary>
|
||||
/// No revocation source was used.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Online OCSP responder.
|
||||
/// </summary>
|
||||
Ocsp,
|
||||
|
||||
/// <summary>
|
||||
/// Certificate Revocation List.
|
||||
/// </summary>
|
||||
Crl,
|
||||
|
||||
/// <summary>
|
||||
/// Pre-fetched (stapled) OCSP response.
|
||||
/// </summary>
|
||||
OcspStapled,
|
||||
|
||||
/// <summary>
|
||||
/// Cached CRL.
|
||||
/// </summary>
|
||||
CrlCached,
|
||||
|
||||
/// <summary>
|
||||
/// Delta CRL applied to base CRL.
|
||||
/// </summary>
|
||||
DeltaCrl
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Certificate revocation reason codes (RFC 5280).
|
||||
/// </summary>
|
||||
public enum RevocationReason
|
||||
{
|
||||
/// <summary>
|
||||
/// No reason specified.
|
||||
/// </summary>
|
||||
Unspecified = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The private key was compromised.
|
||||
/// </summary>
|
||||
KeyCompromise = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The CA's private key was compromised.
|
||||
/// </summary>
|
||||
CaCompromise = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate holder's affiliation changed.
|
||||
/// </summary>
|
||||
AffiliationChanged = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate has been superseded.
|
||||
/// </summary>
|
||||
Superseded = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate is no longer needed.
|
||||
/// </summary>
|
||||
CessationOfOperation = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate is on hold (may be unrevoked).
|
||||
/// </summary>
|
||||
CertificateHold = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Removed from CRL (used in delta CRLs).
|
||||
/// </summary>
|
||||
RemoveFromCrl = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Privilege withdrawn.
|
||||
/// </summary>
|
||||
PrivilegeWithdrawn = 9,
|
||||
|
||||
/// <summary>
|
||||
/// The AA's key was compromised.
|
||||
/// </summary>
|
||||
AaCompromise = 10
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// StapledRevocationData.cs
|
||||
// Sprint: SPRINT_20260119_008 Certificate Status Provider
|
||||
// Task: CSP-001 - Core Abstractions
|
||||
// Description: Model for pre-fetched revocation data for offline verification.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace StellaOps.Cryptography.CertificateStatus.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Pre-fetched revocation data for bundling with signatures or evidence.
|
||||
/// </summary>
|
||||
public sealed record StapledRevocationData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the certificate thumbprint this data is for.
|
||||
/// </summary>
|
||||
public required string CertificateThumbprint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the OCSP response if available.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte>? OcspResponse { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CRL if available.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte>? Crl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when this data was fetched.
|
||||
/// </summary>
|
||||
public required DateTimeOffset FetchedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when this data expires.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the OCSP responder URL used.
|
||||
/// </summary>
|
||||
public string? OcspResponderUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CRL distribution point URL used.
|
||||
/// </summary>
|
||||
public string? CrlDistributionPoint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this data includes OCSP.
|
||||
/// </summary>
|
||||
public bool HasOcsp => OcspResponse is { Length: > 0 };
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this data includes CRL.
|
||||
/// </summary>
|
||||
public bool HasCrl => Crl is { Length: > 0 };
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this data is still fresh.
|
||||
/// </summary>
|
||||
public bool IsFresh => !ExpiresAt.HasValue || ExpiresAt.Value > DateTimeOffset.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Creates stapled data from an OCSP response.
|
||||
/// </summary>
|
||||
public static StapledRevocationData FromOcsp(
|
||||
string thumbprint,
|
||||
ReadOnlyMemory<byte> ocspResponse,
|
||||
string? responderUrl = null,
|
||||
DateTimeOffset? expiresAt = null) => new()
|
||||
{
|
||||
CertificateThumbprint = thumbprint,
|
||||
OcspResponse = ocspResponse,
|
||||
FetchedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = expiresAt,
|
||||
OcspResponderUrl = responderUrl
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates stapled data from a CRL.
|
||||
/// </summary>
|
||||
public static StapledRevocationData FromCrl(
|
||||
string thumbprint,
|
||||
ReadOnlyMemory<byte> crl,
|
||||
string? distributionPoint = null,
|
||||
DateTimeOffset? expiresAt = null) => new()
|
||||
{
|
||||
CertificateThumbprint = thumbprint,
|
||||
Crl = crl,
|
||||
FetchedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = expiresAt,
|
||||
CrlDistributionPoint = distributionPoint
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of stapled revocation data for an entire certificate chain.
|
||||
/// </summary>
|
||||
public sealed record StapledRevocationBundle
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the revocation data for each certificate in the chain.
|
||||
/// </summary>
|
||||
public required IReadOnlyList<StapledRevocationData> Certificates { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when this bundle was created.
|
||||
/// </summary>
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the earliest expiration of any certificate's revocation data.
|
||||
/// </summary>
|
||||
public DateTimeOffset? EarliestExpiration =>
|
||||
Certificates.Where(c => c.ExpiresAt.HasValue)
|
||||
.OrderBy(c => c.ExpiresAt)
|
||||
.FirstOrDefault()?.ExpiresAt;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether all certificates have fresh revocation data.
|
||||
/// </summary>
|
||||
public bool IsComplete => Certificates.All(c => c.IsFresh && (c.HasOcsp || c.HasCrl));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stapled data for a specific certificate thumbprint.
|
||||
/// </summary>
|
||||
public StapledRevocationData? GetForCertificate(string thumbprint) =>
|
||||
Certificates.FirstOrDefault(c =>
|
||||
c.CertificateThumbprint.Equals(thumbprint, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>StellaOps.Cryptography.CertificateStatus.Abstractions</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user