|
|
04a680 |
@@ -, +, @@
|
|
|
04a680 |
---
|
|
|
04a680 |
Lib/ssl.py | 53 ++++++++++++++++++++++++++++++++++++++---------------
|
|
|
04a680 |
1 file changed, 38 insertions(+), 15 deletions(-)
|
|
|
04a680 |
--- a/Lib/ssl.py
|
|
|
04a680 |
+++ a/Lib/ssl.py
|
|
|
04a680 |
@@ -466,24 +466,47 @@ def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
|
|
|
04a680 |
|
|
|
04a680 |
return context
|
|
|
04a680 |
|
|
|
04a680 |
+_https_verify_envvar = 'PYTHONHTTPSVERIFY'
|
|
|
04a680 |
_cert_verification_config = '/etc/python/cert-verification.cfg'
|
|
|
04a680 |
|
|
|
04a680 |
-def _get_verify_status(protocol):
|
|
|
04a680 |
- context_factory = {
|
|
|
04a680 |
- 'platform_default': _create_unverified_context,
|
|
|
04a680 |
- 'enable': create_default_context,
|
|
|
04a680 |
- 'disable': _create_unverified_context
|
|
|
04a680 |
- }
|
|
|
04a680 |
- import ConfigParser
|
|
|
04a680 |
- try:
|
|
|
04a680 |
- config = ConfigParser.RawConfigParser()
|
|
|
04a680 |
- config.read(_cert_verification_config)
|
|
|
04a680 |
- status = config.get(protocol, 'verify')
|
|
|
04a680 |
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
|
|
04a680 |
- status = 'platform_default'
|
|
|
04a680 |
- default = context_factory.get('platform_default')
|
|
|
04a680 |
- return context_factory.get(status, default)
|
|
|
04a680 |
+# To provide same function name as specified in PEP493 with keeping
|
|
|
04a680 |
+# the old name as defined in our previous patch
|
|
|
04a680 |
+_get_https_context_factory = lambda: _get_verify_status('https')
|
|
|
04a680 |
|
|
|
04a680 |
+def _get_verify_status(protocol):
|
|
|
04a680 |
+ # See https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports
|
|
|
04a680 |
+ # Check for an environmental override of the default behaviour
|
|
|
04a680 |
+ if not sys.flags.ignore_environment:
|
|
|
04a680 |
+ config_setting = os.environ.get(_https_verify_envvar)
|
|
|
04a680 |
+ if config_setting is not None:
|
|
|
04a680 |
+ if config_setting == '0':
|
|
|
04a680 |
+ return _create_unverified_context
|
|
|
04a680 |
+ return create_default_context
|
|
|
04a680 |
+
|
|
|
04a680 |
+ # Check for a system-wide override of the default behaviour
|
|
|
04a680 |
+ context_factory = {
|
|
|
71084d |
+ 'platform_default': create_default_context,
|
|
|
04a680 |
+ 'enable': create_default_context,
|
|
|
04a680 |
+ 'disable': _create_unverified_context
|
|
|
04a680 |
+ }
|
|
|
04a680 |
+ import ConfigParser
|
|
|
04a680 |
+ try:
|
|
|
04a680 |
+ config = ConfigParser.RawConfigParser()
|
|
|
04a680 |
+ config.read(_cert_verification_config)
|
|
|
04a680 |
+ status = config.get(protocol, 'verify')
|
|
|
04a680 |
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
|
|
04a680 |
+ status = 'platform_default'
|
|
|
04a680 |
+ default = context_factory.get('platform_default')
|
|
|
04a680 |
+ return context_factory.get(status, default)
|
|
|
04a680 |
+
|
|
|
04a680 |
+# See https://www.python.org/dev/peps/pep-0493/#feature-configuration-api
|
|
|
04a680 |
+def _https_verify_certificates(enable=True):
|
|
|
04a680 |
+ """Verify server HTTPS certificates by default?"""
|
|
|
04a680 |
+ global _create_default_https_context
|
|
|
04a680 |
+ if enable:
|
|
|
04a680 |
+ _create_default_https_context = create_default_context
|
|
|
04a680 |
+ else:
|
|
|
04a680 |
+ _create_default_https_context = _create_unverified_context
|
|
|
04a680 |
|
|
|
04a680 |
# Used by http.client if no context is explicitly passed.
|
|
|
04a680 |
_create_default_https_context = _get_verify_status('https')
|
|
|
04a680 |
--- a/Lib/test/test_ssl.py Thu Jan 14 21:57:57 2016 -0800
|
|
|
04a680 |
+++ a/Lib/test/test_ssl.py Fri Jan 15 17:41:37 2016 +1000
|
|
|
04a680 |
@@ -4,6 +4,7 @@
|
|
|
04a680 |
import sys
|
|
|
04a680 |
import unittest
|
|
|
04a680 |
from test import test_support as support
|
|
|
04a680 |
+from test.script_helper import assert_python_ok
|
|
|
04a680 |
import asyncore
|
|
|
04a680 |
import socket
|
|
|
04a680 |
import select
|
|
|
71084d |
@@ -1149,6 +1149,57 @@
|
|
|
04a680 |
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
|
|
|
04a680 |
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
|
|
|
04a680 |
|
|
|
04a680 |
+ def test__https_verify_certificates(self):
|
|
|
04a680 |
+ # Unit test to check the contect factory mapping
|
|
|
04a680 |
+ # The factories themselves are tested above
|
|
|
04a680 |
+ # This test will fail by design if run under PYTHONHTTPSVERIFY=0
|
|
|
04a680 |
+ # (as will various test_httplib tests)
|
|
|
04a680 |
+
|
|
|
04a680 |
+ # Uses a fresh SSL module to avoid affecting the real one
|
|
|
04a680 |
+ local_ssl = support.import_fresh_module("ssl")
|
|
|
04a680 |
+ # Certificate verification is enabled by default
|
|
|
04a680 |
+ self.assertIs(local_ssl._create_default_https_context,
|
|
|
04a680 |
+ local_ssl.create_default_context)
|
|
|
71084d |
+ # Turn default verification off
|
|
|
04a680 |
+ local_ssl._https_verify_certificates(enable=False)
|
|
|
04a680 |
+ self.assertIs(local_ssl._create_default_https_context,
|
|
|
04a680 |
+ local_ssl._create_unverified_context)
|
|
|
71084d |
+ # And back on
|
|
|
04a680 |
+ local_ssl._https_verify_certificates(enable=True)
|
|
|
71084d |
+ self.assertIs(local_ssl._create_default_https_context,
|
|
|
71084d |
+ local_ssl.create_default_context)
|
|
|
71084d |
+ # The default behaviour is to enable
|
|
|
71084d |
+ local_ssl._https_verify_certificates(enable=False)
|
|
|
04a680 |
+ local_ssl._https_verify_certificates()
|
|
|
04a680 |
+ self.assertIs(local_ssl._create_default_https_context,
|
|
|
04a680 |
+ local_ssl.create_default_context)
|
|
|
04a680 |
+
|
|
|
04a680 |
+ def test__https_verify_envvar(self):
|
|
|
04a680 |
+ # Unit test to check the PYTHONHTTPSVERIFY handling
|
|
|
04a680 |
+ # Need to use a subprocess so it can still be run under -E
|
|
|
71084d |
+ https_is_verified = """import ssl, sys; \
|
|
|
71084d |
+ status = "Error: _create_default_https_context does not verify certs" \
|
|
|
71084d |
+ if ssl._create_default_https_context is \
|
|
|
71084d |
+ ssl._create_unverified_context \
|
|
|
71084d |
+ else None; \
|
|
|
71084d |
+ sys.exit(status)"""
|
|
|
71084d |
+ https_is_not_verified = """import ssl, sys; \
|
|
|
71084d |
+ status = "Error: _create_default_https_context verifies certs" \
|
|
|
71084d |
+ if ssl._create_default_https_context is \
|
|
|
71084d |
+ ssl.create_default_context \
|
|
|
71084d |
+ else None; \
|
|
|
71084d |
+ sys.exit(status)"""
|
|
|
04a680 |
+ extra_env = {}
|
|
|
71084d |
+ # Omitting it leaves verification on
|
|
|
71084d |
+ assert_python_ok("-c", https_is_verified, **extra_env)
|
|
|
04a680 |
+ # Setting it to zero turns verification off
|
|
|
04a680 |
+ extra_env[ssl._https_verify_envvar] = "0"
|
|
|
04a680 |
+ assert_python_ok("-c", https_is_not_verified, **extra_env)
|
|
|
04a680 |
+ # Any other value should also leave it on
|
|
|
04a680 |
+ for setting in ("", "1", "enabled", "foo"):
|
|
|
04a680 |
+ extra_env[ssl._https_verify_envvar] = setting
|
|
|
04a680 |
+ assert_python_ok("-c", https_is_verified, **extra_env)
|
|
|
04a680 |
+
|
|
|
04a680 |
def test_check_hostname(self):
|
|
|
04a680 |
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
|
|
04a680 |
self.assertFalse(ctx.check_hostname)
|