Percio Castelo.
PT Home
Forensic analysis: D4 operations - wire cryptography with TLS 1.3 and SSH hardening
← Back to blog

Forensic analysis: D4 operations - wire cryptography with TLS 1.3 and SSH hardening

6/15/2026 · 5 min · Cybersecurity · 926 views

Introduction: the hostile network assumption (physical zero trust)#

If you manage Linux servers in production, the packets leaving your Network Interface Cards (NICs) will traverse third-party intermediate routers, public transoceanic fiber links, and intercepting proxies before reaching their target. In Day 4 Operations (Network Defense), the core premise is the Physical Zero Trust model: all network traffic in transit is assumed to be mirrored, captured, and archived by threat actors or state-sponsored entities.

The primary threat of passive interception is the "Harvest Now, Decrypt Later" attack. Attackers collect encrypted data flows today in anticipation of decrypting them in the future-either by compromising the server's private key, finding mathematical weaknesses in legacy algorithms (such as static RSA), or leveraging future quantum computing capabilities.

To eliminate this retro-decryption vector, modern security requires Perfect Forward Secrecy (PFS). This article explores the low-level handshake structure of TLS 1.3 and provides instructions for cryptographic hardening of OpenSSH, analyzing logs and wire packets.


1. Dissecting TLS 1.3: demolishing RSA key exchange#

The TLS 1.2 protocol, though widely supported on the internet for backward compatibility, carries architectural design choices that compromise long-term security. It supports CBC-mode ciphers (vulnerable to timing and padding oracle attacks like Lucky Thirteen and the POODLE-TLS variant affecting specific implementations) and static RSA key exchanges.

If an attacker captures a history of TLS 1.2 traffic encrypted via static RSA and, years later, compromises the server's private key file (.pem), they can recalculate the Pre-Master Secret for all historical sessions, decrypting all stored payloads retrospectively.

TLS 1.3 introduces a complete architectural redesign:

  • Mandatory Forward Secrecy: It completely removes static RSA key exchanges. Every TLS 1.3 connection is required to negotiate keys dynamically using ephemeral Elliptic-Curve Diffie-Hellman algorithms, such as ECDHE (specifically Curve X25519).
  • Cryptographic Cleanup: Obsolete hashing and symmetric cipher options are deprecated, including MD5, SHA-1, RC4, DES, 3DES, and CBC-mode ciphers.
  • AEAD Encryption: TLS 1.3 supports exclusively Authenticated Encryption with Associated Data (AEAD) ciphers, combining confidentiality and integrity validation in a single process.

Handshake optimization: 1-rtt (round-trip time)#

In TLS 1.2, establishing a secure session required two full round-trip times (2-RTT) of packet exchanges. TLS 1.3 reduces this overhead to a single round-trip (1-RTT) by allowing the client to guess the server's preferred cryptographic curve (such as X25519) and send its public key contribution (Key Share) in the initial handshake packet.

The TLS 1.3 handshake flow is mapped below:

sequenceDiagram autonumber participant Client participant Net as Wireshark (Wire Capture) participant Server Client->>Server: Client Hello + Key Share (ex: X25519) Note over Net: Only the Client Hello parameters are visible in plaintext. Server-->>Client: Server Hello + Key Share + Certificate + Finished Note over Net: The Server Certificate is transmitted fully encrypted! Client->>Server: Application Data (HTTP GET / Request) Server-->>Client: Application Data (HTTP 200 OK / Response)

Immediately after the Server Hello packet is sent by the server, the encrypted tunnel is established. The server certificate and signature validation are transmitted in an encrypted state, preventing passive eavesdroppers from identifying the target domain in the certificate exchange.

Hardening the Nginx configuration#

To enforce these restrictive TLS parameters on your load balancers or ingress web servers, edit your nginx.conf virtual hosts:

