Claude Code for ssl: Python TLS/SSL Secure Connections — Claude Skills 360 Blog
Blog / AI / Claude Code for ssl: Python TLS/SSL Secure Connections
AI

Claude Code for ssl: Python TLS/SSL Secure Connections

Published: September 3, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s ssl module wraps sockets with TLS/SSL encryption and certificate verification. import ssl. create_default_context: ctx = ssl.create_default_context() — client context that verifies server certificates against system CAs; ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) — for servers. wrap_socket: ctx.wrap_socket(sock, server_hostname="example.com") → SSLSocket. SSLContext: ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) — sets check_hostname=True and verify_mode=CERT_REQUIRED; ssl.PROTOCOL_TLS_SERVER for servers; ctx.load_cert_chain("cert.pem", "key.pem") — load server cert. Custom CA: ctx.load_verify_locations("ca.pem"). Disable verification (testing only): ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE. Protocol options: ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 — require TLS 1.2+. getpeercert: ssl_sock.getpeercert() → dict with subject, issuer, notAfter, subjectAltName. Cipher info: ssl_sock.cipher() → (name, protocol, bits); ssl_sock.version() → “TLSv1.3”. Cert loading: ssl.PEM_cert_to_DER_cert(pem), ssl.DER_cert_to_PEM_cert(der). get_server_certificate: ssl.get_server_certificate((host, port)) → PEM string. Session reuse: ctx.session_tickets = True. ALPN: ctx.set_alpn_protocols(["http/1.1"]). Claude Code generates mutual-TLS clients, certificate expiry checkers, self-signed test setups, and HTTPS proxy tools.

CLAUDE.md for ssl

## ssl Stack
- Stdlib: import ssl
- Client: ctx = ssl.create_default_context()
-          with ctx.wrap_socket(sock, server_hostname=host) as ssock: ...
- Server: ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-          ctx.load_cert_chain("cert.pem", "key.pem")
- mTLS:   ctx.verify_mode = ssl.CERT_REQUIRED; ctx.load_verify_locations("ca.pem")
- Check:  ssl.get_server_certificate((host, 443))

ssl Secure Connection Pipeline

# app/sslutil.py — TLS client, cert inspect, expiry check, mTLS, test setup
from __future__ import annotations

import datetime
import socket
import ssl
import struct
import time
from contextlib import contextmanager
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Generator


# ─────────────────────────────────────────────────────────────────────────────
# 1. Client context helpers
# ─────────────────────────────────────────────────────────────────────────────

def default_client_ctx(
    cafile: str | None = None,
    min_tls: str = "TLSv1.2",
) -> ssl.SSLContext:
    """
    Create a secure client SSL context verifying server certs against system CAs.
    Pass cafile to verify against a custom CA bundle instead.

    Example:
        ctx = default_client_ctx()
        with ctx.wrap_socket(sock, server_hostname="api.example.com") as ssock:
            ssock.sendall(b"...")
    """
    ctx = ssl.create_default_context(cafile=cafile)
    ctx.minimum_version = {
        "TLSv1.2": ssl.TLSVersion.TLSv1_2,
        "TLSv1.3": ssl.TLSVersion.TLSv1_3,
    }.get(min_tls, ssl.TLSVersion.TLSv1_2)
    return ctx


def insecure_client_ctx() -> ssl.SSLContext:
    """
    Create an SSL context that disables certificate verification.
    FOR TESTING / INTERNAL NETWORKS ONLY — never use in production.

    Example:
        ctx = insecure_client_ctx()
        with ctx.wrap_socket(sock, server_hostname="localhost") as ssock: ...
    """
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    return ctx


def mtls_client_ctx(
    client_cert: str,
    client_key: str,
    cafile: str | None = None,
) -> ssl.SSLContext:
    """
    Create a mutual-TLS client context that presents a certificate to the server.

    Example:
        ctx = mtls_client_ctx("client.pem", "client.key", cafile="ca.pem")
    """
    ctx = default_client_ctx(cafile=cafile)
    ctx.load_cert_chain(certfile=client_cert, keyfile=client_key)
    return ctx


# ─────────────────────────────────────────────────────────────────────────────
# 2. Server context helpers
# ─────────────────────────────────────────────────────────────────────────────

def server_ctx(
    certfile: str,
    keyfile: str,
    cafile: str | None = None,
    require_client_cert: bool = False,
) -> ssl.SSLContext:
    """
    Create an SSL server context from a certificate and key.
    Pass cafile + require_client_cert=True for mutual TLS.

    Example:
        ctx = server_ctx("server.pem", "server.key")
        ssl_sock = ctx.wrap_socket(plain_sock, server_side=True)
    """
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
    ctx.minimum_version = ssl.TLSVersion.TLSv1_2
    ctx.options |= ssl.OP_NO_COMPRESSION
    if cafile or require_client_cert:
        ctx.load_verify_locations(cafile)
        ctx.verify_mode = ssl.CERT_REQUIRED if require_client_cert else ssl.CERT_OPTIONAL
    return ctx


# ─────────────────────────────────────────────────────────────────────────────
# 3. Certificate inspection
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class CertInfo:
    subject:    dict[str, str]
    issuer:     dict[str, str]
    san:        list[str]       # subjectAltName values
    not_before: datetime.datetime
    not_after:  datetime.datetime
    serial:     str
    version:    int

    @property
    def days_until_expiry(self) -> int:
        return (self.not_after.replace(tzinfo=None) - datetime.datetime.utcnow()).days

    @property
    def is_expired(self) -> bool:
        return self.days_until_expiry < 0

    def __str__(self) -> str:
        subj = ", ".join(f"{k}={v}" for k, v in self.subject.items())
        return (
            f"Subject: {subj}\n"
            f"SAN: {self.san}\n"
            f"Valid: {self.not_before.date()}{self.not_after.date()} "
            f"({self.days_until_expiry} days remaining)"
        )


def _parse_cert_dict(raw: dict) -> CertInfo:
    """Parse the dict from SSLSocket.getpeercert() into CertInfo."""
    def dn_to_dict(tuples: tuple) -> dict[str, str]:
        return {k: v for rdn in tuples for k, v in rdn}

    def parse_time(s: str) -> datetime.datetime:
        # format: "Jan  1 00:00:00 2025 GMT"
        return datetime.datetime.strptime(s.strip(), "%b %d %H:%M:%S %Y %Z")

    san = [v for _, v in raw.get("subjectAltName", [])]
    return CertInfo(
        subject=dn_to_dict(raw.get("subject", ())),
        issuer=dn_to_dict(raw.get("issuer", ())),
        san=san,
        not_before=parse_time(raw["notBefore"]),
        not_after=parse_time(raw["notAfter"]),
        serial=str(raw.get("serialNumber", "")),
        version=raw.get("version", 0),
    )


def inspect_live_cert(host: str, port: int = 443, timeout: float = 5.0) -> CertInfo:
    """
    Connect to host:port and return the server's certificate as CertInfo.

    Example:
        info = inspect_live_cert("python.org")
        print(info)
    """
    ctx = default_client_ctx()
    with socket.create_connection((host, port), timeout=timeout) as sock:
        with ctx.wrap_socket(sock, server_hostname=host) as ssock:
            raw = ssock.getpeercert()
    return _parse_cert_dict(raw)


def get_server_pem(host: str, port: int = 443, timeout: float = 5.0) -> str:
    """
    Fetch the server's PEM certificate string without verification.

    Example:
        pem = get_server_pem("example.com")
        Path("server.pem").write_text(pem)
    """
    return ssl.get_server_certificate((host, port), timeout=timeout)


def load_pem_cert_info(pem: str) -> dict[str, Any]:
    """
    Parse a PEM certificate (DER-decoded) and return raw openssl-style dict.
    Requires tempfile loading through SSLContext — uses a one-shot approach.

    Example:
        pem = Path("cert.pem").read_text()
        info = load_pem_cert_info(pem)
    """
    import tempfile
    with tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False) as tf:
        tf.write(pem)
        tf_path = tf.name
    try:
        ctx = ssl.SSLContext()
        ctx.load_verify_locations(tf_path)
        # Access via DER round-trip
        der = ssl.PEM_cert_to_DER_cert(pem)
        return {"der_length": len(der), "pem_length": len(pem)}
    finally:
        Path(tf_path).unlink(missing_ok=True)


# ─────────────────────────────────────────────────────────────────────────────
# 4. Expiry monitoring
# ─────────────────────────────────────────────────────────────────────────────

def check_cert_expiry(host: str, port: int = 443, timeout: float = 5.0) -> tuple[bool, int]:
    """
    Return (expired, days_remaining) for the server certificate.

    Example:
        expired, days = check_cert_expiry("api.example.com")
        if days < 30:
            alert("cert expires soon!")
    """
    try:
        info = inspect_live_cert(host, port, timeout=timeout)
        return info.is_expired, info.days_until_expiry
    except Exception:
        return True, -1  # treat connection failure as expired


