using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using BcCertificate = Org.BouncyCastle.X509.X509Certificate;
namespace XFESystem.NativeTls.Tests;
internal sealed class CertificateFixtures : IDisposable
{
public DateTime Now { get; } = DateTime.UtcNow;
public ECDsa RootKey { get; } = ECDsa.Create(ECCurve.NamedCurves.nistP256);
public X509Certificate2 Root { get; }
public BcCertificate RootBc => new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(Root.RawData);
public CertificateFixtures(string? permittedDns = null, string? excludedDns = null, bool serverAuthRoot = true, bool certificateSigning = true)
{
var request = new CertificateRequest("CN=XFE controlled TLS test root", RootKey, HashAlgorithmName.SHA256);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(certificateSigning ? X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign : X509KeyUsageFlags.DigitalSignature, true));
if (!serverAuthRoot) request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new("1.3.6.1.5.5.7.3.2") }, false));
if (permittedDns is not null || excludedDns is not null)
{
Org.BouncyCastle.Asn1.X509.GeneralSubtree[]? permitted = permittedDns is null ? null :
[new(new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.DnsName, permittedDns))];
Org.BouncyCastle.Asn1.X509.GeneralSubtree[]? excluded = excludedDns is null ? null :
[new(new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.DnsName, excludedDns))];
var constraints = new Org.BouncyCastle.Asn1.X509.NameConstraints(
permitted is null ? null! : new Org.BouncyCastle.Asn1.X509.GeneralSubtrees(permitted),
excluded is null ? null! : new Org.BouncyCastle.Asn1.X509.GeneralSubtrees(excluded));
request.CertificateExtensions.Add(new X509Extension("2.5.29.30", constraints.GetDerEncoded(), true));
}
Root = request.CreateSelfSigned(Now.AddDays(-10), Now.AddDays(10));
}
public X509Certificate2 Leaf(string? dns = "test.xfe.invalid", string? ip = null, bool ca = false,
bool serverAuth = true, DateTime? before = null, DateTime? after = null,
ECDsa? signingKey = null, bool unknownCriticalExtension = false, bool signingUsage = true)
{
using var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var request = new CertificateRequest("CN=never-used-for-name-match.invalid", key, HashAlgorithmName.SHA256);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(ca, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(signingUsage ? X509KeyUsageFlags.DigitalSignature : X509KeyUsageFlags.KeyEncipherment, true));
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection
{ new(serverAuth ? "1.3.6.1.5.5.7.3.1" : "1.3.6.1.5.5.7.3.2") }, false));
if (dns is not null || ip is not null)
{
var names = new SubjectAlternativeNameBuilder();
if (dns is not null) names.AddDnsName(dns);
if (ip is not null) names.AddIpAddress(System.Net.IPAddress.Parse(ip));
request.CertificateExtensions.Add(names.Build());
}
if (unknownCriticalExtension) request.CertificateExtensions.Add(new X509Extension("1.3.6.1.4.1.55555.99", [0x05, 0x00], true));
var signature = X509SignatureGenerator.CreateForECDsa(signingKey ?? RootKey);
using var certificate = request.Create(Root.SubjectName, signature,
before ?? Now.AddDays(-1), after ?? Now.AddDays(1), RandomNumberGenerator.GetBytes(16));
return certificate.CopyWithPrivateKey(key);
}
public void Dispose() { Root.Dispose(); RootKey.Dispose(); }
}
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using BcCertificate = Org.BouncyCastle.X509.X509Certificate;
namespace XFESystem.NativeTls.Tests;
internal sealed class CertificateFixtures : IDisposable
{
public DateTime Now { get; } = DateTime.UtcNow;
public ECDsa RootKey { get; } = ECDsa.Create(ECCurve.NamedCurves.nistP256);
public X509Certificate2 Root { get; }
public BcCertificate RootBc => new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(Root.RawData);
public CertificateFixtures(string? permittedDns = null, string? excludedDns = null, bool serverAuthRoot = true, bool certificateSigning = true)
{
var request = new CertificateRequest("CN=XFE controlled TLS test root", RootKey, HashAlgorithmName.SHA256);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(certificateSigning ? X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign : X509KeyUsageFlags.DigitalSignature, true));
if (!serverAuthRoot) request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new("1.3.6.1.5.5.7.3.2") }, false));
if (permittedDns is not null || excludedDns is not null)
{
Org.BouncyCastle.Asn1.X509.GeneralSubtree[]? permitted = permittedDns is null ? null :
[new(new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.DnsName, permittedDns))];
Org.BouncyCastle.Asn1.X509.GeneralSubtree[]? excluded = excludedDns is null ? null :
[new(new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.DnsName, excludedDns))];
var constraints = new Org.BouncyCastle.Asn1.X509.NameConstraints(
permitted is null ? null! : new Org.BouncyCastle.Asn1.X509.GeneralSubtrees(permitted),
excluded is null ? null! : new Org.BouncyCastle.Asn1.X509.GeneralSubtrees(excluded));
request.CertificateExtensions.Add(new X509Extension("2.5.29.30", constraints.GetDerEncoded(), true));
}
Root = request.CreateSelfSigned(Now.AddDays(-10), Now.AddDays(10));
}
public X509Certificate2 Leaf(string? dns = "test.xfe.invalid", string? ip = null, bool ca = false,
bool serverAuth = true, DateTime? before = null, DateTime? after = null,
ECDsa? signingKey = null, bool unknownCriticalExtension = false, bool signingUsage = true)
{
using var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var request = new CertificateRequest("CN=never-used-for-name-match.invalid", key, HashAlgorithmName.SHA256);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(ca, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(signingUsage ? X509KeyUsageFlags.DigitalSignature : X509KeyUsageFlags.KeyEncipherment, true));
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection
{ new(serverAuth ? "1.3.6.1.5.5.7.3.1" : "1.3.6.1.5.5.7.3.2") }, false));
if (dns is not null || ip is not null)
{
var names = new SubjectAlternativeNameBuilder();
if (dns is not null) names.AddDnsName(dns);
if (ip is not null) names.AddIpAddress(System.Net.IPAddress.Parse(ip));
request.CertificateExtensions.Add(names.Build());
}
if (unknownCriticalExtension) request.CertificateExtensions.Add(new X509Extension("1.3.6.1.4.1.55555.99", [0x05, 0x00], true));
var signature = X509SignatureGenerator.CreateForECDsa(signingKey ?? RootKey);
using var certificate = request.Create(Root.SubjectName, signature,
before ?? Now.AddDays(-1), after ?? Now.AddDays(1), RandomNumberGenerator.GetBytes(16));
return certificate.CopyWithPrivateKey(key);
}
public void Dispose() { Root.Dispose(); RootKey.Dispose(); }
}