P2
TLS Handshake Failure — Diagnosis Guide
Diagnose TLS/SSL connection failures. Covers certificate issues, version mismatches, cipher incompatibility, chain problems, SNI, and mTLS failures.
15 min8 steps
Progress: 0/8 steps
0%
Use openssl s_client to attempt a handshake and see the raw error.
openssl s_client -connect HOST:443 -servername HOST </dev/null 2>&1 | head -30
Expected: Look for: 'Verify return code', 'SSL handshake has read', and any error lines. 'verify return:0' means certificate is valid.
Verify the server certificate hasn't expired and is not yet valid.
echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | openssl x509 -noout -dates -subject -issuer
Expected: notBefore and notAfter show the validity window. Subject should match the hostname. Issuer shows the CA.
The most common TLS error — hostname doesn't match the certificate's Subject Alternative Names.
echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | openssl x509 -noout -text | grep -A1 'Subject Alternative Name'
Expected: DNS entries must include the exact hostname or a matching wildcard (*.example.com). IP addresses need IP SAN entries.
Missing intermediate certificates cause 'unable to verify' errors on some clients.
echo | openssl s_client -connect HOST:443 -servername HOST -showcerts 2>/dev/null | grep -E 's:|i:'
Expected: Chain should show: leaf cert → intermediate(s) → root CA. If intermediates are missing, the chain is incomplete.
Server and client must support at least one common TLS version.
for v in tls1 tls1_1 tls1_2 tls1_3; do echo -n "$v: "; echo | openssl s_client -connect HOST:443 -servername HOST -$v 2>&1 | grep -o 'Protocol.*' || echo 'FAILED'; done
Expected: Shows which TLS versions the server accepts. TLS 1.2 and 1.3 should work. TLS 1.0/1.1 are deprecated.
TLS 1.0 and 1.1 are disabled by default in modern OpenSSL. If the server only supports these, it needs upgrading.
Client and server must agree on at least one cipher suite.
echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | grep -E 'Cipher|Protocol'
Expected: Shows negotiated protocol and cipher. If empty or 'no cipher suites in common', there's a cipher mismatch.
curl provides more human-readable TLS error messages than openssl.
curl -vvI https://HOST 2>&1 | grep -E 'TLS|SSL|certificate|error|subject|issuer|expire'
Expected: curl shows the negotiation steps, certificate details, and clear error messages like 'certificate has expired' or 'hostname mismatch'.
If the server requires mutual TLS, the client must present a certificate.
echo | openssl s_client -connect HOST:443 -servername HOST 2>&1 | grep -A5 'Acceptable client certificate'
Expected: If the server sends 'Acceptable client certificate CA names', it expects mTLS. Provide client cert: -cert client.pem -key client.key