Skip to content

Commit cfddf7b

Browse files
committed
Fix TLS-PSK for TLS 1.3
SSL_CTX_set_session_id_context() is a server-side only operation. Using this on the client-side is causing authentication errors
1 parent 9d0f6dc commit cfddf7b

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

Doc/library/ssl.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,12 @@ to speed up repeated connections from the same clients.
20032003

20042004
Setting ``callback`` to :const:`None` removes any existing callback.
20052005

2006+
.. note::
2007+
When using TLS 1.3:
2008+
2009+
- the ``hint`` parameter is always :const:`None`.
2010+
- client-identity must be a non-empty string.
2011+
20062012
Example usage::
20072013

20082014
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
@@ -2041,6 +2047,9 @@ to speed up repeated connections from the same clients.
20412047

20422048
The parameter ``identity_hint`` is an optional identity hint sent to the client.
20432049

2050+
.. note::
2051+
When using TLS 1.3 the ``identity_hint`` parameter is not sent to the client.
2052+
20442053
Example usage::
20452054

20462055
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)

Lib/test/test_ssl.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4259,6 +4259,38 @@ def server_callback(identity):
42594259
with self.assertRaisesRegex(ssl.SSLError, 'Cannot add PSK client callback'):
42604260
server_context.set_psk_client_callback(client_callback)
42614261

4262+
@requires_tls_version('TLSv1_3')
4263+
def test_psk_tls1_3(self):
4264+
psk = bytes.fromhex('deadbeef')
4265+
identity_hint = 'identity-hint'
4266+
client_identity = 'client-identity'
4267+
4268+
def client_callback(hint):
4269+
# identity_hint is not sent to the client in TLS 1.3
4270+
self.assertIsNone(hint)
4271+
return client_identity, psk
4272+
4273+
def server_callback(identity):
4274+
self.assertEqual(identity, client_identity)
4275+
return psk
4276+
4277+
client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4278+
client_context.check_hostname = False
4279+
client_context.verify_mode = ssl.CERT_NONE
4280+
client_context.minimum_version = ssl.TLSVersion.TLSv1_3
4281+
client_context.set_ciphers('PSK')
4282+
client_context.set_psk_client_callback(client_callback)
4283+
4284+
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4285+
server_context.minimum_version = ssl.TLSVersion.TLSv1_3
4286+
server_context.set_ciphers('PSK')
4287+
server_context.set_psk_server_callback(server_callback, identity_hint)
4288+
4289+
server = ThreadedEchoServer(context=server_context)
4290+
with server:
4291+
with client_context.wrap_socket(socket.socket()) as s:
4292+
s.connect((HOST, server.port))
4293+
42624294

42634295
@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
42644296
class TestPostHandshakeAuth(unittest.TestCase):

Modules/_ssl.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,10 +3171,14 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
31713171
usage for no cost at all. */
31723172
SSL_CTX_set_mode(self->ctx, SSL_MODE_RELEASE_BUFFERS);
31733173

3174+
/* Setting the session id context is a server-side only operation.
3175+
* It can cause unexpected behaviour on client-side connections. */
3176+
if (proto_version == PY_SSL_VERSION_TLS_SERVER) {
31743177
#define SID_CTX "Python"
3175-
SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX,
3176-
sizeof(SID_CTX));
3178+
SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX,
3179+
sizeof(SID_CTX));
31773180
#undef SID_CTX
3181+
}
31783182

31793183
params = SSL_CTX_get0_param(self->ctx);
31803184
/* Improve trust chain building when cross-signed intermediate

0 commit comments

Comments
 (0)