コード例 #1
0
        internal async Task UpdateAccount(AcmeProtocolClient client)
        {
            var account = await Retry(client, () => client.CheckAccountAsync());

            _accountManager.CurrentAccount = account;
            client.Account = account;
        }
コード例 #2
0
        public async Task <AcmeProtocolClient> CreateClientAsync()
        {
            var account    = LoadState <AccountDetails>("account.json");
            var accountKey = LoadState <AccountKey>("account_key.json");
            var directory  = LoadState <ServiceDirectory>("directory.json");

            var acmeProtocolClient = new AcmeProtocolClient(_acmeEndpoint, directory, account, accountKey?.GenerateSigner());

            if (directory == null)
            {
                directory = await acmeProtocolClient.GetDirectoryAsync();

                acmeProtocolClient.Directory = directory;
            }

            await acmeProtocolClient.GetNonceAsync();

            if (acmeProtocolClient.Account == null)
            {
                account = await acmeProtocolClient.CreateAccountAsync(new[] { "mailto:" + Settings.Default.Contacts }, true);

                accountKey = new AccountKey
                {
                    KeyType   = acmeProtocolClient.Signer.JwsAlg,
                    KeyExport = acmeProtocolClient.Signer.Export()
                };

                SaveState(account, "account.json");
                SaveState(accountKey, "account_key.json");

                acmeProtocolClient.Account = account;
            }

            return(acmeProtocolClient);
        }
コード例 #3
0
ファイル: AcmeClient.cs プロジェクト: skyhoshi/win-acme
        /// <summary>
        /// Load the account, signer and directory
        /// </summary>
        /// <returns></returns>
        internal async Task ConfigureAcmeClient()
        {
            var httpClient = _proxyService.GetHttpClient();

            httpClient.BaseAddress = _settings.BaseUri;
            _log.Verbose("Constructing ACME protocol client...");
            var client = new AcmeProtocolClient(httpClient, usePostAsGet: _settings.Acme.PostAsGet);

            client.Directory = await EnsureServiceDirectory(client);

            // Try to load prexisting account
            if (_accountManager.CurrentAccount != null &&
                _accountManager.CurrentSigner != null)
            {
                _log.Verbose("Using existing ACME account");
                await client.ChangeAccountKeyAsync(_accountManager.CurrentSigner.JwsTool());

                client.Account = _accountManager.CurrentAccount;
            }
            else
            {
                _log.Verbose("No account found, creating new one");
                await SetupAccount(client);
            }
            if (client.Account == null)
            {
                throw new Exception("AcmeClient was unable to find or create an account");
            }
            _client = client;
            _log.Verbose("ACME client initialized");
        }
コード例 #4
0
        protected async Task <bool> ResolveAccount(AcmeProtocolClient acme)
        {
            // TODO:  All this ASSUMES a fixed key type/size for now
            if (_state.Account == null || _state.AccountKey == null)
            {
                var contacts = _options.AccountContactEmails.Select(x => $"mailto:{x}");
                _logger.LogInformation("Creating ACME Account");
                _state.Account = await acme.CreateAccountAsync(
                    contacts : contacts,
                    termsOfServiceAgreed : _options.AcceptTermsOfService);

                _state.AccountKey = new ExamplesAccountKey
                {
                    KeyType   = acme.Signer.JwsAlg,
                    KeyExport = acme.Signer.Export(),
                };
                Save(_state.AccountFile, _state.Account);
                Save(_state.AccountKeyFile, _state.AccountKey);
                acme.Account = _state.Account;
            }
            else
            {
                acme.Account = _state.Account;
                acme.Signer.Import(_state.AccountKey.KeyExport);
            }

            return(true);
        }
コード例 #5
0
ファイル: AcmeClient.cs プロジェクト: skyhoshi/win-acme
        /// <summary>
        /// Make sure that we find a service directory
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        internal async Task <acme.ServiceDirectory> EnsureServiceDirectory(AcmeProtocolClient client)
        {
            acme.ServiceDirectory?directory;
            try
            {
                _log.Verbose("Getting service directory...");
                directory = await Backoff(async() => await client.GetDirectoryAsync("directory"));

                if (directory != null)
                {
                    return(directory);
                }
            }
            catch
            {
            }
            // Perhaps the BaseUri *is* the directory, such
            // as implemented by Digicert (#1434)
            directory = await Backoff(async() => await client.GetDirectoryAsync(""));

            if (directory != null)
            {
                return(directory);
            }
            throw new Exception("Unable to get service directory");
        }
