Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-44362: ssl: improve deprecation warnings and docs (GH-26646) #26646

Merged
merged 1 commit into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions Doc/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
43 changes: 31 additions & 12 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <whatsnew310-deprecated>` 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
Expand Down Expand Up @@ -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
==========

Expand Down Expand Up @@ -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
Expand Down
23 changes: 15 additions & 8 deletions Lib/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
)
Expand Down
19 changes: 12 additions & 7 deletions Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve :mod:`ssl` module's deprecation messages, error reporting, and
documentation for deprecations.
42 changes: 28 additions & 14 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -2980,36 +2994,36 @@ _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
#if (defined(TLS1_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
#if (defined(TLS1_1_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
#if (defined(TLS1_2_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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}

Expand Down