Ejemplo n.º 1
0
        /// <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");
        }
        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);
        }
        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);
        }
Ejemplo n.º 4
0
        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");
            }
        }
Ejemplo n.º 5
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");
            });
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        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);

            try
            {
                client.Directory = await client.GetDirectoryAsync();
            }
            catch (Exception)
            {
                // Perhaps the BaseUri *is* the directory, such
                // as implemented by Digicert (#1434)
                client.Directory.Directory = "";
                client.Directory           = await client.GetDirectoryAsync();
            }

            // 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");
        }
Ejemplo n.º 9
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");
            });
        }
Ejemplo n.º 10
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");
            });
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
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);
        }
        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);
                }
            }
        }
Ejemplo n.º 15
0
        private async Task EnsureClient()
        {
            var caUri = new Uri(config.CertAuthorityUrl);

            var account = await accountStore.GetAccountAsync();

            if (account != null && account.Account.Kid.Contains(caUri.Host) == false)
            {
                logger.LogWarning("Fetched account KID doesn't contain CA host, ignoring fetched account");
                account = null;
            }

            var client = new AcmeProtocolClient(caUri, null, account?.Account, account?.Signer, usePostAsGet: true, logger: logger);

            client.Directory = await client.GetDirectoryAsync();

            // get nonce, used to communicate w/ server
            await client.GetNonceAsync();

            if (account == null)
            {
                // make request to create account
                var contactEmails = new[] { "mailto:" + config.ContactEmail };
                var newAccount    = await client.CreateAccountAsync(contactEmails, termsOfServiceAgreed : true);

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

                await accountStore.StoreAccountAsync(newAccount, accountKey);

                client.Account = newAccount;
            }

            this.client = client;
        }
Ejemplo n.º 16
0
        private async void agreeTosLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            var url = ResolveCaServerEndpoint();

            if (url == null)
            {
                return;
            }

            var signer = new PkiJwsTool(256);

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

                if (string.IsNullOrEmpty(dir.Meta.TermsOfService))
                {
                    MessageBox.Show("CA Server directory meta data contains no ToS link.", "Missing ToS",
                                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
                System.Diagnostics.Process.Start(dir.Meta.TermsOfService);
            }
        }
Ejemplo n.º 17
0
        private async void createOrderButton_Click(object sender, EventArgs e)
        {
            var url = ResolveCaServerEndpoint();

            if (url == null)
            {
                return;
            }

            var ids = ResolveDnsIdentifiers();

            if (ids == null)
            {
                return;
            }

            var dateRange = ResolveOrderDateRange();

            if (dateRange == 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.CreateOrderAsync(ids,
                                                              dateRange.Value.notBefore, dateRange.Value.notAfter);

                    var order = new DbOrder
                    {
                        FirstOrderUrl = details.OrderUrl,
                        Details       = details,
                    };
                    Repo.Saveorder(order);
                    _lastOrder = order;

                    RebindOrderControls();
                    SetStatus("Order created and saved");

                    await RefreshOrderAuthorizations(acme);
                }

                Repo.Saveorder(_lastOrder);
                RebindOrderControls();
                SetStatus("Order created and Authorization resolved and saved");

                await DecodeOrderAuthorizationChallenges(signer);

                Repo.Saveorder(_lastOrder);
                RebindOrderControls();
                SetStatus("Order created, Authorizations resolved and Challenges decoded and saved");
            });
        }