コード例 #6
0
        public async Task <bool> InitProvider(ILog log = null, Certify.Models.AccountDetails account = null)
        {
            if (log != null)
            {
                _log = log;
            }

            _loggingHandler = new LoggingHandler(new HttpClientHandler(), _log);
            var customHttpClient = new System.Net.Http.HttpClient(_loggingHandler);

            customHttpClient.DefaultRequestHeaders.Add("User-Agent", _userAgentName);

            _httpClient = new HttpClient();

            await LoadSettings();

            _client           = new AcmeProtocolClient(_httpClient);
            _client.Directory = await _client.GetDirectoryAsync();

            if (_client.Account == null)
            {
                throw new Exception("AcmeClient was unable to find or create an account");
            }

            return(true);
        }
コード例 #7
0
ファイル: AcmeClient.cs プロジェクト: ZhHong/win-acme
        internal async Task ConfigureAcmeClient()
        {
            var httpClient = _proxyService.GetHttpClient();

            httpClient.BaseAddress = _settings.BaseUri;

            _log.Verbose("Loading ACME account signer...");
            IJwsTool signer        = null;
            var      accountSigner = AccountSigner;

            if (accountSigner != null)
            {
                signer = accountSigner.JwsTool();
            }

            _log.Verbose("Constructing ACME protocol client...");
            try
            {
                _client = new AcmeProtocolClient(
                    httpClient,
                    signer: signer,
                    usePostAsGet: _settings.Acme.PostAsGet);
            }
            catch (CryptographicException)
            {
                if (signer == null)
                {
                    // There has been a problem generate a signer for the
                    // new account, possibly because some EC curve is not
                    // on available on the system? So we give it another
                    // shot with a less fancy RSA signer
                    _log.Verbose("First chance error generating new signer, retrying with RSA instead of ECC");
                    signer = new RSJwsTool
                    {
                        KeySize = _settings.Security.RSAKeyBits
                    };
                    signer.Init();
                    _client = new AcmeProtocolClient(
                        httpClient,
                        signer: signer,
                        usePostAsGet: _settings.Acme.PostAsGet);
                }
                else
                {
                    throw;
                }
            }
            _client.BeforeHttpSend = (x, r) => _log.Debug("Send {method} request to {uri}", r.Method, r.RequestUri);
            _client.AfterHttpSend  = (x, r) => _log.Verbose("Request completed with status {s}", r.StatusCode);
            _client.Directory      = await _client.GetDirectoryAsync();

            await _client.GetNonceAsync();

            _client.Account = await LoadAccount(signer);

            if (_client.Account == null)
            {
                throw new Exception("AcmeClient was unable to find or create an account");
            }
        }
コード例 #8
0
ファイル: AcmeClient.cs プロジェクト: skyhoshi/win-acme
        /// <summary>
        /// Attempt to create an account using specific parameters
        /// </summary>
        /// <param name="client"></param>
        /// <param name="signer"></param>
        /// <param name="contacts"></param>
        /// <param name="eabAlg"></param>
        /// <param name="eabKid"></param>
        /// <param name="eabKey"></param>
        /// <returns></returns>
        private async Task CreateAccount(
            AcmeProtocolClient client, AccountSigner signer,
            string[]?contacts,
            string eabAlg, string?eabKid, string?eabKey)
        {
            if (client.Account != null)
            {
                throw new Exception("Client already has an account!");
            }
            ExternalAccountBinding?externalAccount = null;

            if (!string.IsNullOrWhiteSpace(eabKey) &&
                !string.IsNullOrWhiteSpace(eabKid))
            {
                externalAccount = new ExternalAccountBinding(
                    eabAlg,
                    JsonConvert.SerializeObject(
                        signer.JwsTool().ExportJwk(),
                        Formatting.None),
                    eabKid,
                    eabKey,
                    client.Directory?.NewAccount ?? "");
            }
            await client.ChangeAccountKeyAsync(signer.JwsTool());

            client.Account = await Retry(client,
                                         () => client.CreateAccountAsync(
                                             contacts,
                                             termsOfServiceAgreed: true,
                                             externalAccountBinding: externalAccount?.Payload() ?? null));

            _accountManager.CurrentSigner  = signer;
            _accountManager.CurrentAccount = client.Account;
        }
