bpo-34670: Add TLS 1.3 post handshake auth (GH-9460)
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
This commit is contained in:
parent
4b860fd777
commit
9fb051f032
|
@ -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
|
||||
|
|
|
@ -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.8
|
||||
|
||||
.. 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.8
|
||||
|
||||
.. 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
|
||||
|
|
|
@ -140,6 +140,14 @@ pathlib
|
|||
contain characters unrepresentable at the OS level.
|
||||
(Contributed by Serhiy Storchaka in :issue:`33721`.)
|
||||
|
||||
ssl
|
||||
---
|
||||
|
||||
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`.)
|
||||
|
||||
venv
|
||||
----
|
||||
|
||||
|
@ -147,7 +155,6 @@ venv
|
|||
activating virtual environments under PowerShell Core 6.1.
|
||||
(Contributed by Brett Cannon in :issue:`32718`.)
|
||||
|
||||
|
||||
Optimizations
|
||||
=============
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -218,7 +218,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
|
||||
|
||||
|
@ -2262,6 +2262,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):
|
||||
|
@ -4148,6 +4165,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
|
||||
|
@ -4183,6 +4373,7 @@ def test_main(verbose=False):
|
|||
tests = [
|
||||
ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
|
||||
SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
|
||||
TestPostHandshakeAuth
|
||||
]
|
||||
|
||||
if support.is_resource_enabled('network'):
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Add SSLContext.post_handshake_auth and
|
||||
SSLSocket.verify_client_post_handshake for TLS 1.3's post
|
||||
handshake authentication feature.
|
100
Modules/_ssl.c
100
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 {
|
||||
|
@ -2643,6 +2646,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*
|
||||
|
@ -2819,6 +2846,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}
|
||||
};
|
||||
|
||||
|
@ -2862,7 +2890,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;
|
||||
|
@ -2882,9 +2910,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;
|
||||
}
|
||||
|
||||
|
@ -2966,13 +2998,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;
|
||||
}
|
||||
|
@ -3065,6 +3097,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;
|
||||
}
|
||||
|
||||
|
@ -3319,7 +3356,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:
|
||||
|
@ -3344,7 +3384,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 *
|
||||
|
@ -3550,7 +3590,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;
|
||||
}
|
||||
}
|
||||
|
@ -3558,6 +3598,43 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -4461,6 +4538,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,
|
||||
|
|
|
@ -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]*/
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue