Fix HTTP01.uri for IPv6 addresses (#10548)

IPv6 addresses in URLs should be enclosed in square brackets.

Note: I chose to fix this by parsing the identifier rather than changing
the method signature. The obvious choice to change the method signature
would be to take `messages.Identifier`. We could even do this backwards
compatibly by taking `str | messages.Identifier`. However, `messages`
imports `challenges`, so referencing `messages.Identifier` here would
require an import loop.

I also considered implementing a new method on, e.g.
messages.Authorization that would take a challenge as a parameter. But
this would be suboptimal because the `uri` method really is specific to
the http-01 challenge type, so it's nice to have it implemented only on
the relevant class.
This commit is contained in:
Jacob Hoffman-Andrews
2026-01-27 20:42:52 -08:00
committed by GitHub
parent 3b9a1d0d64
commit bd7b64f1e7
3 changed files with 18 additions and 3 deletions
@@ -244,6 +244,12 @@ class HTTP01Test(unittest.TestCase):
assert 'http://example.com/.well-known/acme-challenge/' \ assert 'http://example.com/.well-known/acme-challenge/' \
'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA' == \ 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA' == \
self.msg.uri('example.com') self.msg.uri('example.com')
assert 'http://1.2.3.4/.well-known/acme-challenge/' \
'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA' == \
self.msg.uri('1.2.3.4')
assert 'http://[::1]/.well-known/acme-challenge/' \
'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA' == \
self.msg.uri('::1')
def test_to_partial_json(self): def test_to_partial_json(self):
assert self.jmsg == self.msg.to_partial_json() assert self.jmsg == self.msg.to_partial_json()
+11 -3
View File
@@ -2,6 +2,7 @@
import abc import abc
import functools import functools
import hashlib import hashlib
import ipaddress
import logging import logging
from typing import Any from typing import Any
from typing import cast from typing import cast
@@ -365,17 +366,24 @@ class HTTP01(KeyAuthorizationChallenge):
""" """
return '/' + self.URI_ROOT_PATH + '/' + self.encode('token') return '/' + self.URI_ROOT_PATH + '/' + self.encode('token')
def uri(self, domain: str) -> str: def uri(self, identifier: str) -> str:
"""Create an URI to the provisioned resource. """Create an URI to the provisioned resource.
Forms an URI to the HTTPS server provisioned resource Forms an URI to the HTTPS server provisioned resource
(containing :attr:`~SimpleHTTP.token`). (containing :attr:`~SimpleHTTP.token`).
:param str domain: Domain name being verified. :param str identifier: Domain name or IP address being verified.
:rtype: str :rtype: str
""" """
return "http://" + domain + self.path try:
# https://datatracker.ietf.org/doc/html/rfc2732#section-2
# IPv6 addresses in URLs should be enclosed in brackets.
ipaddress.IPv6Address(identifier)
identifier = "[" + identifier + "]"
except ipaddress.AddressValueError:
pass
return "http://" + identifier + self.path
def validation(self, account_key: jose.JWK, **unused_kwargs: Any) -> str: def validation(self, account_key: jose.JWK, **unused_kwargs: Any) -> str:
"""Generate validation. """Generate validation.
+1
View File
@@ -0,0 +1 @@
The HTTP01.uri method will now properly enclose IPv6 addresses in square brackets.