コード例 #9
0
        public async Task GetAuthzWildcard()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                var signer = new Crypto.JOSE.Impl.RSJwsTool();
                signer.Init();
                using (var acme = new AcmeProtocolClient(http, dir,
                                                         signer: signer))
                {
                    await acme.GetNonceAsync();

                    var acct = await acme.CreateAccountAsync(new[] { "mailto:[email protected]" });

                    acme.Account = acct;

                    var dnsIds = new[] { "*.mock.acme2.zyborg.io" };
                    var order  = await acme.CreateOrderAsync(dnsIds);

                    Assert.IsNotNull(order?.OrderUrl);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Authorizations?.Length);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Identifiers?.Length);

                    var authz = await acme.GetAuthorizationDetailsAsync(
                        order.Payload.Authorizations[0]);

                    Assert.IsNotNull(authz);
                    Assert.IsTrue(authz.Wildcard ?? false);
                    Assert.AreEqual(dnsIds[0], authz.Identifier.Value);
                }
            }
        }
コード例 #10
0
        public async Task NewNonce()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                var requ = new HttpRequestMessage(
                    HttpMethod.Head, dir.NewNonce);
                var resp = await http.SendAsync(requ);

                resp.EnsureSuccessStatusCode();

                Assert.AreEqual(HttpStatusCode.NoContent, resp.StatusCode);
                Assert.IsTrue(resp.Headers.Contains(Constants.ReplayNonceHeaderName),
                              "contains nonce response header");

                using (var acme = new AcmeProtocolClient(http, dir))
                {
                    Assert.IsNull(acme.NextNonce);
                    await acme.GetNonceAsync();

                    Assert.IsNotNull(acme.NextNonce);
                }
            }
        }
コード例 #11
0
        private async void refreshAccountButton_Click(object sender, EventArgs e)
        {
            var url = ResolveCaServerEndpoint();

            if (url == null)
            {
                return;
            }

            await InvokeWithWaitCursor(async() =>
            {
                var signer = new PkiJwsTool(256);
                signer.Import(_account.JwsSigner);

                using (var acme = new AcmeProtocolClient(url, signer: signer,
                                                         acct: _account.Details))
                {
                    var dir        = await acme.GetDirectoryAsync();
                    acme.Directory = dir;

                    await acme.GetNonceAsync();

                    var details      = await acme.UpdateAccountAsync();
                    _account.Details = details;
                    Repo.SaveAccount(_account);
                }
                RebindAccountControls();
                SetStatus("Account refreshed and saved");
            });
        }
コード例 #12
0
        public async Task NewOrder()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                var signer = new Crypto.JOSE.Impl.RSJwsTool();
                signer.Init();
                using (var acme = new AcmeProtocolClient(http, dir,
                                                         signer: signer))
                {
                    await acme.GetNonceAsync();

                    var acct = await acme.CreateAccountAsync(new[] { "mailto:[email protected]" });

                    acme.Account = acct;

                    var dnsIds = new[] { "foo.mock.acme2.zyborg.io" };
                    var order  = await acme.CreateOrderAsync(dnsIds);

                    Assert.IsNotNull(order?.OrderUrl);

                    var order2 = await acme.GetOrderDetailsAsync(order.OrderUrl);

                    Assert.AreEqual(order?.Payload?.Finalize, order2?.Payload?.Finalize);
                }
            }
        }
コード例 #13
0
        public async Task <AcmeProtocolClient> CreateClientAsync()
        {
            var account = await LoadStateAsync <AccountDetails>(ACME_ACCOUNT_NAME);

            var accountKey = await LoadStateAsync <AccountKey>(ACME_ACCOUNT_KEY_NAME);

            var acmeProtocolClient = new AcmeProtocolClient(_acmeEndpoint, null, account, accountKey?.GenerateSigner());

            var directory = await acmeProtocolClient.GetDirectoryAsync();

            acmeProtocolClient.Directory = directory;

            await acmeProtocolClient.GetNonceAsync();

            if (acmeProtocolClient.Account == null)
            {
                account = await acmeProtocolClient.CreateAccountAsync(new[] { "mailto:" + _configuration.AcmeAccountEmail }, true);

                acmeProtocolClient.Account = account;

                accountKey = new AccountKey
                {
                    KeyType   = acmeProtocolClient.Signer.JwsAlg,
                    KeyExport = acmeProtocolClient.Signer.Export()
                };

                await SaveStateAsync(ACME_ACCOUNT_NAME, account);
                await SaveStateAsync(ACME_ACCOUNT_KEY_NAME, accountKey);
            }

            return(acmeProtocolClient);
        }
