]> code.ossystems Code Review - openembedded-core.git/blob
321b4afa12c7f89d6ef023635f33ea5efb3f11ae
[openembedded-core.git] /
1 From 758e7463c104f71b810c8588166747eeab6148d7 Mon Sep 17 00:00:00 2001
2 From: Christian Heimes <christian@python.org>
3 Date: Sat, 10 Sep 2016 22:43:48 +0200
4 Subject: [PATCH 1/4] Issue 28043: SSLContext has improved default settings
5
6 The options OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE, OP_NO_SSLv2 (except for PROTOCOL_SSLv2), and OP_NO_SSLv3 (except for PROTOCOL_SSLv3) are set by default. The initial cipher suite list contains only HIGH ciphers, no NULL ciphers and MD5 ciphers (except for PROTOCOL_SSLv2).
7
8 Upstream-Status: Backport
9 [https://github.com/python/cpython/commit/358cfd426ccc0fcd6a7940d306602138e76420ae]
10
11 Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
12 ---
13  Doc/library/ssl.rst  |  9 ++++++-
14  Lib/ssl.py           | 30 +++++----------------
15  Lib/test/test_ssl.py | 62 +++++++++++++++++++++++---------------------
16  Modules/_ssl.c       | 31 ++++++++++++++++++++++
17  4 files changed, 78 insertions(+), 54 deletions(-)
18
19 diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
20 index a2f008346b..14f2d68217 100644
21 --- a/Doc/library/ssl.rst
22 +++ b/Doc/library/ssl.rst
23 @@ -1151,7 +1151,14 @@ to speed up repeated connections from the same clients.
24  
25     .. versionchanged:: 3.5.3
26  
27 -      :data:`PROTOCOL_TLS` is the default value.
28 +      The context is created with secure default values. The options
29 +      :data:`OP_NO_COMPRESSION`, :data:`OP_CIPHER_SERVER_PREFERENCE`,
30 +      :data:`OP_SINGLE_DH_USE`, :data:`OP_SINGLE_ECDH_USE`,
31 +      :data:`OP_NO_SSLv2` (except for :data:`PROTOCOL_SSLv2`),
32 +      and :data:`OP_NO_SSLv3` (except for :data:`PROTOCOL_SSLv3`) are
33 +      set by default. The initial cipher suite list contains only ``HIGH``
34 +      ciphers, no ``NULL`` ciphers and no ``MD5`` ciphers (except for
35 +      :data:`PROTOCOL_SSLv2`).
36  
37  
38  :class:`SSLContext` objects have the following methods and attributes:
39 diff --git a/Lib/ssl.py b/Lib/ssl.py
40 index e1913904f3..4d302a78fa 100644
41 --- a/Lib/ssl.py
42 +++ b/Lib/ssl.py
43 @@ -446,32 +446,16 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
44      if not isinstance(purpose, _ASN1Object):
45          raise TypeError(purpose)
46  
47 +    # SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION,
48 +    # OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE
49 +    # by default.
50      context = SSLContext(PROTOCOL_TLS)
51  
52 -    # SSLv2 considered harmful.
53 -    context.options |= OP_NO_SSLv2
54 -
55 -    # SSLv3 has problematic security and is only required for really old
56 -    # clients such as IE6 on Windows XP
57 -    context.options |= OP_NO_SSLv3
58 -
59 -    # disable compression to prevent CRIME attacks (OpenSSL 1.0+)
60 -    context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)
61 -
62      if purpose == Purpose.SERVER_AUTH:
63          # verify certs and host name in client mode
64          context.verify_mode = CERT_REQUIRED
65          context.check_hostname = True
66      elif purpose == Purpose.CLIENT_AUTH:
67 -        # Prefer the server's ciphers by default so that we get stronger
68 -        # encryption
69 -        context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
70 -
71 -        # Use single use keys in order to improve forward secrecy
72 -        context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0)
73 -        context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0)
74 -
75 -        # disallow ciphers with known vulnerabilities
76          context.set_ciphers(_RESTRICTED_SERVER_CIPHERS)
77  
78      if cafile or capath or cadata:
79 @@ -497,12 +481,10 @@ def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=None,
80      if not isinstance(purpose, _ASN1Object):
81          raise TypeError(purpose)
82  
83 +    # SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION,
84 +    # OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE
85 +    # by default.
86      context = SSLContext(protocol)
87 -    # SSLv2 considered harmful.
88 -    context.options |= OP_NO_SSLv2
89 -    # SSLv3 has problematic security and is only required for really old
90 -    # clients such as IE6 on Windows XP
91 -    context.options |= OP_NO_SSLv3
92  
93      if cert_reqs is not None:
94          context.verify_mode = cert_reqs
95 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
96 index ffb7314f57..f91af7bd05 100644
97 --- a/Lib/test/test_ssl.py
98 +++ b/Lib/test/test_ssl.py
99 @@ -73,6 +73,12 @@ NULLBYTECERT = data_file("nullbytecert.pem")
100  DHFILE = data_file("dh1024.pem")
101  BYTES_DHFILE = os.fsencode(DHFILE)
102  
103 +# Not defined in all versions of OpenSSL
104 +OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
105 +OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
106 +OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
107 +OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
108 +
109  
110  def handle_error(prefix):
111      exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
112 @@ -839,8 +845,9 @@ class ContextTests(unittest.TestCase):
113          ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
114          # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
115          default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
116 -        if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0):
117 -            default |= ssl.OP_NO_COMPRESSION
118 +        # SSLContext also enables these by default
119 +        default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
120 +                    OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE)
121          self.assertEqual(default, ctx.options)
122          ctx.options |= ssl.OP_NO_TLSv1
123          self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
124 @@ -1205,16 +1212,29 @@ class ContextTests(unittest.TestCase):
125              stats["x509"] += 1
126              self.assertEqual(ctx.cert_store_stats(), stats)
127  
128 +    def _assert_context_options(self, ctx):
129 +        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
130 +        if OP_NO_COMPRESSION != 0:
131 +            self.assertEqual(ctx.options & OP_NO_COMPRESSION,
132 +                             OP_NO_COMPRESSION)
133 +        if OP_SINGLE_DH_USE != 0:
134 +            self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
135 +                             OP_SINGLE_DH_USE)
136 +        if OP_SINGLE_ECDH_USE != 0:
137 +            self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
138 +                             OP_SINGLE_ECDH_USE)
139 +        if OP_CIPHER_SERVER_PREFERENCE != 0:
140 +            self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
141 +                             OP_CIPHER_SERVER_PREFERENCE)
142 +
143      def test_create_default_context(self):
144          ctx = ssl.create_default_context()
145 +
146          self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
147          self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
148          self.assertTrue(ctx.check_hostname)
149 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
150 -        self.assertEqual(
151 -            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
152 -            getattr(ssl, "OP_NO_COMPRESSION", 0),
153 -        )
154 +        self._assert_context_options(ctx)
155 +
156  
157          with open(SIGNING_CA) as f:
158              cadata = f.read()
159 @@ -1222,40 +1242,24 @@ class ContextTests(unittest.TestCase):
160                                           cadata=cadata)
161          self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
162          self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
163 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
164 -        self.assertEqual(
165 -            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
166 -            getattr(ssl, "OP_NO_COMPRESSION", 0),
167 -        )
168 +        self._assert_context_options(ctx)
169  
170          ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
171          self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
172          self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
173 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
174 -        self.assertEqual(
175 -            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
176 -            getattr(ssl, "OP_NO_COMPRESSION", 0),
177 -        )
178 -        self.assertEqual(
179 -            ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0),
180 -            getattr(ssl, "OP_SINGLE_DH_USE", 0),
181 -        )
182 -        self.assertEqual(
183 -            ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
184 -            getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
185 -        )
186 +        self._assert_context_options(ctx)
187  
188      def test__create_stdlib_context(self):
189          ctx = ssl._create_stdlib_context()
190          self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
191          self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
192          self.assertFalse(ctx.check_hostname)
193 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
194 +        self._assert_context_options(ctx)
195  
196          ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
197          self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
198          self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
199 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
200 +        self._assert_context_options(ctx)
201  
202          ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1,
203                                           cert_reqs=ssl.CERT_REQUIRED,
204 @@ -1263,12 +1267,12 @@ class ContextTests(unittest.TestCase):
205          self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
206          self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
207          self.assertTrue(ctx.check_hostname)
208 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
209 +        self._assert_context_options(ctx)
210  
211          ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
212          self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
213          self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
214 -        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
215 +        self._assert_context_options(ctx)
216  
217      def test_check_hostname(self):
218          ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
219 diff --git a/Modules/_ssl.c b/Modules/_ssl.c
220 index 86482677ae..0d5c121d2c 100644
221 --- a/Modules/_ssl.c
222 +++ b/Modules/_ssl.c
223 @@ -2330,6 +2330,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
224      PySSLContext *self;
225      long options;
226      SSL_CTX *ctx = NULL;
227 +    int result;
228  #if defined(SSL_MODE_RELEASE_BUFFERS)
229      unsigned long libver;
230  #endif
231 @@ -2393,8 +2394,38 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
232          options |= SSL_OP_NO_SSLv2;
233      if (proto_version != PY_SSL_VERSION_SSL3)
234          options |= SSL_OP_NO_SSLv3;
235 +    /* Minimal security flags for server and client side context.
236 +     * Client sockets ignore server-side parameters. */
237 +#ifdef SSL_OP_NO_COMPRESSION
238 +    options |= SSL_OP_NO_COMPRESSION;
239 +#endif
240 +#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
241 +    options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
242 +#endif
243 +#ifdef SSL_OP_SINGLE_DH_USE
244 +    options |= SSL_OP_SINGLE_DH_USE;
245 +#endif
246 +#ifdef SSL_OP_SINGLE_ECDH_USE
247 +    options |= SSL_OP_SINGLE_ECDH_USE;
248 +#endif
249      SSL_CTX_set_options(self->ctx, options);
250  
251 +    /* A bare minimum cipher list without completly broken cipher suites.
252 +     * It's far from perfect but gives users a better head start. */
253 +    if (proto_version != PY_SSL_VERSION_SSL2) {
254 +        result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL:!MD5");
255 +    } else {
256 +        /* SSLv2 needs MD5 */
257 +        result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL");
258 +    }
259 +    if (result == 0) {
260 +        Py_DECREF(self);
261 +        ERR_clear_error();
262 +        PyErr_SetString(PySSLErrorObject,
263 +                        "No cipher can be selected.");
264 +        return NULL;
265 +    }
266 +
267  #if defined(SSL_MODE_RELEASE_BUFFERS)
268      /* Set SSL_MODE_RELEASE_BUFFERS. This potentially greatly reduces memory
269         usage for no cost at all. However, don't do this for OpenSSL versions
270 -- 
271 2.17.1
272