The TLS handshake is failing because the client and server can’t agree on a cipher suite, or one of them is presenting an invalid certificate.
Common Causes and Fixes
1. Cipher Suite Mismatch:
- Diagnosis: On the client side, run
openssl s_client -connect example.com:443 -cipher ECDHE-RSA-AES128-GCM-SHA256. Observe the "Cipher" line in the output. On the server, check its TLS configuration (e.g., in Nginx, Apache, or a load balancer) for thessl_ciphersdirective. - Fix: Ensure the server’s
ssl_cipherslist includes at least one cipher suite supported by the client. For example, in Nginx, you might changessl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;to include a broader set likessl_ciphers HIGH:!aNULL:!MD5;. - Why it works: This forces a common cryptographic algorithm that both client and server understand, allowing them to proceed with encryption.
2. Expired Server Certificate:
- Diagnosis: Use
openssl s_client -connect example.com:443and check the "Not Before" and "Not After" dates in the certificate details. - Fix: Renew the server certificate with a new one that is within its validity period. For Let’s Encrypt, this might involve running
certbot renew. - Why it works: Certificates have a defined lifespan; once expired, they are no longer trusted by clients, preventing secure connections.
3. Server Certificate Not Trusted by Client:
- Diagnosis: On the client, run
openssl s_client -connect example.com:443. Look for "verify error" messages, such as "unable to get local issuer certificate" or "self signed certificate in certificate chain." - Fix: Ensure the client’s trust store (e.g.,
/etc/ssl/certs/ca-certificates.crton Debian/Ubuntu, orupdate-ca-certificates) contains the root certificate of the Certificate Authority (CA) that issued the server’s certificate. If it’s a self-signed certificate, you’ll need to explicitly add it to the client’s trust store or configure the client to trust it. - Why it works: The client needs to be able to trace the server’s certificate back to a trusted root CA to verify its authenticity.
4. Incorrectly Configured Intermediate Certificates:
- Diagnosis: Use an online SSL checker tool (like SSL Labs) or
openssl s_client -connect example.com:443and examine the certificate chain presented by the server. Ensure all intermediate certificates are present and in the correct order. - Fix: On the server, configure the web server or load balancer to serve the full certificate chain. For Nginx, this means concatenating the server certificate and its intermediate certificates into a single file specified by
ssl_certificate. For example,cat your_domain.crt intermediate.crt > bundle.crtand thenssl_certificate bundle.crt;. - Why it works: Clients need the entire chain to verify the server’s certificate up to a trusted root CA. Missing intermediates break this chain of trust.
5. Weak TLS Version Enabled:
- Diagnosis: Use
openssl s_client -connect example.com:443and observe the "Protocol" line. If it shows TLSv1 or TLSv1.1, it might be too old for some clients. - Fix: Configure the server to disable older TLS versions and prioritize newer, more secure ones. In Nginx, this is done with
ssl_protocols TLSv1.2 TLSv1.3;. - Why it works: Older TLS versions have known vulnerabilities and are deprecated by modern clients and security best practices.
6. SNI (Server Name Indication) Not Supported or Misconfigured:
- Diagnosis: If a server hosts multiple SSL certificates on a single IP address, and the client doesn’t send the correct
Hostheader during the TLS handshake, the server might return the wrong certificate or no certificate at all. This is often seen withopenssl s_client -connect example.com:443where the certificate presented doesn’t matchexample.com. - Fix: Ensure the client is configured to send the correct
Hostheader or that the server is configured to handle requests without SNI gracefully (e.g., by providing a default certificate). Foropenssl s_client, you can explicitly specify the hostname:openssl s_client -connect example.com:443 -servername example.com. - Why it works: SNI allows a server to present different certificates based on the hostname the client is trying to reach, crucial when multiple domains share an IP.
The next error you’ll likely encounter is a "Client Hello" packet being sent but no "Server Hello" received, indicating a network-level issue like a firewall blocking the connection or an incorrect port configuration.
The most surprising thing about TLS decryption in Wireshark is that it’s not actually decryption in the traditional sense; Wireshark doesn’t "break" the encryption, it uses your pre-shared secret key to re-encrypt the traffic in a way it understands.
Let’s see it in action. Imagine you’re running a web server and you want to inspect traffic to example.com.
First, you need the session key. This is typically found in your browser’s logs or can be generated. For Firefox, you’d set environment variables:
export SSLKEYLOGFILE=/tmp/ssl-keys.log
Now, start your browser and navigate to https://example.com. The browser will initiate a TLS handshake, and the session key will be written to /tmp/ssl-keys.log.
Next, start Wireshark and capture traffic on your network interface. Filter for HTTP or TLS traffic: http || tls.
Once you have captured some traffic, you need to tell Wireshark about the session key. Go to Edit -> Preferences -> Protocols -> TLS. Under (Pre)-Master-Secret log filename, enter the path to your log file: /tmp/ssl-keys.log.
Now, if you look at the captured packets, you’ll see the TLS handshake messages. When Wireshark encounters an encrypted TLS record, it will attempt to decrypt it using the key from your log file. The unencrypted HTTP requests and responses will now be visible, for example, GET / HTTP/1.1 and the corresponding HTTP/1.1 200 OK response.
Here’s a snapshot of what you might see in Wireshark after decryption:
Frame 1: TLSv1.3 Application Data
[Expert Info (Chat/Sequence): TLSv1.3 Application Data]
Epoch: 1
Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 299
Handshake Protocol: Client Hello
Type: Client Hello (1)
Length: 295
Client Version: TLS 1.3 (0x0304)
Random: 5b0e9f3b...
Session ID Length: 0
Cipher Suites: ...
Extensions: ...
Frame 10: TLSv1.3 Application Data
[Expert Info (Chat/Sequence): TLSv1.3 Application Data]
Epoch: 1
Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 78
Handshake Protocol: Server Hello
Type: Server Hello (2)
Length: 74
Server Version: TLS 1.2 (0x0303)
Random: 1a2b3c4d...
Session ID: ...
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Compression Method: null (0x00)
Extensions: ...
Frame 15: TCP Segment of a reassembled PDU
Frame 15: TCP Segment of a reassembled PDU
...
Application Data: GET / HTTP/1.1
GET / HTTP/1.1\r\n
Host: example.com\r\n
User-Agent: Mozilla/5.0 ...\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
\r\n
The system solves the problem of inspecting encrypted network traffic without requiring the server administrator to reconfigure the server for debugging or using man-in-the-middle proxies that can break certain security features. Wireshark, when configured with the session key, acts as a passive observer that can reconstruct the plaintext.
The exact levers you control are the capture interface, the capture filters, and the SSLKEYLOGFILE environment variable. The key is that the SSLKEYLOGFILE must be populated before the TLS connection is established and must contain the session master secret (or pre-master secret, depending on TLS version) for that specific session. If you restart your browser or establish a new connection, a new key will be generated and logged.
The subtle but critical point is that Wireshark needs the session key that was negotiated between the client and server for that specific connection. It doesn’t have a universal "master key" to decrypt all TLS traffic. This key is generated during the handshake and is used for symmetric encryption for the duration of the session. Without this specific key, Wireshark can show you the handshake, but the application data will remain an unreadable mess of encrypted bytes.
The next concept you’ll run into is analyzing the certificate chain and understanding how trust is established across different Certificate Authorities.