summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2018-09-23 09:22:52 +0200
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2018-09-23 00:22:52 -0700
commit2756ef31656399a120589b7aa19c32e2b91a4758 (patch)
tree01475d04b12f1f8a51c9a52da1527a93606d7b00
parent44989bc2696320cf55ae6f329aaf58edd49d792a (diff)
downloadcpython-git-2756ef31656399a120589b7aa19c32e2b91a4758.tar.gz
[3.7] bpo-34670: Add TLS 1.3 post handshake auth (GH-9460) (GH-9505)
Add SSLContext.post_handshake_auth and SSLSocket.verify_client_post_handshake for TLS 1.3 post-handshake authentication. Signed-off-by: Christian Heimes <christian@python.org>q https://bugs.python.org/issue34670. (cherry picked from commit 9fb051f032c36b9f6086b79086b4d6b7755a3d70) Co-authored-by: Christian Heimes <christian@python.org> https://bugs.python.org/issue34670
-rw-r--r--.travis.yml2
-rw-r--r--Doc/library/ssl.rst42
-rw-r--r--Doc/whatsnew/3.7.rst4
-rw-r--r--Lib/ssl.py9
-rw-r--r--Lib/test/test_ssl.py193
-rw-r--r--Misc/NEWS.d/next/Library/2018-09-14-14-29-45.bpo-34670.17XwGB.rst3
-rw-r--r--Modules/_ssl.c100
-rw-r--r--Modules/clinic/_ssl.c.h20
-rwxr-xr-xTools/ssl/multissltests.py8
9 files changed, 366 insertions, 15 deletions
diff --git a/.travis.yml b/.travis.yml
index 8b12196366..27a240f1e6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ cache:
env:
global:
- - OPENSSL=1.1.0h
+ - OPENSSL=1.1.0i
- OPENSSL_DIR="$HOME/multissl/openssl/${OPENSSL}"
- PATH="${OPENSSL_DIR}/bin:$PATH"
# Use -O3 because we don't use debugger on Travis-CI
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 99d1d774b4..dd2fccc2e4 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -1314,6 +1314,26 @@ SSL sockets also have the following additional methods and attributes:
returned socket should always be used for further communication with the
other side of the connection, rather than the original socket.
+.. method:: SSLSocket.verify_client_post_handshake()
+
+ Requests post-handshake authentication (PHA) from a TLS 1.3 client. PHA
+ can only be initiated for a TLS 1.3 connection from a server-side socket,
+ after the initial TLS handshake and with PHA enabled on both sides, see
+ :attr:`SSLContext.post_handshake_auth`.
+
+ The method does not perform a cert exchange immediately. The server-side
+ sends a CertificateRequest during the next write event and expects the
+ client to respond with a certificate on the next read event.
+
+ If any precondition isn't met (e.g. not TLS 1.3, PHA not enabled), an
+ :exc:`SSLError` is raised.
+
+ .. versionadded:: 3.7.1
+
+ .. note::
+ Only available with OpenSSL 1.1.1 and TLS 1.3 enabled. Without TLS 1.3
+ support, the method raises :exc:`NotImplementedError`.
+
.. method:: SSLSocket.version()
Return the actual SSL protocol version negotiated by the connection
@@ -1929,6 +1949,28 @@ to speed up repeated connections from the same clients.
>>> ssl.create_default_context().options # doctest: +SKIP
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
+.. attribute:: SSLContext.post_handshake_auth
+
+ Enable TLS 1.3 post-handshake client authentication. Post-handshake auth
+ is disabled by default and a server can only request a TLS client
+ certificate during the initial handshake. When enabled, a server may
+ request a TLS client certificate at any time after the handshake.
+
+ When enabled on client-side sockets, the client signals the server that
+ it supports post-handshake authentication.
+
+ When enabled on server-side sockets, :attr:`SSLContext.verify_mode` must
+ be set to :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`, too. The
+ actual client cert exchange is delayed until
+ :meth:`SSLSocket.verify_client_post_handshake` is called and some I/O is
+ performed.
+
+ .. versionadded:: 3.7.1
+
+ .. note::
+ Only available with OpenSSL 1.1.1 and TLS 1.3 enabled. Without TLS 1.3
+ support, the property value is None and can't be modified
+
.. attribute:: SSLContext.protocol
The protocol version chosen when constructing the context. This attribute
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index a2c5c284f2..132ed00f73 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -1350,6 +1350,10 @@ Supported protocols are indicated by serveral new flags, such as
:data:`~ssl.HAS_TLSv1_1`.
(Contributed by Christian Heimes in :issue:`32609`.)
+Added :attr:`SSLContext.post_handshake_auth` to enable and
+:meth:`ssl.SSLSocket.verify_client_post_handshake` to initiate TLS 1.3
+post-handshake authentication.
+(Contributed by Christian Heimes in :issue:`34670`.)
string
------
diff --git a/Lib/ssl.py b/Lib/ssl.py
index fdd1615744..2f21937b8e 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -777,6 +777,9 @@ class SSLObject:
current SSL channel. """
return self._sslobj.version()
+ def verify_client_post_handshake(self):
+ return self._sslobj.verify_client_post_handshake()
+
class SSLSocket(socket):
"""This class implements a subtype of socket.socket that wraps
@@ -1094,6 +1097,12 @@ class SSLSocket(socket):
else:
raise ValueError("No SSL wrapper around " + str(self))
+ def verify_client_post_handshake(self):
+ if self._sslobj:
+ return self._sslobj.verify_client_post_handshake()
+ else:
+ raise ValueError("No SSL wrapper around " + str(self))
+
def _real_close(self):
self._sslobj = None
super()._real_close()
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 4d5925a935..d4132c5043 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -234,7 +234,7 @@ def testing_context(server_cert=SIGNED_CERTFILE):
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_context.load_cert_chain(server_cert)
- client_context.load_verify_locations(SIGNING_CA)
+ server_context.load_verify_locations(SIGNING_CA)
return client_context, server_context, hostname
@@ -2282,6 +2282,23 @@ class ThreadedEchoServer(threading.Thread):
sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
data = self.sslconn.get_channel_binding("tls-unique")
self.write(repr(data).encode("us-ascii") + b"\n")
+ elif stripped == b'PHA':
+ if support.verbose and self.server.connectionchatty:
+ sys.stdout.write(" server: initiating post handshake auth\n")
+ try:
+ self.sslconn.verify_client_post_handshake()
+ except ssl.SSLError as e:
+ self.write(repr(e).encode("us-ascii") + b"\n")
+ else:
+ self.write(b"OK\n")
+ elif stripped == b'HASCERT':
+ if self.sslconn.getpeercert() is not None:
+ self.write(b'TRUE\n')
+ else:
+ self.write(b'FALSE\n')
+ elif stripped == b'GETCERT':
+ cert = self.sslconn.getpeercert()
+ self.write(repr(cert).encode("us-ascii") + b"\n")
else:
if (support.verbose and
self.server.connectionchatty):
@@ -4175,6 +4192,179 @@ class ThreadedTests(unittest.TestCase):
'Session refers to a different SSLContext.')
+@unittest.skipUnless(ssl.HAS_TLSv1_3, "Test needs TLS 1.3")
+class TestPostHandshakeAuth(unittest.TestCase):
+ def test_pha_setter(self):
+ protocols = [
+ ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
+ ]
+ for protocol in protocols:
+ ctx = ssl.SSLContext(protocol)
+ self.assertEqual(ctx.post_handshake_auth, False)
+
+ ctx.post_handshake_auth = True
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ ctx.post_handshake_auth = False
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ self.assertEqual(ctx.post_handshake_auth, False)
+
+ ctx.verify_mode = ssl.CERT_OPTIONAL
+ ctx.post_handshake_auth = True
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ def test_pha_required(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+ # PHA method just returns true when cert is already available
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'GETCERT')
+ cert_text = s.recv(4096).decode('us-ascii')
+ self.assertIn('Python Software Foundation CA', cert_text)
+
+ def test_pha_required_nocert(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'PHA')
+ # receive CertificateRequest
+ self.assertEqual(s.recv(1024), b'OK\n')
+ # send empty Certificate + Finish
+ s.write(b'HASCERT')
+ # receive alert
+ with self.assertRaisesRegex(
+ ssl.SSLError,
+ 'tlsv13 alert certificate required'):
+ s.recv(1024)
+
+ def test_pha_optional(self):
+ if support.verbose:
+ sys.stdout.write("\n")
+
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ # check CERT_OPTIONAL
+ server_context.verify_mode = ssl.CERT_OPTIONAL
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+
+ def test_pha_optional_nocert(self):
+ if support.verbose:
+ sys.stdout.write("\n")
+
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_OPTIONAL
+ client_context.post_handshake_auth = True
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ # optional doens't fail when client does not have a cert
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+
+ def test_pha_no_pha_client(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ with self.assertRaisesRegex(ssl.SSLError, 'not server'):
+ s.verify_client_post_handshake()
+ s.write(b'PHA')
+ self.assertIn(b'extension not received', s.recv(1024))
+
+ def test_pha_no_pha_server(self):
+ # server doesn't have PHA enabled, cert is requested in handshake
+ client_context, server_context, hostname = testing_context()
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+ # PHA doesn't fail if there is already a cert
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+
+ def test_pha_not_tls13(self):
+ # TLS 1.2
+ client_context, server_context, hostname = testing_context()
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.maximum_version = ssl.TLSVersion.TLSv1_2
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ # PHA fails for TLS != 1.3
+ s.write(b'PHA')
+ self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
+
+
def test_main(verbose=False):
if support.verbose:
import warnings
@@ -4218,6 +4408,7 @@ def test_main(verbose=False):
tests = [
ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
+ TestPostHandshakeAuth
]
if support.is_resource_enabled('network'):
diff --git a/Misc/NEWS.d/next/Library/2018-09-14-14-29-45.bpo-34670.17XwGB.rst b/Misc/NEWS.d/next/Library/2018-09-14-14-29-45.bpo-34670.17XwGB.rst
new file mode 100644
index 0000000000..c1a61293fa
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-09-14-14-29-45.bpo-34670.17XwGB.rst
@@ -0,0 +1,3 @@
+Add SSLContext.post_handshake_auth and
+SSLSocket.verify_client_post_handshake for TLS 1.3's post
+handshake authentication feature.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index faca3a27c5..3c9d46e43d 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -421,6 +421,9 @@ typedef struct {
*/
unsigned int hostflags;
int protocol;
+#ifdef TLS1_3_VERSION
+ int post_handshake_auth;
+#endif
} PySSLContext;
typedef struct {
@@ -2644,6 +2647,30 @@ _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self,
return PyBytes_FromStringAndSize(buf, len);
}
+/*[clinic input]
+_ssl._SSLSocket.verify_client_post_handshake
+
+Initiate TLS 1.3 post-handshake authentication
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self)
+/*[clinic end generated code: output=532147f3b1341425 input=6bfa874810a3d889]*/
+{
+#ifdef TLS1_3_VERSION
+ int err = SSL_verify_client_post_handshake(self->ssl);
+ if (err == 0)
+ return _setSSLError(NULL, 0, __FILE__, __LINE__);
+ else
+ Py_RETURN_NONE;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "Post-handshake auth is not supported by your "
+ "OpenSSL version.");
+ return NULL;
+#endif
+}
+
#ifdef OPENSSL_VERSION_1_1
static SSL_SESSION*
@@ -2820,6 +2847,7 @@ static PyMethodDef PySSLMethods[] = {
_SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
_SSL__SSLSOCKET_COMPRESSION_METHODDEF
_SSL__SSLSOCKET_SHUTDOWN_METHODDEF
+ _SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF
{NULL, NULL}
};
@@ -2863,7 +2891,7 @@ static PyTypeObject PySSLSocket_Type = {
*/
static int
-_set_verify_mode(SSL_CTX *ctx, enum py_ssl_cert_requirements n)
+_set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n)
{
int mode;
int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
@@ -2883,9 +2911,13 @@ _set_verify_mode(SSL_CTX *ctx, enum py_ssl_cert_requirements n)
"invalid value for verify_mode");
return -1;
}
+#ifdef TLS1_3_VERSION
+ if (self->post_handshake_auth)
+ mode |= SSL_VERIFY_POST_HANDSHAKE;
+#endif
/* keep current verify cb */
- verify_cb = SSL_CTX_get_verify_callback(ctx);
- SSL_CTX_set_verify(ctx, mode, verify_cb);
+ verify_cb = SSL_CTX_get_verify_callback(self->ctx);
+ SSL_CTX_set_verify(self->ctx, mode, verify_cb);
return 0;
}
@@ -2967,13 +2999,13 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
/* Don't check host name by default */
if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
self->check_hostname = 1;
- if (_set_verify_mode(self->ctx, PY_SSL_CERT_REQUIRED) == -1) {
+ if (_set_verify_mode(self, PY_SSL_CERT_REQUIRED) == -1) {
Py_DECREF(self);
return NULL;
}
} else {
self->check_hostname = 0;
- if (_set_verify_mode(self->ctx, PY_SSL_CERT_NONE) == -1) {
+ if (_set_verify_mode(self, PY_SSL_CERT_NONE) == -1) {
Py_DECREF(self);
return NULL;
}
@@ -3066,6 +3098,11 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
#endif
X509_VERIFY_PARAM_set_hostflags(params, self->hostflags);
+#ifdef TLS1_3_VERSION
+ self->post_handshake_auth = 0;
+ SSL_CTX_set_post_handshake_auth(self->ctx, self->post_handshake_auth);
+#endif
+
return (PyObject *)self;
}
@@ -3320,7 +3357,10 @@ _ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *self,
static PyObject *
get_verify_mode(PySSLContext *self, void *c)
{
- switch (SSL_CTX_get_verify_mode(self->ctx)) {
+ /* ignore SSL_VERIFY_CLIENT_ONCE and SSL_VERIFY_POST_HANDSHAKE */
+ int mask = (SSL_VERIFY_NONE | SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ switch (SSL_CTX_get_verify_mode(self->ctx) & mask) {
case SSL_VERIFY_NONE:
return PyLong_FromLong(PY_SSL_CERT_NONE);
case SSL_VERIFY_PEER:
@@ -3345,7 +3385,7 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c)
"check_hostname is enabled.");
return -1;
}
- return _set_verify_mode(self->ctx, n);
+ return _set_verify_mode(self, n);
}
static PyObject *
@@ -3551,7 +3591,7 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c)
if (check_hostname &&
SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) {
/* check_hostname = True sets verify_mode = CERT_REQUIRED */
- if (_set_verify_mode(self->ctx, PY_SSL_CERT_REQUIRED) == -1) {
+ if (_set_verify_mode(self, PY_SSL_CERT_REQUIRED) == -1) {
return -1;
}
}
@@ -3560,6 +3600,43 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c)
}
static PyObject *
+get_post_handshake_auth(PySSLContext *self, void *c) {
+#if TLS1_3_VERSION
+ return PyBool_FromLong(self->post_handshake_auth);
+#else
+ Py_RETURN_NONE;
+#endif
+}
+
+#if TLS1_3_VERSION
+static int
+set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
+ int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
+ int mode = SSL_CTX_get_verify_mode(self->ctx);
+ int pha = PyObject_IsTrue(arg);
+
+ if (pha == -1) {
+ return -1;
+ }
+ self->post_handshake_auth = pha;
+
+ /* client-side socket setting, ignored by server-side */
+ SSL_CTX_set_post_handshake_auth(self->ctx, pha);
+
+ /* server-side socket setting, ignored by client-side */
+ verify_cb = SSL_CTX_get_verify_callback(self->ctx);
+ if (pha) {
+ mode |= SSL_VERIFY_POST_HANDSHAKE;
+ } else {
+ mode ^= SSL_VERIFY_POST_HANDSHAKE;
+ }
+ SSL_CTX_set_verify(self->ctx, mode, verify_cb);
+
+ return 0;
+}
+#endif
+
+static PyObject *
get_protocol(PySSLContext *self, void *c) {
return PyLong_FromLong(self->protocol);
}
@@ -4462,6 +4539,13 @@ static PyGetSetDef context_getsetlist[] = {
(setter) set_sni_callback, PySSLContext_sni_callback_doc},
{"options", (getter) get_options,
(setter) set_options, NULL},
+ {"post_handshake_auth", (getter) get_post_handshake_auth,
+#ifdef TLS1_3_VERSION
+ (setter) set_post_handshake_auth,
+#else
+ NULL,
+#endif
+ NULL},
{"protocol", (getter) get_protocol,
NULL, NULL},
{"verify_flags", (getter) get_verify_flags,
diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h
index 5ba34eca59..186e6432c2 100644
--- a/Modules/clinic/_ssl.c.h
+++ b/Modules/clinic/_ssl.c.h
@@ -342,6 +342,24 @@ exit:
return return_value;
}
+PyDoc_STRVAR(_ssl__SSLSocket_verify_client_post_handshake__doc__,
+"verify_client_post_handshake($self, /)\n"
+"--\n"
+"\n"
+"Initiate TLS 1.3 post-handshake authentication");
+
+#define _SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF \
+ {"verify_client_post_handshake", (PyCFunction)_ssl__SSLSocket_verify_client_post_handshake, METH_NOARGS, _ssl__SSLSocket_verify_client_post_handshake__doc__},
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self);
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored))
+{
+ return _ssl__SSLSocket_verify_client_post_handshake_impl(self);
+}
+
static PyObject *
_ssl__SSLContext_impl(PyTypeObject *type, int proto_version);
@@ -1175,4 +1193,4 @@ exit:
#ifndef _SSL_ENUM_CRLS_METHODDEF
#define _SSL_ENUM_CRLS_METHODDEF
#endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
-/*[clinic end generated code: output=e2417fee28666f7c input=a9049054013a1b77]*/
+/*[clinic end generated code: output=c4e73b70ac3618ba input=a9049054013a1b77]*/
diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py
index c4ebe31779..759f5f4a3e 100755
--- a/Tools/ssl/multissltests.py
+++ b/Tools/ssl/multissltests.py
@@ -45,16 +45,16 @@ OPENSSL_OLD_VERSIONS = [
]
OPENSSL_RECENT_VERSIONS = [
- "1.0.2o",
- "1.1.0h",
- # "1.1.1-pre7",
+ "1.0.2p",
+ "1.1.0i",
+ "1.1.1",
]
LIBRESSL_OLD_VERSIONS = [
]
LIBRESSL_RECENT_VERSIONS = [
- "2.7.3",
+ "2.7.4",
]
# store files in ../multissl