OpenSSL Self-Signed Certificate Creation
This skill provides guidance for creating self-signed SSL/TLS certificates using OpenSSL command-line tools, including proper verification and scripting approaches.
Core Workflow
Step 1: Create Directory Structure
Establish the output directory before generating any files:
mkdir -p /path/to/certs
Step 2: Generate Private Key
Generate an RSA private key (2048-bit minimum, 4096-bit recommended for production):
openssl genrsa -out /path/to/certs/server.key 2048
Step 3: Create Self-Signed Certificate
Generate the certificate using the private key:
openssl req -new -x509 -key /path/to/certs/server.key -out /path/to/certs/server.crt -days 365 -subj "/CN=localhost"
Adjust the -subj parameter as needed for the use case. Common fields:
-
/CN=
-
Common Name (domain or hostname)
-
/O=
-
Organization
-
/OU=
-
Organizational Unit
-
/C=
-
Country (2-letter code)
-
/ST=
-
State/Province
-
/L=
-
Locality/City
Step 4: Create Combined PEM File (if required)
Combine the key and certificate into a single PEM file:
cat /path/to/certs/server.key /path/to/certs/server.crt > /path/to/certs/combined.pem
Step 5: Verify Generated Files
Verify the certificate and key are valid and matching:
Verify certificate
openssl x509 -in /path/to/certs/server.crt -text -noout
Verify key
openssl rsa -in /path/to/certs/server.key -check -noout
Verify key matches certificate (modulus should match)
openssl x509 -noout -modulus -in /path/to/certs/server.crt | openssl md5 openssl rsa -noout -modulus -in /path/to/certs/server.key | openssl md5
Writing Verification Scripts
When creating Python scripts for certificate verification, follow these critical guidelines:
Prefer Standard Library Over External Dependencies
Avoid external dependencies like cryptography unless absolutely necessary. The script must work in the target execution environment without relying on virtual environments or pip-installed packages.
Recommended approaches (in order of preference):
- Use subprocess to call OpenSSL commands - Most reliable, no dependencies:
import subprocess
def verify_certificate(cert_path): """Verify certificate using OpenSSL subprocess calls.""" result = subprocess.run( ["openssl", "x509", "-in", cert_path, "-text", "-noout"], capture_output=True, text=True ) return result.returncode == 0, result.stdout
- Use Python's built-in ssl module - Standard library, always available:
import ssl
def load_certificate(cert_path): """Load and parse certificate using ssl module.""" context = ssl.create_default_context() context.load_cert_chain(certfile=cert_path) return True
- If external libraries are required, install system-wide (not in virtual environment):
pip install cryptography # Not: uv add, pip install in venv
Script Execution Environment
Critical consideration: Test scripts the same way they will be executed in the final environment.
-
If the test runs python /path/to/script.py , verify with exactly that command
-
Do NOT rely on uv run python or virtual environment activation
-
System Python must have access to all required modules
Complete Python Script Template
#!/usr/bin/env python3 """Certificate verification script using only standard library."""
import subprocess import sys import os
def verify_certificate(cert_path): """Verify a certificate file exists and is valid.""" if not os.path.exists(cert_path): return False, f"Certificate file not found: {cert_path}"
result = subprocess.run(
["openssl", "x509", "-in", cert_path, "-text", "-noout"],
capture_output=True,
text=True
)
if result.returncode != 0:
return False, f"Invalid certificate: {result.stderr}"
return True, result.stdout
def verify_key(key_path): """Verify a private key file exists and is valid.""" if not os.path.exists(key_path): return False, f"Key file not found: {key_path}"
result = subprocess.run(
["openssl", "rsa", "-in", key_path, "-check", "-noout"],
capture_output=True,
text=True
)
if result.returncode != 0:
return False, f"Invalid key: {result.stderr}"
return True, "Key is valid"
def verify_key_cert_match(key_path, cert_path): """Verify that a key and certificate match.""" key_modulus = subprocess.run( ["openssl", "rsa", "-noout", "-modulus", "-in", key_path], capture_output=True, text=True )
cert_modulus = subprocess.run(
["openssl", "x509", "-noout", "-modulus", "-in", cert_path],
capture_output=True,
text=True
)
if key_modulus.stdout == cert_modulus.stdout:
return True, "Key and certificate match"
return False, "Key and certificate do not match"
if name == "main": # Example usage - adjust paths as needed cert_path = "/path/to/server.crt" key_path = "/path/to/server.key"
success, msg = verify_certificate(cert_path)
print(f"Certificate: {'PASS' if success else 'FAIL'} - {msg[:100] if success else msg}")
success, msg = verify_key(key_path)
print(f"Key: {'PASS' if success else 'FAIL'} - {msg}")
success, msg = verify_key_cert_match(key_path, cert_path)
print(f"Match: {'PASS' if success else 'FAIL'} - {msg}")
Common Pitfalls
- Virtual Environment Isolation
Problem: Installing dependencies in a virtual environment (venv, uv) that won't be available when the script runs in the test/production environment.
Solution: Either use standard library only, or install dependencies system-wide with pip install (not uv add or pip install inside an activated venv).
- Incomplete File Writes
Problem: File write operations may be truncated or incomplete.
Solution: Always verify file contents after writing critical files:
cat /path/to/file # Verify contents wc -l /path/to/file # Verify line count
- Testing in Wrong Environment
Problem: Running uv run python script.py succeeds but python script.py fails.
Solution: Always test with the exact command that will be used in production/testing. If tests run python /app/script.py , verify with exactly that command.
- Assuming OpenSSL Availability
Problem: Script assumes OpenSSL is installed and in PATH.
Solution: Check for OpenSSL availability at script start:
import shutil if not shutil.which("openssl"): sys.exit("Error: OpenSSL not found in PATH")
Verification Checklist
Before declaring the task complete:
-
All required files exist and have correct content
-
Certificate is valid: openssl x509 -in cert.crt -text -noout succeeds
-
Key is valid: openssl rsa -in key.key -check -noout succeeds
-
Key and certificate modulus match
-
Combined PEM contains both key and certificate (if required)
-
Python script runs successfully with system Python (not venv)
-
All file paths in scripts match actual file locations