Skip to content

Commit 024ea21

Browse files
bpo-37463: match_hostname requires quad-dotted IPv4 (GH-14499)
ssl.match_hostname() no longer accepts IPv4 addresses with additional text after the address and only quad-dotted notation without trailing whitespaces. Some inet_aton() implementations ignore whitespace and all data after whitespace, e.g. '127.0.0.1 whatever'. Short notations like '127.1' for '127.0.0.1' were already filtered out. The bug was initially found by Dominik Czarnota and reported by Paul Kehrer. Signed-off-by: Christian Heimes <[email protected]> https://bugs.python.org/issue37463 (cherry picked from commit 477b1b2) Co-authored-by: Christian Heimes <[email protected]>
1 parent 19b8d90 commit 024ea21

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

Lib/ssl.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,22 @@ def _inet_paton(ipname):
243243
Supports IPv4 addresses on all platforms and IPv6 on platforms with IPv6
244244
support.
245245
"""
246-
# inet_aton() also accepts strings like '1'
247-
if ipname.count('.') == 3:
248-
try:
249-
return _socket.inet_aton(ipname)
250-
except OSError:
251-
pass
246+
# inet_aton() also accepts strings like '1', '127.1', some also trailing
247+
# data like '127.0.0.1 whatever'.
248+
try:
249+
addr = _socket.inet_aton(ipname)
250+
except OSError:
251+
# not an IPv4 address
252+
pass
253+
else:
254+
if _socket.inet_ntoa(addr) == ipname:
255+
# only accept injective ipnames
256+
return addr
257+
else:
258+
# refuse for short IPv4 notation and additional trailing data
259+
raise ValueError(
260+
"{!r} is not a quad-dotted IPv4 address.".format(ipname)
261+
)
252262

253263
try:
254264
return _socket.inet_pton(_socket.AF_INET6, ipname)
@@ -262,14 +272,15 @@ def _inet_paton(ipname):
262272
raise ValueError("{!r} is not an IPv4 address.".format(ipname))
263273

264274

265-
def _ipaddress_match(ipname, host_ip):
275+
def _ipaddress_match(cert_ipaddress, host_ip):
266276
"""Exact matching of IP addresses.
267277
268278
RFC 6125 explicitly doesn't define an algorithm for this
269279
(section 1.7.2 - "Out of Scope").
270280
"""
271-
# OpenSSL may add a trailing newline to a subjectAltName's IP address
272-
ip = _inet_paton(ipname.rstrip())
281+
# OpenSSL may add a trailing newline to a subjectAltName's IP address,
282+
# commonly woth IPv6 addresses. Strip off trailing \n.
283+
ip = _inet_paton(cert_ipaddress.rstrip())
273284
return ip == host_ip
274285

275286

Lib/test/test_ssl.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,14 @@ def fail(cert, hostname):
681681
cert = {'subject': ((('commonName', 'example.com'),),),
682682
'subjectAltName': (('DNS', 'example.com'),
683683
('IP Address', '10.11.12.13'),
684-
('IP Address', '14.15.16.17'))}
684+
('IP Address', '14.15.16.17'),
685+
('IP Address', '127.0.0.1'))}
685686
ok(cert, '10.11.12.13')
686687
ok(cert, '14.15.16.17')
688+
# socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
689+
fail(cert, '127.1')
690+
fail(cert, '14.15.16.17 ')
691+
fail(cert, '14.15.16.17 extra data')
687692
fail(cert, '14.15.16.18')
688693
fail(cert, 'example.net')
689694

@@ -696,6 +701,8 @@ def fail(cert, hostname):
696701
('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
697702
ok(cert, '2001::cafe')
698703
ok(cert, '2003::baba')
704+
fail(cert, '2003::baba ')
705+
fail(cert, '2003::baba extra data')
699706
fail(cert, '2003::bebe')
700707
fail(cert, 'example.net')
701708

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ssl.match_hostname() no longer accepts IPv4 addresses with additional text
2+
after the address and only quad-dotted notation without trailing
3+
whitespaces. Some inet_aton() implementations ignore whitespace and all data
4+
after whitespace, e.g. '127.0.0.1 whatever'.

0 commit comments

Comments
 (0)