Skip to content

bpo-37120: Add SSLContext.num_tickets (GH-13719) #13719

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

Merged
merged 1 commit into from
Jun 3, 2019
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
13 changes: 13 additions & 0 deletions Doc/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,19 @@ to speed up repeated connections from the same clients.

.. versionadded:: 3.7

.. attribute:: SSLContext.num_tickets

Control the number of TLS 1.3 session tickets of a
:attr:`TLS_PROTOCOL_SERVER` context. The setting has no impact on TLS
1.0 to 1.2 connections.

.. note::

This attribute is not available unless the ssl module is compiled
with OpenSSL 1.1.1 or newer.

.. versionadded:: 3.8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth noting explicitly that it only affects TLS 1.3 connections, and possibly that it doesn't affect connections that are resumed using a ticket.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, the first sentence mentions that it's about TLS 1.3. I added another sentence to explicitly state that the setting does not affect TLS 1.0 to 1.2.


.. attribute:: SSLContext.options

An integer representing the set of SSL options enabled on this context.
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,24 @@ class MySSLObject(ssl.SSLObject):
obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
self.assertIsInstance(obj, MySSLObject)

@unittest.skipUnless(IS_OPENSSL_1_1_1, "Test requires OpenSSL 1.1.1")
def test_num_tickest(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
self.assertEqual(ctx.num_tickets, 2)
ctx.num_tickets = 1
self.assertEqual(ctx.num_tickets, 1)
ctx.num_tickets = 0
self.assertEqual(ctx.num_tickets, 0)
with self.assertRaises(ValueError):
ctx.num_tickets = -1
with self.assertRaises(TypeError):
ctx.num_tickets = None

ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
self.assertEqual(ctx.num_tickets, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's maybe slightly nicer to make this error out too, I guess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean getattr access? I'm not sure how much trouble it's going to create.

with self.assertRaises(ValueError):
ctx.num_tickets = 1


class SSLErrorTests(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add SSLContext.num_tickets to control the number of TLSv1.3 session tickets.
37 changes: 37 additions & 0 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3617,6 +3617,39 @@ set_maximum_version(PySSLContext *self, PyObject *arg, void *c)
}
#endif /* SSL_CTRL_GET_MAX_PROTO_VERSION */

#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) && !defined(LIBRESSL_VERSION_NUMBER)
static PyObject *
get_num_tickets(PySSLContext *self, void *c)
{
return PyLong_FromLong(SSL_CTX_get_num_tickets(self->ctx));
}

static int
set_num_tickets(PySSLContext *self, PyObject *arg, void *c)
{
long num;
if (!PyArg_Parse(arg, "l", &num))
return -1;
if (num < 0) {
PyErr_SetString(PyExc_ValueError, "value must be non-negative");
return -1;
}
if (self->protocol != PY_SSL_VERSION_TLS_SERVER) {
PyErr_SetString(PyExc_ValueError,
"SSLContext is not a server context.");
return -1;
}
if (SSL_CTX_set_num_tickets(self->ctx, num) != 1) {
PyErr_SetString(PyExc_ValueError, "failed to set num tickets.");
return -1;
}
return 0;
}

PyDoc_STRVAR(PySSLContext_num_tickets_doc,
"Control the number of TLSv1.3 session tickets");
#endif /* OpenSSL 1.1.1 */

static PyObject *
get_options(PySSLContext *self, void *c)
{
Expand Down Expand Up @@ -4654,6 +4687,10 @@ static PyGetSetDef context_getsetlist[] = {
(setter) _PySSLContext_set_msg_callback, NULL},
{"sni_callback", (getter) get_sni_callback,
(setter) set_sni_callback, PySSLContext_sni_callback_doc},
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) && !defined(LIBRESSL_VERSION_NUMBER)
{"num_tickets", (getter) get_num_tickets,
(setter) set_num_tickets, PySSLContext_num_tickets_doc},
#endif
{"options", (getter) get_options,
(setter) set_options, NULL},
{"post_handshake_auth", (getter) get_post_handshake_auth,
Expand Down