Beispiel #1
0
        public void ExportRsaKeyPairWithPassword(int bits)
        {
            var rsaKeys = PkiKeyPair.GenerateRsaKeyPair(bits);

            Assert.AreEqual(PkiAsymmetricAlgorithm.Rsa, rsaKeys.Algorithm);
            Assert.IsFalse(rsaKeys.PublicKey.IsPrivate);
            Assert.AreEqual(PkiAsymmetricAlgorithm.Rsa, rsaKeys.PublicKey.Algorithm);
            Assert.IsTrue(rsaKeys.PrivateKey.IsPrivate);
            Assert.AreEqual(PkiAsymmetricAlgorithm.Rsa, rsaKeys.PrivateKey.Algorithm);

            var pubOut = Path.Combine(_testTemp, $"keypair-rsa-pub{bits}-secure.pem");
            var prvOut = Path.Combine(_testTemp, $"keypair-rsa-prv{bits}-secure.pem");

            File.WriteAllBytes(pubOut, rsaKeys.PublicKey.Export(PkiEncodingFormat.Pem,
                                                                password: "******".ToCharArray()));
            File.WriteAllBytes(prvOut, rsaKeys.PrivateKey.Export(PkiEncodingFormat.Pem,
                                                                 password: "******".ToCharArray()));

            using (var proc = OpenSsl.Start($"rsa -in {pubOut} -pubin"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }

            using (var proc = OpenSsl.Start($"rsa -in {prvOut} -check -passin pass:123456"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }
        }
Beispiel #2
0
        public void CreateEcdsaKeyPair(int bits)
        {
            var ecdsaKeys = PkiKeyPair.GenerateEcdsaKeyPair(bits);

            Assert.AreEqual(PkiAsymmetricAlgorithm.Ecdsa, ecdsaKeys.Algorithm);
            Assert.IsFalse(ecdsaKeys.PublicKey.IsPrivate);
            Assert.AreEqual(PkiAsymmetricAlgorithm.Ecdsa, ecdsaKeys.PublicKey.Algorithm);
            Assert.IsTrue(ecdsaKeys.PrivateKey.IsPrivate);
            Assert.AreEqual(PkiAsymmetricAlgorithm.Ecdsa, ecdsaKeys.PublicKey.Algorithm);

            var pubOut = Path.Combine(_testTemp, $"ecdsa-pub-key-{bits}.pem");
            var prvOut = Path.Combine(_testTemp, $"ecdsa-prv-key-{bits}.pem");

            File.WriteAllBytes(pubOut, ecdsaKeys.PublicKey.Export(PkiEncodingFormat.Pem));
            File.WriteAllBytes(prvOut, ecdsaKeys.PrivateKey.Export(PkiEncodingFormat.Pem));


            using (var proc = OpenSsl.Start($"ec -in {pubOut} -pubin"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode, "OpenSSL exit code checking EC public key");
            }

            using (var proc = OpenSsl.Start($"ec -in {prvOut} -check"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode, "OpenSSL exit code checking EC private key");
            }
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
 public void Import(string exported)
 {
     using (var ms = new MemoryStream(Convert.FromBase64String(exported)))
     {
         _keys = PkiKeyPair.Load(ms);
     }
 }
Beispiel #5
0
        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),
            });
        }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #10
0
        internal static PkiKeyPair GenerateKeyPair(PkiAsymmetricAlgorithm algor, int bits)
        {
            switch (algor)
            {
            case PkiAsymmetricAlgorithm.Rsa:
                return(PkiKeyPair.GenerateRsaKeyPair(bits));

            case PkiAsymmetricAlgorithm.Ecdsa:
                return(PkiKeyPair.GenerateEcdsaKeyPair(bits));

            default:
                throw new NotSupportedException(nameof(PkiAsymmetricAlgorithm));
            }
        }