Ejemplo n.º 18
0
        protected async Task DoTheWorkAsync(object state)
        {
            var cts = new CancellationTokenSource();

            cts.CancelAfter(15000);
            try
            {
                var suggestion = await _registryClient.Registry.SuggestAsync(_gameConfiguration.PublicURL, cts.Token);

                if (suggestion != "localhost")
                {
                    _options.DnsNames = new[] { suggestion }
                }
                ;
                else
                {
                    if (!WarnedLocalMode)
                    {
                        _logger.LogWarning("registry reports we are not accessible on http TCP/80 on our public IP. If you're in development mode, this is fine.");
                    }

                    WarnedLocalMode = true;
                    return;
                }
            }
            catch (Exception e)
            {
                _logger.LogError("** failed to get suggestion from registry: " + e);
            }

            if (_options.DnsNames == null)
            {
                return;
            }

            _logger.LogInformation("** Checking LetsEncrypt status *****************************************");
            _logger.LogInformation($"DNS Names:  {string.Join(",", _options.DnsNames)}");

            if (_state.Certificate != null)
            {
                var now = DateTime.Now;
                if (_state.Certificate.NotAfter > now)
                {
                    _logger.LogInformation("Existing certificate is Good!");
                    return;
                }
                else
                {
                    _logger.LogWarning($"Existing Certificate is Expired! {_state.Certificate.NotAfter} > {now}");
                }
            }
            else
            {
                _logger.LogWarning("Missing Certificate");
            }

            try
            {
                Directory.Delete(_state.RootDir, true);
            }
            catch (Exception) { }
            Reinitialize();


            try
            {
                var acmeUrl = new Uri(_options.CaUrl);
                using (var acme = new AcmeProtocolClient(acmeUrl))
                {
                    _state.ServiceDirectory = await acme.GetDirectoryAsync();

                    Save(_state.ServiceDirectoryFile, _state.ServiceDirectory);
                    acme.Directory = _state.ServiceDirectory;

                    Save(_state.TermsOfServiceFile,
                         await acme.GetTermsOfServiceAsync());

                    await acme.GetNonceAsync();

                    if (!await ResolveAccount(acme))
                    {
                        return;
                    }

                    if (!await ResolveOrder(acme))
                    {
                        return;
                    }

                    if (!await ResolveChallenges(acme))
                    {
                        return;
                    }

                    if (!await ResolveAuthorizations(acme))
                    {
                        return;
                    }

                    if (!await ResolveCertificate(acme))
                    {
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogWarning($"Exception while getting SSL Certificate: {e}");
            }
        }
Ejemplo n.º 19
0
        protected async Task DoTheWorkAsync(object state)
        {
            _logger.LogInformation("** DOING WORKING *****************************************");
            _logger.LogInformation($"DNS Names:  {string.Join(",", _options.DnsNames)}");

            if (_state.Certificate != null)
            {
                var now = DateTime.Now;
                if (_state.Certificate.NotBefore > now && _state.Certificate.NotAfter < now)
                {
                    _logger.LogInformation("Existing certificate is Good!");
                    return;
                }
                {
                    _logger.LogWarning("Existing Certificate is Expired!");
                }
            }
            else
            {
                _logger.LogWarning("Missing Certificate");
            }

            var acmeUrl = new Uri(_options.CaUrl);

            using (var acme = new AcmeProtocolClient(acmeUrl))
            {
                _state.ServiceDirectory = await acme.GetDirectoryAsync();

                Save(_state.ServiceDirectoryFile, _state.ServiceDirectory);
                acme.Directory = _state.ServiceDirectory;

                Save(_state.TermsOfServiceFile,
                     await acme.GetTermsOfServiceAsync());

                await acme.GetNonceAsync();

                if (!await ResolveAccount(acme))
                {
                    return;
                }

                if (!await ResolveOrder(acme))
                {
                    return;
                }

                if (!await ResolveChallenges(acme))
                {
                    return;
                }

                if (!await ResolveAuthorizations(acme))
                {
                    return;
                }

                if (!await ResolveCertificate(acme))
                {
                    return;
                }
            }
        }
Ejemplo n.º 20
0
        async Task CreateAccount()
        {
            var acmeUrl = new Uri(Program.LetsEncryptV2StagingEndpoint);

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

            var sample = Encoding.UTF8.GetBytes("abcdefg");

            // var ecKeys = PkiKeyPair.GenerateEcdsaKeyPair(256);
            // var ecPrvKey = ecKeys.PrivateKey.Export(PkiEncodingFormat.Pem);
            // var ecPubKey = ecKeys.PublicKey.Export(PkiEncodingFormat.Pem);

            // WriteLine(
            //     "getting from: " + acmeUrl
            //     + "\r\necPrv: " + Convert.ToBase64String(ecPrvKey)
            //     + "\r\necPub: " + Convert.ToBase64String(ecPubKey)
            // );

            // var signer = new ACMESharp.Crypto.JOSE.Impl.ESJwsTool();
            // signer.Init();
            // WriteLine($"ECKeys: {signer.Export()}");

            var signer = new PkiJwsTool(256);

            signer.Init();
            var signerExport = signer.Export();

            signer = new PkiJwsTool(256);
            signer.Import(signerExport);
            WriteLine($"ECKeys: {signerExport}");

            var sig1 = signer.Sign(sample);

            WriteLine($"Sig: {Convert.ToBase64String(sig1)}");
            sig1 = signer.Sign(sample);
            WriteLine($"Sig: {Convert.ToBase64String(sig1)}");
            sig1 = signer.Sign(sample);
            WriteLine($"Sig: {Convert.ToBase64String(sig1)}");
            WriteLine($"Vfy: {signer.Verify(sample, sig1)}");
            WriteLine($"JWK: {JsonConvert.SerializeObject(signer.ExportJwk())}");
            WriteLine("Sig1Hex: " + BitConverter.ToString(sig1));

            // var ecAlt = JsonConvert.SerializeObject(signer.KeyPair.ExportEcParameters());
            // WriteLine($"ECAlt:  {ecAlt}");
            // var signer2 = new ACMESharp.Crypto.JOSE.Impl.ESJwsTool();
            // signer2.HashSize = 256;
            // signer2.Init();
            // signer2.Import(ecAlt);

            // WriteLine($"ECKeys2: {signer2.Export()}");
            // var sig2 = signer2.Sign(sample);
            // WriteLine($"Sig2: {Convert.ToBase64String(sig2)}");
            // sig2 = signer2.Sign(sample);
            // WriteLine($"Sig2: {Convert.ToBase64String(sig2)}");
            // sig2 = signer2.Sign(sample);
            // WriteLine($"Sig2: {Convert.ToBase64String(sig2)}");
            // WriteLine($"Vfy2: {signer2.Verify(sample, sig2)}");
            // WriteLine($"JWK2: {JsonConvert.SerializeObject(signer2.ExportJwk())}");
            // WriteLine("Sig2Hex: " + BitConverter.ToString(sig2));

            var lineSeps = "\r\n".ToCharArray();

            using (var acme = new AcmeProtocolClient(_http, signer: signer))
            {
                acme.BeforeAcmeSign = (s, o) => WriteLine($"BEFORE_SIGN({s}, {JsonConvert.SerializeObject(o)})");
                acme.BeforeHttpSend = (s, m) => WriteLine($"BEFORE_SEND({s}, {m.Content?.ReadAsStringAsync().Result}");


                var dir = await acme.GetDirectoryAsync();

                acme.Directory = dir;

                await acme.GetNonceAsync();

                var c    = _contacts.Split(lineSeps, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
                var acct = await acme.CreateAccountAsync(c, _agreeTos);

                var acctStr = JsonConvert.SerializeObject(acct, Formatting.Indented);

                Console.WriteLine("Got Account: " + acctStr);
            }

            signer = new PkiJwsTool(256);
            signer.Import(signerExport);

            using (var acme = new AcmeProtocolClient(_http, signer: signer))
            {
                acme.BeforeAcmeSign = (s, o) => WriteLine($"BEFORE_SIGN({s}, {JsonConvert.SerializeObject(o)})");
                acme.BeforeHttpSend = (s, m) => WriteLine($"BEFORE_SEND({s}, {m.Content?.ReadAsStringAsync().Result}");

                var dir = await acme.GetDirectoryAsync();

                acme.Directory = dir;

                await acme.GetNonceAsync();

                var d     = _dnsNames.Split(lineSeps, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
                var order = await acme.CreateOrderAsync(d);

                var orderStr = JsonConvert.SerializeObject(order, Formatting.Indented);

                Console.WriteLine("Got Order: " + orderStr);
            }
        }
Ejemplo n.º 21
0
        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...");
            try
            {
                _client = new AcmeProtocolClient(httpClient, signer: signer);
            }
            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 = new Rsa(_log, new RsaOptions()).GetRsaKeyBits()
                    };
                    signer.Init();
                    _client = new AcmeProtocolClient(httpClient, signer: signer);
                }
                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");
            }
            return(true);
        }
