public void CreateAndExportRsaCsr(int bits, PkiHashAlgorithm hashAlgor) { var sn = "CN=foo.example.com"; var keys = PkiKeyPair.GenerateRsaKeyPair(bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); var pemOut = Path.Combine(_testTemp, $"csr-rsa-{bits}-{hashAlgor}.pem"); var derOut = Path.Combine(_testTemp, $"csr-rsa-{bits}-{hashAlgor}.der"); Assert.AreEqual(sn, csr.SubjectName); Assert.AreSame(keys.PublicKey, keys.PublicKey); Assert.AreEqual(hashAlgor, csr.HashAlgorithm); File.WriteAllBytes(pemOut, csr.ExportSigningRequest(PkiEncodingFormat.Pem)); File.WriteAllBytes(derOut, csr.ExportSigningRequest(PkiEncodingFormat.Der)); using (var proc = OpenSsl.Start($"req -text -noout -verify -in {pemOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } using (var proc = OpenSsl.Start($"req -text -noout -verify -inform DER -in {derOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } }
public static ITLSConfig GenerateSelfSignedRSA( string cn = "localhost", int keySize = 2048) { var caKeys = PkiKeyPair.GenerateRsaKeyPair(keySize); var loKeys = PkiKeyPair.GenerateRsaKeyPair(keySize); var caCsr = new PkiCertificateSigningRequest("CN=FMRL-CA", caKeys, PkiHashAlgorithm.Sha256); var loCsr = new PkiCertificateSigningRequest($"CN={cn}", loKeys, PkiHashAlgorithm.Sha256); var notBefore = DateTimeOffset.Now.AddMinutes(-30); var notAfter = DateTimeOffset.Now.AddHours(24); var caCert = caCsr.CreateCa(notBefore, notAfter); var loCert = loCsr.Create(caCert, caKeys.PrivateKey, notBefore, notAfter, new[] { (byte)100 }); // Convenience local wrapper function string ToUTF8(byte[] b) => Encoding.UTF8.GetString(b); return(new TLSConfigSimple { CaKey = ToUTF8(caKeys.PrivateKey.Export(PkiEncodingFormat.Pem)), CaCert = ToUTF8(caCert.Export(PkiEncodingFormat.Pem)), ServerKey = ToUTF8(loKeys.PrivateKey.Export(PkiEncodingFormat.Pem)), ServerCert = ToUTF8(loCert.Export(PkiEncodingFormat.Pem)), ServerCertRaw = loCert.Export(PkiEncodingFormat.Der), }); }
public void SaveLoadCsr(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var sn = "CN=foo.example.com"; var sans = new[] { "foo-alt1.example.com", "foo-alt2.example.com", }; var keys = PkiKeyTests.GenerateKeyPair(algor, bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); csr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames(sans)); var saveOut = Path.Combine(_testTemp, $"csrsave-{algor}-{bits}-{hashAlgor}-sans.ser"); using (var ms = new MemoryStream()) { csr.Save(ms); File.WriteAllBytes(saveOut, ms.ToArray()); } PkiCertificateSigningRequest csr2; using (var fs = new FileStream(saveOut, FileMode.Open)) { csr2 = PkiCertificateSigningRequest.Load(fs); } using (var ms = new MemoryStream()) { csr2.Save(ms); File.WriteAllBytes(saveOut + 2, ms.ToArray()); } File.WriteAllBytes(saveOut + "1a.pem", csr.ExportSigningRequest(PkiEncodingFormat.Pem)); File.WriteAllBytes(saveOut + "1b.pem", csr.ExportSigningRequest(PkiEncodingFormat.Pem)); File.WriteAllBytes(saveOut + "2a.pem", csr2.ExportSigningRequest(PkiEncodingFormat.Pem)); File.WriteAllBytes(saveOut + "2b.pem", csr2.ExportSigningRequest(PkiEncodingFormat.Pem)); Assert.AreEqual(csr.SubjectName, csr2.SubjectName); Assert.AreEqual(csr.HashAlgorithm, csr2.HashAlgorithm); CollectionAssert.AreEqual( csr.PublicKey.Export(PkiEncodingFormat.Der), csr2.PublicKey.Export(PkiEncodingFormat.Der)); CollectionAssert.AreEqual( csr.CertificateExtensions, csr2.CertificateExtensions, CertExtComparerInstance); Assert.AreEqual(csr.PublicKey.IsPrivate, csr2.PublicKey.IsPrivate); Assert.AreEqual(csr.PublicKey.Algorithm, csr2.PublicKey.Algorithm); CollectionAssert.AreEqual( csr.PublicKey.Export(PkiEncodingFormat.Der), csr2.PublicKey.Export(PkiEncodingFormat.Der)); }
public PkiCertificate Sign(PkiEncodingFormat format, byte[] encodedCsr, PkiHashAlgorithm signingHashAlgorithm, DateTimeOffset?notBefore = null, DateTimeOffset?notAfter = null) { var csr = new PkiCertificateSigningRequest(format, encodedCsr, signingHashAlgorithm); return(Sign(csr, notBefore, notAfter)); }
public void CsrRsaExportImportPem() { var kpr = PkiKeyPair.GenerateRsaKeyPair(2048); var csr1 = new PkiCertificateSigningRequest("cn=foo.mock.acme2.zyborg.io", kpr, PkiHashAlgorithm.Sha256); var bytes = csr1.ExportSigningRequest(PkiEncodingFormat.Pem); var csr2 = new PkiCertificateSigningRequest(PkiEncodingFormat.Pem, bytes, PkiHashAlgorithm.Sha256); }
public void GenCaCertificate() { var caKpr = PkiKeyPair.GenerateRsaKeyPair(2048); var caCsr = new PkiCertificateSigningRequest("cn=test-ca", caKpr, PkiHashAlgorithm.Sha256); var caCrt = caCsr.CreateCa( DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddDays(30)); }
public void ExportSignedCert(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var isurName = "CN=SelfSigned"; var isurKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var subjName = "CN=foo.example.com"; var subjKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var isurCsr = new PkiCertificateSigningRequest(isurName, isurKeys, hashAlgor); var subjCsr = new PkiCertificateSigningRequest(subjName, subjKeys, hashAlgor); subjCsr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames( new[] { "foo-alt1.example.com", "foo-alt2.example.com", })); var pemOut = Path.Combine(_testTemp, $"cert-{algor}-{bits}-{hashAlgor}.pem"); var derOut = Path.Combine(_testTemp, $"cert-{algor}-{bits}-{hashAlgor}.der"); var isurCert = isurCsr.CreateCa( DateTime.Now.AddMonths(-5), DateTime.Now.AddMonths(5)); Assert.AreEqual(isurName, isurCert.SubjectName, "Issuer Name on Issuer Certificate"); var subjCert = subjCsr.Create(isurCert, isurKeys.PrivateKey, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1), new[] { (byte)0x2b }); Assert.AreEqual(isurName, isurCert.SubjectName, "Subject Name on Subject Certificate"); File.WriteAllBytes(pemOut, subjCert.Export(PkiEncodingFormat.Pem)); File.WriteAllBytes(derOut, subjCert.Export(PkiEncodingFormat.Der)); using (var proc = OpenSsl.Start($"x509 -text -noout -in {pemOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } using (var proc = OpenSsl.Start($"x509 -text -noout -inform DER -in {derOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } }
private void Init() { if (File.Exists(_opts.CaKeyPairSavePath)) { using (var fs = new FileStream(_opts.CaKeyPairSavePath, FileMode.Open)) { _keyPair = PkiKeyPair.Load(fs); } } if (_keyPair == null) { switch (_opts.KeyPairAlgorithm) { case PkiAsymmetricAlgorithm.Rsa: _keyPair = PkiKeyPair.GenerateRsaKeyPair(_opts.BitLength ?? 2048); break; case PkiAsymmetricAlgorithm.Ecdsa: _keyPair = PkiKeyPair.GenerateEcdsaKeyPair(_opts.BitLength ?? 256); break; default: throw new Exception("unsupported Key Pair Algorithm"); } using (var fs = new FileStream(_opts.CaKeyPairSavePath, FileMode.CreateNew)) { _keyPair.Save(fs); } } if (File.Exists(_opts.CaCertificateSavePath)) { using (var fs = new FileStream(_opts.CaCertificateSavePath, FileMode.Open)) { CaCertificate = PkiCertificate.Load(fs); } } if (CaCertificate == null) { var caCsr = new PkiCertificateSigningRequest( _opts.CaSubjectName, _keyPair, _opts.SignatureHashAlgorithm); CaCertificate = caCsr.CreateCa( DateTimeOffset.Now.ToUniversalTime(), DateTimeOffset.Now.AddYears(10).ToUniversalTime()); using (var fs = new FileStream(_opts.CaCertificateSavePath, FileMode.CreateNew)) { CaCertificate.Save(fs); } } }
private (byte[] csr, PkiKeyPair keys) GenerateCertificateRequest(IEnumerable <string> hostnames) { using var ms = new MemoryStream(); var keyPair = PkiKeyPair.GenerateRsaKeyPair(2048); var firstDns = hostnames.First(); var csr = new PkiCertificateSigningRequest($"CN={firstDns}", keyPair, PkiHashAlgorithm.Sha256); csr.CertificateExtensions.Add(PkiCertificateExtension.CreateDnsSubjectAlternativeNames(hostnames)); var certCsr = csr.ExportSigningRequest(PkiEncodingFormat.Der); return(certCsr, keyPair); }
public void ExportSelfSignedCert(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var sn = "CN=foo.example.com"; var keys = PkiKeyTests.GenerateKeyPair(algor, bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); var pemOut = Path.Combine(_testTemp, $"certself-{algor}-{bits}-{hashAlgor}.pem"); var derOut = Path.Combine(_testTemp, $"certself-{algor}-{bits}-{hashAlgor}.der"); Assert.AreEqual(sn, csr.SubjectName); Assert.AreSame(keys.PublicKey, keys.PublicKey); Assert.AreEqual(hashAlgor, csr.HashAlgorithm); var cert = csr.CreateSelfSigned( DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1)); Assert.AreEqual(sn, cert.SubjectName, "Subject Name on PKI Certificate"); var bclCert = cert.ToBclCertificate(); Assert.AreEqual(sn, bclCert.Subject, "Subject Name on BCL Certificate"); Assert.IsFalse(bclCert.HasPrivateKey); Assert.IsNull(bclCert.PrivateKey); File.WriteAllBytes(pemOut, cert.Export(PkiEncodingFormat.Pem)); File.WriteAllBytes(derOut, cert.Export(PkiEncodingFormat.Der)); using (var proc = OpenSsl.Start($"x509 -text -noout -in {pemOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } using (var proc = OpenSsl.Start($"x509 -text -noout -inform DER -in {derOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } }
public void EcdsaCaCertificateSignsImportedPemCsr() { var caKpr = PkiKeyPair.GenerateEcdsaKeyPair(384); var caCsr = new PkiCertificateSigningRequest("cn=test-ca", caKpr, PkiHashAlgorithm.Sha256); var caCrt = caCsr.CreateCa( DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddDays(30)); var kpr = PkiKeyPair.GenerateEcdsaKeyPair(384); var csr1 = new PkiCertificateSigningRequest("cn=foo.mock.acme2.zyborg.io", kpr, PkiHashAlgorithm.Sha256); var bytes = csr1.ExportSigningRequest(PkiEncodingFormat.Pem); var csr2 = new PkiCertificateSigningRequest(PkiEncodingFormat.Pem, bytes, PkiHashAlgorithm.Sha256); csr2.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames(new[] { "foo-alt1.mock.acme2.zyborg.io", "foo-alt2.mock.acme2.zyborg.io", "foo-alt3.mock.acme2.zyborg.io", })); var serNum = DateTime.Now.Ticks; var serNumBytes = BitConverter.GetBytes(serNum); if (BitConverter.IsLittleEndian) { serNumBytes = serNumBytes.Reverse().ToArray(); } var crt = csr2.Create(caCrt, caKpr.PrivateKey, DateTimeOffset.Now.AddHours(-1), DateTimeOffset.Now.AddHours(24), serNumBytes); var crtDer = crt.Export(PkiEncodingFormat.Der); var crtPem = crt.Export(PkiEncodingFormat.Pem); var pth = @"C:\local\prj\bek\ACMESharp\ACMESharpCore\test\ACMESharp.MockServer.UnitTests"; File.WriteAllBytes(pth + "\\pem_imported-ecdsa_signed.der.crt", crtDer); File.WriteAllBytes(pth + "\\pem_imported-ecdsa_signed.pem.crt", crtPem); }
public PkiCertificate Sign(PkiCertificateSigningRequest csr, DateTimeOffset?notBefore = null, DateTimeOffset?notAfter = null) { if (notBefore == null) { notBefore = _opts.MinBefore; } if (notAfter == null) { notAfter = _opts.MinAfter; } if (notBefore.Value > _opts.MaxBefore) { notBefore = _opts.MaxBefore; } if (notBefore.Value < _opts.MinBefore) { notBefore = _opts.MinBefore; } if (notAfter.Value > _opts.MaxAfter) { notAfter = _opts.MaxAfter; } if (notAfter.Value < _opts.MinAfter) { notAfter = _opts.MinAfter; } var serNum = DateTime.Now.Ticks; var serNumBytes = BitConverter.GetBytes(serNum); if (BitConverter.IsLittleEndian) { serNumBytes = serNumBytes.Reverse().ToArray(); } return(csr.Create(CaCertificate, _keyPair.PrivateKey, notBefore.Value, notAfter.Value, serNumBytes)); }
public void CreateAndExportEcdsaSansCsr(int bits, PkiHashAlgorithm hashAlgor) { var sn = "CN=foo.example.com"; var sans = new[] { "foo-alt1.example.com", "foo-alt2.example.com", }; var keys = PkiKeyPair.GenerateEcdsaKeyPair(bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); csr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames(sans)); var pemOut = Path.Combine(_testTemp, $"csr-ecdsa-{bits}-{hashAlgor}-sans.pem"); var derOut = Path.Combine(_testTemp, $"csr-ecdsa-{bits}-{hashAlgor}-sans.der"); Assert.AreEqual(sn, csr.SubjectName); Assert.AreSame(keys.PublicKey, keys.PublicKey); Assert.AreEqual(hashAlgor, csr.HashAlgorithm); Assert.AreEqual(1, csr.CertificateExtensions.Count); File.WriteAllBytes(pemOut, csr.ExportSigningRequest(PkiEncodingFormat.Pem)); File.WriteAllBytes(derOut, csr.ExportSigningRequest(PkiEncodingFormat.Der)); using (var proc = OpenSsl.Start($"req -text -noout -verify -in {pemOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } using (var proc = OpenSsl.Start($"req -text -noout -verify -inform DER -in {derOut}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } }
public void RsaCaCertificateSignsImportedDerCsr() { var caKpr = PkiKeyPair.GenerateRsaKeyPair(2048); var caCsr = new PkiCertificateSigningRequest("cn=test-ca", caKpr, PkiHashAlgorithm.Sha256); var caCrt = caCsr.CreateCa( DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddDays(30)); var kpr = PkiKeyPair.GenerateRsaKeyPair(2048); var csr1 = new PkiCertificateSigningRequest("cn=foo.mock.acme2.zyborg.io", kpr, PkiHashAlgorithm.Sha256); var bytes = csr1.ExportSigningRequest(PkiEncodingFormat.Der); var csr2 = new PkiCertificateSigningRequest(PkiEncodingFormat.Der, bytes, PkiHashAlgorithm.Sha256); var serNum = DateTime.Now.Ticks; var serNumBytes = BitConverter.GetBytes(serNum); if (BitConverter.IsLittleEndian) { serNumBytes = serNumBytes.Reverse().ToArray(); } var crt = csr2.Create(caCrt, caKpr.PrivateKey, DateTimeOffset.Now.AddHours(-1), DateTimeOffset.Now.AddHours(24), serNumBytes); var crtDer = crt.Export(PkiEncodingFormat.Der); var crtPem = crt.Export(PkiEncodingFormat.Pem); File.WriteAllBytes(Path.Combine(DataFolder, "der_imported-rsa_signed.der.crt"), crtDer); File.WriteAllBytes(Path.Combine(DataFolder, "der_imported-rsa_signed.pem.crt"), crtPem); }
public async Task FinalizeOrder() { using (var http = _server.CreateClient()) { var dir = await GetDir(); var signer = new Crypto.JOSE.Impl.RSJwsTool(); signer.Init(); using (var acme = new AcmeProtocolClient(http, dir, signer: signer)) { await acme.GetNonceAsync(); var acct = await acme.CreateAccountAsync(new[] { "mailto:[email protected]" }); acme.Account = acct; var dnsIds = new[] { "foo.mock.acme2.zyborg.io", "foo-alt-1.mock.acme2.zyborg.io", "foo-alt-2.mock.acme2.zyborg.io", "foo-alt-3.mock.acme2.zyborg.io", }; var order = await acme.CreateOrderAsync(dnsIds); Assert.IsNotNull(order?.OrderUrl); Assert.AreEqual(dnsIds.Length, order.Payload.Authorizations?.Length); Assert.AreEqual(dnsIds.Length, order.Payload.Identifiers?.Length); var authzUrl = order.Payload.Authorizations[0]; var authz = await acme.GetAuthorizationDetailsAsync(authzUrl); Assert.IsNotNull(authz); Assert.IsFalse(authz.Wildcard ?? false); Assert.AreEqual(dnsIds[0], authz.Identifier.Value); foreach (var chlng in authz.Challenges) { var chlng2 = await acme.AnswerChallengeAsync(chlng.Url); Assert.IsNotNull(chlng2); Assert.AreEqual("valid", chlng2.Status); } var kpr = PkiKeyPair.GenerateRsaKeyPair(2048); var csr = new PkiCertificateSigningRequest($"cn={dnsIds[0]}", kpr, PkiHashAlgorithm.Sha256); csr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames(dnsIds.Skip(1))); var csrDer = csr.ExportSigningRequest(PkiEncodingFormat.Der); var finalizedOrder = await acme.FinalizeOrderAsync(order.Payload.Finalize, csrDer); Assert.AreEqual("valid", finalizedOrder.Payload.Status); Assert.IsNotNull(finalizedOrder.Payload.Certificate); var getResp = await acme.GetAsync(finalizedOrder.Payload.Certificate); getResp.EnsureSuccessStatusCode(); using (var fs = new FileStream( @"C:\local\prj\bek\ACMESharp\ACMESharpCore\test\ACMESharp.MockServer.UnitTests\finalize-cert.pem", FileMode.Create)) { await getResp.Content.CopyToAsync(fs); } } } }
public void ExportSelfSignedPkcs12(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var sn = "CN=foo.example.com"; var keys = PkiKeyTests.GenerateKeyPair(algor, bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); var pfxSansKey = Path.Combine(_testTemp, $"certselfexp-{algor}-{bits}-{hashAlgor}-sanskey.pfx"); var pfxWithKey = Path.Combine(_testTemp, $"certselfexp-{algor}-{bits}-{hashAlgor}-withkey.pfx"); Assert.AreEqual(sn, csr.SubjectName); Assert.AreSame(keys.PublicKey, keys.PublicKey); Assert.AreEqual(hashAlgor, csr.HashAlgorithm); var cert = csr.CreateSelfSigned( DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1)); Assert.AreEqual(sn, cert.SubjectName, "Subject Name on PKI Certificate"); var bclCert = cert.ToBclCertificate(); Assert.AreEqual(sn, bclCert.Subject, "Subject Name on BCL Certificate"); Assert.IsFalse(bclCert.HasPrivateKey); Assert.IsNull(bclCert.PrivateKey); File.WriteAllBytes(pfxSansKey, cert.Export(PkiArchiveFormat.Pkcs12)); File.WriteAllBytes(pfxWithKey, cert.Export(PkiArchiveFormat.Pkcs12, keys.PrivateKey)); using (var proc = OpenSsl.Start($"pkcs12 -info -in {pfxSansKey} -passin pass:"******"pkcs12 -info -in {pfxWithKey} -passin pass: -nokeys")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } var certSansKey = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(pfxSansKey)); Assert.IsFalse(certSansKey.HasPrivateKey); Assert.IsNull(certSansKey.PrivateKey); var certWithKey = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(pfxWithKey)); Assert.IsTrue(certWithKey.HasPrivateKey); if (algor != PkiAsymmetricAlgorithm.Ecdsa) { // This throws: System.NotSupportedException: The certificate key algorithm is not supported. Assert.IsNotNull(certWithKey.PrivateKey); } }
public void ExportSignedPkcs12(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var isurName = "CN=SelfSigned"; var isurKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var subjName = "CN=foo.example.com"; var subjKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var isurCsr = new PkiCertificateSigningRequest(isurName, isurKeys, hashAlgor); var subjCsr = new PkiCertificateSigningRequest(subjName, subjKeys, hashAlgor); subjCsr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames( new[] { "foo-alt1.example.com", "foo-alt2.example.com", })); var pfxSansKey = Path.Combine(_testTemp, $"certexp-{algor}-{bits}-{hashAlgor}-sanskey.pfx"); var pfxWithKey = Path.Combine(_testTemp, $"certexp-{algor}-{bits}-{hashAlgor}-withkey.pfx"); var isurCert = isurCsr.CreateCa( DateTime.Now.AddMonths(-5), DateTime.Now.AddMonths(5)); Assert.AreEqual(isurName, isurCert.SubjectName, "Issuer Name on Issuer Certificate"); var subjCert = subjCsr.Create(isurCert, isurKeys.PrivateKey, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1), new[] { (byte)0x2b }); Assert.AreEqual(isurName, isurCert.SubjectName, "Subject Name on Subject Certificate"); File.WriteAllBytes(pfxSansKey, subjCert.Export(PkiArchiveFormat.Pkcs12, chain: new[] { isurCert })); File.WriteAllBytes(pfxWithKey, subjCert.Export(PkiArchiveFormat.Pkcs12, subjKeys.PrivateKey, new[] { isurCert })); using (var proc = OpenSsl.Start($"pkcs12 -info -in {pfxSansKey} -passin pass:"******"pkcs12 -info -in {pfxWithKey} -passin pass: -nokeys")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } var certSansKey = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(pfxSansKey)); Assert.IsFalse(certSansKey.HasPrivateKey); Assert.IsNull(certSansKey.PrivateKey); var certWithKey = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(pfxWithKey)); Assert.IsTrue(certWithKey.HasPrivateKey); if (algor != PkiAsymmetricAlgorithm.Ecdsa) { // This throws: System.NotSupportedException: The certificate key algorithm is not supported. Assert.IsNotNull(certWithKey.PrivateKey); } }
public async Task Test_Finalize_Order_ForMultiDns() { if (Clients?.Acme == null) { await base.InitAcmeClient(); //Clients.Acme.GetNonceAsync(); } var testCtx = SetTestContext(); var oldOrder = testCtx.GroupLoadObject <OrderDetails>("order.json"); var rsaKeys = PkiKeyPair.GenerateRsaKeyPair(2048); using (var ms = new MemoryStream()) { rsaKeys.Save(ms); testCtx.GroupWriteTo("order-csr-keys.ser", ms.ToArray()); } var dnsNames = oldOrder.Payload.Identifiers.Select(x => x.Value).ToArray(); var csr = new PkiCertificateSigningRequest($"CN={dnsNames[0]}", rsaKeys, PkiHashAlgorithm.Sha256); csr.CertificateExtensions.Add(PkiCertificateExtension.CreateDnsSubjectAlternativeNames(dnsNames)); var derEncodedCsr = csr.ExportSigningRequest(PkiEncodingFormat.Der); testCtx.GroupWriteTo("order-csr.der", derEncodedCsr); var updatedOrder = await Clients.Acme.FinalizeOrderAsync( oldOrder.Payload.Finalize, derEncodedCsr); int maxTry = 20; int trySleep = 5 * 1000; var valid = false; for (var tryCount = 0; tryCount < maxTry; ++tryCount) { if (tryCount > 0) { // Wait just a bit for // subsequent queries Thread.Sleep(trySleep); // Only need to refresh // after the first check Log.LogInformation($" Retry #{tryCount} refreshing Order"); updatedOrder = await Clients.Acme.GetOrderDetailsAsync(oldOrder.OrderUrl); testCtx.GroupSaveObject("order-updated.json", updatedOrder); } if (!valid) { // The Order is either Valid, still Pending or some other UNEXPECTED state if ("valid" == updatedOrder.Payload.Status) { valid = true; Log.LogInformation("Order is VALID!"); } else if ("pending" != updatedOrder.Payload.Status) { Log.LogInformation("Order in **UNEXPECTED STATUS**: {@UpdateChallengeDetails}", updatedOrder); throw new InvalidOperationException("Unexpected status for Order: " + updatedOrder.Payload.Status); } } if (valid) { // Once it's valid, then we need to wait for the Cert if (!string.IsNullOrEmpty(updatedOrder.Payload.Certificate)) { Log.LogInformation("Certificate URL is ready!"); break; } } } Assert.NotNull(updatedOrder.Payload.Certificate); var certBytes = await Clients.Acme.GetOrderCertificateAsync(updatedOrder); testCtx.GroupWriteTo("order-cert.crt", certBytes); }
public void ExportSelfSignedPemChain(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var sn = "CN=foo.example.com"; var keys = PkiKeyTests.GenerateKeyPair(algor, bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); var pemSansKey = Path.Combine(_testTemp, $"certselfexp-{algor}-{bits}-{hashAlgor}-sanskey.pem"); var pemWithKey = Path.Combine(_testTemp, $"certselfexp-{algor}-{bits}-{hashAlgor}-withkey.pem"); Assert.AreEqual(sn, csr.SubjectName); Assert.AreSame(keys.PublicKey, keys.PublicKey); Assert.AreEqual(hashAlgor, csr.HashAlgorithm); var cert = csr.CreateSelfSigned( DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1)); Assert.AreEqual(sn, cert.SubjectName, "Subject Name on PKI Certificate"); var bclCert = cert.ToBclCertificate(); Assert.AreEqual(sn, bclCert.Subject, "Subject Name on BCL Certificate"); Assert.IsFalse(bclCert.HasPrivateKey); Assert.IsNull(bclCert.PrivateKey); File.WriteAllBytes(pemSansKey, cert.Export(PkiArchiveFormat.Pem)); File.WriteAllBytes(pemWithKey, cert.Export(PkiArchiveFormat.Pem, keys.PrivateKey)); // Check Cert using (var proc = OpenSsl.Start($"x509 -text -noout -in {pemSansKey}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } // Check Cert using (var proc = OpenSsl.Start($"x509 -text -noout -in {pemWithKey}")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } // Check Private Key var opensslCmd = "rsa"; if (algor == PkiAsymmetricAlgorithm.Ecdsa) { opensslCmd = "ec"; } using (var proc = OpenSsl.Start($"{opensslCmd} -in {pemWithKey} -check")) { proc.WaitForExit(); Assert.AreEqual(0, proc.ExitCode); } var certSansKey = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(pemSansKey)); Assert.IsFalse(certSansKey.HasPrivateKey); Assert.IsNull(certSansKey.PrivateKey); }
public void SaveLoadCertificate(PkiAsymmetricAlgorithm algor, int bits) { var hashAlgor = PkiHashAlgorithm.Sha256; var isurName = "CN=SelfSigned"; var isurKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var subjName = "CN=foo.example.com"; var subjKeys = PkiKeyTests.GenerateKeyPair(algor, bits); var isurCsr = new PkiCertificateSigningRequest(isurName, isurKeys, hashAlgor); var subjCsr = new PkiCertificateSigningRequest(subjName, subjKeys, hashAlgor); subjCsr.CertificateExtensions.Add(PkiCertificateExtension.CreateDnsSubjectAlternativeNames( new[] { "foo-alt1.example.com", "foo-alt2.example.com", } )); var selfOut = Path.Combine(_testTemp, $"certsave-{algor}-{bits}-{hashAlgor}-self.ser"); var signedOut = Path.Combine(_testTemp, $"certsave-{algor}-{bits}-{hashAlgor}-signed.ser"); var isurCert = isurCsr.CreateCa( DateTime.Now.AddMonths(-5), DateTime.Now.AddMonths(5)); var subjCert = subjCsr.Create(isurCert, isurKeys.PrivateKey, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(1), new[] { (byte)0x2b }); using (var ms = new MemoryStream()) { isurCert.Save(ms); File.WriteAllBytes(selfOut, ms.ToArray()); } using (var ms = new MemoryStream()) { subjCert.Save(ms); File.WriteAllBytes(signedOut, ms.ToArray()); } PkiCertificate isurCert2; PkiCertificate subjCert2; using (var fs = new FileStream(selfOut, FileMode.Open)) isurCert2 = PkiCertificate.Load(fs); using (var fs = new FileStream(signedOut, FileMode.Open)) subjCert2 = PkiCertificate.Load(fs); var bclIsur = isurCert.ToBclCertificate(); var bclSubj = subjCert.ToBclCertificate(); var bclIsur2 = isurCert2.ToBclCertificate(); var bclSubj2 = subjCert2.ToBclCertificate(); Assert.AreEqual(bclIsur.GetSerialNumberString(), bclIsur2.GetSerialNumberString(), "Issuer Serial Number"); Assert.AreEqual(bclIsur.GetCertHashString(), bclIsur2.GetCertHashString(), "Issuer Hash"); Assert.AreEqual(bclIsur.GetRawCertDataString(), bclIsur2.GetRawCertDataString(), "Issuer Raw Data"); Assert.AreEqual(bclSubj.GetSerialNumberString(), bclSubj2.GetSerialNumberString(), "Subject Serial Number"); Assert.AreEqual(bclSubj.GetCertHashString(), bclSubj2.GetCertHashString(), "Subject Hash"); Assert.AreEqual(bclSubj.GetRawCertDataString(), bclSubj2.GetRawCertDataString(), "Subject Raw Data"); }
public async Task <IActionResult> Post([FromBody] DomainRequest request) { if (!IsValidDomain(request.Domain)) { return(BadRequest(new DomainResponse { Error = "Invalid domain" })); } var domain = string.Join(".", request.Domain.Split(".").TakeLast(2)); var subDomain = string.Join(".", request.Domain.Split(".").SkipLast(2)); var credentials = new AzureCredentialsFactory() .FromServicePrincipal( _configuration["Azure:ClientId"], _configuration["Azure:ClientSecret"], _configuration["Azure:TenantId"], AzureEnvironment.AzureGlobalCloud ); var azure = Azure .Configure() .WithRetryPolicy(new RetryPolicy(new TransientErrorIgnoreStrategy(), 0)) .Authenticate(credentials) .WithSubscription(_configuration["Azure:SubscriptionId"]); var webApp = await azure.AppServices.WebApps.GetByIdAsync( _configuration["Azure:AppId"]); try { webApp.Update() .DefineHostnameBinding() .WithThirdPartyDomain(domain) .WithSubDomain(subDomain) .WithDnsRecordType(CustomHostNameDnsRecordType.CName) .Attach() .Apply(); } catch (Exception e) { return(BadRequest(new DomainResponse { Error = "Unable to validate domain ownership" })); } _ = Task.Run(async() => { using var airtableBase = new AirtableBase(_configuration["Airtable:Key"], _configuration["Airtable:Base"]); try { HttpClient httpClient = new HttpClient { BaseAddress = new Uri(_configuration["Acme:Endpoint"]) }; AcmeProtocolClient acme = new AcmeProtocolClient(httpClient, usePostAsGet: true); var acmeDir = await acme.GetDirectoryAsync(); acme.Directory = acmeDir; await acme.GetNonceAsync(); var account = await acme.CreateAccountAsync(new[] { "mailto:" + _configuration["Acme:Email"] }, true); acme.Account = account; var order = await acme.CreateOrderAsync(new[] { request.Domain }); if (order.Payload.Status == "invalid") { return; } var authorizationUrl = order.Payload.Authorizations.FirstOrDefault(); if (string.IsNullOrEmpty(authorizationUrl)) { return; } var authorization = await acme.GetAuthorizationDetailsAsync(authorizationUrl); foreach (var challenge in authorization.Challenges.Where(x => x.Type == "http-01").ToList()) { var challengeValidationDetails = (Http01ChallengeValidationDetails) AuthorizationDecoder.DecodeChallengeValidation(authorization, challenge.Type, acme.Signer); var path = challengeValidationDetails.HttpResourcePath; var token = path.Split("/", StringSplitOptions.RemoveEmptyEntries).Last(); var value = challengeValidationDetails.HttpResourceValue; var contentType = challengeValidationDetails.HttpResourceContentType; await airtableBase.CreateRecord("Acme", new Fields { FieldsCollection = new Dictionary <string, object> { ["Token"] = token, ["Value"] = value, ["ContentType"] = contentType } }); await Task.Delay(10 * 1000); var challengeUpdated = await acme.AnswerChallengeAsync(challenge.Url); } //Wait for challenge to be resolved var waitUntil = DateTime.Now.AddSeconds(300); Authorization authorizationUpdated; do { await Task.Delay(10 * 1000); authorizationUpdated = await acme.GetAuthorizationDetailsAsync(authorizationUrl); } while (authorizationUpdated.Status != "valid" && DateTime.Now < waitUntil); if (authorizationUpdated.Status != "valid") { return; } //Generate certificate private key and CSR (Certificate signing request) var keyPair = PkiKeyPair.GenerateEcdsaKeyPair(256); var csr = new PkiCertificateSigningRequest($"CN={request.Domain}", keyPair, PkiHashAlgorithm.Sha256); var certCsr = csr.ExportSigningRequest(PkiEncodingFormat.Der); order = await acme.FinalizeOrderAsync(order.Payload.Finalize, certCsr); if (order.Payload.Status != "valid") { return; } if (string.IsNullOrEmpty(order.Payload.Certificate)) { //Wait for certificate var waitUntil2 = DateTime.Now.AddSeconds(300); while (DateTime.Now < waitUntil2) { await Task.Delay(10 * 1000); order = await acme.GetOrderDetailsAsync(order.OrderUrl, existing: order); if (!string.IsNullOrEmpty(order.Payload.Certificate)) { break; } } } if (string.IsNullOrEmpty(order.Payload.Certificate)) { return; } var certResp = await acme.GetAsync(order.Payload.Certificate); if (!certResp.IsSuccessStatusCode) { return; } var certByteArray = await certResp.Content.ReadAsByteArrayAsync(); //Export PFX file var pfxPassword = _configuration["Acme:PfxPassword"]; var privateKey = keyPair.PrivateKey; using var cert = new X509Certificate2(certByteArray); X509Chain chain = new X509Chain(); chain.Build(cert); List <PkiCertificate> chainList = new List <PkiCertificate>(); foreach (var e in chain.ChainElements) { chainList.Add(PkiCertificate.From(e.Certificate)); } var pfx = chainList[0].Export(PkiArchiveFormat.Pkcs12, chain: chainList.Skip(1), privateKey: privateKey, password: pfxPassword?.ToCharArray()); webApp.Update() .DefineSslBinding() .ForHostname(request.Domain) .WithPfxByteArrayToUpload(pfx, pfxPassword) .WithSniBasedSsl() .Attach() .Apply(); } catch (Exception e) { await airtableBase.CreateRecord("Logs", new Fields { FieldsCollection = new Dictionary <string, object> { ["Hostname"] = request.Domain, ["Event"] = "exception-thrown", ["Data"] = JsonConvert.SerializeObject(e) } }); } }); return(Ok(new DomainResponse { IsSuccessful = true })); }