Skip to content

If using match_hostname, subject_alt_name support should be mandatory #17

Description

@jim-minter

A good reason to use backports.ssl is that it makes correct SNI and match_hostname support available to python programs running on RHEL 7 or CentOS 7. These OSes ship with python 2.7.5, and this support was only added into mainstream python in 2.7.9.

However, it turns out that match_hostname silently fails to decode subject_alt_name extension records if the subject_alt_name import fails:

try:
    from .subject_alt_name import get_subject_alt_name
except ImportError:
    get_subject_alt_name = None

This can happen, for example, if the pyasn1 library (python-pyasn1 RPM) isn't installed.

The net effect is that match_hostname erroneously fails, e.g. against domains such as pypi.python.org, which is listed as a SAN.

My RFE is that if match_hostname is being used, it should fail as early as possible if subject_alt_name isn't available.

Here's a test case:

import sys
import socket

if sys.version_info >= (2, 7, 9):
    import ssl
else:
    import backports.ssl as ssl


(OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE,
 OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE) = (16777216, 33554432, 131072, 4194304,
                                          1048576, 524288)

def mk_clientctx():
    ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
    ctx.options |= OP_NO_SSLv2 | OP_NO_SSLv3 | OP_NO_COMPRESSION
    ctx.verify_mode = ssl.CERT_REQUIRED
    ctx.check_hostname = True
    ctx.load_verify_locations("/etc/pki/tls/certs/ca-bundle.crt")
    return ctx

d = "pypi.python.org"
s = socket.socket()
s.connect((d, 443))
clientctx = mk_clientctx()
s = clientctx.wrap_socket(s, server_hostname=d)

On CentOS 7 / RHEL 7, if python-pyasn1 is available, this test case works fine. If not, you get the error:

Traceback (most recent call last):
  File "test.py", line 25, in <module>
    s = clientctx.wrap_socket(s, server_hostname=d)
  File "/usr/lib/python2.7/site-packages/backports/ssl/core.py", line 669, in wrap_socket
    self.check_hostname)
  File "/usr/lib/python2.7/site-packages/backports/ssl/core.py", line 241, in __init__
    self.do_handshake()
  File "/usr/lib/python2.7/site-packages/backports/ssl/core.py", line 263, in do_handshake
    match_hostname(self.getpeercert(), self._conn.get_servername().decode('utf-8'))
  File "/usr/lib/python2.7/site-packages/backports/ssl/core.py", line 184, in match_hostname
    % (hostname, dnsnames[0]))
backports.ssl.core.CertificateError: hostname u'pypi.python.org' doesn't match u'www.python.org'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions