Skip to content

Commit

Permalink
renewal: fix key_type not being preserved on <v1.25.0 renewal configs (
Browse files Browse the repository at this point in the history
…#9636)

Fixes #9635.
  • Loading branch information
alexzorin committed Mar 28, 2023
1 parent 208ef4e commit e10e549
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 2 deletions.
21 changes: 21 additions & 0 deletions certbot-ci/certbot_integration_tests/certbot_tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,3 +936,24 @@ def test_preferred_chain(context: IntegrationTestsContext) -> None:
with open(conf_path, 'r') as f:
assert f'preferred_chain = {requested}' in f.read(), \
'Expected preferred_chain to be set in renewal config'


def test_ancient_rsa_key_type_preserved(context: IntegrationTestsContext) -> None:
certname = context.get_domain('newname')
context.certbot(['certonly', '-d', certname, '--key-type', 'rsa'])
assert_saved_lineage_option(context.config_dir, certname, 'key_type', 'rsa')

# Remove `key_type = rsa` from the renewal config to emulate a <v1.25.0 Certbot certificate.
conf_path = join(context.config_dir, 'renewal', f'{certname}.conf')
conf_contents: str = ''
with open(conf_path) as f:
conf_contents = f.read()
conf_contents = conf_contents.replace('key_type = rsa', '')
with open(conf_path, 'w') as f:
f.write(conf_contents)

context.certbot(['renew', '--cert-name', certname, '--force-renewal'])

assert_saved_lineage_option(context.config_dir, certname, 'key_type', 'rsa')
key2 = join(context.config_dir, 'archive/{0}/privkey2.pem'.format(certname))
assert_rsa_key(key2, 2048)
4 changes: 4 additions & 0 deletions certbot/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).

### Fixed

* Fixed `renew` sometimes not preserving the key type of RSA certificates.
* Users who upgraded from Certbot <v1.25.0 to Certbot >=v2.0.0 may
have had their RSA certificates inadvertently changed to ECDSA certificates. If desired,
the key type may be changed back to RSA. See the [User Guide](https://eff-certbot.readthedocs.io/en/stable/using.html#changing-a-certificate-s-key-type).
* Deprecated flags were inadvertently not printing warnings since v1.16.0. This is now fixed.

More details about these changes can be found on our GitHub repo.
Expand Down
8 changes: 8 additions & 0 deletions certbot/certbot/_internal/renewal.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ def reconstitute(config: configuration.NamespaceConfig,
logger.error("Renewal configuration file %s does not specify "
"an authenticator. Skipping.", full_path)
return None

# Prior to Certbot v1.25.0, the default value of key_type (rsa) was not persisted to the
# renewal params. If the option is absent, it means the certificate was an RSA key.
# Restoring the option here is necessary to preserve the certificate key_type if
# the user has upgraded directly from Certbot <v1.25.0 to >=v2.0.0, where the default
# key_type was changed to ECDSA. See https://github.com/certbot/certbot/issues/9635.
renewalparams["key_type"] = renewalparams.get("key_type", "rsa")

# Now restore specific values along with their data types, if
# those elements are present.
renewalparams = _remove_deprecated_config_elements(renewalparams)
Expand Down
4 changes: 2 additions & 2 deletions certbot/tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1472,13 +1472,13 @@ def test_renew_verb(self):
self._test_renewal_common(True, [], args=args, should_renew=True)

def test_reuse_key(self):
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf', ec=False)
args = ["renew", "--dry-run", "--reuse-key"]
self._test_renewal_common(True, [], args=args, should_renew=True, reuse_key=True)

@mock.patch('certbot._internal.storage.RenewableCert.save_successor')
def test_reuse_key_no_dry_run(self, unused_save_successor):
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf', ec=False)
args = ["renew", "--reuse-key"]
self._test_renewal_common(True, [], args=args, should_renew=True, reuse_key=True)

Expand Down
11 changes: 11 additions & 0 deletions certbot/tests/renewal_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ def test_remove_deprecated_config_elements(self, mock_set_by_cli, unused_mock_ge
# value in the renewal conf file
assert isinstance(lineage_config.manual_public_ip_logging_ok, mock.MagicMock)

@mock.patch('certbot._internal.renewal.cli.set_by_cli')
def test_absent_key_type_restored(self, mock_set_by_cli):
mock_set_by_cli.return_value = False

rc_path = test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf', ec=False)

from certbot._internal import renewal
lineage_config = copy.deepcopy(self.config)
renewal.reconstitute(lineage_config, rc_path)
assert lineage_config.key_type == 'rsa'


class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase):
"""Tests for certbot._internal.renewal.restore_required_config_elements."""
Expand Down

0 comments on commit e10e549

Please sign in to comment.