Commit b5218771 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #4870: Add an `options` attribute to SSL contexts, as well as

several ``OP_*`` constants to the `ssl` module.  This allows to selectively
disable protocol versions, when used in combination with `PROTOCOL_SSLv23`.
parent 955d1b22
...@@ -257,6 +257,37 @@ Functions, Constants, and Exceptions ...@@ -257,6 +257,37 @@ Functions, Constants, and Exceptions
modern version, and probably the best choice for maximum protection, if both modern version, and probably the best choice for maximum protection, if both
sides can speak it. sides can speak it.
.. data:: OP_ALL
Enables workarounds for various bugs present in other SSL implementations.
This option is set by default.
.. versionadded:: 3.2
.. data:: OP_NO_SSLv2
Prevents an SSLv2 connection. This option is only applicable in
conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from
choosing SSLv2 as the protocol version.
.. versionadded:: 3.2
.. data:: OP_NO_SSLv3
Prevents an SSLv3 connection. This option is only applicable in
conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from
choosing SSLv3 as the protocol version.
.. versionadded:: 3.2
.. data:: OP_NO_TLSv1
Prevents a TLSv1 connection. This option is only applicable in
conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from
choosing TLSv1 as the protocol version.
.. versionadded:: 3.2
.. data:: OPENSSL_VERSION .. data:: OPENSSL_VERSION
The version string of the OpenSSL library loaded by the interpreter:: The version string of the OpenSSL library loaded by the interpreter::
...@@ -440,6 +471,17 @@ SSL Contexts ...@@ -440,6 +471,17 @@ SSL Contexts
and *suppress_ragged_eofs* have the same meaning as in the top-level and *suppress_ragged_eofs* have the same meaning as in the top-level
:func:`wrap_socket` function. :func:`wrap_socket` function.
.. attribute:: SSLContext.options
An integer representing the set of SSL options enabled on this context.
The default value is :data:`OP_ALL`, but you can specify other options
such as :data:`OP_NO_SSLv2` by ORing them together.
.. note::
With versions of OpenSSL older than 0.9.8m, it is only possible
to set options, not to clear them. Attempting to clear an option
(by resetting the corresponding bits) will raise a ``ValueError``.
.. attribute:: SSLContext.protocol .. attribute:: SSLContext.protocol
The protocol version chosen when constructing the context. This attribute The protocol version chosen when constructing the context. This attribute
...@@ -794,6 +836,20 @@ to specify :const:`CERT_REQUIRED` and similarly check the client certificate. ...@@ -794,6 +836,20 @@ to specify :const:`CERT_REQUIRED` and similarly check the client certificate.
equivalent unless anonymous ciphers are enabled (they are disabled equivalent unless anonymous ciphers are enabled (they are disabled
by default). by default).
Protocol versions
^^^^^^^^^^^^^^^^^
SSL version 2 is considered insecure and is therefore dangerous to use. If
you want maximum compatibility between clients and servers, it is recommended
to use :const:`PROTOCOL_SSLv23` as the protocol version and then disable
SSLv2 explicitly using the :data:`SSLContext.options` attribute::
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.options |= ssl.OP_NO_SSLv2
The SSL context created above will allow SSLv3 and TLSv1 connections, but
not SSLv2.
.. seealso:: .. seealso::
......
...@@ -63,6 +63,7 @@ from _ssl import _SSLContext, SSLError ...@@ -63,6 +63,7 @@ from _ssl import _SSLContext, SSLError
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23,
PROTOCOL_TLSv1) PROTOCOL_TLSv1)
from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1
from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import RAND_status, RAND_egd, RAND_add
from _ssl import ( from _ssl import (
SSL_ERROR_ZERO_RETURN, SSL_ERROR_ZERO_RETURN,
......
This diff is collapsed.
...@@ -375,6 +375,10 @@ C-API ...@@ -375,6 +375,10 @@ C-API
Library Library
------- -------
- Issue #4870: Add an `options` attribute to SSL contexts, as well as
several ``OP_*`` constants to the `ssl` module. This allows to selectively
disable protocol versions, when used in combination with `PROTOCOL_SSLv23`.
- Issue #8759: Fixed user paths in sysconfig for posix and os2 schemes. - Issue #8759: Fixed user paths in sysconfig for posix and os2 schemes.
- Issue #8663: distutils.log emulates backslashreplace error handler. Fix - Issue #8663: distutils.log emulates backslashreplace error handler. Fix
......
...@@ -113,6 +113,13 @@ static unsigned int _ssl_locks_count = 0; ...@@ -113,6 +113,13 @@ static unsigned int _ssl_locks_count = 0;
# undef HAVE_OPENSSL_RAND # undef HAVE_OPENSSL_RAND
#endif #endif
/* SSL_CTX_clear_options() and SSL_clear_options() were first added in OpenSSL 0.9.8m */
#if OPENSSL_VERSION_NUMBER >= 0x009080dfL
# define HAVE_SSL_CTX_CLEAR_OPTIONS
#else
# undef HAVE_SSL_CTX_CLEAR_OPTIONS
#endif
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
SSL_CTX *ctx; SSL_CTX *ctx;
...@@ -1513,6 +1520,35 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c) ...@@ -1513,6 +1520,35 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c)
return 0; return 0;
} }
static PyObject *
get_options(PySSLContext *self, void *c)
{
return PyLong_FromLong(SSL_CTX_get_options(self->ctx));
}
static int
set_options(PySSLContext *self, PyObject *arg, void *c)
{
long new_opts, opts, set, clear;
if (!PyArg_Parse(arg, "l", &new_opts))
return -1;
opts = SSL_CTX_get_options(self->ctx);
clear = opts & ~new_opts;
set = ~opts & new_opts;
if (clear) {
#ifdef HAVE_SSL_CTX_CLEAR_OPTIONS
SSL_CTX_clear_options(self->ctx, clear);
#else
PyErr_SetString(PyExc_ValueError,
"can't clear options before OpenSSL 0.9.8m");
return -1;
#endif
}
if (set)
SSL_CTX_set_options(self->ctx, set);
return 0;
}
static PyObject * static PyObject *
load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
{ {
...@@ -1636,6 +1672,8 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) ...@@ -1636,6 +1672,8 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds)
} }
static PyGetSetDef context_getsetlist[] = { static PyGetSetDef context_getsetlist[] = {
{"options", (getter) get_options,
(setter) set_options, NULL},
{"verify_mode", (getter) get_verify_mode, {"verify_mode", (getter) get_verify_mode,
(setter) set_verify_mode, NULL}, (setter) set_verify_mode, NULL},
{NULL}, /* sentinel */ {NULL}, /* sentinel */
...@@ -1953,6 +1991,12 @@ PyInit__ssl(void) ...@@ -1953,6 +1991,12 @@ PyInit__ssl(void)
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", PyModule_AddIntConstant(m, "PROTOCOL_TLSv1",
PY_SSL_VERSION_TLS1); PY_SSL_VERSION_TLS1);
/* protocol options */
PyModule_AddIntConstant(m, "OP_ALL", SSL_OP_ALL);
PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2);
PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
/* OpenSSL version */ /* OpenSSL version */
/* SSLeay() gives us the version of the library linked against, /* SSLeay() gives us the version of the library linked against,
which could be different from the headers version. which could be different from the headers version.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment