private async Task ValidateChallenges(IChallengeContext[] challengeContexts, AcmeOrderOptions orderOptions)
        {
            _logger.LogInformation("[LetsEncrypt][Validating] all pending order authorizations.");

            var challengeValidationResponses = await ValidateChallengesAsync(challengeContexts, orderOptions);

            var nonNullChallengeValidationResponses = challengeValidationResponses.Where(x => x != null).ToArray();

            if (challengeValidationResponses.Length > nonNullChallengeValidationResponses.Length)
            {
                _logger.LogInformation("[LetsEncrypt][Validating] Some challenge responses were null.");
            }

            var challengeExceptions = nonNullChallengeValidationResponses
                                      .Where(x => x.Status == ChallengeStatus.Invalid)
                                      .Select(x => new Exception($"{x.Error?.Type ?? "errortype null"}: {x.Error?.Detail ?? "null errordetails"} (challenge type {x.Type ?? "null"})"))
                                      .ToArray();

            if (challengeExceptions.Length > 0)
            {
                throw new LetsEncryptException(
                          "One or more LetsEncrypt orders were invalid." +
                          " Make sure that LetsEncrypt can contact the domain you are trying to request an SSL certificate for, in order to verify it.",
                          new AggregateException(challengeExceptions));
            }

            _logger.LogInformation("[LetsEncrypt][Validating] Completed.");
        }
        private async Task <byte[]> AcquireCertificateBytesFromOrderAsync(
            IOrderContext order,
            AcmeOrderOptions orderOptions,
            AcmeAccountOptions accountOptions,
            CertificateOptions certificateOptions)
        {
            _logger.LogInformation("[LetsEncrypt][Certificate] Acquiring certificate through signing request.");

            var privateKey = KeyFactory.NewKey((Certes.KeyAlgorithm)orderOptions.KeyAlgorithm);

            if (orderOptions?.CertificateSigningRequest == null)
            {
                var commonName = accountOptions.Domains[0];
                _logger.LogDebug("Creating cert for {commonName}", commonName);

                var csrInfo = new CsrInfo
                {
                    CommonName = commonName,
                };

                if (orderOptions != null)
                {
                    orderOptions.CertificateSigningRequest = csrInfo;
                }
            }

            var certificateChain = await order.Generate(orderOptions?.CertificateSigningRequest, privateKey);

            var pfxBuilder = certificateChain.ToPfx(privateKey);

            pfxBuilder.FullChain = true;

            var pfxBytes = pfxBuilder.Build(
                $"Let's Encrypt - {accountOptions.Domains[0]} ",
                certificateOptions?.CertificatePassword ?? string.Empty);

            _logger.LogInformation("[LetsEncrypt][Certificate] Certificate acquired.");

            return(pfxBytes);
        }
        private async Task <Challenge[]> ValidateChallengesAsync(IChallengeContext[] challengeContexts, AcmeOrderOptions orderOptions)
        {
            var challenges = await Task.WhenAll(challengeContexts.Select(x => x.Validate()));

            var retries = 0;
            var delay   = TimeSpan.FromSeconds(orderOptions.ValidationDelay);

            while (true)
            {
                var anyValid   = challenges.Any(x => x.Status == ChallengeStatus.Valid);
                var anyPending = challenges.Any(x => x.Status == ChallengeStatus.Pending);

                var allInvalid = challenges.All(x => (x.Status == ChallengeStatus.Invalid && x.Type == ChallengeTypes.Http01));

                if ((anyValid && !anyPending) ||
                    (allInvalid && retries >= orderOptions.ValidationRetry))
                {
                    break;
                }

                if (retries >= orderOptions.ValidationRetry)
                {
                    break;
                }

                await Task.Delay(delay);

                challenges = await Task.WhenAll(challengeContexts.Select(x => x.Resource()));

                retries++;
            }

            return(challenges);
        }