Changelog
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
2.1.1 - 2026-10-22
Changed
- The command line ends through
duho.run: Ctrl-C ends with status 130 and a closed standard output with status 1, both without a traceback.--help,--versionand a usage error still raiseSystemExit. sslcontext listandsslcontext probetake--format {text,json}besides--json. Their JSON is indented the same way; a non-ASCII character in it is now written as itself, not as a\uXXXXescape. The help text of--jsonnow reads "Same as --format json".- The
cliextra needsduho>=0.7.8,<0.8(was>=0.7.4).
2.1.0 - 2026-10-19
Added
- A PKCS#12 bundle (
.p12/.pfx) is accepted wherever a certificate is (certificate=,load_pem()), decrypted withpassword=; encrypted DER (PKCS#8) private keys are decrypted withpassword=as PEM ones are. - A password may be
bytes, or a file holding it (a path object, or anything withopen()orread(); its first line), read only when needed.
2.0.0 - 2026-10-19
Added
- The
sslcontextcommand (extracli):listandshowkeystore identities,probe URLto see a server's certificate request, the candidates and the certificate sent. KeychainBackend(sslcontext.backends, namekeychain): identities in the macOS Keychain and on smart cards, signed silently or, withKEYSTORE_PROMPT, after macOS's own dialog.system_sources()uses it on macOS.- On Python 3.9, where truststore is unavailable,
system_context()on macOS trusts the Keychain's anchors (system roots, and those an administrator or the user trusted) in addition to OpenSSL's default store. create_context()andsystem_context()takeca=,certificate=,key=,password=andidentity=. Every certificate, key, CA and bundle argument (includingload_pem()andload_pkcs12()) accepts PEM text, PEM or DER bytes, a path, an object withopen()orread(), acryptographycertificate or private key, or a list of them.- Apple's
/usr/bin/python3(LibreSSL 2.8) is supported: keystore identities sign through it over TLS 1.2, and client certificates are chosen when the server asks. system_context(): a client context that behaves like the system's browser: OS verification through truststore (a dependency on Python 3.10+) and client certificates chosen when the server asks by aClientCertificateSelectoroversystem_sources()(the Windows Personal store, the default PKCS#11 module elsewhere), filtered as a browser filters (validity, client-authentication usage, key type, the CAs the server names) and picked by remembered choice,AutoSelectRulerules, the Edge/Chrome/ChromiumAutoSelectCertificateForUrlspolicy (browser_policies()), achoosecallback or the only candidate.create_context()builds a verifyingssl.SSLContextfromverify/cafile/capath/cadata, TLS version bounds and ALPN.load_pem()andload_pkcs12()load a certificate, chain and key from memory, with no temporary files.Identity, theSignerprotocol andload_identity(): a certificate whose private key is used only through a signer, for every handshake signature (RSA PKCS#1 v1.5 and PSS, ECDSA; TLS 1.2 and 1.3). OpenSSL 1.1.1 and 3.x.sslcontext.testing.SoftwareSignerandsoftware_identity().sslcontext.issuing:CertificateAuthority(create, or load from PEM; optional X.509 name constraints; encrypted key export) issuing server certificates (IssuedCertificate) that pass strict verification, made with the interpreter's own OpenSSL.Identity.info(CertificateInfo: subject, issuer, serial, validity, SHA-1/SHA-256 thumbprints, key type and size).sslcontext.backends: theBackendcontract with thumbprint, subject, issuer, label and validity queries, a registry (names(),get(),register_backend(), entry-point groupsslcontext.backends), andCNGBackendfor Windows certificate stores: non-exportable, TPM and smart-card keys through CNG, and legacy CryptoAPI CSP keys (PKCS#1 v1.5, TLS 1.2).- PIN and password sources:
pin=on every backend takes a PIN,KEYSTORE_PROMPT, or a callback receiving aPinRequest(backend, token, certificate, purpose); with no PIN, an operation needing one fails at once instead of showing a dialog or waiting on a PIN pad.load_pem(),load_pkcs12()andSoftwareSigneraccept a password callable, called only for an encrypted key. PKCS11Backendfor PKCS#11 tokens: smart cards (real and virtual, through OpenSC), HSMs, TPMs and software tokens. RSA PKCS#1 v1.5 and PSS and ECDSA, PINs from the PIN source (see below), per-signature login forCKA_ALWAYS_AUTHENTICATEkeys, and recovery after the card is removed and reinserted.SSLCONTEXT_PKCS11_MODULEselects the default module.
Changed
- Rewritten from scratch.
sslcontextnow loads certificates and keystore-held private keys into the standard library'sssl.SSLContext; nothing of the 1.x API (SSLContext/SSLSocketinterfaces,PyOpenSSLContext,SSLContextProvider) remains. The 1.x companionssslcontext-factory,openssl-engineandopenssl-engine-capiare superseded: OpenSSL 4 removed the ENGINE API they were built on.