public async Task Should_POST_to_get_registration_details_if_the_registration_already_exists() { // Arrange var http = new FakeHttpMessageHandler("http://baseaddress/"); var directory = new Directory() { NewRegistration = new Uri("http://baseaddress/registration") }; var registration = new RegistrationResponse(); var client = http.RequestTo("directory").Returns(directory).WithNonce("nonce"). RequestTo("registration").Returns(new Problem(), "application/problem+json").HasStatusCode(HttpStatusCode.Conflict).WithHeader("Location", "http://baseaddress/existingreguri").WithNonce("nonce"). RequestTo("existingreguri").Returns(registration).WithNonce("nonce"). GetHttpClient(); var sut = new AcmeClient(client, new RSACryptoServiceProvider()); // Act var registrationResponse = await sut.RegisterAsync("agreementUri", new[] { "mailto:[email protected]" }); // Assert registrationResponse.Should().NotBeNull(); http.ReceivedRequestsTo("directory").Single().HasMethod(HttpMethod.Get); http.ReceivedRequestsTo("registration").Single().HasMethod(HttpMethod.Post).HasJwsPayload<NewRegistrationRequest>(r => { r.Agreement.Should().Be("agreementUri"); r.Contact.Should().Contain("mailto:[email protected]"); }); http.ReceivedRequestsTo("existingreguri").Single().HasMethod(HttpMethod.Post).HasJwsPayload<UpdateRegistrationRequest>(r => { r.Agreement.Should().BeNull(); r.Contact.Should().BeNull(); }); }
public async Task Should_post_a_valid_Registration_message() { // Arrange var http = new FakeHttpMessageHandler("http://baseaddress/"); var directory = new Directory() { NewRegistration = new Uri("http://baseaddress/registration")}; var registration = new RegistrationResponse(); var client = http.RequestTo("directory").Returns(directory).WithNonce("nonce"). RequestTo("registration").Returns(registration).WithNonce("nonce"). GetHttpClient(); var sut = new AcmeClient(client, new RSACryptoServiceProvider()); // Act var registrationResponse = await sut.RegisterAsync("agreementUri", new []{ "mailto:[email protected]"}); // Assert registrationResponse.Should().NotBeNull(); http.ReceivedRequestsTo("directory").Single().HasMethod(HttpMethod.Get); http.ReceivedRequestsTo("registration").Single().HasMethod(HttpMethod.Post).HasJwsPayload<NewRegistrationRequest>(r => { r.Agreement.Should().Be("agreementUri"); r.Contact.Should().Contain("mailto:[email protected]"); }); }
public static async Task RequestSslCertificate(Options options) { Log.Level = Oocx.Acme.Services.LogLevel.Info; if (!Directory.Exists(options.StoreDirectory)) { Directory.CreateDirectory(options.StoreDirectory); } IKeyStore keyStore = new FileKeyStore(options.StoreDirectory); IAcmeClient client = new AcmeClient( options.AcmeServer, options.AccountKeyName, keyStore ); var challenge = new AzureStorageChallengeProvider( options, client ); IServerConfigurationProvider server = new ConfigureToFiles(options); var acmep = new AcmeProcess( options, challenge, server, client ); await acmep.StartAsync(); await challenge.CleanupUsedChallengeFilesAsync(); }
public void TestInitialize() { RSAParameters Parameters; try { CspParameters CspParams = new CspParameters() { Flags = CspProviderFlags.UseMachineKeyStore, KeyContainerName = directory }; /*using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096, CspParams)) * { * RSA.PersistKeyInCsp = false; * RSA.Clear(); * }*/ using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096, CspParams)) { Parameters = RSA.ExportParameters(true); } } catch (CryptographicException ex) { throw new CryptographicException("Unable to get access to cryptographic key. Was application initially run using another user?", ex); } this.client = new AcmeClient(new Uri(directory), Parameters); }
public async Task TestEndToEndUnoEuro() { var dnsProvider = TestHelper.UnoEuroDnsProvider; var manager = new AcmeClient(dnsProvider, new DnsLookupService(), new NullCertificateStore()); var dnsRequest = new AcmeDnsRequest() { Host = "*.tiimo.dk", PFXPassword = "******", RegistrationEmail = "*****@*****.**", AcmeEnvironment = new LetsEncryptStagingV2(), CsrInfo = new CsrInfo() { CountryName = "DK", Locality = "Copenhagen", Organization = "tiimo ApS", OrganizationUnit = "", State = "DK" } }; var res = await manager.RequestDnsChallengeCertificate(dnsRequest); Assert.IsNotNull(res); File.WriteAllBytes($"{dnsRequest.Host.Substring(2)}.pfx", res.CertificateInfo.PfxCertificate); }
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); } } } }
public async Task Should_post_a_valid_Registration_message() { // Arrange var http = new FakeHttpMessageHandler("http://baseaddress/"); var directory = new Directory { NewRegistration = new Uri("http://baseaddress/registration") }; var registration = new RegistrationResponse(); var client = http.RequestTo("directory").Returns(directory).WithNonce("nonce"). RequestTo("registration").Returns(registration).WithNonce("nonce"). GetHttpClient(); var sut = new AcmeClient(client, new RSACryptoServiceProvider()); // Act var registrationResponse = await sut.RegisterAsync("agreementUri", new [] { "mailto:[email protected]" }); // Assert registrationResponse.Should().NotBeNull(); http.ReceivedRequestsTo("directory").Single().HasMethod(HttpMethod.Get); http.ReceivedRequestsTo("registration").Single().HasMethod(HttpMethod.Post).HasJwsPayload <NewRegistrationRequest>(r => { r.Agreement.Should().Be("agreementUri"); r.Contact.Should().Contain("mailto:[email protected]"); }); }
public static IssuedCertificate RequestCertificate(AcmeClient client, CertificateProvider certProvider, string hostName, List <string> alternativeNames = null) { if (alternativeNames == null) { alternativeNames = new List <string>(); } PrivateKey pk; var csr = GenerateCSR(certProvider, hostName, alternativeNames, out pk); var certRequest = client.RequestCertificate(JwsHelper.Base64UrlEncode(csr)); if (certRequest.StatusCode != HttpStatusCode.Created) { throw new CertificateApplicationException(certRequest, hostName, alternativeNames.ToArray()); } Crt crt; using (var ms = new MemoryStream()) { certRequest.SaveCertificate(ms); ms.Seek(0, SeekOrigin.Begin); crt = certProvider.ImportCertificate(EncodingFormat.DER, ms); } var caCrt = GetCACertificate(certProvider, certRequest); return(new IssuedCertificate { PublicKey = crt, PrivateKey = pk, CAPublicKey = caCrt }); }
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); } } } }
static void RetrieveCertificates(AcmeClient client, string api, string domain, string certificatesFolder, int certBits) { var cp = CertificateProvider.GetProvider(); var rsaPkp = new RsaPrivateKeyParams() { NumBits = certBits }; var rsaKeys = cp.GeneratePrivateKey(rsaPkp); var csrParams = new CsrParams { Details = new CsrDetails { CommonName = domain } }; var derRaw = default(byte[]); var csr = cp.GenerateCsr(csrParams, rsaKeys, Crt.MessageDigest.SHA256); using (var bs = new MemoryStream()) { cp.ExportCsr(csr, EncodingFormat.DER, bs); derRaw = bs.ToArray(); } var derB64U = JwsHelper.Base64UrlEncode(derRaw); var certRequ = client.RequestCertificate(derB64U); if (certRequ.StatusCode == HttpStatusCode.Created) { GenerateCertFiles(cp, rsaKeys, csr, certRequ, certificatesFolder, domain); } }
public async Task TestEndToEndGoDaddy() { var dnsProvider = new GoDaddyDnsProviderTest().DnsService; var manager = new AcmeClient(dnsProvider, new DnsLookupService(), new NullCertificateStore()); var dnsRequest = new AcmeDnsRequest() { Host = "*.Ã¥bningstider.info", PFXPassword = "******", RegistrationEmail = "*****@*****.**", AcmeEnvironment = new LetsEncryptStagingV2(), CsrInfo = new CsrInfo() { CountryName = "DK", Locality = "Copenhagen", Organization = "Sjkp", OrganizationUnit = "", State = "DK" } }; var res = await manager.RequestDnsChallengeCertificate(dnsRequest); Assert.IsNotNull(res); File.WriteAllBytes($"{dnsRequest.Host.Substring(2)}.pfx", res.CertificateInfo.PfxCertificate); var certService = new AzureWebAppService(new[] { TestHelper.AzureWebAppSettings }); await certService.Install(res); }
public async Task Should_POST_to_get_registration_details_if_the_registration_already_exists() { // Arrange var http = new FakeHttpMessageHandler("http://baseaddress/"); var directory = new Directory { NewRegistration = new Uri("http://baseaddress/registration") }; var registration = new RegistrationResponse(); var client = http.RequestTo("directory").Returns(directory).WithNonce("nonce"). RequestTo("registration").Returns(new Problem(), "application/problem+json").HasStatusCode(HttpStatusCode.Conflict).WithHeader("Location", "http://baseaddress/existingreguri").WithNonce("nonce"). RequestTo("existingreguri").Returns(registration).WithNonce("nonce"). GetHttpClient(); var sut = new AcmeClient(client, new RSACryptoServiceProvider()); // Act var registrationResponse = await sut.RegisterAsync("agreementUri", new[] { "mailto:[email protected]" }); // Assert registrationResponse.Should().NotBeNull(); http.ReceivedRequestsTo("directory").Single().HasMethod(HttpMethod.Get); http.ReceivedRequestsTo("registration").Single().HasMethod(HttpMethod.Post).HasJwsPayload <NewRegistrationRequest>(r => { r.Agreement.Should().Be("agreementUri"); r.Contact.Should().Contain("mailto:[email protected]"); }); http.ReceivedRequestsTo("existingreguri").Single().HasMethod(HttpMethod.Post).HasJwsPayload <UpdateRegistrationRequest>(r => { r.Agreement.Should().BeNull(); r.Contact.Should().BeNull(); }); }
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); }
public App(AcmeClient acmeClient, ICertificateStore certificateStore, AzureWebAppService azureWebAppService, ILogger <App> logger = null) { this.acmeClient = acmeClient; this.certificateStore = certificateStore; this.azureWebAppService = azureWebAppService; this.logger = logger ?? NullLogger <App> .Instance; }
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); }
public static void Init(VaultConfig config, AcmeClient client) { client.Init(); if (config.GetInitialDirectory) client.GetDirectory(config.UseRelativeInitialDirectory); }
private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // dispose managed state (managed objects). if (_Client != null) { _Client.Dispose(); _Client = null; } if (_Signer != null) { _Signer.Dispose(); _Signer = null; } } // free unmanaged resources (unmanaged objects) and override a finalizer below. // set large fields to null. disposedValue = true; } }
public async Task AccountCreation() { var acmeClient = new AcmeClient(EnviromentUri); var account = await acmeClient.CreateNewAccountAsync(ContactEmail); Assert.IsNotNull(account); }
private async void loadToolStripMenuItem_Click(object sender, EventArgs e) { var account = cmbAccounts.SelectedItem as Account; if (account == null) { log.Error("not account."); await Task.FromResult(0); return; } RS256Signer signer = null; AcmeClient client = null; try { signer = account.Signer; client = new AcmeClient(new Uri(account.uri), new AcmeServerDirectory(), signer); client.Init(); log.Info("\nGetting AcmeServerDirectory"); client.GetDirectory(true); client.Registration = account.Registration; this.client = client; this.account = account; log.Info("load done."); labInfo.Text = account.ToString(); btnRefreshDomains.PerformClick(); } catch (Exception ex) { if (client != null) { client.Dispose(); client = null; } if (signer != null) { signer.Dispose(); signer = null; } var acmeWebException = ex as AcmeClient.AcmeWebException; if (acmeWebException != null) { log.Error(acmeWebException.Message); log.Error("ACME Server Returned:"); log.Error(acmeWebException.Response.ContentAsString); } else { log.Error(ex); } } }
public CertificateService(Options options, ILogService log, AcmeClient client, string configPath) { _log = log; _options = options; _client = client; _configPath = configPath; InitCertificatePath(); }
public void TestCleanup() { if (this.client != null) { this.client.Dispose(); this.client = null; } }
public AcmeContext(Uri serverAddress) { if (serverAddress == null) { throw new ArgumentNullException(nameof(serverAddress)); } this.client = new AcmeClient(serverAddress); }
public DefaultPlugin(ILogger logger, IAcmeClientService acmeClientService, AcmeClient acmeClient, ICertificateService certificateService) { _logger = logger; _acmeClientService = acmeClientService; _acmeClient = acmeClient; _certificateService = certificateService; }
public static AcmeRegistration CreateNew(AcmeClient client, string contactEmail) { var contacts = new[] { "mailto:" + contactEmail }; var registration = client.Register(contacts); client.UpdateRegistration(true, true); return(registration); }
public static void Init(VaultInfo config, AcmeClient client) { client.Init(); if (config.GetInitialDirectory) { client.GetDirectory(config.UseRelativeInitialDirectory); } }
static Tuple <AuthorizeChallenge, AuthorizationState> RequestChallengeFile( AcmeClient client, string domain) { var state = client.AuthorizeIdentifier(domain); var challenge = client.DecodeChallenge(state, AcmeProtocol.CHALLENGE_TYPE_HTTP); var httpChallenge = challenge.Challenge as HttpChallenge; return(new Tuple <AuthorizeChallenge, AuthorizationState>(challenge, state)); }
public CertificateFactory(IOptions <LetsEncryptOptions> options, IHttpChallengeResponseStore challengeStore, ILogger logger) { _options = options; _challengeStore = challengeStore; _logger = logger; _client = new AcmeClient(_options.Value.AcmeServer); }
public async Task Init(string email, CancellationToken token = default(CancellationToken)) { _accountKey = new RSACryptoServiceProvider(4096); if (File.Exists(_path)) { bool success; try { lock (Locker) { _cache = JsonConvert.DeserializeObject <RegistrationCache>(File.ReadAllText(_path)); } _accountKey.ImportCspBlob(_cache.AccountKey); success = true; } catch { success = false; // if we failed for any reason, we'll just // generate a new registration } if (success) { _client = new AcmeClient(GetCachedClient(_url), _accountKey); return; } } // need to generate new account _client = new AcmeClient(new HttpClient { BaseAddress = new Uri(_url) }, _accountKey); var registration = await _client.RegisterAsync(new NewRegistrationRequest { Contact = new[] { "mailto:" + email } }, token); lock (Locker) { _cache = new RegistrationCache { Location = registration.Location, Id = registration.Id, Key = registration.Key, AccountKey = _accountKey.ExportCspBlob(true) }; File.WriteAllText(_path, JsonConvert.SerializeObject(_cache, Formatting.Indented)); } }
public static void Authorize(AcmeClient client, IDnsProvider dnsProvider, string hostName, List <string> alternativeNames = null) { var dnsIdentifiers = new List <string>() { hostName }; if (alternativeNames != null) { dnsIdentifiers.AddRange(alternativeNames); } var authResults = new List <AuthorizationState>(); foreach (var dnsIdentifier in dnsIdentifiers) { var authzState = client.AuthorizeIdentifier(dnsIdentifier); var challenge = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS); var dnsChallenge = challenge.Challenge as DnsChallenge; var dnsRecordRef = AddRecordToDNS(dnsProvider, dnsChallenge); Thread.Sleep(3 * 1000); // wait for the newly created TXT record to take effect try { authzState.Challenges = new AuthorizeChallenge[] { challenge }; client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS, true); // have to loop to wait for server to stop being pending. // todo: put timeout/retry limit in this loop while (authzState.Status == "pending") { Thread.Sleep(3 * 1000); // this has to be here to give ACME server a chance to think var newAuthzState = client.RefreshIdentifierAuthorization(authzState); if (newAuthzState.Status != "pending") { authzState = newAuthzState; } } authResults.Add(authzState); } finally { if (!string.IsNullOrEmpty(dnsRecordRef)) { dnsProvider.RemoveTxtRecord(dnsRecordRef); } } } if (authResults.Any(result => result.Status != "valid")) { throw new AuthorizationFailedException(authResults); } }
// [Fact] public async Task D() { var privateKey = RSA.Create(RSAPrivateKey.Decode(TestData.PrivateRSA256KeyText)); var client = new AcmeClient(privateKey, directoryUrl: "https://acme-staging-v02.api.letsencrypt.org/directory"); var accountUrl = await client.GetAccountUrlAsync(); throw new Exception(JsonObject.FromObject(new { accountUrl }).ToString()); }
public async Task ExecAsync() { var configBuilder = new ConfigurationBuilder(); if (_options.AzureKeyVaultUrl != null) { configBuilder.AddAzureKeyVault(_options.AzureKeyVaultUrl); } var config = configBuilder.Build(); _services.AddLogging((builder => { builder.AddConsole(); })); _services.AddSingleton <IConfiguration>(config); switch (_options.StorageType) { case StorageType.AzureBlob: SetupAzureBlobStore(); break; case StorageType.LocalFs: SetupLocalFsStore(); break; default: throw new ArgumentException($"Invalid storage type {_options.StorageType}"); } _services.AddSingleton <IAccountStore, FileSystemAccountStore>(); _services.AddSingleton <IChallengeStore, FileSystemChallengeStore>(); _services.AddSingleton <ICertStore, FileSystemCertStore>(); _services.AddSingleton <ICertReader, FileSystemCertStore>(); _services.AddSingleton <IClientStateStore, DelegatedClientStateStore>(); _services.AddSingleton((provider) => { var client = new AcmeClient(_options.CaUrl, CreateLogger <AcmeClient>(provider)); client.InitAsync().Wait(); return(client); }); _services.AddSingleton((provider) => new AcmeOptions { AcceptTermsOfService = true, AccountContactEmails = _options.AccountContactEmails, DnsNames = _options.DnsNames, CertificateKeyAlgor = "rsa" }); _services.AddSingleton <ACMEWorker>(); var serviceProvider = _services.BuildServiceProvider(); var worker = serviceProvider.GetService(typeof(ACMEWorker)) as ACMEWorker; await worker.WorkAsync(); await serviceProvider.DisposeAsync(); }
private bool TryLoad(bool force = false) { if (force == false && this.client != null) { return(true); } RS256Signer signer = null; AcmeClient client = null; try { signer = account.Signer; client = new AcmeClient(new Uri(account.uri), new AcmeServerDirectory(), signer); client.Init(); log.Info("\nGetting AcmeServerDirectory"); client.GetDirectory(true); client.Registration = account.Registration; this.client = client; log.Info("load done."); labInfo.Text = account.ToString(); // return(true); } catch (Exception ex) { if (client != null) { client.Dispose(); client = null; } if (signer != null) { signer.Dispose(); signer = null; } var acmeWebException = ex as AcmeClient.AcmeWebException; if (acmeWebException != null) { log.Error(acmeWebException.Message); log.Error("ACME Server Returned:"); log.Error(acmeWebException.Response.ContentAsString); } else { log.Error(ex); } } return(false); }
public async Task Run() { // Create client alias core object + specify which environment you want to use var acmeClient = new AcmeClient(EnviromentUri); // Create new Account var account = await acmeClient.CreateNewAccountAsync(ContactEmail); // Create new Order var order = await acmeClient.NewOrderAsync(account, Identifiers); // Create DNS challenge (DNS is required for wildcard certificate) var challenges = await acmeClient.GetDnsChallenges(account, order); // Creation of all DNS entries foreach (var challenge in challenges) { var dnsKey = challenge.VerificationKey; var dnsText = challenge.VerificationValue; // value can be e.g.: eBAdFvukOz4Qq8nIVFPmNrMKPNlO8D1cr9bl8VFFsJM // Create DNS TXT record e.g.: // key: _acme-challenge.your.domain.com // value: eBAdFvukOz4Qq8nIVFPmNrMKPNlO8D1cr9bl8VFFsJM } // Validation of all DNS entries foreach (var challenge in challenges) { await acmeClient.ValidateChallengeAsync(account, challenge); // Verify status of challenge var freshChallenge = await acmeClient.GetChallengeAsync(account, challenge); if (freshChallenge.Status == ChallengeStatus.Invalid) { throw new Exception("Something is wrong with your DNS TXT record(s)!"); } } // Generate certificate var certificate = await acmeClient.GenerateCertificateAsync(account, order, "Suppo.biz"); // Save files locally var password = "******"; await LocalFileHandler.WriteAsync("Suppo.biz.pfx", certificate.GeneratePfx(password)); await LocalFileHandler.WriteAsync("Suppo.biz.crt", certificate.GenerateCrt(password)); await LocalFileHandler.WriteAsync("Suppo.biz.crt.pem", certificate.GenerateCrtPem(password)); await LocalFileHandler.WriteAsync("Suppo.biz.key.pem", certificate.GenerateKeyPem()); Assert.Pass(); }
public static AcmeClient GetClient(VaultConfig Config) { var p = Config.Proxy; var _Client = new AcmeClient(); _Client.RootUrl = new Uri(Config.BaseURI); _Client.Directory = Config.ServerDirectory; if (Config.Proxy != null) _Client.Proxy = Config.Proxy.GetWebProxy(); return _Client; }
public override async Task Context() { RestClient = A.Fake<IRestClient>(); A.CallTo( () => RestClient.RequestJson("https://acme-staging.api.letsencrypt.org/directory", HttpMethod.Get, null, null)) .Returns(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(DirectoryJson), Headers = {{"Replay-Nonce", "noncey"}} }); ClassUnderTest = new AcmeClient(RestClient, new JwsBuilder(), "https://acme-staging.api.letsencrypt.org/directory"); }
public async Task Should_get_a_Directory_object_from_the_default_endpoint() { // Arrange var http = new FakeHttpMessageHandler("http://baseaddress/"); var directory = new Directory(); var client = http.RequestTo("directory").Returns(directory).WithNonce("nonce") .GetHttpClient(); var sut = new AcmeClient(client, new RSACryptoServiceProvider()); // Act var discoverResponse = await sut.DiscoverAsync(); // Assert discoverResponse.Should().NotBeNull(); }
static void Main(string[] args) { var commandLineParseResult = Parser.Default.ParseArguments<Options>(args); var parsed = commandLineParseResult as Parsed<Options>; if (parsed == null) { #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif return; // not parsed } Options = parsed.Value; Console.WriteLine("Let's Encrypt (Simple Windows ACME Client)"); BaseURI = Options.BaseURI; if (Options.Test) BaseURI = "https://acme-staging.api.letsencrypt.org/"; //Console.Write("\nUse production Let's Encrypt server? (Y/N) "); //if (PromptYesNo()) // BaseURI = ProductionBaseURI; Console.WriteLine($"\nACME Server: {BaseURI}"); settings = new Settings(clientName, BaseURI); configPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), clientName, CleanFileName(BaseURI)); Console.WriteLine("Config Folder: " + configPath); Directory.CreateDirectory(configPath); try { using (var signer = new RS256Signer()) { signer.Init(); var signerPath = Path.Combine(configPath, "Signer"); if (File.Exists(signerPath)) { Console.WriteLine($"Loading Signer from {signerPath}"); using (var signerStream = File.OpenRead(signerPath)) signer.Load(signerStream); } using (client = new AcmeClient(new Uri(BaseURI), new AcmeServerDirectory(), signer)) { client.Init(); Console.WriteLine("\nGetting AcmeServerDirectory"); client.GetDirectory(true); var registrationPath = Path.Combine(configPath, "Registration"); if (File.Exists(registrationPath)) { Console.WriteLine($"Loading Registration from {registrationPath}"); using (var registrationStream = File.OpenRead(registrationPath)) client.Registration = AcmeRegistration.Load(registrationStream); } else { Console.WriteLine("Calling Register"); var registration = client.Register(new string[] { }); if (!Options.AcceptTOS && !Options.Renew) { Console.WriteLine($"Do you agree to {registration.TosLinkUri}? (Y/N) "); if (!PromptYesNo()) return; } Console.WriteLine("Updating Registration"); client.UpdateRegistration(true, true); Console.WriteLine("Saving Registration"); using (var registrationStream = File.OpenWrite(registrationPath)) client.Registration.Save(registrationStream); Console.WriteLine("Saving Signer"); using (var signerStream = File.OpenWrite(signerPath)) signer.Save(signerStream); } if (Options.Renew) { CheckRenewals(); #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif return; } var targets = new List<Target>(); foreach (var plugin in Target.Plugins.Values) { targets.AddRange(plugin.GetTargets()); } if (targets.Count == 0) { Console.WriteLine("No targets found."); } else { var count = 1; foreach (var binding in targets) { Console.WriteLine($" {count}: {binding}"); count++; } } Console.WriteLine(); foreach (var plugin in Target.Plugins.Values) { plugin.PrintMenu(); } Console.WriteLine(" A: Get certificates for all hosts"); Console.WriteLine(" Q: Quit"); Console.Write("Which host do you want to get a certificate for: "); var response = Console.ReadLine().ToLowerInvariant(); switch (response) { case "a": foreach (var target in targets) { Auto(target); } break; case "q": return; default: var targetId = 0; if (Int32.TryParse(response, out targetId)) { targetId--; if (targetId >= 0 && targetId < targets.Count) { var binding = targets[targetId]; Auto(binding); } } else { foreach (var plugin in Target.Plugins.Values) { plugin.HandleMenuResponse(response, targets); } } break; } } } } catch (Exception e) { Console.ForegroundColor = ConsoleColor.Red; var acmeWebException = e as AcmeClient.AcmeWebException; if (acmeWebException != null) { Console.WriteLine(acmeWebException.Message); Console.WriteLine("ACME Server Returned:"); Console.WriteLine(acmeWebException.Response.ContentAsString); } else { Console.WriteLine(e); } Console.ResetColor(); } #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif }
static void Main(string[] args) { var commandLineParseResult = Parser.Default.ParseArguments<Options>(args); var parsed = commandLineParseResult as Parsed<Options>; if (parsed == null) { #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif return; // not parsed } options = parsed.Value; Console.WriteLine("Let's Encrypt (Simple Windows ACME Client)"); BaseURI = options.BaseURI; if (options.Test) BaseURI = "https://acme-staging.api.letsencrypt.org/"; //Console.Write("\nUse production Let's Encrypt server? (Y/N) "); //if (PromptYesNo()) // BaseURI = ProductionBaseURI; Console.WriteLine($"\nACME Server: {BaseURI}"); settings = new Settings(clientName, BaseURI); configPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), clientName, CleanFileName(BaseURI)); Console.WriteLine("Config Folder: " + configPath); Directory.CreateDirectory(configPath); using (var signer = new RS256Signer()) { signer.Init(); var signerPath = Path.Combine(configPath, "Signer"); if (File.Exists(signerPath)) { Console.WriteLine($"Loading Signer from {signerPath}"); using (var signerStream = File.OpenRead(signerPath)) signer.Load(signerStream); } using (client = new AcmeClient(new Uri(BaseURI), new AcmeServerDirectory(), signer)) { client.Init(); Console.WriteLine("\nGetting AcmeServerDirectory"); client.GetDirectory(true); var registrationPath = Path.Combine(configPath, "Registration"); if (File.Exists(registrationPath)) { Console.WriteLine($"Loading Registration from {registrationPath}"); using (var registrationStream = File.OpenRead(registrationPath)) client.Registration = AcmeRegistration.Load(registrationStream); } else { Console.WriteLine("Calling Register"); var registration = client.Register(new string[] { }); if (!options.AcceptTOS && !options.Renew) { Console.WriteLine($"Do you agree to {registration.TosLinkUri}? (Y/N) "); if (!PromptYesNo()) return; } Console.WriteLine("Updating Registration"); client.UpdateRegistration(true, true); Console.WriteLine("Saving Registration"); using (var registrationStream = File.OpenWrite(registrationPath)) client.Registration.Save(registrationStream); Console.WriteLine("Saving Signer"); using (var signerStream = File.OpenWrite(signerPath)) signer.Save(signerStream); } if (options.Renew) { CheckRenewals(); #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif return; } Console.WriteLine("\nScanning IIS 7 Site Bindings for Hosts (Elevated Permissions Required)"); if (!IsElevated) { Console.WriteLine("Elevated Permissions Required. Please run under an administrator console."); #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif return; } var bindings = GetHostNames(); if (bindings.Count == 0) { Console.WriteLine("No IIS bindings with host names were found. Please add one using IIS Manager. A host name and site path are required to verify domain ownership."); return; } Console.WriteLine("IIS Bindings"); var count = 1; foreach (var binding in bindings) { Console.WriteLine($" {count}: {binding}"); count++; } Console.WriteLine(); Console.WriteLine(" A: Get Certificates for All Bindings"); Console.WriteLine(" Q: Quit"); Console.Write("Which binding do you want to get a cert for: "); var response = Console.ReadLine(); switch (response.ToLowerInvariant()) { case "a": foreach (var binding in bindings) { Auto(binding); } break; case "q": return; default: var bindingId = 0; if (Int32.TryParse(response, out bindingId)) { bindingId--; if (bindingId >= 0 && bindingId < bindings.Count) { var binding = bindings[bindingId]; Auto(binding); } } break; } } } #if DEBUG Console.WriteLine("Press enter to continue."); Console.ReadLine(); #endif }