cryptography

Configuring TLS 1.3 for Secure Communications

TLS 1.3 (RFC 8446) is the latest version of the Transport Layer Security protocol, providing significant improvements over TLS 1.2 in both security and performance. It reduces handshake latency to 1-RTT (and 0-RTT for resumed sessions), removes obsolete cipher suites, and mandates perfect forward secrecy. This skill covers configuring TLS 1.3 on servers, validating configurations, and testing for common misconfigurations.

cryptographynetwork-securityssltlstransport-security
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

TLS 1.3 (RFC 8446) is the latest version of the Transport Layer Security protocol, providing significant improvements over TLS 1.2 in both security and performance. It reduces handshake latency to 1-RTT (and 0-RTT for resumed sessions), removes obsolete cipher suites, and mandates perfect forward secrecy. This skill covers configuring TLS 1.3 on servers, validating configurations, and testing for common misconfigurations.

When to Use

  • When deploying or configuring configuring tls 1 3 for secure communications capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Familiarity with cryptography concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Objectives

  • Configure TLS 1.3 on nginx and Apache web servers
  • Implement TLS 1.3 in Python applications using the ssl module
  • Validate TLS configurations with openssl and testssl.sh
  • Understand TLS 1.3 cipher suites and key exchange mechanisms
  • Configure 0-RTT early data with appropriate protections
  • Disable legacy TLS versions (1.0, 1.1) and weak cipher suites

Key Concepts

TLS 1.3 Cipher Suites

Cipher Suite Key Exchange Authentication Encryption Hash
TLS_AES_256_GCM_SHA384 ECDHE/DHE Certificate AES-256-GCM SHA-384
TLS_AES_128_GCM_SHA256 ECDHE/DHE Certificate AES-128-GCM SHA-256
TLS_CHACHA20_POLY1305_SHA256 ECDHE/DHE Certificate ChaCha20-Poly1305 SHA-256

TLS 1.3 vs 1.2 Improvements

  • 1-RTT Handshake: Full handshake completes in one round trip (vs 2 in TLS 1.2)
  • 0-RTT Resumption: Resumed connections can send data immediately
  • No RSA Key Exchange: Only ephemeral Diffie-Hellman (mandatory PFS)
  • Simplified Cipher Suites: Removed CBC, RC4, 3DES, static RSA, SHA-1
  • Encrypted Handshake: Server certificate is encrypted after ServerHello

Key Exchange Groups

  • x25519: Curve25519 ECDH (preferred, fast)
  • secp256r1: NIST P-256 ECDH (widely supported)
  • secp384r1: NIST P-384 ECDH (higher security margin)
  • x448: Curve448 ECDH (highest security)

Workflow

  1. Verify OpenSSL version supports TLS 1.3 (1.1.1+)
  2. Generate or obtain TLS certificate and private key
  3. Configure server to use TLS 1.3 cipher suites
  4. Disable TLS 1.0 and 1.1 (optionally keep 1.2 for compatibility)
  5. Set preferred key exchange groups
  6. Enable OCSP stapling for certificate validation
  7. Test configuration with openssl s_client and testssl.sh
  8. Configure HSTS header for HTTP Strict Transport Security

Security Considerations

  • 0-RTT data is vulnerable to replay attacks; limit to idempotent requests
  • Always include TLS 1.2 fallback if legacy client support is required
  • Use ECDSA certificates for better performance (vs RSA)
  • Enable OCSP stapling to improve client certificate validation
  • Set HSTS header with long max-age and includeSubDomains
  • Monitor for certificate transparency logs

Validation Criteria

  • TLS 1.3 handshake completes successfully
  • Only approved cipher suites are offered
  • Perfect forward secrecy is enforced
  • TLS 1.0 and 1.1 are rejected
  • OCSP stapling is functional
  • Certificate chain is valid and complete
  • testssl.sh reports no vulnerabilities
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.4 KB

TLS 1.3 Configuration — API Reference

Libraries

Library Install Purpose
cryptography pip install cryptography X.509 certificate parsing
ssl stdlib TLS connection testing
sslyze pip install sslyze Comprehensive TLS/SSL scanner

Python ssl Module Methods

