コード例 #1
0
        public async Task WildCardCertificateRequest()
        {
            var restApi = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT);
            var client  = new ProtoacmeClient(restApi);

            //1. Create a new account.
            var newAccountInfo = new AcmeCreateAccount();

            newAccountInfo.Contact.Add("mailto:[email protected]");
            newAccountInfo.Contact.Add("mailto:[email protected]");
            newAccountInfo.TermsOfServiceAgreed = true;

            var account = await client.Account.CreateAsync(newAccountInfo);

            //2. Request the wildcard cert.
            AcmeCertificateRequest certRequest = new AcmeCertificateRequest();

            certRequest.Identifiers.Add(new DnsCertificateIdentifier()
            {
                Value = wildCardDns
            });
            var promise = await client.Certificate.RequestCertificateAsync(account, certRequest);

            //3. Get Challenges
            var challenge = await client.Challenge.GetChallengesAsync(account, promise, ChallengeType.Dns);

            //4. Save Challenge Information
            challenge[0].SaveToFile(@"c:\temp\dns_challenge.txt");

            //5. Save account and additional info for future request.
            account.SaveToFile(@"c:\temp\account.dat");
            promise.SaveToFile(@"c:\temp\promise.dat");
            challenge.SaveToFile(@"c:\temp\challenge.dat");
        }
コード例 #2
0
        public async Task StandardCertificateRequest()
        {
            var restApi = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT);
            var client  = new ProtoacmeClient(restApi);

            //1. Create a new account.
            var newAccountInfo = new AcmeCreateAccount();

            newAccountInfo.Contact.Add("mailto:[email protected]");
            newAccountInfo.TermsOfServiceAgreed = true;

            var account = await client.Account.CreateAsync(newAccountInfo);

            //2. Request a certificate.
            AcmeCertificateRequest certRequest = new AcmeCertificateRequest();

            foreach (var dns in dnsNames)
            {
                certRequest.Identifiers.Add(new DnsCertificateIdentifier()
                {
                    Value = dns
                });
            }
            var certPromise = await client.Certificate.RequestCertificateAsync(account, certRequest);


            //3. Get challenge
            var challenges = await client.Challenge.GetChallengesAsync(account, certPromise, ChallengeType.Http);

            //4. Save Challenge and Account for next step.
            SaveAccountAndChallengeData(account, challenges, certPromise);
        }
コード例 #3
0
        /// <summary>
        /// Updates an existing accounts contacts
        /// </summary>
        /// <param name="directory">Directory object.</param>
        /// <param name="nonce">Nonce</param>
        /// <param name="account">Must be existing account.</param>
        /// <returns>Return api response with status.</returns>
        public async Task <AcmeApiResponse> UpdateAccountAsync(AcmeDirectory directory, string nonce, AcmeAccount account)
        {
            if (directory == null)
            {
                throw new ArgumentNullException("directory");
            }
            if (string.IsNullOrEmpty(directory.NewAccount))
            {
                throw new ArgumentException("directory is missing Account url.");
            }
            if (string.IsNullOrEmpty(nonce))
            {
                throw new ArgumentNullException("nonce");
            }
            if (account == null)
            {
                throw new ArgumentNullException("account");
            }

            AcmeCreateAccount upd = new AcmeCreateAccount()
            {
                Contact = account.Contact, TermsOfServiceAgreed = true
            };

            JwsContainer <AcmeCreateAccount> jwsObject = new JwsContainer <AcmeCreateAccount>(account.SecurityInfo, nonce, account.KID, account.KID, upd);

            string jwsToken = jwsObject.SerializeSignedToken();

            var apiResp = await SendPostData(
                url : _letsEncryptEndpoint.AppendUrl(ProtoacmeContants.LETSENCRYPT_ACCOUNT_FRAGMENT).AppendUrl(account.Id.ToString()),
                data : jwsToken);

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

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

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

            return(new AcmeApiResponse()
            {
                Status = AcmeApiResponseStatus.Success,
                Nonce = nonces.FirstOrDefault()
            });
        }
コード例 #4
0
        /// <summary>
        /// Create a new account.
        /// </summary>
        /// <param name="accountDetails">Information for new account.</param>
        /// <returns>Returns a serializable account object.</returns>
        public async Task <AcmeAccount> CreateAsync(AcmeCreateAccount accountDetails)
        {
            var directory = await _directoryCache.GetAsync();

            var nonce = await _nonceCache.GetAsync();

            var response = await _acmeApi.CreateAccountAsync(directory, nonce, accountDetails);

            if (response.Status == AcmeApiResponseStatus.Error)
            {
                throw new AcmeProtocolException(response.Message);
            }

            _nonceCache.Update(response.Nonce);

            return(response.Data);
        }
