mirror of
https://github.com/certbot/certbot.git
synced 2026-08-03 20:02:16 +02:00
Add --eab-hmac-alg parameter to support custom HMAC algorithm for EAB (#10319)
fixed: #10281
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
"""Tests for acme.messages."""
|
"""Tests for acme.messages."""
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
@@ -218,17 +219,43 @@ class ExternalAccountBindingTest(unittest.TestCase):
|
|||||||
self.key = jose.jwk.JWKRSA(key=KEY.public_key())
|
self.key = jose.jwk.JWKRSA(key=KEY.public_key())
|
||||||
self.kid = "kid-for-testing"
|
self.kid = "kid-for-testing"
|
||||||
self.hmac_key = "hmac-key-for-testing"
|
self.hmac_key = "hmac-key-for-testing"
|
||||||
|
self.hmac_alg = "HS256"
|
||||||
self.dir = Directory({
|
self.dir = Directory({
|
||||||
'newAccount': 'http://url/acme/new-account',
|
'newAccount': 'http://url/acme/new-account',
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_from_data(self):
|
def test_from_data(self):
|
||||||
from acme.messages import ExternalAccountBinding
|
from acme.messages import ExternalAccountBinding
|
||||||
eab = ExternalAccountBinding.from_data(self.key, self.kid, self.hmac_key, self.dir)
|
eab = ExternalAccountBinding.from_data(self.key, self.kid, self.hmac_key, self.dir, self.hmac_alg)
|
||||||
|
|
||||||
assert len(eab) == 3
|
assert len(eab) == 3
|
||||||
assert sorted(eab.keys()) == sorted(['protected', 'payload', 'signature'])
|
assert sorted(eab.keys()) == sorted(['protected', 'payload', 'signature'])
|
||||||
|
|
||||||
|
def test_from_data_invalid_hmac_alg(self):
|
||||||
|
from acme.messages import ExternalAccountBinding
|
||||||
|
invalid_alg = "HS9999"
|
||||||
|
with pytest.raises(ValueError) as info:
|
||||||
|
ExternalAccountBinding.from_data(self.key, self.kid, self.hmac_key, self.dir, invalid_alg)
|
||||||
|
|
||||||
|
assert "Invalid value for hmac_alg" in str(info.value)
|
||||||
|
|
||||||
|
def test_from_data_default_hmac_alg(self):
|
||||||
|
from acme.messages import ExternalAccountBinding
|
||||||
|
eab_default = ExternalAccountBinding.from_data(self.key, self.kid, self.hmac_key, self.dir)
|
||||||
|
|
||||||
|
assert len(eab_default) == 3
|
||||||
|
assert sorted(eab_default.keys()) == sorted(['protected', 'payload', 'signature'])
|
||||||
|
|
||||||
|
eab_explicit = ExternalAccountBinding.from_data(
|
||||||
|
self.key, self.kid, self.hmac_key, self.dir, "HS256"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert eab_default == eab_explicit
|
||||||
|
|
||||||
|
protected_default = json.loads(
|
||||||
|
jose.b64.b64decode(eab_default['protected']).decode()
|
||||||
|
)
|
||||||
|
assert protected_default['alg'] == 'HS256'
|
||||||
|
|
||||||
class RegistrationTest(unittest.TestCase):
|
class RegistrationTest(unittest.TestCase):
|
||||||
"""Tests for acme.messages.Registration."""
|
"""Tests for acme.messages.Registration."""
|
||||||
@@ -268,10 +295,11 @@ class RegistrationTest(unittest.TestCase):
|
|||||||
key = jose.jwk.JWKRSA(key=KEY.public_key())
|
key = jose.jwk.JWKRSA(key=KEY.public_key())
|
||||||
kid = "kid-for-testing"
|
kid = "kid-for-testing"
|
||||||
hmac_key = "hmac-key-for-testing"
|
hmac_key = "hmac-key-for-testing"
|
||||||
|
hmac_alg = "HS256"
|
||||||
directory = Directory({
|
directory = Directory({
|
||||||
'newAccount': 'http://url/acme/new-account',
|
'newAccount': 'http://url/acme/new-account',
|
||||||
})
|
})
|
||||||
eab = ExternalAccountBinding.from_data(key, kid, hmac_key, directory)
|
eab = ExternalAccountBinding.from_data(key, kid, hmac_key, directory, hmac_alg)
|
||||||
reg = NewRegistration.from_data(email='admin@foo.com', external_account_binding=eab)
|
reg = NewRegistration.from_data(email='admin@foo.com', external_account_binding=eab)
|
||||||
assert reg.contact == (
|
assert reg.contact == (
|
||||||
'mailto:admin@foo.com',
|
'mailto:admin@foo.com',
|
||||||
|
|||||||
@@ -304,15 +304,26 @@ class ExternalAccountBinding:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data(cls, account_public_key: jose.JWK, kid: str, hmac_key: str,
|
def from_data(cls, account_public_key: jose.JWK, kid: str, hmac_key: str,
|
||||||
directory: Directory) -> Dict[str, Any]:
|
directory: Directory, hmac_alg: str = "HS256") -> Dict[str, Any]:
|
||||||
"""Create External Account Binding Resource from contact details, kid and hmac."""
|
"""Create External Account Binding Resource from contact details, kid and hmac."""
|
||||||
|
|
||||||
key_json = json.dumps(account_public_key.to_partial_json()).encode()
|
key_json = json.dumps(account_public_key.to_partial_json()).encode()
|
||||||
decoded_hmac_key = jose.b64.b64decode(hmac_key)
|
decoded_hmac_key = jose.b64.b64decode(hmac_key)
|
||||||
url = directory["newAccount"]
|
url = directory["newAccount"]
|
||||||
|
|
||||||
|
hmac_alg_map = {
|
||||||
|
"HS256": jose.jwa.HS256,
|
||||||
|
"HS384": jose.jwa.HS384,
|
||||||
|
"HS512": jose.jwa.HS512,
|
||||||
|
}
|
||||||
|
alg = hmac_alg_map.get(hmac_alg)
|
||||||
|
if alg is None:
|
||||||
|
supported = ", ".join(hmac_alg_map.keys())
|
||||||
|
raise ValueError(f"Invalid value for hmac_alg: {hmac_alg}. "
|
||||||
|
f"Expected one of: {supported}.")
|
||||||
|
|
||||||
eab = jws.JWS.sign(key_json, jose.jwk.JWKOct(key=decoded_hmac_key),
|
eab = jws.JWS.sign(key_json, jose.jwk.JWKOct(key=decoded_hmac_key),
|
||||||
jose.jwa.HS256, None,
|
alg, None,
|
||||||
url, kid)
|
url, kid)
|
||||||
|
|
||||||
return eab.to_partial_json()
|
return eab.to_partial_json()
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
More details about these changes can be found on our GitHub repo.
|
More details about these changes can be found on our GitHub repo.
|
||||||
|
|
||||||
|
## 4.2.0
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added `--eab-hmac-alg` parameter to support custom HMAC algorithm for External Account Binding.
|
||||||
|
|
||||||
## 4.1.1 - 2025-06-12
|
## 4.1.1 - 2025-06-12
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -134,6 +134,13 @@ def prepare_and_parse_args(plugins: plugins_disco.PluginsRegistry, args: List[st
|
|||||||
metavar="EAB_HMAC_KEY",
|
metavar="EAB_HMAC_KEY",
|
||||||
help="HMAC key for External Account Binding"
|
help="HMAC key for External Account Binding"
|
||||||
)
|
)
|
||||||
|
helpful.add(
|
||||||
|
[None, "run", "certonly", "register"],
|
||||||
|
"--eab-hmac-alg", dest="eab_hmac_alg",
|
||||||
|
metavar="EAB_HMAC_ALG",
|
||||||
|
default=flag_default("eab_hmac_alg"),
|
||||||
|
help="HMAC algorithm for External Account Binding"
|
||||||
|
)
|
||||||
helpful.add(
|
helpful.add(
|
||||||
[None, "run", "certonly", "manage", "delete", "certificates",
|
[None, "run", "certonly", "manage", "delete", "certificates",
|
||||||
"renew", "enhance", "reconfigure"], "--cert-name", dest="certname",
|
"renew", "enhance", "reconfigure"], "--cert-name", dest="certname",
|
||||||
|
|||||||
@@ -238,7 +238,8 @@ def perform_registration(acme: acme_client.ClientV2, config: configuration.Names
|
|||||||
eab = messages.ExternalAccountBinding.from_data(account_public_key=account_public_key,
|
eab = messages.ExternalAccountBinding.from_data(account_public_key=account_public_key,
|
||||||
kid=config.eab_kid,
|
kid=config.eab_kid,
|
||||||
hmac_key=config.eab_hmac_key,
|
hmac_key=config.eab_hmac_key,
|
||||||
directory=acme.directory)
|
directory=acme.directory,
|
||||||
|
hmac_alg=config.eab_hmac_alg)
|
||||||
else:
|
else:
|
||||||
eab = None
|
eab = None
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ CLI_DEFAULTS: Dict[str, Any] = dict( # pylint: disable=use-dict-literal
|
|||||||
random_sleep_on_renew=True,
|
random_sleep_on_renew=True,
|
||||||
eab_hmac_key=None,
|
eab_hmac_key=None,
|
||||||
eab_kid=None,
|
eab_kid=None,
|
||||||
|
eab_hmac_alg="HS256",
|
||||||
issuance_timeout=90,
|
issuance_timeout=90,
|
||||||
run_deploy_hooks=False,
|
run_deploy_hooks=False,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user