# /etc/nginx/conf.d/tls.conf
server {
    listen 443 ssl http2;
    server_name domain.com;

    # Enforce only TLS 1.3 and strict TLS 1.2
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Prioritize the server's cipher suite preferences over the client's
    ssl_prefer_server_ciphers on;

    # TLS 1.2 Ciphers (ECDHE mandatory + AEAD)
    # WARNING: TLS 1.3 ciphers are automatically managed by OpenSSL and CANNOT be configured inside this directive!
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';

    # Elliptic curves allowed for ephemeral key generation (X25519 prioritized)
    ssl_ecdh_curve X25519:secp384r1;

    # OCSP Stapling (avoids client-side verification latency and protects user privacy)
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/domain.com/chain.pem;
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    # Disable session tickets to guarantee absolute Perfect Forward Secrecy
    ssl_session_tickets off;

    # HSTS (HTTP Strict Transport Security)
    # WARNING: Enabling "preload" registers your domain in browser-embedded preload lists.
    # This is hard to revert and will break any subdomains that do not support HTTPS. Enable only after full validation.
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
    
    ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
}

Production and hardening notes for Nginx:#

  • Independent TLS 1.3 Ciphers: In OpenSSL 1.1.1+, the ssl_ciphers directive only manages TLS 1.2 and lower cipher suites. Attempting to define TLS 1.3 ciphers here will either result in them being silently ignored or causing initialization failures in some Nginx builds. The TLS 1.3 cipher suite negotiation is managed automatically in the background.
  • OCSP Stapling: Critical for production efficiency. Rather than forcing the client browser to contact the Certificate Authority (CA) during every handshake to verify revocation status, Nginx caches the signed response from the CA and "staples" it to the handshake. This saves 200–500ms of latency and maintains user privacy.
  • Session Tickets vs PFS: Disabling session tickets (ssl_session_tickets off;) forces the generation of fresh session keys. If a static ticket key on disk were compromised, past sessions captured from the wire could be decrypted, bypassing the protection of Ephemeral Diffie-Hellman.
  • HSTS Preload Warnings: Setting the Strict-Transport-Security header with preload submits the domain to global browser database lists. Removing a domain from this list can take several months, and subdomains running solely on HTTP (such as internal APIs or legacy equipment) will become completely unreachable. Therefore, preload is excluded from the default recommendation.

2. Hardening openssh: disabling legacy ciphers#

OpenSSH manages remote access on Linux servers. By default, many Linux distributions ship with permissive configurations to maintain compatibility with older terminal clients, legacy networking switches, or automated script engines.

These default settings often accept Key Exchange (KEX) algorithms relying on SHA-1, obsolete CBC symmetric ciphers, and outdated RSA key signatures (ssh-rsa).

Securing OpenSSH demands restricting the mathematical operations the CPU is permitted to negotiate for session generation.

Advanced SSHD cryptographic hardening#

⚠️ Compatibility Warning: The following hardened configuration disables legacy cryptography. It will reject connections from legacy SSH clients (OpenSSH < 7.4), systems running OpenSSL < 1.1.1, IoT devices with outdated firmware, and clients relying on Diffie-Hellman Group 14 or lower. Before deploying, check your client version (ssh -V). To prevent legacy lockout, the RSA HostKey is kept as a fallback in the configuration below.

Modify the default configurations in /etc/ssh/sshd_config to adopt CIS (Center for Internet Security) recommendations:

# /etc/ssh/sshd_config

# 1. Key Exchange Algorithms (KEX)
# Restrict KEX to Curve25519 and SHA-512-based Diffie-Hellman Group 16
KexAlgorithms curve25519-sha256,[email protected],diffie-hellman-group16-sha512

# 2. Symmetric Ciphers
# Exclude CBC modes. Accept only AEAD ciphers with built-in side-channel protection
Ciphers [email protected],[email protected],[email protected]

