Ejemplo n.º 1
0
        public async Task ACME_Test_14_AcknowledgeDnsChallenges()
        {
            AcmeOrder Order = await this.OrderCertificate("example.com", "www.example.com");

            AcmeAuthorization[] Authorizations = await Order.GetAuthorizations();

            foreach (AcmeAuthorization Authorization in Authorizations)
            {
                foreach (AcmeChallenge Challenge in Authorization.Challenges)
                {
                    if (Challenge is AcmeDnsChallenge DnsChallenge)
                    {
                        AcmeChallenge Challenge2 = await Challenge.AcknowledgeChallenge();

                        this.Print(Authorization.Value, Challenge2);
                    }
                }
            }

            System.Threading.Thread.Sleep(5000);

            foreach (AcmeAuthorization Authorization in Authorizations)
            {
                AcmeAuthorization Authorization2 = await Authorization.Poll();

                this.Print(Authorization2);
            }
        }
Ejemplo n.º 2
0
        public DnsChallenge(AcmeAccount account, AcmeChallenge challenge, string identifier)
        {
            Account    = account;
            Challenge  = challenge;
            Identifier = identifier;

            Token            = challenge.Token;
            AuthorizationKey = CertificateUtility.CreateAuthorizationKey(account, challenge.Token);
        }
