using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Security;
namespace XFESystem.Tls;
/// The platform must reject unavailable entropy and untrustworthy UTC; no fallback is allowed.
public interface ITlsSecurityContext
{
DateTime UtcNow { get; }
void FillRandom(Span destination);
}
internal sealed class PlatformRandomGenerator(ITlsSecurityContext platform) : IRandomGenerator
{
// Bouncy Castle may add supplemental public material. It must never replace
// the independently seeded, platform-owned CSPRNG with this material.
public void AddSeedMaterial(byte[] seed) { }
public void AddSeedMaterial(ReadOnlySpan seed) { }
public void AddSeedMaterial(long seed) { }
public void NextBytes(byte[] bytes) => platform.FillRandom(bytes);
public void NextBytes(byte[] bytes, int start, int len) => platform.FillRandom(bytes.AsSpan(start, len));
public void NextBytes(Span bytes) => platform.FillRandom(bytes);
}
internal static class TlsSecurity
{
public static DateTime ReadUtc(ITlsSecurityContext platform)
{
DateTime now = platform.UtcNow;
ValidateUtc(now);
return now;
}
internal static void ValidateUtc(DateTime now)
{
if (now.Kind != DateTimeKind.Utc || now < new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc))
throw new InvalidOperationException("HTTPS requires a reliable UTC clock.");
}
public static SecureRandom CreateRandom(ITlsSecurityContext platform)
{
// Probe before the ClientHello. This is an availability check, not an
// entropy estimate; the platform performs the actual source checks.
Span probe = stackalloc byte[32];
try { platform.FillRandom(probe); }
finally { probe.Clear(); }
return new SecureRandom(new PlatformRandomGenerator(platform));
}
}