Method Description
ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) Create TLS client context
ctx.minimum_version = ssl.TLSVersion.TLSv1_3 Set minimum TLS version
ctx.wrap_socket(sock, server_hostname=) Wrap socket with TLS
ssock.cipher() Get negotiated cipher tuple
ssock.getpeercert(binary_form=True) Get server certificate DER bytes

TLS 1.3 Cipher Suites

Cipher Suite Security
TLS_AES_256_GCM_SHA384 Recommended
TLS_AES_128_GCM_SHA256 Recommended
TLS_CHACHA20_POLY1305_SHA256 Recommended (mobile)

Deprecated Versions

Version Status Risk
SSL 3.0 Deprecated (RFC 7568) POODLE attack
TLS 1.0 Deprecated (RFC 8996) BEAST, CRIME
TLS 1.1 Deprecated (RFC 8996) Weak ciphers

External References

standards.md2.5 KB

Standards and References - TLS 1.3 Configuration

Primary Standards

RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3

  • URL: https://www.rfc-editor.org/rfc/rfc8446
  • Description: The core TLS 1.3 specification
  • Key changes: 1-RTT handshake, mandatory PFS, removed RSA key transport, encrypted handshake messages

RFC 8447 - IANA Registry Updates for TLS and DTLS

RFC 8449 - Record Size Limit Extension for TLS

RFC 8470 - Using Early Data in HTTP (0-RTT)

RFC 6961 - TLS Multiple Certificate Status Extension (OCSP Stapling)

RFC 6797 - HTTP Strict Transport Security (HSTS)

NIST Guidelines

NIST SP 800-52 Rev. 2 - Guidelines for TLS Implementations

NIST SP 800-57 Part 3 Rev. 1 - Application-Specific Key Management

Testing Tools

testssl.sh

SSL Labs Server Test

Mozilla SSL Configuration Generator

Compliance

PCI DSS v4.0

  • TLS 1.0 and early TLS prohibited since June 2018
  • TLS 1.2+ required; TLS 1.3 recommended
  • Strong cipher suites must be configured

HIPAA

  • Encryption in transit required for ePHI
  • TLS 1.2+ satisfies the requirement
workflows.md2.3 KB

Workflows - Configuring TLS 1.3

Workflow 1: TLS 1.3 Handshake (1-RTT)

Client                              Server
  |                                    |
  |--- ClientHello ------------------>|
  |    (supported_versions: TLS 1.3)  |
  |    (key_share: x25519)            |
  |    (signature_algorithms)         |
  |    (cipher_suites)                |
  |                                    |
  |<-- ServerHello -------------------|
  |    (selected cipher suite)        |
  |    (key_share: x25519)            |
  |<-- {EncryptedExtensions} ---------|
  |<-- {Certificate} -----------------|
  |<-- {CertificateVerify} -----------|
  |<-- {Finished} --------------------|
  |                                    |
  |--- {Finished} ------------------->|
  |                                    |
  |<== Application Data ==============>|

Workflow 2: nginx TLS 1.3 Configuration

1. Check OpenSSL version (>= 1.1.1)
   $ openssl version
 
2. Generate ECDSA certificate
   $ openssl ecparam -genkey -name prime256v1 -out server.key
   $ openssl req -new -x509 -key server.key -out server.crt -days 365
 
3. Configure nginx
   Edit /etc/nginx/nginx.conf
 
4. Test configuration
   $ nginx -t
 
5. Reload nginx
   $ systemctl reload nginx
 
6. Verify TLS 1.3
   $ openssl s_client -connect localhost:443 -tls1_3

Workflow 3: TLS Configuration Validation

[Server] --> [openssl s_client test]
                  |
          [Check protocol version]
          [Check cipher suite]
          [Check certificate chain]
                  |
          [testssl.sh full scan]
                  |
          [Check for vulnerabilities]
          - BEAST, POODLE, Heartbleed
          - ROBOT, DROWN, FREAK
          - Weak ciphers, expired certs
                  |
          [SSL Labs grade assessment]
          Target: A+ rating

Workflow 4: Certificate Lifecycle

[Generate Key Pair]
      |
[Create CSR] --> [Submit to CA]
                       |
               [CA Issues Certificate]
                       |
               [Install Certificate]
                       |
               [Configure OCSP Stapling]
                       |
               [Set Up Auto-Renewal]
               (certbot / ACME)
                       |
               [Monitor Expiration]

