private async Task <byte[]> AcquireCertificateBytesFromOrderAsync( IOrderContext order, CsrInfo certificateSigningRequest, string certificateFriendlyName, string certificatePassword, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); _logger.LogInformation("Acquiring certificate through signing request."); var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); var certificateChain = await order.Generate(certificateSigningRequest, privateKey); var pfxBuilder = certificateChain.ToPfx(privateKey); pfxBuilder.FullChain = true; var pfxBytes = pfxBuilder.Build(certificateFriendlyName, certificatePassword); _logger.LogInformation("Certificate acquired."); return(pfxBytes); }
public async Task <(X509Certificate2 cert, byte[] rawCert)> AcquireNewCertificateForHosts( string hostName, CsrInfo certificateSigningRequest, string certificateFriendlyName, string certificatePassword, CancellationToken cancellationToken) { _logger.LogInformation("Ordering LetsEncrypt certificate for hosts {0}.", new object[] { hostName }); var order = await _acmeContext.NewOrder(new string[] { hostName }); await ValidateOrderAsync(order, cancellationToken); var certificateBytes = await AcquireCertificateBytesFromOrderAsync( order, certificateSigningRequest, certificateFriendlyName, certificatePassword, cancellationToken); if (certificateBytes == null) { throw new InvalidOperationException("The certificate from the order was null."); } var certificate = new X509Certificate2(certificateBytes, certificatePassword); return(certificate, certificateBytes); }
private async Task <X509Certificate2> CompleteCertificateRequestAsync(IOrderContext order, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_client == null) { throw new InvalidOperationException(); } var commonName = _options.Value.DomainNames[0]; _logger.LogDebug("Creating cert for {commonName}", commonName); var csrInfo = new CsrInfo { CommonName = commonName, }; var privateKey = KeyFactory.NewKey((Certes.KeyAlgorithm)_options.Value.KeyAlgorithm); var acmeCert = await _client.GetCertificateAsync(csrInfo, privateKey, order); _logger.LogAcmeAction("NewCertificate"); var pfxBuilder = acmeCert.ToPfx(privateKey); var pfx = pfxBuilder.Build("HTTPS Cert - " + _options.Value.DomainNames, string.Empty); return(new X509Certificate2(pfx, string.Empty, X509KeyStorageFlags.Exportable)); }
public static async Task InitAsync(ILogger logger, CertificateMode certificateMode) { _logger = logger; _logger.LogInformation($"Initializing LetsEncrypt bits"); //ACCOUNT _logger.LogInformation(" Creating or Retrieving account"); var accountKeyFileName = Constants.AccountKeyFileName; if (Settings.UseStaging) { accountKeyFileName = "staging" + accountKeyFileName; } IAccountContext account; if (await AzureHelper.CheckIfFileExistsBlobStorageAsync(accountKeyFileName)) { _logger.LogInformation(" Retrieving existing account"); // Load the saved account key var pemKey = await AzureHelper.ReadFileFromBlobStorageToStringAsync(accountKeyFileName); var accountKey = KeyFactory.FromPem(pemKey); _acme = new AcmeContext(certificateMode == CertificateMode.Production ? WellKnownServers.LetsEncryptV2 : WellKnownServers.LetsEncryptStagingV2, accountKey); account = await _acme.Account(); } else { _logger.LogInformation(" Creating new account"); _acme = new AcmeContext(certificateMode == CertificateMode.Production ? WellKnownServers.LetsEncryptV2 : WellKnownServers.LetsEncryptStagingV2); account = await _acme.NewAccount(Settings.CertificateOwnerEmail, true); // Save the account key for later use var pemKey = _acme.AccountKey.ToPem(); await AzureHelper.SaveFileToBlobStorageAsync(accountKeyFileName, pemKey); } _logger.LogInformation($" Account set - { account.Location }"); _logger.LogInformation(Environment.NewLine); _logger.LogInformation("Loading Certificate Info for Issuance"); _certinfo = await BuildCertificaeInfoAsync(); _logger.LogInformation(" Certificate Info loaded"); _logger.LogInformation(Environment.NewLine); }
private async Task <byte[]> AcquireCertificateBytesFromOrderAsync( IOrderContext order, AcmeOrderOptions orderOptions, AcmeAccountOptions accountOptions, CertificateOptions certificateOptions) { _logger.LogInformation("[LetsEncrypt][Certificate] Acquiring certificate through signing request."); var privateKey = KeyFactory.NewKey((Certes.KeyAlgorithm)orderOptions.KeyAlgorithm); if (orderOptions?.CertificateSigningRequest == null) { var commonName = accountOptions.Domains[0]; _logger.LogDebug("Creating cert for {commonName}", commonName); var csrInfo = new CsrInfo { CommonName = commonName, }; if (orderOptions != null) { orderOptions.CertificateSigningRequest = csrInfo; } } var certificateChain = await order.Generate(orderOptions?.CertificateSigningRequest, privateKey); var pfxBuilder = certificateChain.ToPfx(privateKey); pfxBuilder.FullChain = true; var pfxBytes = pfxBuilder.Build( $"Let's Encrypt - {accountOptions.Domains[0]} ", certificateOptions?.CertificatePassword ?? string.Empty); _logger.LogInformation("[LetsEncrypt][Certificate] Certificate acquired."); return(pfxBytes); }
public async Task <CertificateChain> GetCertificateAsync(CsrInfo csrInfo, IKey privateKey, IOrderContext order) { _logger.LogAcmeAction("GenerateCertificate", order); return(await order.Generate(csrInfo, privateKey)); }
public static async void Run([TimerTrigger("0 0 0 1 JAN,APR,JUL,OCT *")] TimerInfo myTimer, ILogger log) { var domainName = "cityforcity.com"; var connString = Environment.GetEnvironmentVariable("STORAGE_CONN_STRING"); var shareName = "nginx-volume"; var ownerEmail = Environment.GetEnvironmentVariable("OWNER_EMAIL"); var wildcardDomainName = $"*.{domainName}"; var dnsAddr = $"_acme-challenge"; AcmeContext acme = new AcmeContext(WellKnownServers.LetsEncryptV2); // change this for production, using staging to not get blocked await acme.NewAccount(ownerEmail, true); var order = await acme.NewOrder(new [] { wildcardDomainName }); var orderUri = order.Location; var authorization = await order.Authorization(wildcardDomainName); var dnsChallenge = await authorization.Dns(); var dnsTxt = acme.AccountKey.DnsTxt(dnsChallenge.Token); try { AzureHelper.AuthenticateAzure(); var dnsUpdated = AzureHelper.AddTextDnsRecord(domainName, dnsAddr, dnsTxt); if (!dnsUpdated) { throw new Exception("Failed to update dns record"); } // wait for dns change to propogate await Task.Delay(500); var validatedChallege = await dnsChallenge.Validate(); var startedValidation = DateTime.Now; while (validatedChallege.Status != Certes.Acme.Resource.ChallengeStatus.Valid) { await Task.Delay(500); if (DateTime.Now > startedValidation.AddSeconds(300)) { throw new Exception("Failed to validate dns record"); } validatedChallege = await dnsChallenge.Resource(); } var dnsRemoved = AzureHelper.RemoveTextDnsRecord(domainName, dnsAddr); if (!dnsRemoved) { log.LogInformation("Failed to remove DNS record do it manually"); } var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); var certinfo = new CsrInfo(); certinfo.CommonName = wildcardDomainName; var cert = await order.Generate(certinfo, privateKey); var certUpdated = AzureHelper.WriteStringToAzureFileShare(connString, shareName, "fullchain1.pem", cert.ToPem()); if (!certUpdated) { throw new Exception("Failed to update certificate"); } var privKeyUpdated = AzureHelper.WriteStringToAzureFileShare(connString, shareName, "privKey1.pem", privateKey.ToPem()); if (!privKeyUpdated) { throw new Exception("Failed to update private key"); } } catch (Exception _) { log.LogError(_.Message); } }
public async Task <ProcessStepResult> PerformCertificateRequestProcess(string primaryDnsIdentifier, string[] alternativeDnsIdentifiers, CertRequestConfig config) { // create our new certificate var orderContext = _currentOrders[config.PrimaryDomain]; //update order status var order = await orderContext.Resource(); // order.Generate() var csrKey = KeyFactory.NewKey(KeyAlgorithm.RS256); var csr = new CsrInfo { CommonName = config.PrimaryDomain }; //alternative to certes IOrderContextExtension.Finalize var builder = new CertificationRequestBuilder(csrKey); foreach (var authzCtx in await orderContext.Authorizations()) { var authz = await authzCtx.Resource(); if (!builder.SubjectAlternativeNames.Contains(authz.Identifier.Value)) { if (config.PrimaryDomain != $"*.{authz.Identifier.Value}") { //only add domain to SAN if it is not derived from a wildcard domain eg test.com from *.test.com builder.SubjectAlternativeNames.Add(authz.Identifier.Value); } } } // if main request is for a wildcard domain, add that to SAN list if (config.PrimaryDomain.StartsWith("*.")) { //add wildcard domain to san builder.SubjectAlternativeNames.Add(config.PrimaryDomain); } builder.AddName("CN", config.PrimaryDomain); /* foreach (var f in csr.AllFieldsDictionary) * { * builder.AddName(f.Key, f.Value); * }*/ if (string.IsNullOrWhiteSpace(csr.CommonName)) { builder.AddName("CN", builder.SubjectAlternativeNames[0]); } var certResult = await orderContext.Finalize(builder.Generate()); var pem = await orderContext.Download(); var cert = new CertificateInfo(pem, csrKey); var certFriendlyName = config.PrimaryDomain + "[Certify]"; var certFolderPath = _settingsFolder + "\\assets\\pfx"; if (!System.IO.Directory.Exists(certFolderPath)) { System.IO.Directory.CreateDirectory(certFolderPath); } string certFile = Guid.NewGuid().ToString() + ".pfx"; string pfxPath = certFolderPath + "\\" + certFile; System.IO.File.WriteAllBytes(pfxPath, cert.ToPfx(certFriendlyName, "")); return(new ProcessStepResult { IsSuccess = true, Result = pfxPath }); }