public async Task CanGenerateWildcard()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts = new[] { $"*.wildcard-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx   = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));

                var orderCtx = await AuthzDns(ctx, hosts);

                var certKey        = KeyFactory.NewKey(KeyAlgorithm.RS256);
                var finalizedOrder = await orderCtx.Finalize(new CsrInfo
                {
                    CountryName      = "CA",
                    State            = "Ontario",
                    Locality         = "Toronto",
                    Organization     = "Certes",
                    OrganizationUnit = "Dev",
                    CommonName       = hosts[0],
                }, certKey);

                var pem = await orderCtx.Download(null);

                var builder = new PfxBuilder(pem.Certificate.ToDer(), certKey);

                foreach (var issuer in pem.Issuers)
                {
                    builder.AddIssuer(issuer.ToDer());
                }

                builder.AddTestCerts();

                var pfx = builder.Build("ci", "abcd1234");

                Assert.NotNull(pfx);
            }
Esempio n. 2
0
        public async Task <ICertificate> CreateCertificate()
        {
            try {
                _logger.Write("Generating certificate for {0}", domain.ZoneName);
                IKey privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
                domain.Csr.CommonName = domain.DomainName;
                CertificateChain cert = await _orderContext.Generate(domain.Csr, privateKey);

                PfxBuilder pfxBuilder = cert.ToPfx(privateKey);
                byte[]     pfx        = pfxBuilder.Build(domain.ZoneName, "cert_password");

                FileWorker.WriteFile(pfx, string.Format(@"{0}{1}.pfx", _certDir, domain.ZoneName));
                FileWorker.WriteFile(cert.ToPem(certKey: privateKey), string.Format(@"{0}{1}.pem", _certDir, domain.ZoneName));
                FileWorker.WriteFile(cert.Certificate.ToDer( ), string.Format(@"{0}{1}.der", _certDir, domain.ZoneName));
                return(new Certificate {
                    status = true,
                    Cert = this.GetX509Certificate2(pfx),
                    isExpired = false
                });
            } catch (Exception e) {
                _logger.Write("Error occured while generating certificate for {0} :: error==>{1}", domain.ZoneName, e.Message);
                _logger.Write(e.StackTrace);
                return(new Certificate {
                    status = false,
                    errorDescription = e.Message
                });
            }
        }
        /// <summary>
        /// Converts the certificate to PFX with the key.
        /// </summary>
        /// <param name="certificateChain">The certificate chain.</param>
        /// <param name="certKey">The certificate private key.</param>
        /// <returns>The PFX.</returns>
        public static PfxBuilder ToPfx(this CertificateChain certificateChain, IKey certKey)
        {
            var pfx = new PfxBuilder(certificateChain.Certificate.ToDer(), certKey);

            if (certificateChain.Issuers != null)
            {
                foreach (var issuer in certificateChain.Issuers)
                {
                    pfx.AddIssuer(issuer.ToDer());
                }
            }

            return(pfx);
        }
Esempio n. 4
0
        private async Task <byte[]> CreateCertificate(IOrderContext order)
        {
            IKey privateKey = KeyFactory.NewKey(KeyAlgorithm.RS256);

            CertificateChain certificateChain = await order.Generate(new CsrInfo
            {
                CommonName = Hostname
            }, privateKey);

            PfxBuilder pfxBuilder = certificateChain.ToPfx(privateKey);

            byte[] pfx = pfxBuilder.Build(Hostname, string.Empty);

            return(pfx);
        }
Esempio n. 5
0
        /// <summary>
        /// Converts the certificate To the PFX builder.
        /// </summary>
        /// <param name="cert">The certificate.</param>
        /// <returns>The PFX builder.</returns>
        /// <exception cref="System.Exception">If the certificate data is missing.</exception>
        public static PfxBuilder ToPfx(this AcmeCertificate cert)
        {
            if (cert?.Raw == null)
            {
                throw new Exception($"Certificate data missing, please fetch the certificate from ${cert.Location}");
            }

            var pfxBuilder = new PfxBuilder(cert.Raw, cert.Key);
            var issuer     = cert.Issuer;

            while (issuer != null)
            {
                pfxBuilder.AddIssuer(issuer.Raw);
                issuer = issuer.Issuer;
            }

            return(pfxBuilder);
        }
