summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2019-07-02 20:39:42 +0200
committerNed Deily <nad@python.org>2019-07-02 14:42:08 -0400
commit070fae6d0ff49e63bfd5f2bdc66f8eb1df3b6557 (patch)
treebf94f445c48b472916d502d4f2f06a4994ff7ee8
parentdcc0eb379613f279864af61023ea44c94aa0535c (diff)
downloadcpython-git-070fae6d0ff49e63bfd5f2bdc66f8eb1df3b6557.tar.gz
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 <christian@python.org> https://bugs.python.org/issue37463
-rw-r--r--Lib/ssl.py29
-rw-r--r--Lib/test/test_ssl.py9
-rw-r--r--Misc/NEWS.d/next/Security/2019-07-01-08-46-14.bpo-37463.1CHwjE.rst4
3 files changed, 32 insertions, 10 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py
index b12f8a1be6..b89c9ad344 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -243,12 +243,22 @@ def _inet_paton(ipname):
Supports IPv4 addresses on all platforms and IPv6 on platforms with IPv6
support.
"""
- # inet_aton() also accepts strings like '1'
- if ipname.count('.') == 3:
- try:
- return _socket.inet_aton(ipname)
- except OSError:
- pass
+ # inet_aton() also accepts strings like '1', '127.1', some also trailing
+ # data like '127.0.0.1 whatever'.
+ try:
+ addr = _socket.inet_aton(ipname)
+ except OSError:
+ # not an IPv4 address
+ pass
+ else:
+ if _socket.inet_ntoa(addr) == ipname:
+ # only accept injective ipnames
+ return addr
+ else:
+ # refuse for short IPv4 notation and additional trailing data
+ raise ValueError(
+ "{!r} is not a quad-dotted IPv4 address.".format(ipname)
+ )
try:
return _socket.inet_pton(_socket.AF_INET6, ipname)
@@ -262,14 +272,15 @@ def _inet_paton(ipname):
raise ValueError("{!r} is not an IPv4 address.".format(ipname))
-def _ipaddress_match(ipname, host_ip):
+def _ipaddress_match(cert_ipaddress, host_ip):
"""Exact matching of IP addresses.
RFC 6125 explicitly doesn't define an algorithm for this
(section 1.7.2 - "Out of Scope").
"""
- # OpenSSL may add a trailing newline to a subjectAltName's IP address
- ip = _inet_paton(ipname.rstrip())
+ # OpenSSL may add a trailing newline to a subjectAltName's IP address,
+ # commonly woth IPv6 addresses. Strip off trailing \n.
+ ip = _inet_paton(cert_ipaddress.rstrip())
return ip == host_ip
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 86f790b4a2..4a61711f0e 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -681,9 +681,14 @@ class BasicSocketTests(unittest.TestCase):
cert = {'subject': ((('commonName', 'example.com'),),),
'subjectAltName': (('DNS', 'example.com'),
('IP Address', '10.11.12.13'),
- ('IP Address', '14.15.16.17'))}
+ ('IP Address', '14.15.16.17'),
+ ('IP Address', '127.0.0.1'))}
ok(cert, '10.11.12.13')
ok(cert, '14.15.16.17')
+ # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
+ fail(cert, '127.1')
+ fail(cert, '14.15.16.17 ')
+ fail(cert, '14.15.16.17 extra data')
fail(cert, '14.15.16.18')
fail(cert, 'example.net')
@@ -696,6 +701,8 @@ class BasicSocketTests(unittest.TestCase):
('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
ok(cert, '2001::cafe')
ok(cert, '2003::baba')
+ fail(cert, '2003::baba ')
+ fail(cert, '2003::baba extra data')
fail(cert, '2003::bebe')
fail(cert, 'example.net')
diff --git a/Misc/NEWS.d/next/Security/2019-07-01-08-46-14.bpo-37463.1CHwjE.rst b/Misc/NEWS.d/next/Security/2019-07-01-08-46-14.bpo-37463.1CHwjE.rst
new file mode 100644
index 0000000000..4f4a62e783
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2019-07-01-08-46-14.bpo-37463.1CHwjE.rst
@@ -0,0 +1,4 @@
+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'.