コード例 #5
0
        public async Task CreateAccount_ShouldReturnExpectedNewAccount()
        {
            //ARRANGE
            var acmeApiMock        = new Mock <IAcmeRestApi>();
            var directoryCacheMock = new Mock <ICachedRepository <AcmeDirectory> >();
            var nonceCacheMock     = new Mock <ICachedRepository <string> >();

            AcmeCreateAccount             inputAccount    = TestHelpers.CreateAccount;
            AcmeApiResponse <AcmeAccount> accountResponse = TestHelpers.AcmeAccountResponse;

            acmeApiMock.Setup(method => method.CreateAccountAsync(It.IsAny <AcmeDirectory>(), It.IsAny <string>(), It.IsAny <AcmeCreateAccount>()))
            .ReturnsAsync(accountResponse);

            AcmeAccountService srv = new AcmeAccountService(acmeApiMock.Object, directoryCacheMock.Object, nonceCacheMock.Object);

            //ACT
            var expected = await srv.CreateAsync(inputAccount);

            //ASSERT
            expected.ShouldBe(accountResponse.Data);
        }
コード例 #6
0
        public async Task CreateAccount_ShouldUpdateLastNonce()
        {
            //ARRANGE
            var acmeApiMock        = new Mock <IAcmeRestApi>();
            var directoryCacheMock = new Mock <ICachedRepository <AcmeDirectory> >();
            var nonceCacheMock     = new Mock <ICachedRepository <string> >();

            AcmeCreateAccount             inputAccount    = TestHelpers.CreateAccount;
            AcmeApiResponse <AcmeAccount> accountResponse = TestHelpers.AcmeAccountResponse;

            acmeApiMock.Setup(method => method.CreateAccountAsync(It.IsAny <AcmeDirectory>(), It.IsAny <string>(), It.IsAny <AcmeCreateAccount>()))
            .ReturnsAsync(accountResponse);

            AcmeAccountService srv = new AcmeAccountService(acmeApiMock.Object, directoryCacheMock.Object, nonceCacheMock.Object);

            //ACT
            await srv.CreateAsync(inputAccount);

            //ASSERT
            nonceCacheMock.Verify(method => method.Update(accountResponse.Nonce), Times.Once());
        }
コード例 #7
0
        /// <summary>
        /// Creates a new account.
        /// </summary>
        /// <param name="directory">Directory object.</param>
        /// <param name="nonce">Nonce</param>
        /// <param name="account">Information for new account.</param>
        /// <returns>Returns a serializable account object. Wrapped by a response object.</returns>
        /// <remarks>It is best to serialize and save the account object so it can be retrieved later and used for renewing domains.</remarks>
        public async Task <AcmeApiResponse <AcmeAccount> > CreateAccountAsync(AcmeDirectory directory, string nonce, AcmeCreateAccount account)
        {
            if (directory == null)
            {
                throw new ArgumentNullException("directory");
            }
            if (string.IsNullOrEmpty(directory.NewAccount))
            {
                throw new ArgumentException("directory is missing Account url.");
            }
            if (string.IsNullOrEmpty(nonce))
            {
                throw new ArgumentNullException("nonce");
            }
            if (account == null)
            {
                throw new ArgumentNullException("account");
            }

            RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider(2048);
            RSAParameters            rsaPrams       = cryptoProvider.ExportParameters(true);

            JwsContainer <AcmeCreateAccount> jwsObject = new JwsContainer <AcmeCreateAccount>(rsaPrams, nonce, directory.NewAccount, account);

            string jwsToken = jwsObject.SerializeSignedToken();

            var apiResp = await SendPostData(
                url : directory.NewAccount,
                data : jwsToken);

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

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

            if (!apiResp.Headers.TryGetValues(ProtoacmeContants.HEADER_LOCATION, out IEnumerable <string> locations))
            {
                return(ErrorResponse <AcmeAccount>("Missing Location Header on CreateAccount Response."));
            }

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

            Dictionary <string, object> oResp = JsonConvert.DeserializeObject <Dictionary <string, object> >(apiRespString);

            var loc = locations.FirstOrDefault();
            var id  = int.Parse((new Uri(loc)).Segments.Last());

            return(new AcmeApiResponse <AcmeAccount>()
            {
                Status = AcmeApiResponseStatus.Success,
                Nonce = nonces.FirstOrDefault(),
                Data = new AcmeAccount()
                {
                    Id = id,
                    KID = loc,
                    SecurityInfo = rsaPrams,
                    Contact = account.Contact
                }
            });
        }