openssl-selfsigned-cert
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
subprocessto 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
sslmodule - 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 pythonor 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
1. 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).
2. 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
3. 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.
4. 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 -nooutsucceeds - Key is valid:
openssl rsa -in key.key -check -nooutsucceeds - 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