コード例 #14
0
        public async Task <AcmeProtocolClient> CreateClientAsync()
        {
            var account    = LoadState <AccountDetails>("account.json");
            var accountKey = LoadState <AccountKey>("account_key.json");
            var directory  = LoadState <ServiceDirectory>("directory.json");

            var acmeProtocolClient = new AcmeProtocolClient(_baseUri, directory, account, accountKey?.GenerateSigner(), usePostAsGet: true);

            if (directory == null)
            {
                try
                {
                    directory = await acmeProtocolClient.GetDirectoryAsync();
                }
                catch (AcmeProtocolException)
                {
                    acmeProtocolClient.Directory.Directory = "";

                    directory = await acmeProtocolClient.GetDirectoryAsync();
                }

                SaveState(directory, "directory.json");

                acmeProtocolClient.Directory = directory;
            }

            await acmeProtocolClient.GetNonceAsync();

            if (acmeProtocolClient.Account == null)
            {
                var externalAccountBinding = directory.Meta.ExternalAccountRequired ?? false?CreateExternalAccountBinding(acmeProtocolClient) : null;

                account = await acmeProtocolClient.CreateAccountAsync(new[] { $"mailto:{_options.Contacts}" }, true, externalAccountBinding);

                accountKey = new AccountKey
                {
                    KeyType   = acmeProtocolClient.Signer.JwsAlg,
                    KeyExport = acmeProtocolClient.Signer.Export()
                };

                SaveState(account, "account.json");
                SaveState(accountKey, "account_key.json");

                acmeProtocolClient.Account = account;
            }

            if (acmeProtocolClient.Account.Payload.Contact[0] != $"mailto:{_options.Contacts}")
            {
                account = await acmeProtocolClient.UpdateAccountAsync(new[] { $"mailto:{_options.Contacts}" });

                SaveState(account, "account.json");

                acmeProtocolClient.Account = account;
            }

            return(acmeProtocolClient);
        }
