A thin Python wrapper over OpenSSL that exposes TLS connection handling and X.509 certificate operations for tasks the high-level cryptography recipes don't cover.
pyOpenSSL bridges Python to the OpenSSL library, giving direct access to SSL/TLS contexts, handshakes, and certificate/key objects. It is useful for grabbing and inspecting certificates straight off a live TLS service, generating self-signed certs for lab servers, and probing protocol/cipher behaviour. Much of the low-level crypto has migrated to cryptography, but pyOpenSSL remains the practical choice for live-connection certificate retrieval.
pip install pyOpenSSLimport socket
from OpenSSL import SSL
context = SSL.Context(SSL.TLS_METHOD)
connection = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
try:
connection.connect(("127.0.0.1", 443))
connection.set_tlsext_host_name(b"localhost") # SNI
connection.do_handshake()
cert = connection.get_peer_certificate()
print("subject:", dict(cert.get_subject().get_components()))
print("expired:", cert.has_expired())
finally:
connection.close()Note
For most work the standard library's [[SSL-Module|ssl]] module or cryptography is the better choice. pyOpenSSL is for cases needing direct OpenSSL access.
| API | Purpose |
|---|---|
SSL.Context(method) |
TLS context; set verification and ciphers |
SSL.Connection(context, socket) |
Wrap a socket |
connection.do_handshake() |
Perform the TLS handshake |
connection.set_tlsext_host_name(bytes) |
Set SNI — required for virtual hosts |
connection.get_peer_certificate() |
The server's certificate |
connection.get_peer_cert_chain() |
The full presented chain |
cert.get_subject() / get_issuer() |
Distinguished names |
cert.has_expired() |
Validity check against now |
cert.get_notAfter() |
Expiry as YYYYMMDDHHMMSSZ bytes |
cert.digest("sha256") |
Certificate fingerprint |
crypto.dump_certificate(FILETYPE_PEM, cert) |
Serialise to PEM |
context.set_verify(mode, callback) |
Configure peer verification |
Retrieve and inspect a certificate from a live TLS service (authorized target):
import socket
from OpenSSL import SSL
ctx = SSL.Context(SSL.TLS_CLIENT_METHOD)
conn = SSL.Connection(ctx, socket.socket())
conn.set_tlsext_host_name(b"example.com") # SNI
conn.connect(("example.com", 443))
conn.do_handshake()
cert = conn.get_peer_certificate()
print("subject:", cert.get_subject().CN)
print("issuer :", cert.get_issuer().CN)
print("expires:", cert.get_notAfter().decode())
conn.close()subject: example.com
issuer : DigiCert Global G2 TLS RSA SHA256 2020 CA1
expires: 20261101000000Z
Generate a self-signed certificate for a lab server:
from OpenSSL import crypto
key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
cert.get_subject().CN = "lab.local"
cert.set_serial_number(1000)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(365 * 24 * 3600)
cert.set_issuer(cert.get_subject()) # self-signed
cert.set_pubkey(key)
cert.sign(key, "sha256")
print(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode()[:64], "...")-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgI...
Check certificate expiry and flag near-expiry certs:
from datetime import datetime, timezone
from OpenSSL import crypto
with open("server.crt", "rb") as fh:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, fh.read())
not_after = datetime.strptime(cert.get_notAfter().decode(), "%Y%m%d%H%M%SZ")
not_after = not_after.replace(tzinfo=timezone.utc)
days_left = (not_after - datetime.now(timezone.utc)).days
print(f"days until expiry: {days_left}")
print("EXPIRED!" if cert.has_expired() else "valid")days until expiry: 102
valid
- Certificate harvesting — pull certs directly off live HTTPS/SMTPS services to enumerate SANs and discover related hostnames.
- TLS posture review — inspect issuer, key size, signature algorithm, and validity during an infrastructure assessment.
- Lab cert generation — mint self-signed certs for test servers, MITM proxies, and interception labs you control.
- Expiry monitoring — automate alerts for certificates nearing expiry across an estate.
- SNI / vhost probing — set the SNI name to reveal per-host certificates behind shared IPs.
- Forgetting SNI. Without
set_tlsext_host_name()a virtual host returns the wrong certificate, and your audit reports the wrong result. - Not calling
do_handshake()explicitly, so certificate methods returnNone. - Assuming
has_expired()validates the certificate — it checks dates only, not the chain, hostname, or revocation. - Misparsing
get_notAfter()— it returns bytes inYYYYMMDDHHMMSSZform, not a datetime. - Leaving verification disabled because it made the handshake succeed.
- Reaching for pyOpenSSL when
sslorcryptographywould do — it is a lower-level, more error-prone API. - Confusing the packages —
pyOpenSSLis the pip name,OpenSSLthe import name.
[!warning] Authorized use only Connect only to hosts you own or are authorized to test.
- Parsing a certificate is not validating it. A full check requires chain building to a trusted root, hostname matching, validity dates, and revocation status.
has_expired()covers one of those. - Disabling verification defeats TLS entirely. If a handshake fails, fix the trust store — do not turn verification off.
- Certificates leak infrastructure detail. SANs frequently enumerate internal hostnames, which is useful reconnaissance and should be treated as sensitive.
- Keep the library and OpenSSL current. TLS libraries are a high-value target and ship security fixes regularly.
- Prefer the maintained alternatives. The standard library's [[SSL-Module|
ssl]] module handles most auditing needs, andcryptographycovers X.509 parsing with a safer API. - Never use production private keys in course exercises; generate throwaway keys for the lab.
- Prefer the
cryptographylibrary for new pure-crypto code; reach for pyOpenSSL when you need live TLS connections or OpenSSL objects. - Set the SNI host name (
set_tlsext_host_name) or you may receive a default/wrong certificate. - Generate at least 2048-bit RSA (or ECDSA) keys and sign with SHA-256 or better.
- Keep private keys for lab certs out of version control.
- Handle handshake exceptions to distinguish protocol/cipher failures from network errors.
- [[Cryptography]] — the modern library pyOpenSSL increasingly defers to
- [[requests]] — the client whose TLS endpoints you inspect here
- [[Readme|Python for Security Professionals]] — course home