public AcmeClient(IDnsProvider dnsProvider, DnsLookupService dnsLookupService, ICertificateStore certifcateStore, ILogger <AcmeClient> logger = null) { this.dnsProvider = dnsProvider; this.dnsLookupService = dnsLookupService; this.certificateStore = certifcateStore; this.logger = logger ?? NullLogger <AcmeClient> .Instance; }
public AcmeClient(IDnsProvider dnsProvider, DnsLookupService dnsLookupService, IFileSystem fileSystem = null, ILogger <AcmeClient> logger = null) { this.dnsProvider = dnsProvider; this.dnsLookupService = dnsLookupService; this.fileSystem = fileSystem ?? new FileSystem(); this.logger = logger ?? NullLogger <AcmeClient> .Instance; }
/// <summary> /// Request a certificate from lets encrypt using the DNS challenge, placing the challenge record in Azure DNS. /// The certifiacte is not assigned, but just returned. /// </summary> /// <param name="azureDnsEnvironment"></param> /// <param name="acmeConfig"></param> /// <returns></returns> public async Task <CertificateInstallModel> RequestDnsChallengeCertificate(IAcmeDnsRequest acmeConfig) { logger.LogInformation("Starting request DNS Challenge certificate for {AcmeEnvironment} and {Email}", acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.RegistrationEmail); var acmeContext = await GetOrCreateAcmeContext(acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.RegistrationEmail); var idn = new IdnMapping(); var order = await acmeContext.NewOrder(new[] { "*." + idn.GetAscii(acmeConfig.Host.Substring(2)) }); var a = await order.Authorizations(); var authz = a.First(); var challenge = await authz.Dns(); var dnsTxt = acmeContext.AccountKey.DnsTxt(challenge.Token); logger.LogInformation("Got DNS challenge token {Token}", dnsTxt); ///add dns entry await this.dnsProvider.PersistChallenge(String.Concat("_acme-challenge.", DnsLookupService.GetNoneWildcardSubdomain(acmeConfig.Host)), dnsTxt); if (!(await this.dnsLookupService.Exists(acmeConfig.Host, dnsTxt, this.dnsProvider.MinimumTtl))) { throw new TimeoutException($"Unable to validate that _acme-challenge was stored in txt _acme-challenge record after {this.dnsProvider.MinimumTtl} seconds"); } Challenge chalResp = await challenge.Validate(); while (chalResp.Status == ChallengeStatus.Pending || chalResp.Status == ChallengeStatus.Processing) { logger.LogInformation("Dns challenge response status {ChallengeStatus} more info at {ChallengeStatusUrl} retrying in 5 sec", chalResp.Status, chalResp.Url.ToString()); await Task.Delay(5000); chalResp = await challenge.Resource(); } logger.LogInformation("Finished validating dns challenge token, response was {ChallengeStatus} more info at {ChallengeStatusUrl}", chalResp.Status, chalResp.Url); var privateKey = await GetOrCreateKey(acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.Host); var cert = await order.Generate(new Certes.CsrInfo { CountryName = acmeConfig.CsrInfo.CountryName, State = acmeConfig.CsrInfo.State, Locality = acmeConfig.CsrInfo.Locality, Organization = acmeConfig.CsrInfo.Organization, OrganizationUnit = acmeConfig.CsrInfo.OrganizationUnit, CommonName = acmeConfig.CsrInfo.CommonName, }, privateKey); var certPem = cert.ToPem(); var pfxBuilder = cert.ToPfx(privateKey); var pfx = pfxBuilder.Build(acmeConfig.Host, acmeConfig.PFXPassword); await this.dnsProvider.Cleanup(dnsTxt); return(new CertificateInstallModel() { CertificateInfo = new CertificateInfo() { Certificate = new X509Certificate2(pfx, acmeConfig.PFXPassword, X509KeyStorageFlags.DefaultKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable), Name = $"{acmeConfig.Host} {DateTime.Now}", Password = acmeConfig.PFXPassword, PfxCertificate = pfx }, Host = acmeConfig.Host }); }