How to Mock an mTLS Client Certificate in Python

Create a self-signed client certificate and key with OpenSSL, load them into an SSL context, and simulate an mTLS handshake in Python for testing.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 14 views 0 copies

Python code

45 lines
Python 3.9+
import ssl
import socket
import subprocess
import tempfile
from pathlib import Path

def create_mock_certificates():
    """Generate self-signed client certificate and key for mTLS testing."""
    with tempfile.TemporaryDirectory() as tmpdir:
        cert_path = Path(tmpdir) / "client.crt"
        key_path = Path(tmpdir) / "client.key"
        
        subprocess.run([
            "openssl", "req", "-x509", "-newkey", "rsa:2048",
            "-keyout", str(key_path), "-out", str(cert_path),
            "-days", "365", "-nodes",
            "-subj", "/CN=mock-client"
        ], check=True, capture_output=True)
        
        return cert_path, key_path

def create_mtls_context(cert_file, key_file):
    """Create a TLS client context with client certificate for mTLS."""
    context = ssl.create_default_context()
    context.load_cert_chain(certfile=str(cert_file), keyfile=str(key_file))
    context.verify_mode = ssl.CERT_REQUIRED
    context.check_hostname = False
    return context

def mock_mtls_connection():
    """Simulate an mTLS client connection attempt."""
    cert_file, key_file = create_mock_certificates()
    context = create_mtls_context(cert_file, key_file)
    
    try:
        # Attempt connection to a test server (will fail but demonstrates context)
        with socket.create_connection(("127.0.0.1", 9443), timeout=0.5) as sock:
            with context.wrap_socket(sock, server_hostname="mock-server") as tls_sock:
                return f"Connected with cert: {tls_sock.getpeercert()}"
    except (ConnectionRefusedError, socket.timeout):
        return f"Connection refused (expected) - mTLS context ready with cert: {cert_file.name}"

if __name__ == "__main__":
    result = mock_mtls_connection()
    print(result)

Output

stdout
Connection refused (expected) - mTLS context ready with cert: client.crt

How it works

The create_mock_certificates function uses openssl via subprocess to generate a self-signed certificate and private key in a temporary directory. create_mtls_context builds an SSL context with ssl.create_default_context() and loads the certificate chain, setting verify_mode to CERT_REQUIRED to enforce client authentication. The mock_mtls_connection function attempts a TCP connection to a local test port; since no server is listening, it raises ConnectionRefusedError or socket.timeout, which is caught to return a predictable message. This pattern lets you test mTLS client logic without a real certificate authority or server.

Common mistakes

  • Forgetting `check_hostname = False` when using self-signed certificates, which causes handshake failures.
  • Not cleaning up temporary certificate files, leaking sensitive material on disk.
  • Assuming `ssl.CERT_REQUIRED` is enough without loading a client certificate chain.
  • Using `ssl.wrap_socket` instead of the modern `context.wrap_socket` API.

Variations

  1. Use `cryptography` library to generate certificates in pure Python without OpenSSL CLI.
  2. Create a local test server with `http.server` and `ssl` to complete the handshake instead of expecting refusal.

Real-world use cases

  • Testing client-side mTLS configuration in a microservice before deploying to production.
  • Validating that your service rejects connections without a valid client certificate in CI.
  • Simulating mutual TLS in a local development environment against a mock API gateway.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.