コード例 #15
0
        protected async Task <bool> ResolveChallenges(AcmeProtocolClient acme)
        {
            if (AcmeState.PendingStatus == _state.Order?.Payload?.Status)
            {
                _logger.LogInformation("Order is pending, resolving Authorizations");
                if (_state.Authorizations == null)
                {
                    _state.Authorizations = new Dictionary <string, Authorization>();
                }
                foreach (var authzUrl in _state.Order.Payload.Authorizations)
                {
                    var authz = await acme.GetAuthorizationDetailsAsync(authzUrl);

                    _state.Authorizations[authzUrl] = authz;

                    if (AcmeState.PendingStatus == authz.Status)
                    {
                        foreach (var chlng in authz.Challenges)
                        {
                            if (string.IsNullOrEmpty(_options.ChallengeType) ||
                                _options.ChallengeType == chlng.Type)
                            {
                                var chlngValidation = AuthorizationDecoder.DecodeChallengeValidation(
                                    authz, chlng.Type, acme.Signer);
                                if (_options.ChallengeHandler(_services, chlngValidation))
                                {
                                    _logger.LogInformation("Challenge Handler has handled challenge:");
                                    _logger.LogInformation(JsonConvert.SerializeObject(chlngValidation, Formatting.Indented));
                                    var chlngUpdated = await acme.AnswerChallengeAsync(chlng.Url);

                                    if (chlngUpdated.Error != null)
                                    {
                                        _logger.LogError("Submitting Challenge Answer reported an error:");
                                        _logger.LogError(JsonConvert.SerializeObject(chlngUpdated.Error));
                                    }
                                }

                                _logger.LogInformation("Refreshing Authorization status");
                                authz = await acme.GetAuthorizationDetailsAsync(authzUrl);

                                if (AcmeState.PendingStatus != authz.Status)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
                Save(_state.AuthorizationsFile, _state.Authorizations);

                _logger.LogInformation("Refreshing Order status");
                _state.Order = await acme.GetOrderDetailsAsync(_state.Order.OrderUrl, _state.Order);

                Save(_state.OrderFile, _state.Order);
            }
            return(true);
        }
コード例 #16
0
 public AddCertificateFunctions(IHttpClientFactory httpClientFactory, CertbotConfiguration configuration, LookupClient lookupClient, KeyVaultClient keyVaultClient, IAzure azure, BlobContainerClient blobContainerClient, IAcmeProtocolClientFactory acmeProtocolClientFactory)
 {
     _httpClientFactory   = httpClientFactory;
     _configuration       = configuration;
     _lookupClient        = lookupClient;
     _keyVaultClient      = keyVaultClient;
     _azure               = azure;
     _blobContainerClient = blobContainerClient;
     _acmeProtocolClient  = acmeProtocolClientFactory.CreateClientAsync().Result;
 }
コード例 #17
0
        private async void createAccountButton_Click(object sender, EventArgs e)
        {
            if (!agreeTosCheckbox.Checked)
            {
                MessageBox.Show("You must agree to the Terms of Service.", "Terms of Service",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            var url = ResolveCaServerEndpoint();

            if (url == null)
            {
                return;
            }

            var contacts = ResolveEmailContacts();

            if (contacts == null)
            {
                return;
            }

            await InvokeWithWaitCursor(async() =>
            {
                var signer = new PkiJwsTool(256);
                signer.Init();

                using (var acme = new AcmeProtocolClient(url, signer: signer))
                {
                    var dir        = await acme.GetDirectoryAsync();
                    acme.Directory = dir;

                    await acme.GetNonceAsync();

                    var details = await acme.CreateAccountAsync(
                        contacts,
                        agreeTosCheckbox.Checked,
                        throwOnExistingAccount: true);

                    var acct = new DbAccount
                    {
                        AcmeServerEndpoint = url.ToString(),
                        JwsSigner          = signer.Export(),
                        Details            = details,
                    };
                    Repo.SaveAccount(acct);
                    _account = acct;
                }
                RebindAccountControls();
                SetStatus("Account created and saved");
            });
        }
コード例 #18
0
        private async void submitDnsAnswerButton_Click(object sender, EventArgs e)
        {
            var url = ResolveCaServerEndpoint();

            if (url == null)
            {
                return;
            }

            await InvokeWithWaitCursor(async() =>
            {
                var signer = new PkiJwsTool(256);
                signer.Import(_account.JwsSigner);

                using (var acme = new AcmeProtocolClient(url, signer: signer,
                                                         acct: _account.Details))
                {
                    var dir        = await acme.GetDirectoryAsync();
                    acme.Directory = dir;

                    await acme.GetNonceAsync();

                    var dnsChallenge = SelectedAuthorization.Details.Challenges.First(
                        x => x.Type == Dns01ChallengeValidationDetails.Dns01ChallengeType);

                    var updatedDnsChallenge = await acme.AnswerChallengeAsync(dnsChallenge.Url);
                    var details             = await acme.GetOrderDetailsAsync(
                        _lastOrder.Details.OrderUrl ?? _lastOrder.FirstOrderUrl);
                    _lastOrder.Details = details;
                    Repo.Saveorder(_lastOrder);

                    RebindOrderControls();
                    SetStatus("DNS Challenge Answered; Order refreshed and saved");

                    await RefreshOrderAuthorizations(acme);
                }

                Repo.Saveorder(_lastOrder);
                RebindOrderControls();
                SetStatus("DNS Challenge Answered; Order details and Authorizations refreshed and saved");

                await DecodeOrderAuthorizationChallenges(signer);

                Repo.Saveorder(_lastOrder);
                RebindOrderControls();
                SetStatus("DNS Challenge Answered; Order details and Authorizations refreshed, Challenges decoded and saved");
            });
        }
コード例 #19
0
        protected async Task <bool> ResolveOrder(AcmeProtocolClient acme)
        {
            var now = DateTime.Now;

            if (!string.IsNullOrEmpty(_state.Order?.OrderUrl))
            {
                _logger.LogInformation("Existing Order found; refreshing");
                _state.Order = await acme.GetOrderDetailsAsync(
                    _state.Order.OrderUrl, _state.Order);
            }

            if (_state.Order?.Payload?.Error != null)
            {
                _logger.LogWarning("Existing Order reported an Error:");
                _logger.LogWarning(JsonConvert.SerializeObject(_state.Order.Payload.Error));
                _logger.LogWarning("Resetting existing order");
                _state.Order = null;
            }

            if (AcmeState.InvalidStatus == _state.Order?.Payload.Status)
            {
                _logger.LogInformation("Existing Order is INVALID; resetting");
                _state.Order = null;
            }

            if (!DateTime.TryParse(_state.Order?.Payload?.Expires, out var orderExpires) ||
                orderExpires < now)
            {
                _logger.LogInformation("Existing Order is EXPIRED; resetting");
                _state.Order = null;
            }

            if (DateTime.TryParse(_state.Order?.Payload?.NotAfter, out var orderNotAfter) &&
                orderNotAfter < now)
            {
                _logger.LogInformation("Existing Order is OUT-OF-DATE; resetting");
                _state.Order = null;
            }

            if (_state.Order?.Payload == null)
            {
                _logger.LogInformation("Creating NEW Order");
                _state.Order = await acme.CreateOrderAsync(_options.DnsNames);
            }

            Save(_state.OrderFile, _state.Order);
            return(true);
        }
コード例 #20
0
        private object CreateExternalAccountBinding(AcmeProtocolClient acmeProtocolClient)
        {
            byte[] HmacSignature(byte[] x)
            {
                var hmacKeyBytes = CryptoHelper.Base64.UrlDecode(_options.ExternalAccountBinding.HmacKey);

                var hmac = (HMAC)(_options.ExternalAccountBinding.Algorithm switch
                {
                    "HS256" => new HMACSHA256(hmacKeyBytes),
                    "HS384" => new HMACSHA384(hmacKeyBytes),
                    "HS512" => new HMACSHA512(hmacKeyBytes),
                    _ => throw new NotSupportedException($"The signature algorithm {_options.ExternalAccountBinding.Algorithm} is not supported.")
                });

                return(hmac.ComputeHash(x));
            }
コード例 #21
0
ファイル: AcmeClient.cs プロジェクト: ysunil702/win-acme
        private async Task <AccountDetails?> LoadAccount(AcmeProtocolClient client, IJwsTool?signer)
        {
            AccountDetails?account = null;

            if (File.Exists(AccountPath))
            {
                if (signer != null)
                {
                    _log.Debug("Loading account information from {registrationPath}", AccountPath);
                    account        = JsonConvert.DeserializeObject <AccountDetails>(File.ReadAllText(AccountPath));
                    client.Account = account;
                    // Maybe we should update the account details
                    // on every start of the program to figure out
                    // if it hasn't been suspended or cancelled?
                    // UpdateAccount();
                }
                else
                {
                    _log.Error("Account found but no valid signer could be loaded");
                }
            }
            else
            {
                var contacts = await GetContacts();

                var(_, filename, content) = await client.GetTermsOfServiceAsync();

                if (!string.IsNullOrEmpty(filename))
                {
                    if (!await AcceptTos(filename, content))
                    {
                        return(null);
                    }
                }
                account = await client.CreateAccountAsync(contacts, termsOfServiceAgreed : true);

                _log.Debug("Saving registration");
                var accountKey = new AccountSigner
                {
                    KeyType   = client.Signer.JwsAlg,
                    KeyExport = client.Signer.Export(),
                };
                AccountSigner = accountKey;
                File.WriteAllText(AccountPath, JsonConvert.SerializeObject(account));
            }
            return(account);
        }
コード例 #22
0
        public async Task NewAccount()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                using (var acme = new AcmeProtocolClient(http, dir))
                {
                    Assert.IsNull(acme.NextNonce);
                    await acme.GetNonceAsync();

                    Assert.IsNotNull(acme.NextNonce);

                    await acme.CreateAccountAsync(new[] { "*****@*****.**" });
                }
            }
        }
コード例 #23
0
        private async Task RefreshOrderAuthorizations(AcmeProtocolClient acme)
        {
            var details = _lastOrder.Details;
            var authzs  = new List <DbAuthz>();

            foreach (var authzUrl in details.Payload.Authorizations)
            {
                var authzDetails = await acme.GetAuthorizationDetailsAsync(authzUrl);

                authzs.Add(new DbAuthz
                {
                    Url     = authzUrl,
                    Details = authzDetails,
                });
            }
            _lastOrder.Authorizations = authzs.ToArray();
        }
コード例 #24
0
        public async Task GetAuthzMulti()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                var signer = new Crypto.JOSE.Impl.RSJwsTool();
                signer.Init();
                using (var acme = new AcmeProtocolClient(http, dir,
                                                         signer: signer))
                {
                    await acme.GetNonceAsync();

                    var acct = await acme.CreateAccountAsync(new[] { "mailto:[email protected]" });

                    acme.Account = acct;

                    var dnsIds = new[]
                    {
                        "foo1.mock.acme2.zyborg.io",
                        "foo2.mock.acme2.zyborg.io",
                        "foo3.mock.acme2.zyborg.io",
                    };
                    var order = await acme.CreateOrderAsync(dnsIds);

                    Assert.IsNotNull(order?.OrderUrl);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Authorizations?.Length);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Identifiers?.Length);

                    var dnsIdsList = new List <string>(dnsIds);
                    foreach (var authzUrl in order.Payload.Authorizations)
                    {
                        var authz = await acme.GetAuthorizationDetailsAsync(authzUrl);

                        Assert.IsNotNull(authz);
                        Assert.IsFalse(authz.Wildcard ?? false);
                        Assert.IsTrue(dnsIdsList.Remove(authz.Identifier.Value),
                                      "DNS Identifiers contains authz DNS Identifier");
                    }
                    Assert.AreEqual(0, dnsIdsList.Count);
                }
            }
        }
コード例 #25
0
        public async Task AnswerChallenge()
        {
            using (var http = _server.CreateClient())
            {
                var dir = await GetDir();

                var dnsIds = new[] { "foo.mock.acme2.zyborg.io" };

                var signer = new Crypto.JOSE.Impl.RSJwsTool();
                signer.Init();
                using (var acme = new AcmeProtocolClient(http, dir,
                                                         signer: signer))
                {
                    await acme.GetNonceAsync();

                    var acct = await acme.CreateAccountAsync(new[] { "mailto:[email protected]" });

                    acme.Account = acct;

                    var order = await acme.CreateOrderAsync(dnsIds);

                    Assert.IsNotNull(order?.OrderUrl);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Authorizations?.Length);
                    Assert.AreEqual(dnsIds.Length, order.Payload.Identifiers?.Length);

                    var authzUrl = order.Payload.Authorizations[0];
                    var authz    = await acme.GetAuthorizationDetailsAsync(authzUrl);

                    Assert.IsNotNull(authz);
                    Assert.IsFalse(authz.Wildcard ?? false);
                    Assert.AreEqual(dnsIds[0], authz.Identifier.Value);

                    foreach (var chlng in authz.Challenges)
                    {
                        var chlng2 = await acme.AnswerChallengeAsync(chlng.Url);

                        Assert.IsNotNull(chlng2);
                        Assert.AreEqual("valid", chlng2.Status);
                    }
                }
            }
        }
