From fa01e99d0f61ec3ffb9bc525775eb78f6263f388 Mon Sep 17 00:00:00 2001 From: "Seth M. Larson" Date: Fri, 29 Jun 2018 12:53:44 -0500 Subject: [PATCH] Make pyOpenSSL skip DNS names which can't be idna- encoded. See #1405 and #requests/requests/4569 --- urllib3/contrib/pyopenssl.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/urllib3/contrib/pyopenssl.py b/urllib3/contrib/pyopenssl.py index 4d4b1aff97..4de877a79a 100644 --- a/urllib3/contrib/pyopenssl.py +++ b/urllib3/contrib/pyopenssl.py @@ -163,6 +163,9 @@ def _dnsname_to_stdlib(name): from ASCII bytes. We need to idna-encode that string to get it back, and then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + + If the name cannot be idna-encoded then we return None signalling that + the name given should be skipped. """ def idna_encode(name): """ @@ -172,14 +175,19 @@ def idna_encode(name): """ import idna - for prefix in [u'*.', u'.']: - if name.startswith(prefix): - name = name[len(prefix):] - return prefix.encode('ascii') + idna.encode(name) - return idna.encode(name) + try: + for prefix in [u'*.', u'.']: + if name.startswith(prefix): + name = name[len(prefix):] + return prefix.encode('ascii') + idna.encode(name) + return idna.encode(name) + except idna.core.IDNAError: + return None name = idna_encode(name) - if sys.version_info >= (3, 0): + if name is None: + return None + elif sys.version_info >= (3, 0): name = name.decode('utf-8') return name @@ -223,10 +231,12 @@ def get_subj_alt_name(peer_cert): # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 # decoded. This is pretty frustrating, but that's what the standard library # does with certificates, and so we need to attempt to do the same. - names = [ - ('DNS', _dnsname_to_stdlib(name)) - for name in ext.get_values_for_type(x509.DNSName) - ] + # We also want to skip over names which cannot be idna encoded. + names = [] + for name in ext.get_values_for_type(x509.DNSName): + name = _dnsname_to_stdlib(name) + if name is not None: + names.append(('DNS', name)) names.extend( ('IP Address', str(name)) for name in ext.get_values_for_type(x509.IPAddress)