"""
TLS/SSL support for WebSocket server.
Provides secure WebSocket connections (wss://) with TLS encryption.
"""
import ssl
from pathlib import Path
from typing import Optional
def create_ssl_context(
cert_file: Path,
key_file: Path,
ca_file: Optional[Path] = None
) -> ssl.SSLContext:
"""
Create SSL context for secure WebSocket connections.
Args:
cert_file: Path to server certificate file
key_file: Path to server private key file
ca_file: Optional path to CA certificate for client verification
Returns:
Configured SSLContext
"""
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# Load server certificate and key
ssl_context.load_cert_chain(cert_file, key_file)
# Optional: Require client certificates
if ca_file:
ssl_context.load_verify_locations(ca_file)
ssl_context.verify_mode = ssl.CERT_REQUIRED
else:
ssl_context.verify_mode = ssl.CERT_NONE
# Security settings
ssl_context.check_hostname = False
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
return ssl_context
def create_client_ssl_context(
ca_file: Optional[Path] = None,
cert_file: Optional[Path] = None,
key_file: Optional[Path] = None
) -> ssl.SSLContext:
"""
Create SSL context for WebSocket client.
Args:
ca_file: Optional path to CA certificate for server verification
cert_file: Optional path to client certificate
key_file: Optional path to client private key
Returns:
Configured SSLContext
"""
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# Server verification
if ca_file:
ssl_context.load_verify_locations(ca_file)
ssl_context.check_hostname = True
ssl_context.verify_mode = ssl.CERT_REQUIRED
else:
# Don't verify server certificate (for testing)
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# Optional: Client certificate
if cert_file and key_file:
ssl_context.load_cert_chain(cert_file, key_file)
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
return ssl_context
# Example usage for self-signed certificates
def generate_self_signed_cert(output_dir: Path):
"""
Generate self-signed certificate for testing.
Requires: openssl command
Args:
output_dir: Directory to store certificate files
"""
import subprocess
output_dir.mkdir(parents=True, exist_ok=True)
cert_file = output_dir / "server.crt"
key_file = output_dir / "server.key"
# Generate private key
subprocess.run([
"openssl", "genrsa",
"-out", str(key_file),
"2048"
], check=True)
# Generate self-signed certificate
subprocess.run([
"openssl", "req", "-new", "-x509",
"-key", str(key_file),
"-out", str(cert_file),
"-days", "365",
"-subj", "/CN=localhost"
], check=True)
print(f"✓ Generated certificate: {cert_file}")
print(f"✓ Generated key: {key_file}")
return cert_file, key_file