M10 PKI: add 6 cmdlets (Get-/Search-/ConvertTo-/Install-/Uninstall-/Export-InfisicalCertificate), BouncyCastle-backed PemCertificateBuilder, formatting/type metadata for PKI models, and cert-manager <-> pki route alias fallback via InvokeWithCandidateFallback. Primary CA paths now /api/v1/cert-manager/ca/internal[/{caId}]; legacy /api/v1/pki/* retained as fallback. 190/190 tests passing.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using PSInfisicalAPI.Pki;
|
||||
using Xunit;
|
||||
|
||||
namespace PSInfisicalAPI.Tests
|
||||
{
|
||||
public class PemCertificateBuilderTests
|
||||
{
|
||||
private static (string CertPem, string KeyPem, string Thumbprint) CreateSelfSigned(string commonName)
|
||||
{
|
||||
using (RSA rsa = RSA.Create(2048))
|
||||
{
|
||||
CertificateRequest request = new CertificateRequest(
|
||||
"CN=" + commonName,
|
||||
rsa,
|
||||
HashAlgorithmName.SHA256,
|
||||
RSASignaturePadding.Pkcs1);
|
||||
|
||||
DateTimeOffset notBefore = DateTimeOffset.UtcNow.AddMinutes(-5);
|
||||
DateTimeOffset notAfter = DateTimeOffset.UtcNow.AddDays(1);
|
||||
using (X509Certificate2 cert = request.CreateSelfSigned(notBefore, notAfter))
|
||||
{
|
||||
byte[] derBytes = cert.Export(X509ContentType.Cert);
|
||||
string certPem = "-----BEGIN CERTIFICATE-----\n" +
|
||||
Convert.ToBase64String(derBytes, Base64FormattingOptions.InsertLineBreaks) +
|
||||
"\n-----END CERTIFICATE-----\n";
|
||||
|
||||
byte[] pkcs8 = rsa.ExportPkcs8PrivateKey();
|
||||
string keyPem = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
Convert.ToBase64String(pkcs8, Base64FormattingOptions.InsertLineBreaks) +
|
||||
"\n-----END PRIVATE KEY-----\n";
|
||||
|
||||
return (certPem, keyPem, cert.Thumbprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_From_Cert_Only_Returns_X509Certificate2_Without_Key()
|
||||
{
|
||||
(string certPem, _, string thumbprint) = CreateSelfSigned("PemBuilderTest.NoKey");
|
||||
X509Certificate2 cert = PemCertificateBuilder.Build(certPem, null, null, X509KeyStorageFlags.DefaultKeySet);
|
||||
try
|
||||
{
|
||||
Assert.NotNull(cert);
|
||||
Assert.Equal(thumbprint, cert.Thumbprint);
|
||||
Assert.False(cert.HasPrivateKey);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cert.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_With_Pkcs8_Key_Attaches_Private_Key()
|
||||
{
|
||||
(string certPem, string keyPem, string thumbprint) = CreateSelfSigned("PemBuilderTest.WithKey");
|
||||
X509Certificate2 cert = PemCertificateBuilder.Build(certPem, keyPem, null, X509KeyStorageFlags.Exportable);
|
||||
try
|
||||
{
|
||||
Assert.NotNull(cert);
|
||||
Assert.Equal(thumbprint, cert.Thumbprint);
|
||||
Assert.True(cert.HasPrivateKey);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cert.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadCertificateChain_Returns_All_Certificates()
|
||||
{
|
||||
(string leafPem, _, _) = CreateSelfSigned("PemBuilderTest.Leaf");
|
||||
(string intermediatePem, _, _) = CreateSelfSigned("PemBuilderTest.Intermediate");
|
||||
string combined = leafPem + intermediatePem;
|
||||
|
||||
System.Collections.Generic.List<X509Certificate2> chain = PemCertificateBuilder.ReadCertificateChain(combined);
|
||||
try
|
||||
{
|
||||
Assert.Equal(2, chain.Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (X509Certificate2 c in chain) { c.Dispose(); }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_Empty_Certificate_Pem_Throws()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => PemCertificateBuilder.Build(null, null, null, X509KeyStorageFlags.DefaultKeySet));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user