diff --git a/acme/acme/client.py b/acme/acme/client.py index bdc07fb1c..29b42c381 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -16,6 +16,7 @@ from requests_toolbelt.adapters.source import SourceAddressAdapter import requests from requests.adapters import HTTPAdapter import sys +import json from acme import crypto_util from acme import errors @@ -832,6 +833,35 @@ class BackwardsCompatibleClientV2(object): """ return self.client.revoke(cert, rsn) + def build_new_registration(self, email, kid=None, hmac_key=None, phone=None, **kwargs): + """Create registration resource from contact details.""" + details = list(kwargs.pop('contact', ())) + if phone is not None: + details.append(messages.Registration.phone_prefix + phone) + if email is not None: + details.append(messages.Registration.email_prefix + email) + kwargs['contact'] = tuple(details) + + if kid is not None and hmac_key is not None: + kwargs['external_account_binding'] = self.build_external_account_binding(kid, hmac_key) + + return messages.NewRegistration(**kwargs) + + def build_external_account_binding(self, kid, hmac_key): + account_public_key = self.client.net.key.public_key() + directory = self.client.directory + + key_json = json.dumps(account_public_key.to_partial_json()) + decoded_hmac_key = jose.b64.b64decode(hmac_key) + url = directory["newAccount"] + + eab = jws.JWS.sign(key_json, jose.jwk.JWKOct(key=decoded_hmac_key), + jose.jwa.HS256, None, + url, kid) + + return eab.to_partial_json() + + def _acme_version_from_directory(self, directory): if hasattr(directory, 'newNonce'): return 2 diff --git a/certbot/client.py b/certbot/client.py index 26d985662..649380acc 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -196,13 +196,10 @@ def perform_registration(acme, config, tos_cb): if config.eab_kid is None or config.eab_hmac_key is None: raise errors.Error("Server requires external account binding. Please use --eab-kid and --eab-hmac-key.") - account_public_key = acme.client.net.key.public_key() try: - return acme.new_account_and_tos(messages.NewRegistration.from_data(account_public_key=account_public_key, - kid=config.eab_kid, - hmac_key=config.eab_hmac_key, - email=config.email, - directory=acme.client.directory), + return acme.new_account_and_tos(acme.build_new_registration(config.eab_kid, + config.eab_hmac_key, + config.email), tos_cb) except messages.Error as e: if e.code == "invalidEmail" or e.code == "invalidContact":