gh-63284: Add support for TLS-PSK (pre-shared key) to the ssl module (#103181)

Add support for TLS-PSK (pre-shared key) to the ssl module.

---------

Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
Grant Ramsay 2023-11-27 17:01:44 +13:00 committed by GitHub
parent fb202af447
commit e954ac7205
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 561 additions and 1 deletions

View file

@ -2006,6 +2006,94 @@ to speed up repeated connections from the same clients.
>>> ssl.create_default_context().verify_mode # doctest: +SKIP
<VerifyMode.CERT_REQUIRED: 2>
.. method:: SSLContext.set_psk_client_callback(callback)
Enables TLS-PSK (pre-shared key) authentication on a client-side connection.
In general, certificate based authentication should be preferred over this method.
The parameter ``callback`` is a callable object with the signature:
``def callback(hint: str | None) -> tuple[str | None, bytes]``.
The ``hint`` parameter is an optional identity hint sent by the server.
The return value is a tuple in the form (client-identity, psk).
Client-identity is an optional string which may be used by the server to
select a corresponding PSK for the client. The string must be less than or
equal to ``256`` octets when UTF-8 encoded. PSK is a
:term:`bytes-like object` representing the pre-shared key. Return a zero
length PSK to reject the connection.
Setting ``callback`` to :const:`None` removes any existing callback.
.. note::
When using TLS 1.3:
- the ``hint`` parameter is always :const:`None`.
- client-identity must be a non-empty string.
Example usage::
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
context.maximum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('PSK')
# A simple lambda:
psk = bytes.fromhex('c0ffee')
context.set_psk_client_callback(lambda hint: (None, psk))
# A table using the hint from the server:
psk_table = { 'ServerId_1': bytes.fromhex('c0ffee'),
'ServerId_2': bytes.fromhex('facade')
}
def callback(hint):
return 'ClientId_1', psk_table.get(hint, b'')
context.set_psk_client_callback(callback)
.. versionadded:: 3.13
.. method:: SSLContext.set_psk_server_callback(callback, identity_hint=None)
Enables TLS-PSK (pre-shared key) authentication on a server-side connection.
In general, certificate based authentication should be preferred over this method.
The parameter ``callback`` is a callable object with the signature:
``def callback(identity: str | None) -> bytes``.
The ``identity`` parameter is an optional identity sent by the client which can
be used to select a corresponding PSK.
The return value is a :term:`bytes-like object` representing the pre-shared key.
Return a zero length PSK to reject the connection.
Setting ``callback`` to :const:`None` removes any existing callback.
The parameter ``identity_hint`` is an optional identity hint string sent to
the client. The string must be less than or equal to ``256`` octets when
UTF-8 encoded.
.. note::
When using TLS 1.3 the ``identity_hint`` parameter is not sent to the client.
Example usage::
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.maximum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('PSK')
# A simple lambda:
psk = bytes.fromhex('c0ffee')
context.set_psk_server_callback(lambda identity: psk)
# A table using the identity of the client:
psk_table = { 'ClientId_1': bytes.fromhex('c0ffee'),
'ClientId_2': bytes.fromhex('facade')
}
def callback(identity):
return psk_table.get(identity, b'')
context.set_psk_server_callback(callback, 'ServerId_1')
.. versionadded:: 3.13
.. index:: single: certificates
.. index:: single: X509 certificate