Beispiel #11
0
        public static IServerPKIDetails GenerateRSA(
            SimplePKIConfig serverConfig = null,
            SimplePKIConfig issuerConfig = null,
            DateTime?notBefore           = null,
            DateTime?notAfter            = null)
        {
            if (serverConfig == null)
            {
                serverConfig = SimplePKIConfig.DefaultServerConfig;
            }
            if (issuerConfig == null)
            {
                issuerConfig = SimplePKIConfig.DefaultIssuerConfig;
            }

            if (notBefore == null)
            {
                notBefore = DateTime.Now.AddMinutes(-30);
            }
            if (notAfter == null)
            {
                notAfter = DateTime.Now.AddHours(24);
            }

            var details = new SimplePKIDetails();

            details._issuerKeyPair = PkiKeyPair.GenerateRsaKeyPair(issuerConfig.KeySize);
            details._serverKeyPair = PkiKeyPair.GenerateRsaKeyPair(serverConfig.KeySize);

            details._issuerCsr = new PkiCertificateSigningRequest(
                $"CN={issuerConfig.CommonName}",
                details._issuerKeyPair, issuerConfig.HashAlgorithm);
            details._serverCsr = new PkiCertificateSigningRequest(
                $"CN={serverConfig.CommonName}",
                details._serverKeyPair, serverConfig.HashAlgorithm);

            details._issuerCert = details._issuerCsr.CreateCa(notBefore.Value, notAfter.Value);
            details._serverCert = details._serverCsr.Create(details._issuerCert, details._issuerKeyPair.PrivateKey,
                                                            notBefore.Value, notAfter.Value,
                                                            new[] { (byte)100 });

            // Convenience local wrapper function
            string ToUTF8(byte[] b) => Encoding.UTF8.GetString(b);

            details.IssuerCertificate = ToUTF8(details._issuerCert.Export(PkiEncodingFormat.Pem));
            details.ServerCertificate = ToUTF8(details._serverCert.Export(PkiEncodingFormat.Pem));
            details.ServerPrivateKey  = ToUTF8(details._serverKeyPair.PrivateKey.Export(PkiEncodingFormat.Pem));

            return(details);
        }
        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);
        }
Beispiel #13
0
        public void SaveLoadKeyPair(PkiAsymmetricAlgorithm algor, int bits)
        {
            PkiKeyPair kp;

            switch (algor)
            {
            case PkiAsymmetricAlgorithm.Rsa:
                kp = PkiKeyPair.GenerateRsaKeyPair(bits);
                break;

            case PkiAsymmetricAlgorithm.Ecdsa:
                kp = PkiKeyPair.GenerateEcdsaKeyPair(bits);
                break;

            default:
                throw new NotSupportedException();
            }

            var saveOut = Path.Combine(_testTemp, $"keypairsave-{algor}-{bits}.ser");

            using (var ms = new MemoryStream())
            {
                kp.Save(ms);
                File.WriteAllBytes(saveOut, ms.ToArray());
            }

            PkiKeyPair kp2;

            using (var fs = new FileStream(saveOut, FileMode.Open))
            {
                kp2 = PkiKeyPair.Load(fs);
            }

            Assert.AreEqual(kp.Algorithm, kp2.Algorithm);
            Assert.AreEqual(kp.PrivateKey.Algorithm, kp2.PrivateKey.Algorithm);
            Assert.AreEqual(kp.PrivateKey.IsPrivate, kp2.PrivateKey.IsPrivate);
            Assert.AreEqual(kp.PublicKey.Algorithm, kp2.PublicKey.Algorithm);
            Assert.AreEqual(kp.PublicKey.IsPrivate, kp2.PublicKey.IsPrivate);
            CollectionAssert.AreEqual(
                kp.PrivateKey.Export(PkiEncodingFormat.Der),
                kp2.PrivateKey.Export(PkiEncodingFormat.Der));
            CollectionAssert.AreEqual(
                kp.PublicKey.Export(PkiEncodingFormat.Der),
                kp2.PublicKey.Export(PkiEncodingFormat.Der));
        }
Beispiel #14
0
        ///// <summary>
        ///// Specifies the elliptic curve to use.
        ///// </summary>
        ///// <returns></returns>
        //public ECCurve Curve { get; private set; }

        ///// <summary>
        ///// As per:  https://tools.ietf.org/html/rfc7518#section-6.2.1.1
        ///// </summary>
        //public string CurveName { get; private set; }

        public void Init()
        {
            //switch (Bits)
            //{
            //    case 256:
            //        Curve = ECCurve.NamedCurves.nistP256;
            //        CurveName = "P-256";
            //        break;
            //    case 384:
            //        Curve = ECCurve.NamedCurves.nistP384;
            //        CurveName = "P-384";
            //        break;
            //    case 512:
            //        Curve = ECCurve.NamedCurves.nistP521;
            //        CurveName = "P-521";
            //        break;
            //    default:
            //        throw new System.InvalidOperationException("illegal SHA2 hash size");
            //}

            _keys = PkiKeyPair.GenerateEcdsaKeyPair(Bits);
        }
Beispiel #15
0
        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);
            }
        }
Beispiel #16
0
        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);
                    }
                }
            }
        }
Beispiel #18
0
        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
            }));
        }
Beispiel #19
0
 public void Init()
 {
     _jwk  = null;
     _keys = PkiKeyPair.GenerateEcdsaKeyPair(Bits);
 }
        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);
        }
Beispiel #21
0
 public void Dispose()
 {
     _keys = null;
     _jwk  = null;
 }