Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If using match_hostname, subject_alt_name support should be mandatory #17

Open
jim-minter opened this issue Jan 18, 2016 · 0 comments
Open

Comments

@jim-minter
Copy link

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'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant