Skip to main content

TLS-PSK socket wrapper for Python 3.10+ — no compiled extensions required

Project description

openssl-psk

TLS-PSK (pre-shared key) socket wrapper for Python 3.10+.
No compiled extensions — pure Python using the standard ssl module and ctypes.

pip install openssl-psk

Why this exists

The standard ssl module has no PSK support below Python 3.13, and the only existing library (sslpsk) is broken on Python 3.12+ because its wrap_socket() creates a default context with check_hostname=True, which raises ValueError for server-side sockets.

openssl-psk fixes this by:

  • Calling libssl's SSL_CTX_set_psk_*_callback directly via ctypes on Python 3.10–3.12
  • Using the native SSLContext.set_psk_*_callback() API transparently on Python 3.13+

No C extension to compile. Just pip install.


Quick start

Client

import socket
from openssl_psk import wrap_socket_client

tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.connect(("192.168.1.1", 4116))

# simplest form — just the key
ssl_sock = wrap_socket_client(tcp, psk=b"84155C93FDB08FB384B75C44A7D3B625")

ssl_sock.sendall(b"GET /resource HTTP/1.1\r\nHost: 192.168.1.1\r\n\r\n")
print(ssl_sock.recv(4096))
ssl_sock.close()

Server

import socket
from openssl_psk import wrap_socket_server

PSK_DB = {
    b"device-001": b"84155C93FDB08FB384B75C44A7D3B625",
    b"device-002": b"0AE9DF505E3D3B9A5305409550D42C96",
}

tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp.bind(("0.0.0.0", 4116))
tcp.listen(5)

while True:
    conn, addr = tcp.accept()
    ssl_sock = wrap_socket_server(
        conn,
        psk=lambda identity: PSK_DB[identity],
        hint="my-server",                   # optional identity hint sent to clients
    )
    data = ssl_sock.recv(4096)
    ssl_sock.sendall(b"HTTP/1.1 200 OK\r\n\r\n")
    ssl_sock.close()

API

wrap_socket_client(sock, psk, ciphers=..., server_hostname=None)

Parameter Type Description
sock socket.socket Connected TCP socket to wrap
psk bytes | tuple | callable Pre-shared key — see accepted shapes below
ciphers str OpenSSL cipher string (default: PSK-AES128-CBC-SHA256)
server_hostname str | None SNI hostname passed to wrap_socket

Accepted psk shapes:

# 1. Just the key — identity sent to server is b''
wrap_socket_client(sock, psk=b"mypsk")

# 2. Key + client identity
wrap_socket_client(sock, psk=(b"mypsk", b"myidentity"))

# 3. Callable: server hint → key
PSK_FOR = {b"server1": b"abcdef", b"server2": b"123456"}
wrap_socket_client(sock, psk=lambda hint: PSK_FOR[hint])

Returns an ssl.SSLSocket after completing the handshake.


wrap_socket_server(sock, psk, hint=None, ciphers=...)

Parameter Type Description
sock socket.socket Accepted TCP socket to wrap (from socket.accept())
psk bytes | callable Pre-shared key — see accepted shapes below
hint str | None PSK identity hint sent to clients (optional)
ciphers str OpenSSL cipher string (default: PSK-AES128-CBC-SHA256)

Accepted psk shapes:

# 1. Just the key — same key accepted for every client identity
wrap_socket_server(sock, psk=b"mypsk")

# 2. Callable: client identity → key (raise to reject)
PSK_FOR = {b"clientA": b"abcdef", b"clientB": b"123456"}
wrap_socket_server(sock, psk=lambda identity: PSK_FOR[identity])

Returns an ssl.SSLSocket after completing the handshake.
When using a callable, raise any exception to reject the client.


Compatibility

Python Mechanism CPython only?
3.10 ctypes → libssl Yes
3.11 ctypes → libssl Yes
3.12 ctypes → libssl Yes
3.13+ ssl.SSLContext.set_psk_*_callback() No

The ctypes path reads the SSL_CTX* pointer out of CPython's PySSLContext struct at a fixed offset that has been stable across CPython 3.x. It will raise a RuntimeError with a clear message if the pointer is NULL, so you will know immediately if anything changes in a future CPython release.

Requires OpenSSL ≥ 1.0.1 (for PSK cipher support).


Running the tests

pip install pytest
pytest

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openssl_psk-0.1.0.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openssl_psk-0.1.0-py3-none-any.whl (7.5 kB view details)

Uploaded Python 3

File details

Details for the file openssl_psk-0.1.0.tar.gz.

File metadata

  • Download URL: openssl_psk-0.1.0.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openssl_psk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 13f60354defd7fc78fd2f04a38f096eddc449db266336fbb8c2baa16aac27a2f
MD5 a729d647fa0acdd8c4d7e702775c340e
BLAKE2b-256 18e913bf02546e6ac08ed63c478c21ac820a6ed9771e209d3548752ccad1eb68

See more details on using hashes here.

Provenance

The following attestation bundles were made for openssl_psk-0.1.0.tar.gz:

Publisher: publish.yml on angeguillaumekoffi/openssl-psk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openssl_psk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: openssl_psk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openssl_psk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 35dcbe783c04370430b0aa3edd909216de4a7cfdabd2dac0db614e8489f178f4
MD5 62dc9890740ac4559c910f5b603b14bd
BLAKE2b-256 086a329d92c32e030ca9e60384a3a7e59e6f4b201d91a0ff3516c06cde64d5e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for openssl_psk-0.1.0-py3-none-any.whl:

Publisher: publish.yml on angeguillaumekoffi/openssl-psk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page