# 3. Message Authentication Codes (MACs)
# AEAD ciphers handle authentication. The following MACs apply to the initial handshake phase (Encrypt-then-MAC)
MACs [email protected],[email protected]

# 4. Host Key Formats
# Enable Ed25519 and keep RSA as a fallback to prevent incompatibility issues and lockouts
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

# 5. Strict Authentication
# Disable password authentication (blocks brute-force and credential stuffing attempts)
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
KbdInteractiveAuthentication no
AuthenticationMethods publickey

# 6. Access Protection and Rate Limits
# Limit attempts, active sessions, and connection grace period
MaxAuthTries 3
LoginGraceTime 30
MaxSessions 3
MaxStartups 10:30:60

# 7. Restrict Allowed Users (Adjust to your environment)
# Restrict access to specific users/networks. OpenSSH supports wildcard match syntax (e.g. [email protected].*)
# AllowUsers [email protected].* [email protected].*
# or
# AllowGroups ssh-users

# 8. Advanced Audit Logging
# Set LogLevel to VERBOSE to record user key fingerprints upon connection
LogLevel VERBOSE

Validating and deploying configs#

⚠️ CRITICAL LOCKOUT WARNING: If there is any syntax or key configuration error, you could lose SSH access permanently. Never close your current active terminal session while applying and verifying these modifications. Keep at least one active pipeline open to rollback configurations if needed.

Before restarting the system service, validate the syntax of your configuration file to prevent remote lockout:

# Test configuration syntax
sudo sshd -t

If it returns without errors, restart the SSH daemon:

sudo systemctl restart sshd

3. Day 7 visibility: log auditing and cipher verification#

With LogLevel VERBOSE enabled, successful user public key connections (such as Ed25519 signatures) record the cryptographic footprint of the connection inside system logs (/var/log/auth.log or journal output) (Note: Verbose login records can grow significantly in environments with heavy connection rates. Ensure log rotation policies are configured in /etc/logrotate.d/rsyslog or via systemd-journald to avoid partition disk space depletion):

sudo tail -f /var/log/auth.log | grep sshd

Expected output:

sshd[45192]: Connection from 10.0.0.55 port 45192 on 10.0.0.10 port 22
sshd[45192]: Accepted publickey for user from 10.0.0.55 port 45192 ssh2: ED25519 SHA256:4oY5lJ9NnLgH4kPqRxTYuZ81mWt2K83aD1ePfV9g
sshd[45192]: pam_unix(sshd:session): session opened for user user(uid=1000) by (uid=0)
sshd[45192]: Connection closed by authenticated user user 10.0.0.55 port 45192 [preauth]

These records provide:

  • The source IP address (10.0.0.55) and the connection port.
  • The public key algorithm used (ED25519).
  • The SHA256 fingerprint of the key, allowing you to trace the login to a specific private key file.

Remote cipher auditing (nmap)#

You can verify the active host algorithms from an external machine using the Nmap audit script:

nmap -p 22 --script ssh2-enum-algos domain.com

Expected audit response:

Starting Nmap 7.92 ( https://nmap.org ) at 2026-06-15 03:00
Nmap scan report for domain.com (10.0.0.10)
Host is up (0.012s latency).

PORT   STATE SERVICE
22/tcp open  ssh
| ssh2-enum-algos: 
|   kex_algorithms: (3)
|       curve25519-sha256
|       [email protected]
|       diffie-hellman-group16-sha512
|   server_host_key_algorithms: (1)
|       ssh-ed25519
|   encryption_algorithms: (3)
|       [email protected]
|       [email protected]
|_      [email protected]

This output confirms that only the authorized, modern algorithms defined in your SSH config are exposed, blocking connections using outdated ciphers and protecting your server from passive traffic analysis decryption risks.

Was this article helpful?

Leave a quick reaction to help prioritize future technical guides:

926 reads
Creative Commons Attribution-NonCommercial

This post is licensed under CC BY-NC.

Comments

Join the discussion below.

0 comments