Scripts 2

agent.py5.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""TLS 1.3 configuration audit agent using ssl and cryptography libraries."""

import json
import sys
import argparse
import ssl
import socket
from datetime import datetime

try:
    from cryptography import x509
except ImportError:
    print("Install: pip install cryptography")
    sys.exit(1)


def check_tls_versions(host, port=443):
    """Check supported TLS versions on a server."""
    results = {}
    protocols = {
        "TLSv1.0": ssl.TLSVersion.TLSv1 if hasattr(ssl.TLSVersion, 'TLSv1') else None,
        "TLSv1.1": ssl.TLSVersion.TLSv1_1 if hasattr(ssl.TLSVersion, 'TLSv1_1') else None,
        "TLSv1.2": ssl.TLSVersion.TLSv1_2,
        "TLSv1.3": ssl.TLSVersion.TLSv1_3,
    }
    for version_name, version in protocols.items():
        if version is None:
            results[version_name] = {"supported": False, "note": "Not available in this Python build"}
            continue
        try:
            ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
            ctx.check_hostname = False
            ctx.verify_mode = ssl.CERT_NONE
            ctx.minimum_version = version
            ctx.maximum_version = version
            with socket.create_connection((host, port), timeout=5) as sock:
                with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                    results[version_name] = {
                        "supported": True,
                        "cipher": ssock.cipher()[0],
                        "severity": "CRITICAL" if "1.0" in version_name or "1.1" in version_name else "INFO",
                    }
        except (ssl.SSLError, ConnectionRefusedError, socket.timeout, OSError):
            results[version_name] = {"supported": False}
    return results


def get_certificate_info(host, port=443):
    """Retrieve and analyze server certificate."""
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    try:
        with socket.create_connection((host, port), timeout=5) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                der_cert = ssock.getpeercert(binary_form=True)
                cert = x509.load_der_x509_certificate(der_cert)
                days_remaining = (cert.not_valid_after_utc.replace(tzinfo=None) - datetime.utcnow()).days
                return {
                    "subject": cert.subject.rfc4514_string(),
                    "issuer": cert.issuer.rfc4514_string(),
                    "not_after": str(cert.not_valid_after_utc),
                    "days_remaining": days_remaining,
                    "key_size": cert.public_key().key_size,
                    "signature_algorithm": cert.signature_hash_algorithm.name if cert.signature_hash_algorithm else "unknown",
                    "issues": [],
                }
    except Exception as e:
        return {"error": str(e)}


def check_cipher_suites(host, port=443):
    """Check negotiated cipher suites."""
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    try:
        with socket.create_connection((host, port), timeout=5) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                cipher = ssock.cipher()
                return {
                    "negotiated_cipher": cipher[0],
                    "protocol": cipher[1],
                    "bits": cipher[2],
                    "tls13_ciphers": ["TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256",
                                       "TLS_CHACHA20_POLY1305_SHA256"],
                }
    except Exception as e:
        return {"error": str(e)}


def run_audit(host, port=443):
    """Execute TLS 1.3 configuration audit."""
    print(f"\n{'='*60}")
    print(f"  TLS 1.3 CONFIGURATION AUDIT")
    print(f"  Target: {host}:{port}")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    versions = check_tls_versions(host, port)
    print(f"--- TLS VERSION SUPPORT ---")
    for ver, info in versions.items():
        status = "SUPPORTED" if info.get("supported") else "NOT SUPPORTED"
        sev = info.get("severity", "")
        print(f"  {ver}: {status} {f'[{sev}]' if sev else ''}")

    cert = get_certificate_info(host, port)
    print(f"\n--- CERTIFICATE ---")
    if "error" not in cert:
        print(f"  Subject: {cert['subject']}")
        print(f"  Issuer: {cert['issuer']}")
        print(f"  Expires: {cert['not_after']} ({cert['days_remaining']} days)")
        print(f"  Key size: {cert['key_size']}")

    cipher = check_cipher_suites(host, port)
    print(f"\n--- CIPHER SUITE ---")
    if "error" not in cipher:
        print(f"  Negotiated: {cipher['negotiated_cipher']}")
        print(f"  Protocol: {cipher['protocol']}")

    return {"versions": versions, "certificate": cert, "cipher": cipher}


def main():
    parser = argparse.ArgumentParser(description="TLS 1.3 Audit Agent")
    parser.add_argument("--host", required=True, help="Target hostname")
    parser.add_argument("--port", type=int, default=443, help="Target port")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_audit(args.host, args.port)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
process.py14.1 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
TLS 1.3 Configuration and Validation Tool

Implements TLS 1.3 server/client testing, configuration generation,
and vulnerability scanning using Python's ssl module and OpenSSL.

Requirements:
    pip install cryptography

Usage:
    python process.py test-server --host example.com --port 443
    python process.py generate-nginx --domain example.com --cert-path /etc/ssl
    python process.py generate-cert --domain example.com --output ./certs
    python process.py check-ciphers --host example.com
"""