Esempio n. 6
0
        /// <summary>
        /// Converts the certificate To the PFX builder.
        /// </summary>
        /// <param name="cert">The certificate.</param>
        /// <returns>The PFX builder.</returns>
        /// <exception cref="System.Exception">If the certificate data is missing.</exception>
        public static PfxBuilder ToPfx(this AcmeCertificate cert)
        {
            if ((cert ?? throw new ArgumentNullException(nameof(cert))).Raw == null)
            {
                throw new AcmeException(
                          string.Format(Strings.ErrorMissingCertificateData, cert.Location));
            }

            var pfxBuilder = new PfxBuilder(cert.Raw, cert.Key);
            var issuer     = cert.Issuer;

            while (issuer != null)
            {
                pfxBuilder.AddIssuer(issuer.Raw);
                issuer = issuer.Issuer;
            }

            return(pfxBuilder);
        }
Esempio n. 7
0
        private static async Task <CertificateInner> UploadCertificate(
            IWebSiteManagementClient client, string resourceGroup, string appName, string appSlot, PfxBuilder pfx, string thumbprint)
        {
            var pfxName     = string.Format(CultureInfo.InvariantCulture, "[certes] {0:yyyyMMddhhmmss}", DateTime.UtcNow);
            var pfxPassword = Guid.NewGuid().ToString("N");
            var pfxBytes    = pfx.Build(pfxName, pfxPassword);

            var webApp = string.IsNullOrWhiteSpace(appSlot) ?
                         await client.WebApps.GetAsync(resourceGroup, appName) :
                         await client.WebApps.GetSlotAsync(resourceGroup, appName, appSlot);

            var certData = new CertificateInner
            {
                PfxBlob  = pfxBytes,
                Password = pfxPassword,
                Location = webApp.Location,
            };

            return(await client.Certificates.CreateOrUpdateAsync(
                       resourceGroup, thumbprint, certData));
        }
Esempio n. 8
0
        /// <summary>
        /// Gets a certificate in pfx format for the specified domain names.  If there is an error, an exception is thrown.
        /// </summary>
        /// <param name="emailAddress">The email address to use for authorization.</param>
        /// <param name="domains">The domain names to authorize.  If any domain fails authoriation, an exception is thrown and the certificate request is not completed.</param>
        /// <param name="pfx_password">The password to use for the pfx (certificate) file.  You will need to use this to open the pfx file later.</param>
        /// <param name="prepareForChallenge">This is called by the GetCertificate method once for each domain, specifying the challenge that will be sent and the expected response.  It is the caller's responsibility to ensure that when the challenge is received, the expected response is sent.</param>
        public static async Task <byte[]> GetCertificate(string emailAddress, string[] domains, string pfx_password, Action <CertificateChallenge> prepareForChallenge, Action <string> statusUpdate)
        {
            // Remove duplicates from domains array, preserving order.
            HashSet <string> domainSet  = new HashSet <string>();
            List <string>    domainList = new List <string>();

            foreach (string domain in domains)
            {
                if (domainSet.Contains(domain))
                {
                    continue;
                }
                else
                {
                    domainSet.Add(domain);
                    domainList.Add(domain);
                }
            }
            domains = domainList.ToArray();
            if (domains.Length == 0)
            {
                throw new ArgumentException("No domains specified", "domains");
            }

            statusUpdate("Starting certificate renewal for domains \"" + string.Join("\", \"", domains));

            using (AcmeClient client = new AcmeClient(WellKnownServers.LetsEncrypt))
            {
                // Create new registration
                AcmeAccount account = await client.NewRegistraton("mailto:" + emailAddress);

                // Accept terms of services
                account.Data.Agreement = account.GetTermsOfServiceUri();
                account = await client.UpdateRegistration(account);


                foreach (string domain in domains)
                {
                    statusUpdate("Authorizing domain " + domain);
                    // Initialize authorization
                    AuthorizationIdentifier authorizationIdentifier = new AuthorizationIdentifier();
                    authorizationIdentifier.Type  = AuthorizationIdentifierTypes.Dns;
                    authorizationIdentifier.Value = domain;
                    AcmeResult <Authorization> authz = await client.NewAuthorization(authorizationIdentifier);

                    // Compute key authorization for http-01
                    Challenge httpChallengeInfo = authz.Data.Challenges.Where(c => c.Type == ChallengeTypes.Http01).First();
                    string    keyAuthString     = client.ComputeKeyAuthorization(httpChallengeInfo);

                    // Do something to fullfill the challenge,
                    // e.g. upload key auth string to well known path, or make changes to DNS
                    prepareForChallenge(new CertificateChallenge(domain, httpChallengeInfo.Token, keyAuthString));

                    // Invite ACME server to validate the identifier
                    AcmeResult <Challenge> httpChallenge = await client.CompleteChallenge(httpChallengeInfo);

                    // Check authorization status
                    authz = await client.GetAuthorization(httpChallenge.Location);

                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    while (authz.Data.Status == EntityStatus.Pending)
                    {
                        if (sw.Elapsed > TimeSpan.FromMinutes(5))
                        {
                            throw new Exception("Timed out waiting for domain \"" + domain + "\" authorization");
                        }
                        // Wait for ACME server to validate the identifier
                        await Task.Delay(10000);

                        authz = await client.GetAuthorization(httpChallenge.Location);
                    }

                    if (authz.Data.Status != EntityStatus.Valid)
                    {
                        throw new Exception("Failed to authorize domain \"" + domain + "\"");
                    }
                }
                statusUpdate("Authorization complete. Creating certificate.");

                // Create certificate
                CertificationRequestBuilder csr = new CertificationRequestBuilder();
                for (int i = 0; i < domains.Length; i++)
                {
                    if (i == 0)
                    {
                        csr.AddName("CN", domains[i]);
                    }
                    else
                    {
                        csr.SubjectAlternativeNames.Add(domains[i]);
                    }
                }

                AcmeCertificate cert = await client.NewCertificate(csr);

                // Export Pfx
                PfxBuilder pfxBuilder = cert.ToPfx();
                byte[]     pfx        = pfxBuilder.Build("LetsEncryptAuto", pfx_password);
                return(pfx);
            }
        }
