public async Task <FinalizeOutput> FinalizeOrder(FinalizeInput input, ILogger logger) { var context = new AcmeContext(State.LetsEncryptEndpoint, KeyFactory.FromPem(State.Pem)); var orderId = string.Join("", input.Domains).ToMD5Hash(); var orderCtx = context.Order(new Uri(State.Orders[orderId])); var order = await orderCtx.Resource(); if (order.Status == OrderStatus.Ready) { var certKey = KeyFactory.NewKey(KeyAlgorithm.ES256); order = await orderCtx.Finalize( input.CsrInfo, certKey); if (order.Status == Certes.Acme.Resource.OrderStatus.Invalid) { throw new Exception(order?.Error?.ToString() ?? $"{orderCtx} is invalid"); } var certChain = await orderCtx.Download(); var pfx = certChain.ToPfx(certKey).Build("CN=" + input.Domains.First(), ""); var cert = new X509Certificate2(pfx); return(new FinalizeOutput { Pfx = pfx, Thumbprint = cert.Thumbprint }); } throw new Exception(order?.Error?.ToString() ?? $"{orderCtx} is invalid"); }
public static void TestHost( [Required(Description = "Host name")] string hostName, [Optional(null, "cfg", Description = "Custom configuration file name")] string cfgFileName, [Optional(false, Description = "Show verbose error messages")] bool verbose) { verboseMode = verbose; if (cfgStore == null) { LoadConfig(cfgFileName); } hostName = hostName.Trim().ToLower(); var result = AcmeContext.TestAuthorization(hostName, CreateChallenge, CleanupChallenge); Trace.WriteLine(string.Empty); if (result) { Trace.WriteLine("Test authorization was successful. The real verification may still fail,"); Trace.WriteLine("ie. when server is not accessible from outside."); } else { Trace.WriteLine("Test authorization failed. Examine the above to find out why."); } }
public static async Task <Client> Login(string mail, Func <HttpClient> httpClientGenerator, string dnsimpleToken, Account?account = null, bool production = true) { var acmeHttpClient = new AcmeHttpClient(GetServer(production), httpClientGenerator()); AcmeContext acme; if (account == null) { acme = new AcmeContext(GetServer(production), null, acmeHttpClient); await acme.NewAccount(mail, true); account = new Account(acme.AccountKey); } else { acme = new AcmeContext(GetServer(production), account.Key, acmeHttpClient); } var client = new DNSimple.Client(httpClientGenerator()); client.UseToken(dnsimpleToken); var dnsimple = await client.GetAccount(mail); return(new Client(acme, dnsimple, account)); }
public async Task <AcmeContext> NewAcmeContextAsync(string serverAlias) { Uri acmeServerUri = GetAcmeServerUri(serverAlias); AcmeContext acmeCtx; var accountKey = await keyCache.GetAccountKey(serverAlias); if (accountKey != null) { acmeCtx = new AcmeContext(acmeServerUri, accountKey); await acmeCtx.Account(); logger.LogInformation("Created ACME account from cached key, server: {serverUri}", acmeServerUri); } else { acmeCtx = new AcmeContext(acmeServerUri); await acmeCtx.NewAccount(settings.AcmeAccount.Email, true); await keyCache.SaveAccountKey(acmeCtx.AccountKey, serverAlias); logger.LogInformation("Created new ACME account, server: {serverUri}", acmeServerUri); } return(acmeCtx); }
public async Task <IActionResult> Delete([FromServices] AcmeContext context, [FromRoute] TKey id) { int next; lock (random) { next = random.Next(0, 2); } if (next == 0) { return(BadRequest(new Exception("BLEEE"))); } else if (next == 1) { return(BadRequest("Reeee 2")); } var model = context.Set <T>().Find(id); context.Set <T>().Remove(model); await context.SaveChangesAsync(); return(Ok()); }
public async Task <string> InitWithNewAccountAsync(string emailId) { acmeContext = new AcmeContext(WellKnownServers.LetsEncryptV2); await acmeContext.NewAccount(emailId, true); return(acmeContext.AccountKey.ToPem()); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AcmeContext context) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } context.Database.Migrate(); // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "ACME Account Management V1"); //c.RoutePrefix = string.Empty; }); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
private async Task <IAcmeContext> GetContext() { if (_acme != null) { return(_acme); } var existingAccountKey = await _persistenceService.GetPersistedAccountCertificateAsync(); if (existingAccountKey != null) { _logger.LogDebug("Using existing LetsEncrypt account."); var acme = new AcmeContext(_options.LetsEncryptUri, existingAccountKey); await acme.Account(); return(_acme = acme); } else { _logger.LogDebug("Creating LetsEncrypt account with email {0}.", _options.Email); var acme = new AcmeContext(_options.LetsEncryptUri); await acme.NewAccount(_options.Email, true); await _persistenceService.PersistAccountCertificateAsync(acme.AccountKey); return(_acme = acme); } }
public async Task RetryOnBadNonce() { var accountLoc = new Uri("https://acme.d/acct/1"); var httpMock = new Mock <IAcmeHttpClient>(); httpMock.Setup(m => m.Get <Directory>(It.IsAny <Uri>())) .ReturnsAsync(new AcmeHttpResponse <Directory>( accountLoc, MockDirectoryV2, null, null)); httpMock.SetupSequence( m => m.Post <Account>(MockDirectoryV2.NewAccount, It.IsAny <object>())) .ReturnsAsync(new AcmeHttpResponse <Account>( accountLoc, null, null, new AcmeError { Status = HttpStatusCode.BadRequest, Type = "urn:ietf:params:acme:error:badNonce" })) .ReturnsAsync(new AcmeHttpResponse <Account>( accountLoc, new Account { Status = AccountStatus.Valid }, null, null)); var key = KeyFactory.NewKey(KeyAlgorithm.RS256); var ctx = new AcmeContext( WellKnownServers.LetsEncryptStagingV2, key, httpMock.Object); await ctx.NewAccount("", true); httpMock.Verify(m => m.Post <Account>(MockDirectoryV2.NewAccount, It.IsAny <object>()), Times.Exactly(2)); }
private void ShowThumbprint(AcmeContext context) { var account = new AccountKey(context.Account.Key); var thumbprint = JwsConvert.ToBase64String(account.GenerateThumbprint()); ConsoleLogger.Info(thumbprint); }
private async Task <AcmeContext> UpdateAccount(AcmeContext context) { bool changed = false; var account = context.Account; using (var client = new AcmeClient(Options.Server)) { client.Use(account.Key); if (!string.IsNullOrWhiteSpace(Options.Email)) { account.Data.Contact = new[] { $"mailto:{Options.Email}" }; changed = true; } var currentTos = account.GetTermsOfServiceUri(); if (Options.AgreeTos && account.Data.Agreement != currentTos) { account.Data.Agreement = currentTos; changed = true; } if (changed) { account = await client.UpdateRegistration(account); } } ConsoleLogger.Info("Registration updated."); return(context); }
static ContextAccountBundle GetNonStagingParameters() { Uri server = WellKnownServers.LetsEncryptV2; AcmeContext ctx; if (File.Exists(ACC_LOC)) { ctx = AccountHelper.GetContextWithAccount(ACC_LOC, server); } else { ctx = new AcmeContext(server); } IAccountContext account = AccountHelper.RetriveAccount(ctx); Account accInfo = AccountHelper.RetriveAccountDetails(account); if (!accInfo.Status.HasValue) { throw new AcmeException("Account has not had its status set yet"); } else if (accInfo.Status.Value == AccountStatus.Revoked || accInfo.Status.Value == AccountStatus.Deactivated) { throw new AcmeException("Account is either revoked or deactivated"); } return(new ContextAccountBundle(ctx, account)); }
public static async Task InitAsync(ILogger logger, CertificateMode certificateMode) { _logger = logger; _logger.LogInformation($"Initializing LetsEncrypt bits"); //ACCOUNT _logger.LogInformation(" Creating or Retrieving account"); if (await AzureHelper.CheckIfFileExistsBlobStorageAsync(Constants.AccountKeyFileName)) { _logger.LogInformation(" Retrieving existing account"); // Load the saved account key var pemKey = await AzureHelper.ReadFileFromBlobStorageToStringAsync(Constants.AccountKeyFileName); var accountKey = KeyFactory.FromPem(pemKey); _acme = new AcmeContext(certificateMode == CertificateMode.Production ? WellKnownServers.LetsEncryptV2 : WellKnownServers.LetsEncryptStagingV2, accountKey); var account = await _acme.Account(); } else { _logger.LogInformation(" Creating new account"); _acme = new AcmeContext(certificateMode == CertificateMode.Production ? WellKnownServers.LetsEncryptV2 : WellKnownServers.LetsEncryptStagingV2); var account = await _acme.NewAccount(Settings.CertificateOwnerEmail, true); // Save the account key for later use var pemKey = _acme.AccountKey.ToPem(); await AzureHelper.SaveFileToBlobStorageAsync(Constants.AccountKeyFileName, pemKey); } _logger.LogInformation(" Account set"); _logger.LogInformation(Environment.NewLine); }
private async Task <AcmeContext> GetOrCreateAcmeContext(Uri acmeDirectoryUri, string email) { AcmeContext acme = null; string filename = $"account{email}--{acmeDirectoryUri.Host}"; var secret = await this.certificateStore.GetSecret(filename); if (string.IsNullOrEmpty(secret)) { acme = new AcmeContext(acmeDirectoryUri); var account = acme.NewAccount(email, true); // Save the account key for later use var pemKey = acme.AccountKey.ToPem(); await certificateStore.SaveSecret(filename, pemKey); await Task.Delay(10000); //Wait a little before using the new account. acme = new AcmeContext(acmeDirectoryUri, acme.AccountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } else { var accountKey = KeyFactory.FromPem(secret); acme = new AcmeContext(acmeDirectoryUri, accountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } return(acme); }
private static async Task <AcmeContext> LoadAccount() { AcmeContext acme; var server = _configuration.IsStaging ? WellKnownServers.LetsEncryptStagingV2 : WellKnownServers.LetsEncryptV2; Log($" 1. Setting Environment {server}..."); if (String.IsNullOrEmpty(_configuration.AccountPem)) { Log(" 2. Creating account..."); acme = new AcmeContext(server); var account = await acme.NewAccount(_configuration.AccountEmail, true); _configuration.AccountPem = acme.AccountKey.ToPem(); } else { Log(" 2. Using existing account..."); var accountKey = KeyFactory.FromPem(_configuration.AccountPem); acme = new AcmeContext(server, accountKey); } return(acme); }
public override async Task <AcmeContext> Process(AcmeContext context) { if (context?.Account == null) { throw new Exception("Account not specified."); } var values = await GetAllValues(); if (values.Length == 0) { throw new Exception("Value not specified."); } if (!string.IsNullOrWhiteSpace(Options.Complete)) { await CompleteChallenge(context, values); } else if (!string.IsNullOrWhiteSpace(Options.KeyAuthentication)) { ComputeKeyAuthorization(context, values); } else if (!string.IsNullOrWhiteSpace(Options.Refresh)) { await RefreshAuthorization(context, values); } else { await NewAuthorization(context, values); } return(context); }
/// <summary> /// Register a new account with the ACME CA (Let's Encrypt), accepting terms and conditions /// </summary> /// <param name="log"> </param> /// <param name="email"> </param> /// <returns> </returns> public async Task <bool> AddNewAccountAndAcceptTOS(ILog log, string email) { try { // start new account context, create new account _acme = new AcmeContext(_serviceUri); var account = await _acme.NewAccount(email, true); _settings.AccountEmail = email; //store account key SaveAccountKey(account); SaveSettings(); log.Information($"Registering account {email} with certificate authority"); // re-init provider based on new account key InitProvider(); return(true); } catch (Exception exp) { log.Error($"Failed to register account {email} with certificate authority: {exp.Message}"); return(false); } }
private void ComputeKeyAuthorization(AcmeContext context, string[] values) { var authorizations = context.Authorizations?.TryGet(Options.Type); using (var client = new AcmeClient(Options.Server)) { client.Use(context.Account.Key); foreach (var name in values) { var auth = authorizations?.TryGet(name); var challenge = auth? .Data? .Challenges? .Where(c => c.Type == Options.KeyAuthentication) .FirstOrDefault(); if (challenge == null) { ConsoleLogger.Warn("{0} NotFound", name); } else { if (string.IsNullOrWhiteSpace(challenge.KeyAuthorization) || Options.Force) { challenge.KeyAuthorization = client.ComputeKeyAuthorization(challenge); } ConsoleLogger.Info("{0} {1}", name, challenge.KeyAuthorization); } } } }
private async Task RefreshAuthorization(AcmeContext context, string[] values) { var authorizations = context.Authorizations?.TryGet(Options.Type); using (var client = new AcmeClient(Options.Server)) { client.Use(context.Account.Key); foreach (var name in values) { var auth = authorizations?.TryGet(name); if (auth != null) { auth = authorizations[name] = await client.GetAuthorization(auth.Location); var challenge = auth? .Data? .Challenges? .Where(c => c.Type == Options.Refresh) .FirstOrDefault(); ConsoleLogger.Info("{0} {1}", name, challenge.Status); } } } }
private async Task <bool> HandleDns(AcmeContext acme, AcmeConfig config, IEnumerable <IChallengeContext> authorizations, List <INotifyConfig> notificationsList) { bool isValid = true; Dictionary <string, string> dnsValidation = new Dictionary <string, string>(); var index = -1; foreach (var challenge in authorizations) { index++; var domainName = config.DNS.DomainNames[index].Replace("*.", ""); var acmeDomain = "_acme-challenge." + domainName; var dnsText = acme.AccountKey.DnsTxt(challenge.Token); dnsValidation.Add(acmeDomain, dnsText); _log.LogInfo($"Add TXT dns for {acmeDomain} to '{dnsText}'"); } await AwaitDnsChanges(dnsValidation, notificationsList); Task.WaitAll(authorizations.Select(c => Task.Run(async() => { var validation = await c.Validate(); do { if (validation.Status == Certes.Acme.Resource.ChallengeStatus.Pending) { System.Threading.Thread.Sleep(2000); validation = await c.Resource(); } } while (validation.Status == Certes.Acme.Resource.ChallengeStatus.Pending); isValid = isValid && (validation.Status != Certes.Acme.Resource.ChallengeStatus.Invalid); })).ToArray()); return(isValid); }
private async Task <AcmeContext> GetOrCreateAcmeContext(Uri acmeDirectoryUri, string email) { if (!Directory.Exists(configPath)) { Directory.CreateDirectory(configPath); } AcmeContext acme = null; string filename = $"account{email}--{acmeDirectoryUri.Host}"; var filePath = Path.Combine(configPath, filename); if (!File.Exists(filePath) || string.IsNullOrEmpty(File.ReadAllText(filePath))) { acme = new AcmeContext(acmeDirectoryUri); var account = acme.NewAccount(email, true); // Save the account key for later use var pemKey = acme.AccountKey.ToPem(); File.WriteAllText(filePath, pemKey); await Task.Delay(10000); //Wait a little before using the new account. acme = new AcmeContext(acmeDirectoryUri, acme.AccountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } else { var secret = File.ReadAllText(filePath); var accountKey = KeyFactory.FromPem(secret); acme = new AcmeContext(acmeDirectoryUri, accountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } return(acme); }
private async Task <AcmeContext> GetOrCreateAcmeContext(Uri acmeDirectoryUri, string email) { AcmeContext acme = null; string filename = $"account{email}--{acmeDirectoryUri.Host}.pem"; if (!await fileSystem.Exists(filename)) { acme = new AcmeContext(acmeDirectoryUri); var account = acme.NewAccount(email, true); // Save the account key for later use var pemKey = acme.AccountKey.ToPem(); await fileSystem.WriteAllText(filename, pemKey); await Task.Delay(10000); //Wait a little before using the new account. acme = new AcmeContext(acmeDirectoryUri, acme.AccountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } else { var pemKey = await fileSystem.ReadAllText(filename); var accountKey = KeyFactory.FromPem(pemKey); acme = new AcmeContext(acmeDirectoryUri, accountKey, new AcmeHttpClient(acmeDirectoryUri, new HttpClient())); } return(acme); }
public static async Task Main(string[] args) { // var acme = new AcmeContext(WellKnownServers.LetsEncryptV2); // var account = await acme.NewAccount("*****@*****.**", true); // // // Save the account key for later use // var pemKey = acme.AccountKey.ToPem(); // File.WriteAllText(@"C:\temp\letsencrypt\pem", pemKey); var accountKey = KeyFactory.FromPem(File.ReadAllText(@"C:\temp\letsencrypt\pem")); var acme = new AcmeContext(WellKnownServers.LetsEncryptV2, accountKey); //var (uri, token, s) = await NewOrderHttp(acme, "peoplemeter.ru"); await CheckOrderHttp(acme, "https://acme-v02.api.letsencrypt.org/acme/order/50945428/303515634"); // var newOrderLocation = newOrder.Location; //await CheckOrderDns(acme, "https://acme-v02.api.letsencrypt.org/acme/order/50945428/303477312"); // if (validate.Status == ChallengeStatus.Valid) // { // var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); // var cert = await order.Generate(new CsrInfo // { // CountryName = "CA", // State = "Ontario", // Locality = "Toronto", // Organization = "Certes", // OrganizationUnit = "Dev", // CommonName = "your.domain.name", // }, privateKey); // } }
public async Task <byte[]> GetCertificateAsync(Action <string> setDnsTxt) { IOrderContext order = await AcmeContext.NewOrder(new[] { Configuration.CertificateIdentifier }); var authz = (await order.Authorizations()).First(); var dnsChallenge = await authz.Dns(); var dnsTxt = AcmeContext.AccountKey.DnsTxt(dnsChallenge.Token); var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); setDnsTxt(dnsTxt); Challenge challenge = null; for (int i = 0; challenge?.Status != ChallengeStatus.Valid && i < 10; i++) { challenge = await dnsChallenge.Validate(); if (challenge.Status == ChallengeStatus.Valid) { break; } Thread.Sleep(1000); } var cert = await order.Generate(Configuration.CsrInfo, privateKey); var pfxBuilder = cert.ToPfx(privateKey); return(pfxBuilder.Build(Configuration.CertificateName, Configuration.CertificatePassword)); }
public async Task <string> GetAccountKey() { if (!string.IsNullOrEmpty(_accountKey)) { return(_accountKey); } _logger.LogInformation("Getting a new account key"); var acme = new AcmeContext(_options.AcmeServer); IAccountContext account; try { account = await acme.NewAccount(_options.EmailAddress, true); } catch (Exception e) { _logger.LogError(e.ToString()); return(null); } var pemKey = acme.AccountKey.ToPem(); if (!string.IsNullOrEmpty(_keyFile)) { File.WriteAllText(_keyFile, pemKey); } return(pemKey); }
private static async Task RunAcmeRequestHandlerJob( HostBuilderContext hostBuilderContext, IServiceCollection services, string[] args) { services.AddTransient <IAcmeContext, AcmeContext>(); services.AddTransient <IDnsManagementClient, DnsManagementClient>(); services.AddTransient <IResourceManagementClient, ResourceManagementClient>(); services.AddTransient <IWebSiteManagementClient, WebSiteManagementClient>(); var acme = new AcmeContext(WellKnownServers.LetsEncryptV2); var account = await acme.NewAccount("*****@*****.**", true); var pemKey = acme.AccountKey.ToPem(); var order = await acme.NewOrder(new[] { "*.dev.xiaodong.world" }); var authz = (await order.Authorizations()).First(); var dnsChallenge = await authz.Dns(); var dnsText = acme.AccountKey.DnsTxt(dnsChallenge.Token); // TODO: add dns txt record to _acme-challenge.dev.xiaodong.world with dnsText value var httpChallenge = await authz.Http(); var keyAuthz = httpChallenge.KeyAuthz; }
static async Task <CertRequest> CreateAccountAsync(bool staging) { Console.WriteLine("Creating letsencrypt account"); var certRequest = ReadRequest("cert.json"); var fileInfo = new FileInfo(certRequestFile); if (!fileInfo.Directory.Exists) { Directory.CreateDirectory(fileInfo.DirectoryName); } File.Copy("cert.json", certRequestFile); acmeContext = new AcmeContext(staging ? WellKnownServers.LetsEncryptStagingV2 : WellKnownServers.LetsEncryptV2); account = await acmeContext.NewAccount(certRequest.Account, true); var pemKey = acmeContext.AccountKey.ToPem(); var fi = new FileInfo(accountFile); Directory.CreateDirectory(fi.DirectoryName); await File.WriteAllTextAsync(accountFile, pemKey); Console.WriteLine("Letsencrypt account created"); return(certRequest); }
private async Task <AcmeContext> RegisterAccount(AcmeContext context) { if (context != null && !Options.Force) { throw new Exception($"A config exists at {Options.Path}, use a different path or --force option."); } using (var client = new AcmeClient(Options.Server)) { var account = Options.NoEmail ? await client.NewRegistraton() : await client.NewRegistraton($"mailto:{Options.Email}"); if (Options.AgreeTos) { account.Data.Agreement = account.GetTermsOfServiceUri(); account = await client.UpdateRegistration(account); } context = new AcmeContext { Account = account }; } ConsoleLogger.Info("Registration created."); return(context); }
static async Task <int> Main(string[] args) { Args = CommandLineParser.ParseOrWriteUsageToConsole <CmdLine>(args); if (Args == null) { return(1); } var outputPath = Path.GetDirectoryName(Args.ConfigPath); var identifier = Path.GetFileNameWithoutExtension(Args.ConfigPath); var cfg = Args.Config; Console.WriteLine($"This will create/renew a LetsEncrypt certificate for {cfg.Domain}"); PressYToContinue(); // https://community.letsencrypt.org/t/what-are-accounts-do-i-need-to-backup-them/21318/2 // We won't try to preserve the account key, and will simply create a new one every time. var acme = new AcmeContext(WellKnownServers.LetsEncryptV2); await acme.NewAccount(cfg.NotifyEmail, true); var commonName = cfg.Domain; var order = await acme.NewOrder(new[] { commonName }); var authz = (await order.Authorizations()).First(); var challenge = await authz.Dns(); Console.WriteLine(); Console.WriteLine("DNS challenge required:"); Console.WriteLine($" update TXT record for _acme-challenge.{cfg.Domain.Replace("*.", "")}"); Console.WriteLine($" {acme.AccountKey.DnsTxt(challenge.Token)}"); Console.WriteLine(); PressYToContinue(); await challenge.Validate(); var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); var cert = await order.Generate(new CsrInfo { CountryName = cfg.CountryName, State = cfg.State, Locality = cfg.Locality, Organization = cfg.Domain.Replace("*.", ""), OrganizationUnit = "IT", CommonName = commonName, }, privateKey); File.WriteAllText(Path.Combine(outputPath, $"{identifier}.ca-bundle"), string.Join("\r\n", cert.Issuers.Select(s => s.ToPem()))); File.WriteAllText(Path.Combine(outputPath, $"{identifier}.crt"), cert.Certificate.ToPem()); File.WriteAllText(Path.Combine(outputPath, $"{identifier}.private.key"), privateKey.ToPem()); if (cfg.PfxPassword != null) { var pfxBuilder = cert.ToPfx(privateKey); var pfx = pfxBuilder.Build(identifier, cfg.PfxPassword); File.WriteAllBytes(Path.Combine(outputPath, $"{identifier}.pfx"), pfx); } Console.WriteLine($"Certificate files saved to: {outputPath}\\{identifier}.*"); return(0); }
/// <summary> /// Address repository constructor /// </summary> /// <param name="context">Acme DB context</param> public AddressRepository(AcmeContext context) : base(context) { // Set Country Entity countryEntity = _context.Set <Country>(); // Set Postcode Entity postcodeEntity = _context.Set <Postcodes>(); }