import os
import ssl
import sys
import json
import socket
import argparse
import logging
import subprocess
import datetime
from pathlib import Path
from typing import Optional, Dict, List

from cryptography import x509
from cryptography.x509.oid import NameOID, ExtensionOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, rsa

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

TLS_13_CIPHERS = [
    "TLS_AES_256_GCM_SHA384",
    "TLS_AES_128_GCM_SHA256",
    "TLS_CHACHA20_POLY1305_SHA256",
]

RECOMMENDED_TLS_12_CIPHERS = [
    "ECDHE-ECDSA-AES256-GCM-SHA384",
    "ECDHE-RSA-AES256-GCM-SHA384",
    "ECDHE-ECDSA-AES128-GCM-SHA256",
    "ECDHE-RSA-AES128-GCM-SHA256",
    "ECDHE-ECDSA-CHACHA20-POLY1305",
    "ECDHE-RSA-CHACHA20-POLY1305",
]


def test_tls_connection(host: str, port: int = 443, timeout: int = 10) -> Dict:
    """Test TLS connection to a server and report protocol details."""
    results = {
        "host": host,
        "port": port,
        "tls_13_supported": False,
        "tls_12_supported": False,
        "protocol_version": None,
        "cipher_suite": None,
        "certificate": None,
        "issues": [],
    }

    # Test TLS 1.3
    try:
        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        ctx.minimum_version = ssl.TLSVersion.TLSv1_3
        ctx.maximum_version = ssl.TLSVersion.TLSv1_3

        with socket.create_connection((host, port), timeout=timeout) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                results["tls_13_supported"] = True
                results["protocol_version"] = ssock.version()
                cipher = ssock.cipher()
                results["cipher_suite"] = {
                    "name": cipher[0],
                    "protocol": cipher[1],
                    "bits": cipher[2],
                }
                cert = ssock.getpeercert()
                results["certificate"] = {
                    "subject": dict(x[0] for x in cert.get("subject", ())),
                    "issuer": dict(x[0] for x in cert.get("issuer", ())),
                    "notBefore": cert.get("notBefore"),
                    "notAfter": cert.get("notAfter"),
                    "serialNumber": cert.get("serialNumber"),
                    "version": cert.get("version"),
                }
                logger.info(f"TLS 1.3 connection successful: {cipher[0]}")
    except ssl.SSLError as e:
        results["issues"].append(f"TLS 1.3 not supported: {e}")
        logger.warning(f"TLS 1.3 not supported on {host}:{port}")
    except Exception as e:
        results["issues"].append(f"Connection error: {e}")

    # Test TLS 1.2
    try:
        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        ctx.minimum_version = ssl.TLSVersion.TLSv1_2
        ctx.maximum_version = ssl.TLSVersion.TLSv1_2

        with socket.create_connection((host, port), timeout=timeout) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                results["tls_12_supported"] = True
                if not results["tls_13_supported"]:
                    results["protocol_version"] = ssock.version()
                    cipher = ssock.cipher()
                    results["cipher_suite"] = {
                        "name": cipher[0],
                        "protocol": cipher[1],
                        "bits": cipher[2],
                    }
    except (ssl.SSLError, Exception):
        pass

    # Test deprecated protocols
    for version_name, version_enum in [
        ("TLS 1.1", ssl.TLSVersion.TLSv1_1),
        ("TLS 1.0", ssl.TLSVersion.TLSv1),
    ]:
        try:
            ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
            ctx.minimum_version = version_enum
            ctx.maximum_version = version_enum
            ctx.check_hostname = False
            ctx.verify_mode = ssl.CERT_NONE
            with socket.create_connection((host, port), timeout=timeout) as sock:
                with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                    results["issues"].append(
                        f"VULNERABLE: {version_name} is still enabled (should be disabled)"
                    )
                    logger.warning(f"{version_name} is enabled on {host}:{port}")
        except (ssl.SSLError, OSError):
            pass

    return results


