ff452418 |
--- a/Lib/ssl.py 2018-04-30 04:17:33.000000000 +0530
+++ b/Lib/ssl.py 2018-08-17 05:48:06.389881269 +0530
@@ -146,6 +146,11 @@ from socket import SOL_SOCKET, SO_TYPE |
bb1e8689 |
import base64 # for DER-to-PEM translation
import errno |
a40b4bfd |
import warnings |
bb1e8689 |
+try:
+ from ipaddr import IPAddress
+except ImportError:
+ # ipaddr is missing. Make ip address cert match functionality to behave as before.
+ def IPAddress(*_args): raise ValueError("Not supported")
if _ssl.HAS_TLS_UNIQUE:
CHANNEL_BINDING_TYPES = ['tls-unique'] |
ff452418 |
@@ -251,7 +250,15 @@ def _dnsname_match(dn, hostname, max_wil |
bb1e8689 |
pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
return pat.match(hostname)
+def _ipaddress_match(ipname, 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 = IPAddress(ipname.rstrip())
+ return ip == host_ip
def match_hostname(cert, hostname):
"""Verify that *cert* (in decoded format as returned by
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 |
ff452418 |
@@ -264,6 +271,13 @@ def match_hostname(cert, hostname): |
bb1e8689 |
raise ValueError("empty or no certificate, match_hostname needs a "
"SSL socket or SSL context with either "
"CERT_OPTIONAL or CERT_REQUIRED")
+
+ try:
+ host_ip = IPAddress(hostname)
+ except ValueError:
+ # Not an IP address (common case)
+ host_ip = None
+
dnsnames = []
san = cert.get('subjectAltName', ())
for key, value in san: |
ff452418 |
@@ -271,6 +285,10 @@ def match_hostname(cert, hostname): |
d0453118 |
if _dnsname_match(value, hostname): |
bb1e8689 |
return
dnsnames.append(value)
+ elif key == 'IP Address':
+ if host_ip is not None and _ipaddress_match(value, host_ip):
+ return
+ dnsnames.append(value)
if not dnsnames:
# The subject is only checked when there is no dNSName entry
# in subjectAltName |