summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 61bd775..0726cae 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -327,12 +327,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)
@@ -346,14 +356,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 ef17239..d2b9e20 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -669,9 +669,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')
@@ -684,6 +689,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 0000000..4f4a62e
--- /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'.