Skip to content

Commit e82c034

Browse files
authored
bpo-31431: SSLContext.check_hostname auto-sets CERT_REQUIRED (python#3531)
Signed-off-by: Christian Heimes <[email protected]>
1 parent a170fa1 commit e82c034

File tree

4 files changed

+41
-8
lines changed

4 files changed

+41
-8
lines changed

Doc/library/ssl.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,10 @@ to speed up repeated connections from the same clients.
16741674
:meth:`SSLSocket.do_handshake`. The context's
16751675
:attr:`~SSLContext.verify_mode` must be set to :data:`CERT_OPTIONAL` or
16761676
:data:`CERT_REQUIRED`, and you must pass *server_hostname* to
1677-
:meth:`~SSLContext.wrap_socket` in order to match the hostname.
1677+
:meth:`~SSLContext.wrap_socket` in order to match the hostname. Enabling
1678+
hostname checking automatically sets :attr:`~SSLContext.verify_mode` from
1679+
:data:`CERT_NONE` to :data:`CERT_REQUIRED`. It cannot be set back to
1680+
:data:`CERT_NONE` as long as hostname checking is enabled.
16781681

16791682
Example::
16801683

@@ -1691,6 +1694,13 @@ to speed up repeated connections from the same clients.
16911694

16921695
.. versionadded:: 3.4
16931696

1697+
.. versionchanged:: 3.7
1698+
1699+
:attr:`~SSLContext.verify_mode` is now automatically changed
1700+
to :data:`CERT_REQUIRED` when hostname checking is enabled and
1701+
:attr:`~SSLContext.verify_mode` is :data:`CERT_NONE`. Previously
1702+
the same operation would have failed with a :exc:`ValueError`.
1703+
16941704
.. note::
16951705

16961706
This features requires OpenSSL 0.9.8f or newer.

Lib/test/test_ssl.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,24 +1363,45 @@ def test__create_stdlib_context(self):
13631363
def test_check_hostname(self):
13641364
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
13651365
self.assertFalse(ctx.check_hostname)
1366+
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
13661367

1367-
# Requires CERT_REQUIRED or CERT_OPTIONAL
1368-
with self.assertRaises(ValueError):
1369-
ctx.check_hostname = True
1368+
# Auto set CERT_REQUIRED
1369+
ctx.check_hostname = True
1370+
self.assertTrue(ctx.check_hostname)
1371+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1372+
ctx.check_hostname = False
13701373
ctx.verify_mode = ssl.CERT_REQUIRED
13711374
self.assertFalse(ctx.check_hostname)
1375+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1376+
1377+
# Changing verify_mode does not affect check_hostname
1378+
ctx.check_hostname = False
1379+
ctx.verify_mode = ssl.CERT_NONE
1380+
ctx.check_hostname = False
1381+
self.assertFalse(ctx.check_hostname)
1382+
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1383+
# Auto set
13721384
ctx.check_hostname = True
13731385
self.assertTrue(ctx.check_hostname)
1386+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
13741387

1388+
ctx.check_hostname = False
13751389
ctx.verify_mode = ssl.CERT_OPTIONAL
1390+
ctx.check_hostname = False
1391+
self.assertFalse(ctx.check_hostname)
1392+
self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1393+
# keep CERT_OPTIONAL
13761394
ctx.check_hostname = True
13771395
self.assertTrue(ctx.check_hostname)
1396+
self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
13781397

13791398
# Cannot set CERT_NONE with check_hostname enabled
13801399
with self.assertRaises(ValueError):
13811400
ctx.verify_mode = ssl.CERT_NONE
13821401
ctx.check_hostname = False
13831402
self.assertFalse(ctx.check_hostname)
1403+
ctx.verify_mode = ssl.CERT_NONE
1404+
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
13841405

13851406
def test_context_client_server(self):
13861407
# PROTOCOL_TLS_CLIENT has sane defaults
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SSLContext.check_hostname now automatically sets SSLContext.verify_mode to
2+
ssl.CERT_REQUIRED instead of failing with a ValueError.

Modules/_ssl.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,10 +3227,10 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c)
32273227
return -1;
32283228
if (check_hostname &&
32293229
SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) {
3230-
PyErr_SetString(PyExc_ValueError,
3231-
"check_hostname needs a SSL context with either "
3232-
"CERT_OPTIONAL or CERT_REQUIRED");
3233-
return -1;
3230+
/* check_hostname = True sets verify_mode = CERT_REQUIRED */
3231+
if (_set_verify_mode(self->ctx, PY_SSL_CERT_REQUIRED) == -1) {
3232+
return -1;
3233+
}
32343234
}
32353235
self->check_hostname = check_hostname;
32363236
return 0;

0 commit comments

Comments
 (0)