sslcontext
Client certificates whose private keys never leave the OS keystore, in a
plain ssl.SSLContext. sslcontext signs TLS handshakes through Windows
CNG, the macOS Keychain or a PKCS#11 token (smart cards included), so every
library that accepts an ssl_context gets mutual TLS with no patching, no
temporary key files and no compiled extension; system_context() also picks the certificate as the
browser would. Documentation: https://jose-pr.github.io/sslcontext/.
Features
- Keystore identities in stdlib
ssl— non-exportable and smart-card keys work, because the key is used through the keystore, never copied. - Pure Python — ctypes over the OpenSSL that Python itself loaded: an OpenSSL 3 provider on modern builds, an OpenSSL 1.1 engine on older ones.
- In-memory credentials — load PEM or PKCS#12 bytes into a context without writing a key to disk.
- Never blocks on a PIN — PINs and passwords come from a value or a callback you write; with none, operations fail at once. Keystore dialogs and PIN pads are opt-in.
- The system's context —
system_context(): the OS verifies servers (truststore) and, when a server asks, the client certificate is chosen as the browser would: from the system's keystores, matching the CAs the server names, following Edge's and Chrome'sAutoSelectCertificateForUrlspolicy, your rules or your callback, and never blocking. - One context builder —
create_context()for the verify/cafile/capath combinations every HTTP client reimplements.
Keystores
| Backend | Platform | Keys | Extra |
|---|---|---|---|
cng |
Windows | certificate stores: software (incl. non-exportable), TPM, smart cards and virtual smart cards, legacy CryptoAPI CSPs | none |
pkcs11 |
any | PKCS#11 tokens: smart cards (real or virtual) via OpenSC, HSMs, TPMs, SoftHSM | none |
Installation
pip install sslcontext
Quick start
Behave like the system's browser: the OS verifies the server, and when a server asks for a client certificate the matching one is chosen from the system's keystores. Build it once and share it:
import urllib.request
import sslcontext
ctx = sslcontext.system_context()
urllib.request.urlopen("https://intranet.example.com/", context=ctx)
A client certificate and key, from files, PEM text, bytes, pathlib
paths or cryptography objects alike:
import sslcontext
ctx = sslcontext.create_context(ca="ca.pem", certificate="client.pem", key=key_pem)
Use a certificate from the Windows store whose key cannot be exported:
import urllib.request
import sslcontext
from sslcontext.backends import CNGBackend
ctx = sslcontext.create_context()
sslcontext.load_identity(ctx, CNGBackend().find_identity(subject="alice"))
urllib.request.urlopen("https://mtls.example.com/", context=ctx)
Use a smart card through its PKCS#11 module. The PIN callback decides how the PIN is obtained; with no PIN, signing fails instead of waiting:
from getpass import getpass
from sslcontext.backends import PKCS11Backend
def pin(request: sslcontext.PinRequest):
if request.purpose == "list":
return None # list without logging in
return getpass(f"PIN for {request.token}: ")
card = PKCS11Backend(pin=pin)
sslcontext.load_identity(ctx, card.find_identity(subject="alice"))
API overview
| Module | Purpose |
|---|---|
sslcontext |
context builders (system_context, create_context), identity loading, client certificate selection, the Signer contract |
sslcontext.backends |
keystore backends and their registry |
sslcontext.issuing |
a local certificate authority issuing server certificates |
sslcontext.testing |
SoftwareSigner, an in-memory signer for tests |
sslcontext.exceptions |
the package's errors |
Command line
pip install "sslcontext[cli]" adds sslcontext: sslcontext list shows the
client certificates the system's keystores hold, and sslcontext probe https://intranet.example/ shows what a server asks for and which
certificate answers it.
Development
dotagents pyvenv && dotagents pyvenv 3.9
.pyvenv/<tag>/Scripts/python -m pip install -e ".[dev]"
.pyvenv/<tag>/Scripts/python -m pytest -q -rs
Releasing
This project follows Semantic Versioning and keeps a
CHANGELOG.md.
Pushing a tag matching v* triggers the release workflow: test gate → build
(checking the tag names the version built) → a strict docs build as a gate →
GitHub release → publish. The release workflow never deploys the docs site
itself: for a final release its last job dispatches the docs workflow at the
tag, which owns every Pages deploy.
License
MIT — see LICENSE.
Metadata
Release files for sslcontext 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sslcontext-2.1.0.tar.gz | 113.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sslcontext-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 216.2 kB
Release files / sslcontext-2.1.0.tar.gz
| Download URL | sslcontext-2.1.0.tar.gz |
|---|---|
| Size | 113.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dca3bf4be4201c2f0ed32f804df5b04e73bc97f332be1c86b385050985caf6d5
|
|
BLAKE2b-256 checksum How to use checksums |
62101e13c1a0c653590007d5912e4a32db16065eeb232a4b9a9dd532680582f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sslcontext-2.1.0-py3-none-any.whl
| Download URL | sslcontext-2.1.0-py3-none-any.whl |
|---|---|
| Size | 103.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cf48d90f1dd59064c05748f963d9f4c05d41ec19342171df0df9c53ee3d3de1d
|
|
BLAKE2b-256 checksum How to use checksums |
a8a00ffd45f239028c1c1d985faf55052ccb3f50c8cc46668ff6732e4d73fbe4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logSecurity for sslcontext 2.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for sslcontext-2.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.