From 33b851b6c5d5e802c1b1404ecf615d06fb3d0402 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:22:12 -0800 Subject: [PATCH 1/7] remove continuity challenges from acme_util --- letsencrypt/tests/acme_util.py | 58 ++------------------------ letsencrypt/tests/auth_handler_test.py | 47 ++++++--------------- 2 files changed, 16 insertions(+), 89 deletions(-) diff --git a/letsencrypt/tests/acme_util.py b/letsencrypt/tests/acme_util.py index 71ebb471d..ea5438923 100644 --- a/letsencrypt/tests/acme_util.py +++ b/letsencrypt/tests/acme_util.py @@ -17,56 +17,14 @@ HTTP01 = challenges.HTTP01( TLSSNI01 = challenges.TLSSNI01( token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA")) DNS = challenges.DNS(token="17817c66b60ce2e4012dfad92657527a") -RECOVERY_CONTACT = challenges.RecoveryContact( - activation_url="https://example.ca/sendrecovery/a5bd99383fb0", - success_url="https://example.ca/confirmrecovery/bb1b9928932", - contact="c********n@example.com") -POP = challenges.ProofOfPossession( - alg="RS256", nonce=jose.b64decode("eET5udtV7aoX8Xl8gYiZIA"), - hints=challenges.ProofOfPossession.Hints( - jwk=jose.JWKRSA(key=KEY.public_key()), - cert_fingerprints=( - "93416768eb85e33adc4277f4c9acd63e7418fcfe", - "16d95b7b63f1972b980b14c20291f3c0d1855d95", - "48b46570d9fc6358108af43ad1649484def0debf" - ), - certs=(), # TODO - subject_key_identifiers=("d0083162dcc4c8a23ecb8aecbd86120e56fd24e5"), - serial_numbers=(34234239832, 23993939911, 17), - issuers=( - "C=US, O=SuperT LLC, CN=SuperTrustworthy Public CA", - "O=LessTrustworthy CA Inc, CN=LessTrustworthy But StillSecure", - ), - authorized_for=("www.example.com", "example.net"), - ) -) -CHALLENGES = [HTTP01, TLSSNI01, DNS, RECOVERY_CONTACT, POP] -DV_CHALLENGES = [chall for chall in CHALLENGES - if isinstance(chall, challenges.DVChallenge)] -CONT_CHALLENGES = [chall for chall in CHALLENGES - if isinstance(chall, challenges.ContinuityChallenge)] +CHALLENGES = [HTTP01, TLSSNI01, DNS] def gen_combos(challbs): """Generate natural combinations for challbs.""" - dv_chall = [] - cont_chall = [] - - for i, challb in enumerate(challbs): # pylint: disable=redefined-outer-name - if isinstance(challb.chall, challenges.DVChallenge): - dv_chall.append(i) - else: - cont_chall.append(i) - - if cont_chall: - # Gen combos for 1 of each type, lowest - # index included first (makes testing easier) - return tuple((i, j) if i < j else (j, i) - for i in dv_chall for j in cont_chall) - else: - # completing a single DV chall satisfies the CA - return tuple((i,) for i in dv_chall) + # completing a single DV challenge satisfies the CA + return tuple((i,) for i, _ in enumerate(challbs)) def chall_to_challb(chall, status): # pylint: disable=redefined-outer-name @@ -87,16 +45,8 @@ def chall_to_challb(chall, status): # pylint: disable=redefined-outer-name TLSSNI01_P = chall_to_challb(TLSSNI01, messages.STATUS_PENDING) HTTP01_P = chall_to_challb(HTTP01, messages.STATUS_PENDING) DNS_P = chall_to_challb(DNS, messages.STATUS_PENDING) -RECOVERY_CONTACT_P = chall_to_challb(RECOVERY_CONTACT, messages.STATUS_PENDING) -POP_P = chall_to_challb(POP, messages.STATUS_PENDING) -CHALLENGES_P = [HTTP01_P, TLSSNI01_P, DNS_P, RECOVERY_CONTACT_P, POP_P] -DV_CHALLENGES_P = [challb for challb in CHALLENGES_P - if isinstance(challb.chall, challenges.DVChallenge)] -CONT_CHALLENGES_P = [ - challb for challb in CHALLENGES_P - if isinstance(challb.chall, challenges.ContinuityChallenge) -] +CHALLENGES_P = [HTTP01_P, TLSSNI01_P, DNS_P] def gen_authzr(authz_status, domain, challs, statuses, combos=True): diff --git a/letsencrypt/tests/auth_handler_test.py b/letsencrypt/tests/auth_handler_test.py index dcf8a5ab3..426a269ac 100644 --- a/letsencrypt/tests/auth_handler_test.py +++ b/letsencrypt/tests/auth_handler_test.py @@ -35,10 +35,10 @@ class ChallengeFactoryTest(unittest.TestCase): self.dom, range(0, len(acme_util.CHALLENGES))) self.assertEqual( - [achall.chall for achall in achalls], acme_util.DV_CHALLENGES) + [achall.chall for achall in achalls], acme_util.CHALLENGES) def test_one_tls_sni(self): - achalls = self.handler._challenge_factory(self.dom, [1, 3]) + achalls = self.handler._challenge_factory(self.dom, [1]) self.assertEqual( [achall.chall for achall in achalls], [acme_util.TLSSNI01]) @@ -83,7 +83,7 @@ class GetAuthorizationsTest(unittest.TestCase): @mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges") def test_name1_tls_sni_01_1(self, mock_poll): self.mock_net.request_domain_challenges.side_effect = functools.partial( - gen_dom_authzr, challs=acme_util.DV_CHALLENGES) + gen_dom_authzr, challs=acme_util.CHALLENGES) mock_poll.side_effect = self._validate_all @@ -106,7 +106,7 @@ class GetAuthorizationsTest(unittest.TestCase): @mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges") def test_name1_tls_sni_01_1_http_01_1_dns_1(self, mock_poll): self.mock_net.request_domain_challenges.side_effect = functools.partial( - gen_dom_authzr, challs=acme_util.DV_CHALLENGES, combos=False) + gen_dom_authzr, challs=acme_util.CHALLENGES, combos=False) mock_poll.side_effect = self._validate_all self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01) @@ -131,7 +131,7 @@ class GetAuthorizationsTest(unittest.TestCase): @mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges") def test_name3_tls_sni_01_3(self, mock_poll): self.mock_net.request_domain_challenges.side_effect = functools.partial( - gen_dom_authzr, challs=acme_util.DV_CHALLENGES) + gen_dom_authzr, challs=acme_util.CHALLENGES) mock_poll.side_effect = self._validate_all @@ -156,7 +156,7 @@ class GetAuthorizationsTest(unittest.TestCase): def test_perform_failure(self): self.mock_net.request_domain_challenges.side_effect = functools.partial( - gen_dom_authzr, challs=acme_util.DV_CHALLENGES) + gen_dom_authzr, challs=acme_util.CHALLENGES) self.mock_auth.perform.side_effect = errors.AuthorizationError self.assertRaises( @@ -189,15 +189,16 @@ class PollChallengesTest(unittest.TestCase): self.doms = ["0", "1", "2"] self.handler.authzr[self.doms[0]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[0], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) + [acme_util.HTTP01, acme_util.TLSSNI01], + [messages.STATUS_PENDING] * 2, False) self.handler.authzr[self.doms[1]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[1], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) + acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False) self.handler.authzr[self.doms[2]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[2], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) + acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False) self.chall_update = {} for dom in self.doms: @@ -234,7 +235,7 @@ class PollChallengesTest(unittest.TestCase): from letsencrypt.auth_handler import challb_to_achall self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid self.chall_update[self.doms[0]].append( - challb_to_achall(acme_util.RECOVERY_CONTACT_P, "key", self.doms[0])) + challb_to_achall(acme_util.DNS_P, "key", self.doms[0])) self.assertRaises( errors.AuthorizationError, self.handler._poll_challenges, self.chall_update, False) @@ -335,32 +336,8 @@ class GenChallengePathTest(unittest.TestCase): self.assertEqual(self._call(challbs[::-1], prefs, combos), (1,)) self.assertTrue(self._call(challbs[::-1], prefs, None)) - def test_common_case_with_continuity(self): - challbs = (acme_util.POP_P, - acme_util.RECOVERY_CONTACT_P, - acme_util.TLSSNI01_P, - acme_util.HTTP01_P) - prefs = [challenges.ProofOfPossession, challenges.TLSSNI01] - combos = acme_util.gen_combos(challbs) - self.assertEqual(self._call(challbs, prefs, combos), (0, 2)) - - def test_full_cont_server(self): - challbs = (acme_util.RECOVERY_CONTACT_P, - acme_util.POP_P, - acme_util.TLSSNI01_P, - acme_util.HTTP01_P, - acme_util.DNS_P) - # Typical webserver client that can do everything except DNS - # Attempted to make the order realistic - prefs = [challenges.ProofOfPossession, - challenges.HTTP01, - challenges.TLSSNI01, - challenges.RecoveryContact] - combos = acme_util.gen_combos(challbs) - self.assertEqual(self._call(challbs, prefs, combos), (1, 3)) - def test_not_supported(self): - challbs = (acme_util.POP_P, acme_util.TLSSNI01_P) + challbs = (acme_util.DNS_P, acme_util.TLSSNI01_P) prefs = [challenges.TLSSNI01] combos = ((0, 1),) From b0280ac17e221fcaefb27753f6b5bc91f7ebcaa7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:25:05 -0800 Subject: [PATCH 2/7] no PoP or RC in auth_handler --- letsencrypt/auth_handler.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/letsencrypt/auth_handler.py b/letsencrypt/auth_handler.py index a324dd4b7..659f4b721 100644 --- a/letsencrypt/auth_handler.py +++ b/letsencrypt/auth_handler.py @@ -320,12 +320,6 @@ def challb_to_achall(challb, account_key, domain): challb=challb, domain=domain, account_key=account_key) elif isinstance(chall, challenges.DNS): return achallenges.DNS(challb=challb, domain=domain) - elif isinstance(chall, challenges.RecoveryContact): - return achallenges.RecoveryContact( - challb=challb, domain=domain) - elif isinstance(chall, challenges.ProofOfPossession): - return achallenges.ProofOfPossession( - challb=challb, domain=domain) else: raise errors.Error( "Received unsupported challenge of type: %s", chall.typ) From eb71506be9e4aa5de78f9cc504165549be2feaa1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:27:56 -0800 Subject: [PATCH 3/7] remove PoP and RC achalls --- letsencrypt/achallenges.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/letsencrypt/achallenges.py b/letsencrypt/achallenges.py index 4d85f5d6a..0cdec06df 100644 --- a/letsencrypt/achallenges.py +++ b/letsencrypt/achallenges.py @@ -59,15 +59,3 @@ class DNS(AnnotatedChallenge): """Client annotated "dns" ACME challenge.""" __slots__ = ('challb', 'domain') acme_type = challenges.DNS - - -class RecoveryContact(AnnotatedChallenge): - """Client annotated "recoveryContact" ACME challenge.""" - __slots__ = ('challb', 'domain') - acme_type = challenges.RecoveryContact - - -class ProofOfPossession(AnnotatedChallenge): - """Client annotated "proofOfPossession" ACME challenge.""" - __slots__ = ('challb', 'domain') - acme_type = challenges.ProofOfPossession From f2e728cd4e7d94ffb17077c8895f2fcc02c543ff Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:29:08 -0800 Subject: [PATCH 4/7] Remove ContAuthError --- letsencrypt/errors.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index 99bb29d9d..4f9e655d8 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -48,10 +48,6 @@ class FailedChallenges(AuthorizationError): for achall in self.failed_achalls if achall.error is not None)) -class ContAuthError(AuthorizationError): - """Let's Encrypt Continuity Authenticator error.""" - - class DvAuthError(AuthorizationError): """Let's Encrypt DV Authenticator error.""" From f1e3563f98a188324121b717818efc8af322b70b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:34:01 -0800 Subject: [PATCH 5/7] remove needlessly specific and unused challenge types --- letsencrypt/errors.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index 4f9e655d8..eb9f8dd0e 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -48,15 +48,6 @@ class FailedChallenges(AuthorizationError): for achall in self.failed_achalls if achall.error is not None)) -class DvAuthError(AuthorizationError): - """Let's Encrypt DV Authenticator error.""" - - -# Authenticator - Challenge specific errors -class TLSSNI01Error(DvAuthError): - """Let's Encrypt TLSSNI01 error.""" - - # Plugin Errors class PluginError(Error): """Let's Encrypt Plugin error.""" From 4a208d4821d84cea1dde2193d4ad3327465c11d1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:53:59 -0800 Subject: [PATCH 6/7] remove stray references to DV challs in auth_handler --- letsencrypt/auth_handler.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/letsencrypt/auth_handler.py b/letsencrypt/auth_handler.py index 659f4b721..285a1f3b7 100644 --- a/letsencrypt/auth_handler.py +++ b/letsencrypt/auth_handler.py @@ -21,7 +21,7 @@ class AuthHandler(object): """ACME Authorization Handler for a client. :ivar auth: Authenticator capable of solving - :class:`~acme.challenges.DVChallenge` types + :class:`~acme.challenges.Challenge` types :type auth: :class:`letsencrypt.interfaces.IAuthenticator` :ivar acme.client.Client acme: ACME client API. @@ -117,9 +117,8 @@ class AuthHandler(object): """ # TODO: chall_update is a dirty hack to get around acme-spec #105 chall_update = dict() - active_achalls = [] - active_achalls.extend( - self._send_responses(self.achalls, resp, chall_update)) + active_achalls = self._send_responses(self.achalls, + resp, chall_update) # Check for updated status... try: @@ -253,8 +252,7 @@ class AuthHandler(object): if achall_list is None: achalls = self.achalls else: - achalls = [achall for achall in achall_list - if isinstance(achall.chall, challenges.DVChallenge)] + achalls = achall_list if achalls: self.auth.cleanup(achalls) @@ -280,7 +278,7 @@ class AuthHandler(object): :param list path: List of indices from `challenges`. - :returns: achalls, list of DVChallenge type + :returns: achalls, list of challenge type :class:`letsencrypt.achallenges.Indexed` :rtype: list @@ -291,12 +289,7 @@ class AuthHandler(object): for index in path: challb = self.authzr[domain].body.challenges[index] - chall = challb.chall - - achall = challb_to_achall(challb, self.account.key, domain) - - if isinstance(chall, challenges.DVChallenge): - achalls.append(achall) + achalls.append(challb_to_achall(challb, self.account.key, domain)) return achalls From 26ffd8df3b5d12ea3707391caf70a32bc7999a2e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Mar 2016 17:56:23 -0800 Subject: [PATCH 7/7] constants.DV_CHALLENGES is not the constant you are looking for --- letsencrypt/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index d0bdb1f85..6134c4e6e 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -163,7 +163,7 @@ class Client(object): dispatch DV challenges to appropriate authenticators (providing `.IAuthenticator` interface). :ivar .IAuthenticator auth: Prepared (`.IAuthenticator.prepare`) - authenticator that can solve the `.constants.DV_CHALLENGES`. + authenticator that can solve ACME challenges. :ivar .IInstaller installer: Installer. :ivar acme.client.Client acme: Optional ACME client API handle. You might already have one from `register`.