From de3d510f12b57f7da649b8cd2d424b60f232bbf4 Mon Sep 17 00:00:00 2001 From: Erica Portnoy Date: Tue, 14 Jan 2025 16:20:04 -0800 Subject: [PATCH] Pass the optionally-existing key back into obtain_certificates on retry so that the existing key can be used for the new certificate --- certbot/certbot/_internal/client.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/certbot/certbot/_internal/client.py b/certbot/certbot/_internal/client.py index 9bd4c682c..1c83da698 100644 --- a/certbot/certbot/_internal/client.py +++ b/certbot/certbot/_internal/client.py @@ -380,11 +380,11 @@ class Client: with open(old_keypath, "rb") as f: keypath = old_keypath keypem = f.read() - key: Optional[util.Key] = util.Key(file=keypath, pem=keypem) + optional_key: Optional[util.Key] = util.Key(file=keypath, pem=keypem) logger.info("Reusing existing private key from %s.", old_keypath) else: # The key is set to None here but will be created below. - key = None + optional_key = None key_size = self.config.rsa_key_size elliptic_curve = "secp256r1" @@ -402,7 +402,7 @@ class Client: # Create CSR from names if self.config.dry_run: - key = key or util.Key( + key: util.Key = optional_key or util.Key( file=None, pem=crypto_util.make_key( bits=key_size, @@ -415,7 +415,7 @@ class Client: data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: - key = key or crypto_util.generate_key( + key: util.Key = optional_key or crypto_util.generate_key( key_size=key_size, key_dir=None, key_type=self.config.key_type, @@ -434,7 +434,7 @@ class Client: if self.config.allow_subset_of_names: successful_domains = self._successful_domains_from_error(error, domains) if successful_domains != domains and len(successful_domains) != 0: - return self._retry_obtain_certificate(domains, successful_domains) + return self._retry_obtain_certificate(domains, successful_domains, old_keypath) raise authzr = orderr.authorizations auth_domains = {a.body.identifier.value for a in authzr} @@ -446,7 +446,7 @@ class Client: # domains contains a wildcard because the ACME spec forbids identifiers # in authzs from containing a wildcard character. if self.config.allow_subset_of_names and successful_domains != domains: - return self._retry_obtain_certificate(domains, successful_domains) + return self._retry_obtain_certificate(domains, successful_domains, old_keypath) else: try: cert, chain = self.obtain_certificate_from_csr(csr, orderr) @@ -458,7 +458,8 @@ class Client: if self.config.allow_subset_of_names: successful_domains = self._successful_domains_from_error(error, domains) if successful_domains != domains and len(successful_domains) != 0: - return self._retry_obtain_certificate(domains, successful_domains) + return self._retry_obtain_certificate( + domains, successful_domains, old_keypath) raise def _get_order_and_authorizations(self, csr_pem: bytes, @@ -540,13 +541,14 @@ class Client: return successful_domains return [] - def _retry_obtain_certificate(self, domains: List[str], successful_domains: List[str] + def _retry_obtain_certificate(self, domains: List[str], successful_domains: List[str], + old_keypath: Optional[str] ) -> Tuple[bytes, bytes, util.Key, util.CSR]: failed_domains = [d for d in domains if d not in successful_domains] domains_list = ", ".join(failed_domains) display_util.notify("Unable to obtain a certificate with every requested " f"domain. Retrying without: {domains_list}") - return self.obtain_certificate(successful_domains) + return self.obtain_certificate(successful_domains, old_keypath) def _choose_lineagename(self, domains: List[str], certname: Optional[str]) -> str: """Chooses a name for the new lineage.