Esempio n. 9
0
 public static void AddTestCert(this PfxBuilder pfx) => pfx.AddIssuers(TestCertificates);
Esempio n. 10
0
        /// <summary>
        /// HTTP-01 challenge.
        /// </summary>
        /// <exception cref="LetsEncryptMikroTikException"/>
        public async Task <LetsEncryptCert> GetCertAsync(string?accountPemKey = null)
        {
            AcmeContext     acme;
            IAccountContext account;

            //Uri knownServer = _letsEncryptAddress;

            if (accountPemKey != null)
            {
                // Load the saved account key
                var accountKey = KeyFactory.FromPem(accountPemKey);
                acme = new AcmeContext(_letsEncryptAddress, accountKey);
                Log.Information("Авторизация в Let's Encrypt.");
                account = await acme.Account().ConfigureAwait(false);
            }
            else
            {
                acme = new AcmeContext(_letsEncryptAddress);
                Log.Information("Авторизация в Let's Encrypt.");
                account = await acme.NewAccount(_config.Email, termsOfServiceAgreed : true).ConfigureAwait(false);

                // Save the account key for later use
                //string pemKey = acme.AccountKey.ToPem();
            }

            Log.Information("Заказываем новый сертификат.");
            IOrderContext order = await acme.NewOrder(new[] { _config.DomainName }).ConfigureAwait(false);

            // Get the token and key authorization string.
            Log.Information("Получаем способы валидации заказа.");
            var authz = (await order.Authorizations().ConfigureAwait(false)).First();

            if (_config.UseAlpn)
            {
                Log.Information("Выбираем TLS-ALPN-01 способ валидации.");
                IChallengeContext challenge = await authz.TlsAlpn().ConfigureAwait(false);

                string keyAuthz = challenge.KeyAuthz;
                string token    = challenge.Token;

                await ChallengeAlpnAsync(challenge, keyAuthz).ConfigureAwait(false);
            }
            else
            {
                Log.Information("Выбираем HTTP-01 способ валидации.");
                IChallengeContext challenge = await authz.Http().ConfigureAwait(false);

                string keyAuthz = challenge.KeyAuthz;

                await HttpChallengeAsync(challenge, keyAuthz).ConfigureAwait(false);
            }

            Log.Information("Загружаем сертификат.");

            // Download the certificate once validation is done
            IKey privateKey = KeyFactory.NewKey(KeyAlgorithm.RS256);

            CertificateChain cert = await order.Generate(new CsrInfo
            {
                CommonName       = _config.DomainName,
                CountryName      = "CA",
                State            = "Ontario",
                Locality         = "Toronto",
                Organization     = "Certes",
                OrganizationUnit = "Dev",
            }, privateKey)
                                    .ConfigureAwait(false);

            // Export full chain certification.
            string certPem = cert.ToPem();
            string keyPem  = privateKey.ToPem();

            // Export PFX
            PfxBuilder pfxBuilder = cert.ToPfx(privateKey);

            byte[] pfx = pfxBuilder.Build(friendlyName: _config.DomainName, password: "");

            //await acme.RevokeCertificate(pfx, RevocationReason.Superseded, privateKey);

            using (var cert2 = new X509Certificate2(pfx))
            {
                return(new LetsEncryptCert(cert2.NotAfter, certPem, keyPem, cert2.GetCommonName(), cert2.GetSha2Thumbprint()));
            }
        }