diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index afa3d87f5767a1..4902d34888ebcc 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -681,19 +681,23 @@ Constants .. deprecated:: 3.10 + TLS clients and servers require different default settings for secure + communication. The generic TLS protocol constant is deprecated in + favor of :data:`PROTOCOL_TLS_CLIENT` and :data:`PROTOCOL_TLS_SERVER`. + .. data:: PROTOCOL_TLS_CLIENT - Auto-negotiate the highest protocol version like :data:`PROTOCOL_TLS`, - but only support client-side :class:`SSLSocket` connections. The protocol - enables :data:`CERT_REQUIRED` and :attr:`~SSLContext.check_hostname` by - default. + Auto-negotiate the highest protocol version that both the client and + server support, and configure the context client-side connections. The + protocol enables :data:`CERT_REQUIRED` and + :attr:`~SSLContext.check_hostname` by default. .. versionadded:: 3.6 .. data:: PROTOCOL_TLS_SERVER - Auto-negotiate the highest protocol version like :data:`PROTOCOL_TLS`, - but only support server-side :class:`SSLSocket` connections. + Auto-negotiate the highest protocol version that both the client and + server support, and configure the context server-side connections. .. versionadded:: 3.6 diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index df9806a2118339..249eb733a88bf8 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1214,18 +1214,11 @@ The ssl module has preliminary support for OpenSSL 3.0.0 and new option :issue:`43789`, and :issue:`43811`.) Deprecated function and use of deprecated constants now result in -a :exc:`DeprecationWarning`. The following features have been deprecated -since Python 3.6, Python 3.7, or OpenSSL 1.1.0: -:data:`~ssl.OP_NO_SSLv2`, :data:`~ssl.OP_NO_SSLv3`, :data:`~ssl.OP_NO_TLSv1`, -:data:`~ssl.OP_NO_TLSv1_1`, :data:`~ssl.OP_NO_TLSv1_2`, -:data:`~ssl.OP_NO_TLSv1_3`, :data:`~ssl.PROTOCOL_SSLv2`, -:data:`~ssl.PROTOCOL_SSLv3`, :data:`~ssl.PROTOCOL_SSLv23`, -:data:`~ssl.PROTOCOL_TLSv1`, :data:`~ssl.PROTOCOL_TLSv1_1`, -:data:`~ssl.PROTOCOL_TLSv1_2`, :data:`~ssl.PROTOCOL_TLS`, -:func:`~ssl.wrap_socket`, :func:`~ssl.match_hostname`, -:func:`~ssl.RAND_pseudo_bytes`, :func:`~ssl.RAND_egd`, -:meth:`ssl.SSLSocket.selected_npn_protocol`, -:meth:`ssl.SSLContext.set_npn_protocols`. +a :exc:`DeprecationWarning`. :attr:`ssl.SSLContext.options` has +:data:`~ssl.OP_NO_SSLv2` and :data:`~ssl.OP_NO_SSLv3` set by default and +therefore cannot warn about setting the flag again. The +:ref:`deprecation section ` has a list of deprecated +features. (Contributed by Christian Heimes in :issue:`43880`.) The ssl module now has more secure default settings. Ciphers without forward @@ -1441,6 +1434,8 @@ Optimizations readers or writers, just like its equivalent classes in :mod:`gzip` and :mod:`lzma` have always been. (Contributed by Inada Naoki in :issue:`43785`). +.. _whatsnew310-deprecated: + Deprecated ========== @@ -1609,6 +1604,30 @@ Deprecated * ``cgi.log()`` is deprecated and slated for removal in Python 3.12. (Contributed by Inada Naoki in :issue:`41139`.) +* The following :mod:`ssl` features have been deprecated since Python 3.6, + Python 3.7, or OpenSSL 1.1.0 and will be removed in 3.11: + + * :data:`~ssl.OP_NO_SSLv2`, :data:`~ssl.OP_NO_SSLv3`, :data:`~ssl.OP_NO_TLSv1`, + :data:`~ssl.OP_NO_TLSv1_1`, :data:`~ssl.OP_NO_TLSv1_2`, and + :data:`~ssl.OP_NO_TLSv1_3` are replaced by + :attr:`sslSSLContext.minimum_version` and + :attr:`sslSSLContext.maximum_version`. + + * :data:`~ssl.PROTOCOL_SSLv2`, :data:`~ssl.PROTOCOL_SSLv3`, + :data:`~ssl.PROTOCOL_SSLv23`, :data:`~ssl.PROTOCOL_TLSv1`, + :data:`~ssl.PROTOCOL_TLSv1_1`, :data:`~ssl.PROTOCOL_TLSv1_2`, and + :data:`~ssl.PROTOCOL_TLS` are deprecated in favor of + :data:`~ssl.PROTOCOL_TLS_CLIENT` and :data:`~ssl.PROTOCOL_TLS_SERVER` + + * :func:`~ssl.wrap_socket` is replaced by :meth:`ssl.SSLContext.wrap_socket` + + * :func:`~ssl.match_hostname` + + * :func:`~ssl.RAND_pseudo_bytes`, :func:`~ssl.RAND_egd` + + * NPN features like :meth:`ssl.SSLSocket.selected_npn_protocol` and + :meth:`ssl.SSLContext.set_npn_protocols` are replaced by ALPN. + .. _whatsnew310-removed: Removed diff --git a/Lib/ssl.py b/Lib/ssl.py index aeb2958da24be0..e667e9658d5110 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -94,7 +94,7 @@ import os from collections import namedtuple from enum import Enum as _Enum, IntEnum as _IntEnum, IntFlag as _IntFlag -from enum import _simple_enum, _test_simple_enum +from enum import _simple_enum import _ssl # if we can't import it, let the error propagate @@ -387,7 +387,7 @@ def match_hostname(cert, hostname): returns nothing. """ warnings.warn( - "ssl module: match_hostname() is deprecated", + "ssl.match_hostname() is deprecated", category=DeprecationWarning, stacklevel=2 ) @@ -492,8 +492,7 @@ class SSLContext(_SSLContext): def __new__(cls, protocol=None, *args, **kwargs): if protocol is None: warnings.warn( - "ssl module: " - "SSLContext() without protocol argument is deprecated.", + "ssl.SSLContext() without protocol argument is deprecated.", category=DeprecationWarning, stacklevel=2 ) @@ -536,7 +535,11 @@ def wrap_bio(self, incoming, outgoing, server_side=False, ) def set_npn_protocols(self, npn_protocols): - warnings.warn("NPN is deprecated, use ALPN instead", stacklevel=2) + warnings.warn( + "ssl NPN is deprecated, use ALPN instead", + DeprecationWarning, + stacklevel=2 + ) protos = bytearray() for protocol in npn_protocols: b = bytes(protocol, 'ascii') @@ -940,7 +943,9 @@ def selected_npn_protocol(self): if a next protocol was not negotiated or if NPN is not supported by one of the peers.""" warnings.warn( - "ssl module: NPN is deprecated, use ALPN instead", stacklevel=2 + "ssl NPN is deprecated, use ALPN instead", + DeprecationWarning, + stacklevel=2 ) def selected_alpn_protocol(self): @@ -1157,7 +1162,9 @@ def getpeercert(self, binary_form=False): def selected_npn_protocol(self): self._checkClosed() warnings.warn( - "ssl module: NPN is deprecated, use ALPN instead", stacklevel=2 + "ssl NPN is deprecated, use ALPN instead", + DeprecationWarning, + stacklevel=2 ) return None @@ -1419,7 +1426,7 @@ def wrap_socket(sock, keyfile=None, certfile=None, suppress_ragged_eofs=True, ciphers=None): warnings.warn( - "ssl module: wrap_socket is deprecated, use SSLContext.wrap_socket()", + "ssl.wrap_socket() is deprecated, use SSLContext.wrap_socket()", category=DeprecationWarning, stacklevel=2 ) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index fdf5f19d8d4c53..31bc199e930a6c 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1750,7 +1750,7 @@ class MySSLObject(ssl.SSLObject): with ctx.wrap_socket(socket.socket(), server_side=True) as sock: self.assertIsInstance(sock, MySSLSocket) - obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO()) + obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(), server_side=True) self.assertIsInstance(obj, MySSLObject) def test_num_tickest(self): @@ -2884,24 +2884,29 @@ def test_echo(self): server_context=client_context, chatty=True, connectionchatty=True, sni_name=hostname) - self.assertIn('called a function you should not call', - str(e.exception)) + self.assertIn( + 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context', + str(e.exception) + ) with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER): with self.assertRaises(ssl.SSLError) as e: server_params_test(client_context=server_context, server_context=server_context, chatty=True, connectionchatty=True) - self.assertIn('called a function you should not call', - str(e.exception)) + self.assertIn( + 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context', + str(e.exception) + ) with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT): with self.assertRaises(ssl.SSLError) as e: server_params_test(client_context=server_context, server_context=client_context, chatty=True, connectionchatty=True) - self.assertIn('called a function you should not call', - str(e.exception)) + self.assertIn( + 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context', + str(e.exception)) def test_getpeercert(self): if support.verbose: diff --git a/Misc/NEWS.d/next/Library/2021-06-10-20-07-32.bpo-44362.oVOMfd.rst b/Misc/NEWS.d/next/Library/2021-06-10-20-07-32.bpo-44362.oVOMfd.rst new file mode 100644 index 00000000000000..0e6aef3c90e6fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-06-10-20-07-32.bpo-44362.oVOMfd.rst @@ -0,0 +1,2 @@ +Improve :mod:`ssl` module's deprecation messages, error reporting, and +documentation for deprecations. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 73544bb12d1d8b..8daf04dd08bbb4 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -697,10 +697,9 @@ _setSSLError (_sslmodulestate *state, const char *errstr, int errcode, const cha } static int -_ssl_deprecated(const char* name, int stacklevel) { - return PyErr_WarnFormat( - PyExc_DeprecationWarning, stacklevel, - "ssl module: %s is deprecated", name +_ssl_deprecated(const char* msg, int stacklevel) { + return PyErr_WarnEx( + PyExc_DeprecationWarning, msg, stacklevel ); } @@ -788,6 +787,21 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, SSL_CTX *ctx = sslctx->ctx; _PySSLError err = { 0 }; + if ((socket_type == PY_SSL_SERVER) && + (sslctx->protocol == PY_SSL_VERSION_TLS_CLIENT)) { + _setSSLError(get_state_ctx(sslctx), + "Cannot create a server socket with a " + "PROTOCOL_TLS_CLIENT context", 0, __FILE__, __LINE__); + return NULL; + } + if ((socket_type == PY_SSL_CLIENT) && + (sslctx->protocol == PY_SSL_VERSION_TLS_SERVER)) { + _setSSLError(get_state_ctx(sslctx), + "Cannot create a client socket with a " + "PROTOCOL_TLS_SERVER context", 0, __FILE__, __LINE__); + return NULL; + } + self = PyObject_GC_New(PySSLSocket, get_state_ctx(sslctx)->PySSLSocket_Type); if (self == NULL) @@ -2980,7 +2994,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) switch(proto_version) { #if defined(SSL3_VERSION) && !defined(OPENSSL_NO_SSL3) case PY_SSL_VERSION_SSL3: - PY_SSL_DEPRECATED("PROTOCOL_SSLv3", 2, NULL); + PY_SSL_DEPRECATED("ssl.PROTOCOL_SSLv3 is deprecated", 2, NULL); method = SSLv3_method(); break; #endif @@ -2988,7 +3002,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) !defined(OPENSSL_NO_TLS1) && \ !defined(OPENSSL_NO_TLS1_METHOD)) case PY_SSL_VERSION_TLS1: - PY_SSL_DEPRECATED("PROTOCOL_TLSv1", 2, NULL); + PY_SSL_DEPRECATED("ssl.PROTOCOL_TLSv1 is deprecated", 2, NULL); method = TLSv1_method(); break; #endif @@ -2996,7 +3010,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) !defined(OPENSSL_NO_TLS1_1) && \ !defined(OPENSSL_NO_TLS1_1_METHOD)) case PY_SSL_VERSION_TLS1_1: - PY_SSL_DEPRECATED("PROTOCOL_TLSv1_1", 2, NULL); + PY_SSL_DEPRECATED("ssl.PROTOCOL_TLSv1_1 is deprecated", 2, NULL); method = TLSv1_1_method(); break; #endif @@ -3004,12 +3018,12 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) !defined(OPENSSL_NO_TLS1_2) && \ !defined(OPENSSL_NO_TLS1_2_METHOD)) case PY_SSL_VERSION_TLS1_2: - PY_SSL_DEPRECATED("PROTOCOL_TLSv1_2", 2, NULL); + PY_SSL_DEPRECATED("ssl.PROTOCOL_TLSv1_2 is deprecated", 2, NULL); method = TLSv1_2_method(); break; #endif case PY_SSL_VERSION_TLS: - PY_SSL_DEPRECATED("PROTOCOL_TLS", 2, NULL); + PY_SSL_DEPRECATED("ssl.PROTOCOL_TLS is deprecated", 2, NULL); method = TLS_method(); break; case PY_SSL_VERSION_TLS_CLIENT: @@ -3433,13 +3447,13 @@ set_min_max_proto_version(PySSLContext *self, PyObject *arg, int what) /* check for deprecations and supported values */ switch(v) { case PY_PROTO_SSLv3: - PY_SSL_DEPRECATED("TLSVersion.SSLv3", 2, -1); + PY_SSL_DEPRECATED("ssl.TLSVersion.SSLv3 is deprecated", 2, -1); break; case PY_PROTO_TLSv1: - PY_SSL_DEPRECATED("TLSVersion.TLSv1", 2, -1); + PY_SSL_DEPRECATED("ssl.TLSVersion.TLSv1 is deprecated", 2, -1); break; case PY_PROTO_TLSv1_1: - PY_SSL_DEPRECATED("TLSVersion.TLSv1_1", 2, -1); + PY_SSL_DEPRECATED("ssl.TLSVersion.TLSv1_1 is deprecated", 2, -1); break; case PY_PROTO_MINIMUM_SUPPORTED: case PY_PROTO_MAXIMUM_SUPPORTED: @@ -3583,7 +3597,7 @@ set_options(PySSLContext *self, PyObject *arg, void *c) set = ~opts & new_opts; if ((set & opt_no) != 0) { - if (_ssl_deprecated("Setting OP_NO_SSL* or SSL_NO_TLS* options is " + if (_ssl_deprecated("ssl.OP_NO_SSL*/ssl.SSL_NO_TLS* options are " "deprecated", 2) < 0) { return -1; } @@ -5146,7 +5160,7 @@ static PyObject * _ssl_RAND_pseudo_bytes_impl(PyObject *module, int n) /*[clinic end generated code: output=b1509e937000e52d input=58312bd53f9bbdd0]*/ { - PY_SSL_DEPRECATED("RAND_pseudo_bytes", 1, NULL); + PY_SSL_DEPRECATED("ssl.RAND_pseudo_bytes() is deprecated", 1, NULL); return PySSL_RAND(module, n, 1); }