:meth:`SSLSocket.do_handshake`. The context's
:attr:`~SSLContext.verify_mode` must be set to :data:`CERT_OPTIONAL` or
:data:`CERT_REQUIRED`, and you must pass *server_hostname* to
- :meth:`~SSLContext.wrap_socket` in order to match the hostname.
+ :meth:`~SSLContext.wrap_socket` in order to match the hostname. Enabling
+ hostname checking automatically sets :attr:`~SSLContext.verify_mode` from
+ :data:`CERT_NONE` to :data:`CERT_REQUIRED`. It cannot be set back to
+ :data:`CERT_NONE` as long as hostname checking is enabled.
Example::
.. versionadded:: 3.4
+ .. versionchanged:: 3.7
+
+ :attr:`~SSLContext.verify_mode` is now automatically changed
+ to :data:`CERT_REQUIRED` when hostname checking is enabled and
+ :attr:`~SSLContext.verify_mode` is :data:`CERT_NONE`. Previously
+ the same operation would have failed with a :exc:`ValueError`.
+
.. note::
This features requires OpenSSL 0.9.8f or newer.
def test_check_hostname(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
self.assertFalse(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
- # Requires CERT_REQUIRED or CERT_OPTIONAL
- with self.assertRaises(ValueError):
- ctx.check_hostname = True
+ # Auto set CERT_REQUIRED
+ ctx.check_hostname = True
+ self.assertTrue(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_REQUIRED
self.assertFalse(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+
+ # Changing verify_mode does not affect check_hostname
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+ ctx.check_hostname = False
+ self.assertFalse(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
+ # Auto set
ctx.check_hostname = True
self.assertTrue(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_OPTIONAL
+ ctx.check_hostname = False
+ self.assertFalse(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
+ # keep CERT_OPTIONAL
ctx.check_hostname = True
self.assertTrue(ctx.check_hostname)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
# Cannot set CERT_NONE with check_hostname enabled
with self.assertRaises(ValueError):
ctx.verify_mode = ssl.CERT_NONE
ctx.check_hostname = False
self.assertFalse(ctx.check_hostname)
+ ctx.verify_mode = ssl.CERT_NONE
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
def test_context_client_server(self):
# PROTOCOL_TLS_CLIENT has sane defaults
return -1;
if (check_hostname &&
SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) {
- PyErr_SetString(PyExc_ValueError,
- "check_hostname needs a SSL context with either "
- "CERT_OPTIONAL or CERT_REQUIRED");
- return -1;
+ /* check_hostname = True sets verify_mode = CERT_REQUIRED */
+ if (_set_verify_mode(self->ctx, PY_SSL_CERT_REQUIRED) == -1) {
+ return -1;
+ }
}
self->check_hostname = check_hostname;
return 0;