def check_certs_bulk(endpoints: list[tuple[str, int]], warn_days: int = 30) -> list[dict]:
    """
    Check certificate expiry for multiple endpoints; return status dicts.

    Example:
        report = check_certs_bulk([("api.example.com", 443), ("cdn.example.com", 443)])
        for r in report:
            print(f"{r['host']}:{r['port']} — {r['days']} days")
    """
    from concurrent.futures import ThreadPoolExecutor, as_completed

    def _check(h: str, p: int) -> dict:
        expired, days = check_cert_expiry(h, p)
        return {
            "host": h, "port": p, "days": days,
            "expired": expired, "warning": days < warn_days and not expired,
        }

    with ThreadPoolExecutor(max_workers=len(endpoints)) as ex:
        futures = {ex.submit(_check, h, p): (h, p) for h, p in endpoints}
        return [fut.result() for fut in as_completed(futures)]


# ─────────────────────────────────────────────────────────────────────────────
# 5. TLS connection details
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class TLSHandshakeInfo:
    host:     str
    port:     int
    protocol: str   # e.g. "TLSv1.3"
    cipher:   str   # cipher suite name
    bits:     int   # key bits
    alpn:     str | None  # negotiated ALPN protocol

    def __str__(self) -> str:
        alpn_str = f" ALPN={self.alpn}" if self.alpn else ""
        return f"{self.host}:{self.port} {self.protocol} {self.cipher} ({self.bits}-bit){alpn_str}"


def tls_handshake_info(host: str, port: int = 443, timeout: float = 5.0) -> TLSHandshakeInfo:
    """
    Connect and return TLS handshake details without transferring application data.

    Example:
        info = tls_handshake_info("python.org")
        print(info)
    """
    ctx = default_client_ctx()
    ctx.set_alpn_protocols(["http/1.1", "h2"])
    with socket.create_connection((host, port), timeout=timeout) as sock:
        with ctx.wrap_socket(sock, server_hostname=host) as ssock:
            cipher_name, protocol, bits = ssock.cipher()
            alpn = ssock.selected_alpn_protocol()
            version = ssock.version() or protocol
    return TLSHandshakeInfo(
        host=host, port=port, protocol=version,
        cipher=cipher_name, bits=bits or 0, alpn=alpn,
    )


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== ssl demo ===")

    # All demos use public internet hosts — skip gracefully if offline
    test_hosts = [("python.org", 443)]

    for host, port in test_hosts:
        print(f"\n--- {host}:{port} ---")
        try:
            info = tls_handshake_info(host, port, timeout=5.0)
            print(f"  TLS info:  {info}")

            cert = inspect_live_cert(host, port, timeout=5.0)
            print(f"  Cert CN:   {cert.subject.get('commonName', cert.subject)}")
            print(f"  SAN:       {cert.san[:3]}")
            print(f"  Expires:   {cert.not_after.date()} ({cert.days_until_expiry} days)")
            print(f"  Expired:   {cert.is_expired}")

        except OSError as e:
            print(f"  Network error: {e} (offline?)")

    print("\n--- default_client_ctx ---")
    ctx = default_client_ctx()
    print(f"  min_version: {ctx.minimum_version}")
    print(f"  verify_mode: {ctx.verify_mode}")
    print(f"  check_hostname: {ctx.check_hostname}")

    print("\n--- insecure_client_ctx (testing only) ---")
    ctx_insecure = insecure_client_ctx()
    print(f"  verify_mode: {ctx_insecure.verify_mode}")
    print(f"  check_hostname: {ctx_insecure.check_hostname}")

    print("\n=== done ===")

For the requests / httpx alternative — requests and httpx (both PyPI) handle TLS automatically through their Session objects; requests uses certifi for its CA bundle; they also manage HTTP parsing, cookies, redirects, and connection pooling — use requests or httpx for all HTTPS API communication; use ssl directly when you need custom TLS configuration (mutual TLS, custom CA pinning, non-HTTP protocols like SMTP over TLS, FTPS, or raw TLS socket servers). For the cryptography / pyOpenSSL alternative — cryptography (PyPI) provides full access to X.509 certificate creation, parsing, signing, PKCS, and PEM/DER conversion without the overhead of a C OpenSSL binding; pyOpenSSL wraps libssl directly; both offer more certificate introspection than stdlib ssl.SSLSocket.getpeercert() — use cryptography when you need to parse certificate extensions, generate self-signed certificates programmatically, or implement a PKI tool; use ssl for application-layer TLS configuration where you just need to secure an existing socket connection. The Claude Skills 360 bundle includes ssl skill sets covering default_client_ctx()/insecure_client_ctx()/mtls_client_ctx() client context helpers, server_ctx() server context builder, CertInfo dataclass with inspect_live_cert()/get_server_pem(), check_cert_expiry()/check_certs_bulk() expiry monitoring, and TLSHandshakeInfo with tls_handshake_info(). Start with the free tier to try TLS security patterns and ssl pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free