Ejemplo n.º 3
0
        public async Task VerifyChallenge_ShouldVerifyTheChallenge()
        {
            //SETUP
            AcmeRestApi api = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT);
            AcmeApiResponse <AcmeDirectory> directory;
            AcmeApiResponse nonceResponse = null;
            AcmeApiResponse <AcmeAccount> accountResponse = null;
            AcmeApiResponse <AcmeCertificateFulfillmentPromise> certificateFulfillmentPromise = null;
            List <AcmeApiResponse <AcmeAuthorization> >         authorizations = null;
            AcmeApiResponse <AcmeChallengeStatus> challengeStatusResponse;

            AcmeCertificateRequest certifcateRequest = new AcmeCertificateRequest()
            {
                Identifiers = new List <DnsCertificateIdentifier>()
                {
                    new DnsCertificateIdentifier()
                    {
                        Value = "taco.com"
                    },
                    new DnsCertificateIdentifier()
                    {
                        Value = "www.taco.com"
                    }
                }
            };

            //EXECUTE
            directory = await api.GetDirectoryAsync();

            nonceResponse = await api.GetNonceAsync(directory.Data);

            accountResponse = await api.CreateAccountAsync(directory.Data, nonceResponse.Nonce, new AcmeCreateAccount()
            {
                Contact = new List <string>()
                {
                    "mailto:[email protected]"
                }, TermsOfServiceAgreed = true
            });

            certificateFulfillmentPromise = await api.RequestCertificateAsync(directory.Data, accountResponse.Nonce, accountResponse.Data, certifcateRequest);

            authorizations = await api.GetChallengesAsync(certificateFulfillmentPromise.Data);

            AcmeChallenge httpChallenge = authorizations.First().Data.Challenges.First(t => t.Type.Equals("http-01"));
            string        authKey       = CreateAuthorizationKey(accountResponse.Data, httpChallenge.Token);

            challengeStatusResponse = await api.VerifyChallengeAsync(accountResponse.Data, httpChallenge, certificateFulfillmentPromise.Nonce, authKey);

            //ASSERT
            challengeStatusResponse.ShouldNotBeNull();
            challengeStatusResponse.Status.ShouldBe(AcmeApiResponseStatus.Success);
            challengeStatusResponse.Data.ShouldNotBeNull();
            challengeStatusResponse.Data.Status.ShouldBe("pending");
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Gets challenges used to verify domain ownership.
        /// </summary>
        /// <param name="account">Existing account.</param>
        /// <param name="acmeCertificateFulfillmentPromise">The certificate fulfillment promise retrieved from the RequestCertificate call.</param>
        /// <param name="challengeType">The challenge type expected back.</param>
        /// <returns>Challenge used to verify domain ownership</returns>
        /// <remarks>If requesting a challenge for a wildcard domain, only dns challenge is supported.</remarks>
        /// <exception cref="NotSupportedException">If the challenge type is not supported.</exception>
        /// <exception cref="AcmeProtocolException">On all other Acme related exceptions</exception>
        public async Task <ChallengeCollection> GetChallengesAsync(AcmeAccount account, AcmeCertificateFulfillmentPromise acmeCertificateFulfillmentPromise, ChallengeType challengeType)
        {
            var response = await _acmeApi.GetChallengesAsync(acmeCertificateFulfillmentPromise);

            var errorResponse = response.Where(t => t.Status == AcmeApiResponseStatus.Error);

            if (errorResponse.Any())
            {
                throw new AcmeProtocolException(string.Join(" | ", errorResponse.Select(t => t.Message)));
            }

            ChallengeCollection challenges = new ChallengeCollection();

            foreach (var resp in response)
            {
                AcmeChallenge sChallenge = resp.Data.Challenges.FirstOrDefault(t => t.Type.Equals(challengeType.Value));
                if (sChallenge == null)
                {
                    throw new NotSupportedException($"{challengeType.Value} challenge type not supported in this context.");
                }
                IAcmeChallengeContent challengeContent = null;
                switch (challengeType.Value)
                {
                case ProtoacmeContants.CHALLENGE_HTTP:
                    challengeContent = new HttpChallenge(account, sChallenge, resp.Data.Identifier?.Value);
                    challenges.Add(challengeContent);
                    break;

                case ProtoacmeContants.CHALLENGE_DNS:
                    challengeContent = new DnsChallenge(account, sChallenge, resp.Data.Identifier?.Value);
                    challenges.Add(challengeContent);
                    break;

                case ProtoacmeContants.CHALLENGE_TLS:
                    challengeContent = new TlsChallenge(account, sChallenge, resp.Data.Identifier?.Value);
                    challenges.Add(challengeContent);
                    break;

                default:
                    break;
                }
            }

            return(challenges);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Gets the status of the challenge verification.
        /// </summary>
        /// <param name="challenge">Single challenge from the AcmeAuthorization</param>
        /// <returns>Returns the status of the challenge. Wrapped by a response object.</returns>
        public async Task <AcmeApiResponse <AcmeChallengeVerificationStatus> > GetChallengeVerificationStatusAsync(AcmeChallenge challenge)
        {
            if (challenge == null)
            {
                throw new ArgumentNullException("challenge");
            }

            var apiResp = await _httpClient.GetAsync(challenge.Url);

            string apiRespString = await apiResp.Content?.ReadAsStringAsync();

            if (apiResp.StatusCode != HttpStatusCode.OK)
            {
                return(ErrorResponse <AcmeChallengeVerificationStatus>(apiRespString));
            }

            return(new AcmeApiResponse <AcmeChallengeVerificationStatus>()
            {
                Status = AcmeApiResponseStatus.Success,
                Data = JsonConvert.DeserializeObject <AcmeChallengeVerificationStatus>(apiRespString)
            });
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Start the challenge verification process.
        /// </summary>
        /// <param name="account">Must be existing account.</param>
        /// <param name="challenge">Single challenge from the AcmeAuthorization</param>
        /// <param name="nonce">Nonce</param>
        /// <param name="keyAuthorization">Authorization that identifies the domain and user.</param>
        /// <returns>The status of the challenge authorization. Wrapped by a response object.</returns>
        /// <remarks>This will need to be called on each domain that is used in the RequestCertificate call. You should not call this until the challenges are ready to verify. See https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.5 for more information.</remarks>
        public async Task <AcmeApiResponse <AcmeChallengeStatus> > VerifyChallengeAsync(AcmeAccount account, AcmeChallenge challenge, string nonce, string keyAuthorization)
        {
            if (string.IsNullOrEmpty(nonce))
            {
                throw new ArgumentNullException("nonce");
            }
            if (account == null)
            {
                throw new ArgumentNullException("account");
            }
            if (challenge == null)
            {
                throw new ArgumentNullException("challenge");
            }
            if (string.IsNullOrEmpty(keyAuthorization))
            {
                throw new ArgumentNullException("keyAuthorization");
            }

            JwsContainer <KEYAUTH> jwsObject = new JwsContainer <KEYAUTH>(account.SecurityInfo, nonce, challenge.Url, account.KID, new KEYAUTH()
            {
                keyAuthorization = keyAuthorization
            });

            string jwsToken = jwsObject.SerializeSignedToken();

            var apiResp = await SendPostData(
                url : challenge.Url,
                data : jwsToken);

            string apiRespString = await apiResp.Content?.ReadAsStringAsync();

            if (apiResp.StatusCode != HttpStatusCode.OK)
            {
                return(ErrorResponse <AcmeChallengeStatus>(apiRespString));
            }

            if (!apiResp.Headers.TryGetValues(ProtoacmeContants.HEADER_NONCE, out IEnumerable <string> nonces))
            {
                return(ErrorResponse <AcmeChallengeStatus>("Missing Replay-Nonce Header on CompleteChallenge Response."));
            }

            return(new AcmeApiResponse <AcmeChallengeStatus>()
            {
                Status = AcmeApiResponseStatus.Success,
                Nonce = nonces.FirstOrDefault(),
                Data = JsonConvert.DeserializeObject <AcmeChallengeStatus>(apiRespString)
            });
        }
Ejemplo n.º 7
0
        public async Task DownloadCertificate_ShouldComplete()
        {
            //SETUP
            AcmeRestApi api = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT);
            AcmeApiResponse <AcmeDirectory> directory;
            AcmeApiResponse nonceResponse = null;
            AcmeApiResponse <AcmeAccount> accountResponse = null;
            AcmeApiResponse <AcmeCertificateFulfillmentPromise> certificateFulfillmentPromise = null;
            List <AcmeApiResponse <AcmeAuthorization> >         authorizations                = null;
            AcmeApiResponse <AcmeChallengeStatus>               challengeStatusResponse       = null;
            AcmeApiResponse <AcmeChallengeVerificationStatus>   challengeVerificationResponse = null;
            AcmeApiResponse <AcmeCertificateFulfillmentPromise> certificatePromiseResult      = null;
            AcmeApiResponse <ArraySegment <byte> >              certificateResult             = null;

            AcmeCertificateRequest certifcateRequest = new AcmeCertificateRequest()
            {
                Identifiers = new List <DnsCertificateIdentifier>()
                {
                    new DnsCertificateIdentifier()
                    {
                        Value = "test.com"
                    }
                }
            };

            //EXECUTE
            directory = await api.GetDirectoryAsync();

            nonceResponse = await api.GetNonceAsync(directory.Data);

            accountResponse = await api.CreateAccountAsync(directory.Data, nonceResponse.Nonce, new AcmeCreateAccount()
            {
                Contact = new List <string>()
                {
                    "mailto:[email protected]"
                }, TermsOfServiceAgreed = true
            });

            certificateFulfillmentPromise = await api.RequestCertificateAsync(directory.Data, accountResponse.Nonce, accountResponse.Data, certifcateRequest);

            authorizations = await api.GetChallengesAsync(certificateFulfillmentPromise.Data);

            AcmeChallenge httpChallenge = authorizations.First().Data.Challenges.First(t => t.Type.Equals("http-01"));
            string        authKey       = CreateAuthorizationKey(accountResponse.Data, httpChallenge.Token);

            challengeStatusResponse = await api.VerifyChallengeAsync(accountResponse.Data, httpChallenge, certificateFulfillmentPromise.Nonce, authKey);

            while (
                challengeVerificationResponse == null ||
                challengeVerificationResponse.Data.Status == "pending")
            {
                challengeVerificationResponse = await api.GetChallengeVerificationStatusAsync(httpChallenge);

                await Task.Delay(3000);
            }

            string csr = GenerateCSR(accountResponse.Data, "test.com");

            certificatePromiseResult = await api.FinalizeCertificatePromiseAsync(accountResponse.Data, challengeStatusResponse.Nonce, certificateFulfillmentPromise.Data, csr);

            certificateResult = await api.GetCertificateAsync(certificatePromiseResult.Data, CertificateType.Cert);

            //We will write the cert out to a temp directory if it exists. Otherwise, forget it.
            if (Directory.Exists(@"c:\temp"))
            {
                using (FileStream fs = new FileStream(@"c:\temp\mycert.cer", FileMode.Create))
                {
                    byte[] bytes = certificateResult.Data.Array;
                    fs.Write(bytes, 0, bytes.Length);
                }
            }

            //ASSERT (Cant really assert anything here. This call will mostlikey fail. There is no way to validate the domain here)
        }
Ejemplo n.º 8
0
        public async Task FinalizeChallenge_ShouldComplete()
        {
            //SETUP
            AcmeRestApi api = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT);
            AcmeApiResponse <AcmeDirectory> directory;
            AcmeApiResponse nonceResponse = null;
            AcmeApiResponse <AcmeAccount> accountResponse = null;
            AcmeApiResponse <AcmeCertificateFulfillmentPromise> certificateFulfillmentPromise = null;
            List <AcmeApiResponse <AcmeAuthorization> >         authorizations                = null;
            AcmeApiResponse <AcmeChallengeStatus>               challengeStatusResponse       = null;
            AcmeApiResponse <AcmeChallengeVerificationStatus>   challengeVerificationResponse = null;
            AcmeApiResponse <AcmeCertificateFulfillmentPromise> certificatePromiseResult      = null;

            AcmeCertificateRequest certifcateRequest = new AcmeCertificateRequest()
            {
                Identifiers = new List <DnsCertificateIdentifier>()
                {
                    new DnsCertificateIdentifier()
                    {
                        Value = "test.com"
                    }
                }
            };

            //EXECUTE
            directory = await api.GetDirectoryAsync();

            nonceResponse = await api.GetNonceAsync(directory.Data);

            accountResponse = await api.CreateAccountAsync(directory.Data, nonceResponse.Nonce, new AcmeCreateAccount()
            {
                Contact = new List <string>()
                {
                    "mailto:[email protected]"
                }, TermsOfServiceAgreed = true
            });

            certificateFulfillmentPromise = await api.RequestCertificateAsync(directory.Data, accountResponse.Nonce, accountResponse.Data, certifcateRequest);

            authorizations = await api.GetChallengesAsync(certificateFulfillmentPromise.Data);

            AcmeChallenge httpChallenge = authorizations.First().Data.Challenges.First(t => t.Type.Equals("http-01"));
            string        authKey       = CreateAuthorizationKey(accountResponse.Data, httpChallenge.Token);

            challengeStatusResponse = await api.VerifyChallengeAsync(accountResponse.Data, httpChallenge, certificateFulfillmentPromise.Nonce, authKey);

            while (
                challengeVerificationResponse == null ||
                challengeVerificationResponse.Data.Status == "pending")
            {
                challengeVerificationResponse = await api.GetChallengeVerificationStatusAsync(httpChallenge);

                await Task.Delay(3000);
            }

            string csr = GenerateCSR(accountResponse.Data, "test.com");

            certificatePromiseResult = await api.FinalizeCertificatePromiseAsync(accountResponse.Data, challengeStatusResponse.Nonce, certificateFulfillmentPromise.Data, csr);

            //ASSERT (Cant really assert anything here. This call will mostlikey fail. There is no way to validate the domain here)
            certificatePromiseResult.ShouldNotBeNull();
        }