]> granicus.if.org Git - python/commitdiff
bpo-37463: match_hostname requires quad-dotted IPv4 (GH-14499)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 2 Jul 2019 21:06:18 +0000 (14:06 -0700)
committerGitHub <noreply@github.com>
Tue, 2 Jul 2019 21:06:18 +0000 (14:06 -0700)
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
(cherry picked from commit 477b1b25768945621d466a8b3f0739297a842439)

Co-authored-by: Christian Heimes <christian@python.org>
Lib/ssl.py
Lib/test/test_ssl.py
Misc/NEWS.d/next/Security/2019-07-01-08-46-14.bpo-37463.1CHwjE.rst [new file with mode: 0644]

index 61bd775f759b09adda6ef4dcfad718f76eecf127..0726caee49aa579d5eb6d05c01f8aa0b04b17cb5 100644 (file)
@@ -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
 
 
index 1898990fb7963e7a8f52a2d810c52040f4ebf270..f1b7aa731e9a2b08bc4e679d6bb2d79aa9849115 100644 (file)
@@ -666,9 +666,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')
 
@@ -681,6 +686,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 (file)
index 0000000..4f4a62e
--- /dev/null
@@ -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'.