def check_cipher_suites(host: str, port: int = 443, timeout: int = 10) -> Dict:
    """Check which cipher suites a server supports."""
    results = {"host": host, "port": port, "supported_ciphers": [], "weak_ciphers": []}

    weak_patterns = ["RC4", "DES", "3DES", "MD5", "NULL", "EXPORT", "anon"]

    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    try:
        with socket.create_connection((host, port), timeout=timeout) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                cipher = ssock.cipher()
                results["negotiated_cipher"] = {
                    "name": cipher[0],
                    "protocol": cipher[1],
                    "bits": cipher[2],
                }
                shared = ssock.shared_ciphers()
                if shared:
                    for c in shared:
                        cipher_info = {"name": c[0], "protocol": c[1], "bits": c[2]}
                        results["supported_ciphers"].append(cipher_info)
                        if any(weak in c[0] for weak in weak_patterns):
                            results["weak_ciphers"].append(cipher_info)
    except Exception as e:
        results["error"] = str(e)

    return results


def generate_self_signed_cert(
    domain: str, output_dir: str, key_type: str = "ecdsa"
) -> Dict:
    """Generate a self-signed TLS certificate for testing."""
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    if key_type == "ecdsa":
        private_key = ec.generate_private_key(ec.SECP256R1())
        key_filename = "server-ecdsa.key"
        cert_filename = "server-ecdsa.crt"
    else:
        private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
        key_filename = "server-rsa.key"
        cert_filename = "server-rsa.crt"

    subject = issuer = x509.Name([
        x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
        x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
        x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Test Organization"),
        x509.NameAttribute(NameOID.COMMON_NAME, domain),
    ])

    cert = (
        x509.CertificateBuilder()
        .subject_name(subject)
        .issuer_name(issuer)
        .public_key(private_key.public_key())
        .serial_number(x509.random_serial_number())
        .not_valid_before(datetime.datetime.utcnow())
        .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
        .add_extension(
            x509.SubjectAlternativeName([
                x509.DNSName(domain),
                x509.DNSName(f"*.{domain}"),
            ]),
            critical=False,
        )
        .add_extension(
            x509.BasicConstraints(ca=False, path_length=None),
            critical=True,
        )
        .sign(private_key, hashes.SHA256())
    )

    key_path = output_path / key_filename
    cert_path = output_path / cert_filename

    key_path.write_bytes(
        private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        )
    )

    cert_path.write_bytes(cert.public_bytes(serialization.Encoding.PEM))

    logger.info(f"Generated {key_type.upper()} certificate for {domain}")
    logger.info(f"  Key:  {key_path}")
    logger.info(f"  Cert: {cert_path}")

    return {
        "domain": domain,
        "key_type": key_type,
        "key_path": str(key_path),
        "cert_path": str(cert_path),
        "valid_days": 365,
    }


def generate_nginx_config(
    domain: str, cert_path: str, key_path: str, enable_tls12: bool = True
) -> str:
    """Generate nginx TLS 1.3 configuration."""
    tls_protocols = "TLSv1.3"
    if enable_tls12:
        tls_protocols = "TLSv1.2 TLSv1.3"

    tls12_ciphers = ":".join(RECOMMENDED_TLS_12_CIPHERS)

    config = f"""# TLS 1.3 Optimized nginx Configuration
# Generated for: {domain}
# Mozilla SSL Configuration Generator: Modern profile

server {{
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name {domain};

    # Certificate paths
    ssl_certificate {cert_path};
    ssl_certificate_key {key_path};

    # Protocol versions
    ssl_protocols {tls_protocols};

    # TLS 1.2 cipher suites (TLS 1.3 ciphers are configured automatically)
    ssl_ciphers '{tls12_ciphers}';
    ssl_prefer_server_ciphers off;

    # ECDH curve
    ssl_ecdh_curve X25519:secp256r1:secp384r1;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    # Session configuration
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Security headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-XSS-Protection "0" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Root and index
    root /var/www/{domain}/html;
    index index.html;

    location / {{
        try_files $uri $uri/ =404;
    }}
}}

# HTTP to HTTPS redirect
server {{
    listen 80;
    listen [::]:80;
    server_name {domain};
    return 301 https://$server_name$request_uri;
}}
"""
    return config


