public AcmeRegistration Register(string[] contacts) { AssertInit(); var requMsg = new NewRegRequest { Contact = contacts, }; var resp = RequestHttpPost(new Uri(RootUrl, Directory[AcmeServerDirectory.RES_NEW_REG]), requMsg); // HTTP 409 (Conflict) response for a previously registered pub key // Location: still had the regUri if (resp.IsError) { if (resp.StatusCode == HttpStatusCode.Conflict) { throw new AcmeWebException(resp.Error as WebException, "Conflict due to previously registered public key", resp); } else if (resp.IsError) { throw new AcmeWebException(resp.Error as WebException, "Unexpected error", resp); } } var regUri = resp.Headers[AcmeProtocol.HEADER_LOCATION]; if (string.IsNullOrEmpty(regUri)) { throw new AcmeException("server did not provide a registration URI in the response"); } var respMsg = JsonConvert.DeserializeObject <RegResponse>(resp.ContentAsString); var newReg = new AcmeRegistration { PublicKey = Signer.ExportJwk(), RegistrationUri = regUri, Contacts = respMsg.Contact, Links = resp.Links, /// Extracts the "Terms of Service" related link header if there is one and /// returns the URI associated with it. Otherwise returns <c>null</c>. TosLinkUri = resp.Links[AcmeProtocol.LINK_HEADER_REL_TOS].FirstOrDefault(), AuthorizationsUri = respMsg.Authorizations, CertificatesUri = respMsg.Certificates, TosAgreementUri = respMsg.Agreement, }; Registration = newReg; return(Registration); }
public AcmeClient(Uri rootUrl = null, AcmeServerDirectory dir = null, ISigner signer = null, AcmeRegistration reg = null) { RootUrl = rootUrl; Directory = dir; Signer = signer; Registration = reg; UserAgent = string.Format(AcmeProtocol.HTTP_USER_AGENT_FMT, this.GetType().Assembly.GetName().Version); }
public AcmeRegistration UpdateRegistration(bool useRootUrl = false, bool agreeToTos = false, string[] contacts = null) { AssertInit(); AssertRegistration(); var requMsg = new UpdateRegRequest(); if (contacts != null) { requMsg.Contact = contacts; } if (agreeToTos && !string.IsNullOrWhiteSpace(Registration.TosLinkUri)) { requMsg.Agreement = Registration.TosLinkUri; } // Compute the URL to submit the request to, either exactly as // provided in the Registration object or relative to the Root URL var requUri = new Uri(Registration.RegistrationUri); if (useRootUrl) { requUri = new Uri(RootUrl, requUri.PathAndQuery); } var resp = RequestHttpPost(requUri, requMsg); if (resp.IsError) { throw new AcmeWebException(resp.Error as WebException, "Unexpected error", resp); } var respMsg = JsonConvert.DeserializeObject <RegResponse>(resp.ContentAsString); var updReg = new AcmeRegistration { PublicKey = Signer.ExportJwk(), RegistrationUri = Registration.RegistrationUri, Contacts = respMsg.Contact, Links = resp.Links, /// Extracts the "Terms of Service" related link header if there is one and /// returns the URI associated with it. Otherwise returns <c>null</c>. TosLinkUri = resp.Links[AcmeProtocol.LINK_HEADER_REL_TOS].FirstOrDefault(), AuthorizationsUri = respMsg.Authorizations, CertificatesUri = respMsg.Certificates, TosAgreementUri = respMsg.Agreement, }; Registration = updReg; return(Registration); }
public void Test0190_RefreshCertificateRequest() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } //var csrRaw = File.ReadAllBytes($"{_baseLocalStore}\\test-csr.der"); //var csrB64u = JwsHelper.Base64UrlEncode(csrRaw); using (var client = BuildClient(testTagHeader: nameof(Test0190_RefreshCertificateRequest))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); CertificateRequest certRequ; using (var fs = new FileStream(_testCertRequ_AcmeCertRequFile, FileMode.Open)) { certRequ = CertificateRequest.Load(fs); } client.RefreshCertificateRequest(certRequ, true); _testCertRequRefreshed_AcmeCertRequFile = $"{_baseLocalStore}\\TestCertRequ-Refreshed.acmeCertRequ"; using (var fs = new FileStream(_testCertRequRefreshed_AcmeCertRequFile, FileMode.Create)) { certRequ.Save(fs); } if (!string.IsNullOrEmpty(certRequ.CertificateContent)) { _testCertRequRefreshed_CerFile = $"{_baseLocalStore}\\TestCertRequ-Refreshed.cer"; using (var fs = new FileStream(_testCertRequRefreshed_CerFile, FileMode.Create)) { certRequ.SaveCertificate(fs); } } } } }
public void Test0141_HandleHttpChallenge() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0141_HandleHttpChallenge))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); AuthorizationState authzState; using (var fs = new FileStream(_testAuthz_AcmeAuthzFile, FileMode.Open)) { authzState = AuthorizationState.Load(fs); } var authzChallenge = client.GenerateAuthorizeChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP); _testAuthzChallengeHttpHandled_AcmeAuthzFile = $"{_baseLocalStore}\\TestAuthz-ChallengeAnswersHandleHttp.acmeAuthz"; using (var fs = new FileStream(_testAuthzChallengeHttpHandled_AcmeAuthzFile, FileMode.Create)) { authzState.Save(fs); } var wsFilePath = authzChallenge.ChallengeAnswer.Key; var wsFileBody = authzChallenge.ChallengeAnswer.Value; var wsInfo = WebServerInfo.Load(File.ReadAllText("config\\webServerInfo.json")); using (var s = new MemoryStream(Encoding.UTF8.GetBytes(wsFileBody))) { var fileUrl = new Uri($"http://{authzState.Identifier}/{wsFilePath}"); wsInfo.Provider.UploadFile(fileUrl, s); } } } Thread.Sleep(90 * 1000); }
public void Test0090_AuthorizeIdentifier() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0090_AuthorizeIdentifier))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); var authzState = client.AuthorizeIdentifier(TEST_CN1); foreach (var c in authzState.Challenges) { if (c.Type == AcmeProtocol.CHALLENGE_TYPE_DNS) { var dnsResponse = c.GenerateDnsChallengeAnswer( authzState.Identifier, signer); } else if (c.Type == AcmeProtocol.CHALLENGE_TYPE_HTTP) { var httpResponse = c.GenerateHttpChallengeAnswer( authzState.Identifier, signer); } } _testAuthz_AcmeAuthzFile = $"{_baseLocalStore}\\TestAuthz.acmeAuthz"; using (var fs = new FileStream(_testAuthz_AcmeAuthzFile, FileMode.Create)) { authzState.Save(fs); } } } }
public void Test0120_GenerateChallengeAnswers() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0120_GenerateChallengeAnswers))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); AuthorizationState authzState; using (var fs = new FileStream(_testAuthz_AcmeAuthzFile, FileMode.Open)) { authzState = AuthorizationState.Load(fs); } //client.GenerateAuthorizeChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS); //client.GenerateAuthorizeChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_LEGACY_HTTP); client.GenerateAuthorizeChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP); _testAuthzChallengeAnswers_AcmeAuthzFile = $"{_baseLocalStore}\\TestAuthz-ChallengeAnswers.acmeAuthz"; using (var fs = new FileStream(_testAuthzChallengeAnswers_AcmeAuthzFile, FileMode.Create)) { authzState.Save(fs); } } } }
public void Test0095_RefreshIdentifierAuthorization() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0095_RefreshIdentifierAuthorization))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); AuthorizationState authzState; using (var fs = new FileStream(_testAuthz_AcmeAuthzFile, FileMode.Open)) { authzState = AuthorizationState.Load(fs); } var authzRefreshState = client.RefreshIdentifierAuthorization(authzState, true); _testAuthzRefresh_AcmeAuthzFile = $"{_baseLocalStore}\\TestAuthz-Refresh.acmeAuthz"; using (var fs = new FileStream(_testAuthzRefresh_AcmeAuthzFile, FileMode.Create)) { authzRefreshState.Save(fs); } } } }
public void Test0080_AuthorizeDnsBlacklisted() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0080_AuthorizeDnsBlacklisted))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); try { client.AuthorizeIdentifier("acme-win-test.example.com"); } catch (AcmeClient.AcmeWebException ex) { Assert.IsNotNull(ex.WebException); Assert.IsNotNull(ex.Response); Assert.IsNotNull(ex.Response.ProblemDetail); Assert.AreEqual(HttpStatusCode.Forbidden, ex.Response.StatusCode); Assert.AreEqual("urn:acme:error:unauthorized", ex.Response.ProblemDetail.Type); StringAssert.Contains(ex.Response.ProblemDetail.Detail, "blacklist"); } } } }
public void Test0160_RequestCertificateInvalidCsr() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0160_RequestCertificateInvalidCsr))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); try { client.RequestCertificate("FOOBARNON"); Assert.Fail("WebException expected"); } catch (AcmeClient.AcmeWebException ex) { Assert.IsNotNull(ex.WebException); Assert.IsNotNull(ex.Response); Assert.AreEqual(HttpStatusCode.BadRequest, ex.Response.StatusCode); } } } }
public void Test0040_RegisterEmptyUpdate() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0040_RegisterEmptyUpdate))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); // Do a simple update with no data changes requested client.UpdateRegistration(true); Assert.IsNotNull(client.Registration); Assert.IsFalse(string.IsNullOrWhiteSpace(client.Registration.RegistrationUri)); _testRegisterUpdate_AcmeRegFile = $"{_baseLocalStore}\\TestRegisterEmptyUpdate.acmeReg"; using (var fs = new FileStream(_testRegisterUpdate_AcmeRegFile, FileMode.Create)) { client.Registration.Save(fs); } } } }
public void Test0060_RegisterUpdateContacts() { using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } using (var client = BuildClient(testTagHeader: nameof(Test0060_RegisterUpdateContacts))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); client.UpdateRegistration(true, contacts: new string[] { TEST_EM2, }); Assert.IsNotNull(client.Registration); Assert.IsFalse(string.IsNullOrWhiteSpace(client.Registration.RegistrationUri)); _testRegisterUpdate_AcmeRegFile = $"{_baseLocalStore}\\TestRegisterUpdate.acmeReg"; using (var fs = new FileStream(_testRegisterUpdate_AcmeRegFile, FileMode.Create)) { client.Registration.Save(fs); } } } }
public void Test0170_GenCsrAndRequestCertificate() { using (var cp = CertificateProvider.GetProvider()) { var rsaKeyParams = new RsaPrivateKeyParams(); var rsaKey = cp.GeneratePrivateKey(rsaKeyParams); _testGenCsr_RsaKeysFile = $"{_baseLocalStore}\\TestGenCsr-rsaKeys.txt"; using (var fs = new FileStream(_testGenCsr_RsaKeysFile, FileMode.Create)) { cp.SavePrivateKey(rsaKey, fs); } var csrParams = new CsrParams { Details = new CsrDetails { CommonName = TEST_CN1 } }; var csr = cp.GenerateCsr(csrParams, rsaKey, Crt.MessageDigest.SHA256); _testGenCsr_CsrDetailsFile = $"{_baseLocalStore}\\TestGenCsr-csrDetails.txt"; using (var fs = new FileStream(_testGenCsr_CsrDetailsFile, FileMode.Create)) { cp.SaveCsrParams(csrParams, fs); } _testGenCsr_CsrFile = $"{_baseLocalStore}\\TestGenCsr-csr.txt"; using (var fs = new FileStream(_testGenCsr_CsrFile, FileMode.Create)) { cp.SaveCsr(csr, fs); } using (var signer = new RS256Signer()) { signer.Init(); using (var fs = new FileStream(_testRegister_AcmeSignerFile, FileMode.Open)) { signer.Load(fs); } AcmeRegistration reg; using (var fs = new FileStream(_testRegister_AcmeRegFile, FileMode.Open)) { reg = AcmeRegistration.Load(fs); } byte[] derRaw; using (var bs = new MemoryStream()) { cp.ExportCsr(csr, EncodingFormat.DER, bs); derRaw = bs.ToArray(); } var derB64u = JwsHelper.Base64UrlEncode(derRaw); using (var client = BuildClient(testTagHeader: nameof(Test0170_GenCsrAndRequestCertificate))) { client.RootUrl = _rootUrl; client.Signer = signer; client.Registration = reg; client.Init(); client.GetDirectory(true); var certRequ = client.RequestCertificate(derB64u); _testCertRequ_AcmeCertRequFile = $"{_baseLocalStore}\\TestCertRequ.acmeCertRequ"; using (var fs = new FileStream(_testCertRequ_AcmeCertRequFile, FileMode.Create)) { certRequ.Save(fs); } } } } }
public AcmeRegistration UpdateRegistration(bool useRootUrl = false, bool agreeToTos = false, string[] contacts = null) { AssertInit(); AssertRegistration(); var requMsg = new UpdateRegRequest(); if (contacts != null) requMsg.Contact = contacts; if (agreeToTos && !string.IsNullOrWhiteSpace(Registration.TosLinkUri)) requMsg.Agreement = Registration.TosLinkUri; // Compute the URL to submit the request to, either exactly as // provided in the Registration object or relative to the Root URL var requUri = new Uri(Registration.RegistrationUri); if (useRootUrl) requUri = new Uri(RootUrl, requUri.PathAndQuery); var resp = RequestHttpPost(requUri, requMsg); if (resp.IsError) { throw new AcmeWebException(resp.Error as WebException, "Unexpected error", resp); } var respMsg = JsonConvert.DeserializeObject<RegResponse>(resp.ContentAsString); var updReg = new AcmeRegistration { PublicKey = Signer.ExportJwk(), RegistrationUri = Registration.RegistrationUri, Contacts = respMsg.Contact, Links = resp.Links, /// Extracts the "Terms of Service" related link header if there is one and /// returns the URI associated with it. Otherwise returns <c>null</c>. TosLinkUri = resp.Links[AcmeProtocol.LINK_HEADER_REL_TOS].FirstOrDefault(), AuthorizationsUri = respMsg.Authorizations, CertificatesUri = respMsg.Certificates, TosAgreementUri = respMsg.Agreement, }; Registration = updReg; return Registration; }
public AcmeRegistration Register(string[] contacts) { AssertInit(); var requMsg = new NewRegRequest { Contact = contacts, }; var resp = RequestHttpPost(new Uri(RootUrl, Directory[AcmeServerDirectory.RES_NEW_REG]), requMsg); // HTTP 409 (Conflict) response for a previously registered pub key // Location: still had the regUri if (resp.IsError) { if (resp.StatusCode == HttpStatusCode.Conflict) throw new AcmeWebException(resp.Error as WebException, "Conflict due to previously registered public key", resp); else if (resp.IsError) throw new AcmeWebException(resp.Error as WebException, "Unexpected error", resp); } var regUri = resp.Headers[AcmeProtocol.HEADER_LOCATION]; if (string.IsNullOrEmpty(regUri)) throw new AcmeException("server did not provide a registration URI in the response"); var respMsg = JsonConvert.DeserializeObject<RegResponse>(resp.ContentAsString); var newReg = new AcmeRegistration { PublicKey = Signer.ExportJwk(), RegistrationUri = regUri, Contacts = respMsg.Contact, Links = resp.Links, /// Extracts the "Terms of Service" related link header if there is one and /// returns the URI associated with it. Otherwise returns <c>null</c>. TosLinkUri = resp.Links[AcmeProtocol.LINK_HEADER_REL_TOS].FirstOrDefault(), AuthorizationsUri = respMsg.Authorizations, CertificatesUri = respMsg.Certificates, TosAgreementUri = respMsg.Agreement, }; Registration = newReg; return Registration; }