コード例 #26
0
ファイル: Program.cs プロジェクト: divinci/ACMESharpCore
        async Task GetTermsOfService()
        {
            var signer  = new ACMESharp.Crypto.JOSE.Impl.RSJwsTool();
            var acmeUrl = new Uri(Program.LetsEncryptV2StagingEndpoint);

            _http             = new HttpClient();
            _http.BaseAddress = acmeUrl;

            WriteLine("getting from: " + acmeUrl);

            using (var acme = new AcmeProtocolClient(_http, signer: signer))
            {
                acme.BeforeAcmeSign = (s, o) => WriteLine($"BEFORE({s}, {JsonConvert.SerializeObject(o)})");

                var dir = await acme.GetDirectoryAsync();

                WriteLine("Got Directory: " + dir);
                WriteLine("TOS: " + dir.Meta?.TermsOfService);
            }
        }
コード例 #27
0
ファイル: AcmeClient.cs プロジェクト: sujai-menni-tm/win-acme
        /// <summary>
        /// According to the ACME standard, we SHOULD retry calls
        /// if there is an invalid nonce. TODO: check for the proper
        /// exception feedback, now *any* failed request is retried
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="executor"></param>
        /// <returns></returns>
        private async Task <T> Retry <T>(AcmeProtocolClient client, Func <Task <T> > executor, int attempt = 0)
        {
            if (attempt == 0)
            {
                await _requestLock.WaitAsync();
            }
            try
            {
                if (string.IsNullOrEmpty(client.NextNonce))
                {
                    await client.GetNonceAsync();
                }
                return(await executor());
            }
            catch (AcmeProtocolException apex)
            {
                if (attempt < 3 && apex.ProblemType == ProblemType.BadNonce)
                {
                    _log.Warning("First chance error calling into ACME server, retrying with new nonce...");
                    await client.GetNonceAsync();

                    return(await Retry(client, executor, attempt + 1));
                }
                else if (apex.ProblemType == ProblemType.UserActionRequired)
                {
                    _log.Error("{detail}: {instance}", apex.ProblemDetail, apex.ProblemInstance);
                    throw;
                }
                else
                {
                    throw;
                }
            }
            finally
            {
                if (attempt == 0)
                {
                    _requestLock.Release();
                }
            }
        }