def generate_apache_config(
    domain: str, cert_path: str, key_path: str, enable_tls12: bool = True
) -> str:
    """Generate Apache TLS 1.3 configuration."""
    tls_protocols = "TLSv1.3"
    if enable_tls12:
        tls_protocols = "TLSv1.2 TLSv1.3"

    tls12_ciphers = ":".join(RECOMMENDED_TLS_12_CIPHERS)

    config = f"""# TLS 1.3 Optimized Apache Configuration
# Generated for: {domain}

<VirtualHost *:443>
    ServerName {domain}
    DocumentRoot /var/www/{domain}/html

    SSLEngine on
    SSLCertificateFile {cert_path}
    SSLCertificateKeyFile {key_path}

    # Protocol versions
    SSLProtocol all -{" -".join(["SSLv3", "TLSv1", "TLSv1.1"])}
    {"" if enable_tls12 else "SSLProtocol TLSv1.3"}

    # Cipher suites
    SSLCipherSuite {tls12_ciphers}
    SSLHonorCipherOrder off

    # OCSP Stapling
    SSLUseStapling on
    SSLStaplingCache shmcb:/var/run/ocsp(128000)

    # Security headers
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
</VirtualHost>

# HTTP to HTTPS redirect
<VirtualHost *:80>
    ServerName {domain}
    Redirect permanent / https://{domain}/
</VirtualHost>
"""
    return config


def main():
    parser = argparse.ArgumentParser(description="TLS 1.3 Configuration Tool")
    subparsers = parser.add_subparsers(dest="command")

    # Test server
    test = subparsers.add_parser("test-server", help="Test TLS configuration of a server")
    test.add_argument("--host", required=True, help="Server hostname")
    test.add_argument("--port", type=int, default=443, help="Server port")

    # Check ciphers
    ciphers = subparsers.add_parser("check-ciphers", help="Check supported cipher suites")
    ciphers.add_argument("--host", required=True, help="Server hostname")
    ciphers.add_argument("--port", type=int, default=443, help="Server port")

    # Generate certificate
    cert = subparsers.add_parser("generate-cert", help="Generate self-signed certificate")
    cert.add_argument("--domain", required=True, help="Domain name")
    cert.add_argument("--output", default="./certs", help="Output directory")
    cert.add_argument("--key-type", choices=["ecdsa", "rsa"], default="ecdsa")

    # Generate nginx config
    nginx = subparsers.add_parser("generate-nginx", help="Generate nginx TLS config")
    nginx.add_argument("--domain", required=True, help="Domain name")
    nginx.add_argument("--cert-path", required=True, help="Certificate file path")
    nginx.add_argument("--key-path", required=True, help="Private key file path")
    nginx.add_argument("--tls12", action="store_true", default=True, help="Enable TLS 1.2")

    # Generate Apache config
    apache = subparsers.add_parser("generate-apache", help="Generate Apache TLS config")
    apache.add_argument("--domain", required=True, help="Domain name")
    apache.add_argument("--cert-path", required=True, help="Certificate file path")
    apache.add_argument("--key-path", required=True, help="Private key file path")

    args = parser.parse_args()

    if args.command == "test-server":
        result = test_tls_connection(args.host, args.port)
        print(json.dumps(result, indent=2, default=str))
    elif args.command == "check-ciphers":
        result = check_cipher_suites(args.host, args.port)
        print(json.dumps(result, indent=2))
    elif args.command == "generate-cert":
        result = generate_self_signed_cert(args.domain, args.output, args.key_type)
        print(json.dumps(result, indent=2))
    elif args.command == "generate-nginx":
        config = generate_nginx_config(args.domain, args.cert_path, args.key_path, args.tls12)
        print(config)
    elif args.command == "generate-apache":
        config = generate_apache_config(args.domain, args.cert_path, args.key_path)
        print(config)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 2.1 KB
Keep exploring