An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
@@ -, +, @@ 
---
 Lib/ssl.py | 53 ++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 15 deletions(-)
--- a/Lib/ssl.py    
+++ a/Lib/ssl.py    
@@ -466,24 +466,47 @@ def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
 
     return context
 
+_https_verify_envvar = 'PYTHONHTTPSVERIFY'
 _cert_verification_config = '/etc/python/cert-verification.cfg'
 
-def _get_verify_status(protocol):
-   context_factory = {
-       'platform_default': _create_unverified_context,
-       'enable': create_default_context,
-       'disable': _create_unverified_context
-   }
-   import ConfigParser
-   try:
-       config = ConfigParser.RawConfigParser()
-       config.read(_cert_verification_config)
-       status = config.get(protocol, 'verify')
-   except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
-       status = 'platform_default'
-   default = context_factory.get('platform_default')
-   return context_factory.get(status, default)
+# To provide same function name as specified in PEP493 with keeping
+# the old name as defined in our previous patch
+_get_https_context_factory = lambda: _get_verify_status('https')
 
+def _get_verify_status(protocol):
+    # See https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports
+    # Check for an environmental override of the default behaviour
+    if not sys.flags.ignore_environment:
+        config_setting = os.environ.get(_https_verify_envvar)
+        if config_setting is not None:
+            if config_setting == '0':
+                return _create_unverified_context
+            return create_default_context
+
+    # Check for a system-wide override of the default behaviour
+    context_factory = {
+        'platform_default': create_default_context,
+        'enable': create_default_context,
+        'disable': _create_unverified_context
+    }
+    import ConfigParser
+    try:
+        config = ConfigParser.RawConfigParser()
+        config.read(_cert_verification_config)
+        status = config.get(protocol, 'verify')
+    except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+        status = 'platform_default'
+    default = context_factory.get('platform_default')
+    return context_factory.get(status, default)
+
+# See https://www.python.org/dev/peps/pep-0493/#feature-configuration-api
+def _https_verify_certificates(enable=True):
+    """Verify server HTTPS certificates by default?"""
+    global _create_default_https_context
+    if enable:
+        _create_default_https_context = create_default_context
+    else:
+        _create_default_https_context = _create_unverified_context
 
 # Used by http.client if no context is explicitly passed.
 _create_default_https_context = _get_verify_status('https')
--- a/Lib/test/test_ssl.py    Thu Jan 14 21:57:57 2016 -0800
+++ a/Lib/test/test_ssl.py    Fri Jan 15 17:41:37 2016 +1000
@@ -4,6 +4,7 @@
 import sys
 import unittest
 from test import test_support as support
+from test.script_helper import assert_python_ok
 import asyncore
 import socket
 import select
@@ -1149,6 +1149,57 @@
         self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
         self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
 
+    def test__https_verify_certificates(self):
+        # Unit test to check the contect factory mapping
+        # The factories themselves are tested above
+        # This test will fail by design if run under PYTHONHTTPSVERIFY=0
+        # (as will various test_httplib tests)
+
+        # Uses a fresh SSL module to avoid affecting the real one
+        local_ssl = support.import_fresh_module("ssl")
+        # Certificate verification is enabled by default
+        self.assertIs(local_ssl._create_default_https_context,
+                      local_ssl.create_default_context)
+        # Turn default verification off
+        local_ssl._https_verify_certificates(enable=False)
+        self.assertIs(local_ssl._create_default_https_context,
+                      local_ssl._create_unverified_context)
+        # And back on
+        local_ssl._https_verify_certificates(enable=True)
+        self.assertIs(local_ssl._create_default_https_context,
+                      local_ssl.create_default_context)
+        # The default behaviour is to enable
+        local_ssl._https_verify_certificates(enable=False)
+        local_ssl._https_verify_certificates()
+        self.assertIs(local_ssl._create_default_https_context,
+                      local_ssl.create_default_context)
+
+    def test__https_verify_envvar(self):
+        # Unit test to check the PYTHONHTTPSVERIFY handling
+        # Need to use a subprocess so it can still be run under -E
+        https_is_verified = """import ssl, sys; \
+            status = "Error: _create_default_https_context does not verify certs" \
+                       if ssl._create_default_https_context is \
+                          ssl._create_unverified_context \
+                     else None; \
+            sys.exit(status)"""
+        https_is_not_verified = """import ssl, sys; \
+            status = "Error: _create_default_https_context verifies certs" \
+                       if ssl._create_default_https_context is \
+                          ssl.create_default_context \
+                     else None; \
+            sys.exit(status)"""
+        extra_env = {}
+        # Omitting it leaves verification on
+        assert_python_ok("-c", https_is_verified, **extra_env)
+        # Setting it to zero turns verification off
+        extra_env[ssl._https_verify_envvar] = "0"
+        assert_python_ok("-c", https_is_not_verified, **extra_env)
+        # Any other value should also leave it on
+        for setting in ("", "1", "enabled", "foo"):
+            extra_env[ssl._https_verify_envvar] = setting
+            assert_python_ok("-c", https_is_verified, **extra_env)
+
     def test_check_hostname(self):
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
         self.assertFalse(ctx.check_hostname)