コード例 #28
0
ファイル: AcmeClient.cs プロジェクト: fbasar/win-acme
        private async Task <bool> ConfigureAcmeClient()
        {
            var httpClientHandler = new HttpClientHandler()
            {
                Proxy = _proxyService.GetWebProxy(),
            };
            var httpClient = new HttpClient(httpClientHandler)
            {
                BaseAddress = new Uri(_arguments.MainArguments.GetBaseUri())
            };

            _log.Verbose("Loading ACME account signer...");
            IJwsTool signer        = null;
            var      accountSigner = AccountSigner;

            if (accountSigner != null)
            {
                signer = accountSigner.JwsTool();
            }

            _log.Verbose("Constructing ACME protocol client...");
            _client = new AcmeProtocolClient(httpClient, signer: signer)
            {
                BeforeHttpSend = (x, r) =>
                {
                    _log.Debug("Send {method} request to {uri}", r.Method, r.RequestUri);
                },
            };

            _client.Directory = await _client.GetDirectoryAsync();

            await _client.GetNonceAsync();

            _client.Account = await LoadAccount(signer);

            if (_client.Account == null)
            {
                throw new Exception("AcmeClient was unable to find or create an account");
            }
            return(true);
        }
コード例 #29
0
        private static async Task <AcmeProtocolClient> CreateAcmeClientAsync()
        {
            var account    = default(AccountDetails);
            var accountKey = default(AccountKey);
            var acmeDir    = default(ServiceDirectory);

            LoadState(ref account, "account.json");
            LoadState(ref accountKey, "account_key.json");
            LoadState(ref acmeDir, "directory.json");

            var acme = new AcmeProtocolClient(_acmeHttpClient, acmeDir, account, accountKey?.GenerateSigner());

            if (acmeDir == null)
            {
                acmeDir = await acme.GetDirectoryAsync();

                SaveState(acmeDir, "directory.json");

                acme.Directory = acmeDir;
            }

            await acme.GetNonceAsync();

            if (account == null || accountKey == null)
            {
                account = await acme.CreateAccountAsync(new[] { "mailto:" + Settings.Default.Contacts }, true);

                accountKey = new AccountKey
                {
                    KeyType   = acme.Signer.JwsAlg,
                    KeyExport = acme.Signer.Export()
                };

                SaveState(account, "account.json");
                SaveState(accountKey, "account_key.json");

                acme.Account = account;
            }

            return(acme);
        }
コード例 #30
0
        private async Task <ServiceDirectory> GetDir()
        {
            // var dir = new ServiceDirectory
            // {
            //     Directory = $"{DefaultServerUrl}acme/directory",
            //     NewNonce = $"{DefaultServerUrl}acme/new-nonce",
            //     NewAccount = $"{DefaultServerUrl}acme/new-acct",
            //     NewOrder = $"{DefaultServerUrl}acme/new-order",
            // };
            // return Task.FromResult(dir);

            using (var http = _server.CreateClient())
            {
                using (var acme = new AcmeProtocolClient(http))
                {
                    var dir = await acme.GetDirectoryAsync();

                    return(dir);
                }
            }
        }