bpo-37120: Add SSLContext.num_tickets (GH-13719)
authorChristian Heimes <christian@python.org>
Mon, 3 Jun 2019 19:00:10 +0000 (21:00 +0200)
committerGitHub <noreply@github.com>
Mon, 3 Jun 2019 19:00:10 +0000 (21:00 +0200)
Signed-off-by: Christian Heimes <christian@python.org>
Doc/library/ssl.rst
Lib/test/test_ssl.py
Misc/NEWS.d/next/Library/2019-06-01-09-03-32.bpo-37120.FOKQLU.rst [new file with mode: 0644]
Modules/_ssl.c

index be09f38f7dfa0bca50af3e54214e02f37d934233..279af5728913d9b7e6dedb07e7ac391b5b7aaf06 100644 (file)
@@ -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
+
 .. attribute:: SSLContext.options
 
    An integer representing the set of SSL options enabled on this context.
index 455a12ea7f2f0c44bb83ceeecaa516c70d8fd3c9..7ba8156eef5da8a640b6a121937f409ff86436ab 100644 (file)
@@ -1634,6 +1634,24 @@ class ContextTests(unittest.TestCase):
         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)
+        with self.assertRaises(ValueError):
+            ctx.num_tickets = 1
+
 
 class SSLErrorTests(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2019-06-01-09-03-32.bpo-37120.FOKQLU.rst b/Misc/NEWS.d/next/Library/2019-06-01-09-03-32.bpo-37120.FOKQLU.rst
new file mode 100644 (file)
index 0000000..6bea492
--- /dev/null
@@ -0,0 +1 @@
+Add SSLContext.num_tickets to control the number of TLSv1.3 session tickets.
index f40127d3d932bbaaa918d32007b9ef59368122c7..2331c58ad77d5a015fef59b873d4e2e6a616b65d 100644 (file)
@@ -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)
 {
@@ -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,