Ejemplo n.º 22
0
        public async Task <IActionResult> Post([FromBody] DomainRequest request)
        {
            if (!IsValidDomain(request.Domain))
            {
                return(BadRequest(new DomainResponse {
                    Error = "Invalid domain"
                }));
            }

            var domain    = string.Join(".", request.Domain.Split(".").TakeLast(2));
            var subDomain = string.Join(".", request.Domain.Split(".").SkipLast(2));

            var credentials = new AzureCredentialsFactory()
                              .FromServicePrincipal(
                _configuration["Azure:ClientId"],
                _configuration["Azure:ClientSecret"],
                _configuration["Azure:TenantId"],
                AzureEnvironment.AzureGlobalCloud
                );

            var azure = Azure
                        .Configure()
                        .WithRetryPolicy(new RetryPolicy(new TransientErrorIgnoreStrategy(), 0))
                        .Authenticate(credentials)
                        .WithSubscription(_configuration["Azure:SubscriptionId"]);

            var webApp = await azure.AppServices.WebApps.GetByIdAsync(
                _configuration["Azure:AppId"]);

            try
            {
                webApp.Update()
                .DefineHostnameBinding()
                .WithThirdPartyDomain(domain)
                .WithSubDomain(subDomain)
                .WithDnsRecordType(CustomHostNameDnsRecordType.CName)
                .Attach()
                .Apply();
            }
            catch (Exception e)
            {
                return(BadRequest(new DomainResponse {
                    Error = "Unable to validate domain ownership"
                }));
            }

            _ = Task.Run(async() =>
            {
                using var airtableBase = new AirtableBase(_configuration["Airtable:Key"], _configuration["Airtable:Base"]);
                try
                {
                    HttpClient httpClient = new HttpClient {
                        BaseAddress = new Uri(_configuration["Acme:Endpoint"])
                    };
                    AcmeProtocolClient acme = new AcmeProtocolClient(httpClient, usePostAsGet: true);

                    var acmeDir    = await acme.GetDirectoryAsync();
                    acme.Directory = acmeDir;

                    await acme.GetNonceAsync();

                    var account  = await acme.CreateAccountAsync(new[] { "mailto:" + _configuration["Acme:Email"] }, true);
                    acme.Account = account;

                    var order = await acme.CreateOrderAsync(new[] { request.Domain });
                    if (order.Payload.Status == "invalid")
                    {
                        return;
                    }

                    var authorizationUrl = order.Payload.Authorizations.FirstOrDefault();
                    if (string.IsNullOrEmpty(authorizationUrl))
                    {
                        return;
                    }
                    var authorization = await acme.GetAuthorizationDetailsAsync(authorizationUrl);

                    foreach (var challenge in authorization.Challenges.Where(x => x.Type == "http-01").ToList())
                    {
                        var challengeValidationDetails = (Http01ChallengeValidationDetails)
                                                         AuthorizationDecoder.DecodeChallengeValidation(authorization, challenge.Type, acme.Signer);

                        var path        = challengeValidationDetails.HttpResourcePath;
                        var token       = path.Split("/", StringSplitOptions.RemoveEmptyEntries).Last();
                        var value       = challengeValidationDetails.HttpResourceValue;
                        var contentType = challengeValidationDetails.HttpResourceContentType;

                        await airtableBase.CreateRecord("Acme", new Fields
                        {
                            FieldsCollection = new Dictionary <string, object>
                            {
                                ["Token"]       = token,
                                ["Value"]       = value,
                                ["ContentType"] = contentType
                            }
                        });

                        await Task.Delay(10 * 1000);
                        var challengeUpdated = await acme.AnswerChallengeAsync(challenge.Url);
                    }

                    //Wait for challenge to be resolved
                    var waitUntil = DateTime.Now.AddSeconds(300);
                    Authorization authorizationUpdated;
                    do
                    {
                        await Task.Delay(10 * 1000);
                        authorizationUpdated = await acme.GetAuthorizationDetailsAsync(authorizationUrl);
                    } while (authorizationUpdated.Status != "valid" && DateTime.Now < waitUntil);

                    if (authorizationUpdated.Status != "valid")
                    {
                        return;
                    }

                    //Generate certificate private key and CSR (Certificate signing request)
                    var keyPair = PkiKeyPair.GenerateEcdsaKeyPair(256);
                    var csr     = new PkiCertificateSigningRequest($"CN={request.Domain}", keyPair, PkiHashAlgorithm.Sha256);
                    var certCsr = csr.ExportSigningRequest(PkiEncodingFormat.Der);

                    order = await acme.FinalizeOrderAsync(order.Payload.Finalize, certCsr);
                    if (order.Payload.Status != "valid")
                    {
                        return;
                    }

                    if (string.IsNullOrEmpty(order.Payload.Certificate))
                    {
                        //Wait for certificate
                        var waitUntil2 = DateTime.Now.AddSeconds(300);
                        while (DateTime.Now < waitUntil2)
                        {
                            await Task.Delay(10 * 1000);
                            order = await acme.GetOrderDetailsAsync(order.OrderUrl, existing: order);

                            if (!string.IsNullOrEmpty(order.Payload.Certificate))
                            {
                                break;
                            }
                        }
                    }
                    if (string.IsNullOrEmpty(order.Payload.Certificate))
                    {
                        return;
                    }

                    var certResp = await acme.GetAsync(order.Payload.Certificate);
                    if (!certResp.IsSuccessStatusCode)
                    {
                        return;
                    }

                    var certByteArray = await certResp.Content.ReadAsByteArrayAsync();

                    //Export PFX file
                    var pfxPassword = _configuration["Acme:PfxPassword"];
                    var privateKey  = keyPair.PrivateKey;

                    using var cert = new X509Certificate2(certByteArray);

                    X509Chain chain = new X509Chain();
                    chain.Build(cert);
                    List <PkiCertificate> chainList = new List <PkiCertificate>();
                    foreach (var e in chain.ChainElements)
                    {
                        chainList.Add(PkiCertificate.From(e.Certificate));
                    }

                    var pfx = chainList[0].Export(PkiArchiveFormat.Pkcs12,
                                                  chain: chainList.Skip(1),
                                                  privateKey: privateKey,
                                                  password: pfxPassword?.ToCharArray());

                    webApp.Update()
                    .DefineSslBinding()
                    .ForHostname(request.Domain)
                    .WithPfxByteArrayToUpload(pfx, pfxPassword)
                    .WithSniBasedSsl()
                    .Attach()
                    .Apply();
                }
                catch (Exception e)
                {
                    await airtableBase.CreateRecord("Logs", new Fields
                    {
                        FieldsCollection = new Dictionary <string, object>
                        {
                            ["Hostname"] = request.Domain,
                            ["Event"]    = "exception-thrown",
                            ["Data"]     = JsonConvert.SerializeObject(e)
                        }
                    });
                }
            });



            return(Ok(new DomainResponse {
                IsSuccessful = true
            }));
        }
Ejemplo n.º 23
0
        public async Task <Uri> GetAcmeTermsOfService()
        {
            var tos = await _client.GetDirectoryAsync();

            return(new Uri(tos.Meta.TermsOfService));
        }