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); }
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 }); } }
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); }
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)); }
/// <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); } }
/// <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())); } }