Stage 3 · Build
TLS & Certificate Management
Debugging TLS Issues
openssl s_client, certificate expiry alerts, and TLS inspection.
openssl s_client Deep Dive
openssl s_client is the Swiss Army knife of TLS debugging. It connects to a server, performs the TLS handshake, and shows detailed information about the connection, certificate, and cipher suite.
# Basic TLS connection test
openssl s_client -connect example.com:443
# Show full certificate chain
openssl s_client -connect example.com:443 -showcerts
# Test with specific TLS version
openssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -tls1_2
# Check for specific certificate issues
openssl s_client -connect example.com:443 2>&1 | grep -E "(Verify|error|depth)"
# Test with client certificate
openssl s_client -connect example.com:443 -cert client.pem -key client-key.pemLook for Verify return code: 0 (ok) at the end of the output. Non-zero values indicate certificate verification failures. The -showcerts flag shows every certificate in the chain, which helps identify missing intermediates.
Common Certificate Issues
| Issue | Symptom | Fix |
|---|---|---|
| Expired certificate | ERR_CERT_DATE_INVALID | Renew the certificate |
| Missing intermediate | ERR_CERT_AUTHORITY_INVALID | Add intermediate to chain |
| Hostname mismatch | ERR_CERT_COMMON_NAME_INVALID | Add correct SAN to cert |
| Self-signed cert | ERR_CERT_AUTHORITY_INVALID | Add to trust store or use CA-signed |
| Revoked certificate | ERR_CERT_REVOKED | Issue new certificate, check CRL/OCSP |
# Check certificate expiry
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# Check SAN entries
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
# Check the full chain
echo | openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
grep -E "(s:|i:)"
# Verify chain against your trust store
echo | openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt 2>&1 | \
grep "Verify return"The chain output shows 's:' (subject) and 'i:' (issuer) for each certificate. If the chain ends with a self-signed root instead of going through intermediates, the server is not sending the full chain.
TLS Error Messages Decoded
# error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
# -> Client does not trust the server's CA certificate
# error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
# -> No common cipher suite between client and server
# error:14094415:SSL routines:ssl3_read_bytes:sslv3 alert certificate expired
# -> Server certificate has expired
# error:1408F10B:SSL routines:ssl3_get_record:wrong version number
# -> Server is not speaking TLS (plain HTTP on HTTPS port)
# error:0A000086:SSL routines:tls_process_server_certificate:certificate verify failed
# -> Full chain verification failedThe error format is library:function:reason. The reason after the colon is the most useful part. 'alert unknown ca' means trust issue. 'handshake failure' means cipher mismatch. 'wrong version number' usually means HTTP on an HTTPS port.
Production TLS Debugging
# 1. Test basic connectivity
openssl s_client -connect example.com:443 -servername example.com </dev/null
# 2. Check what TLS version and cipher is negotiated
openssl s_client -connect example.com:443 </dev/null | grep -E "(Protocol|Cipher)"
# 3. Compare with known-good server
openssl s_client -connect google.com:443 </dev/null | grep -E "(Protocol|Cipher)"
# 4. Test with verbose output
openssl s_client -connect example.com:443 -msg </dev/null
# 5. Capture TLS handshake with tcpdump
sudo tcpdump -i eth0 port 443 -w tls-debug.pcap
# Open in Wireshark to see TLS handshake details
# 6. Check OCSP stapling
echo | openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A3 "OCSP"The -servername flag sends the hostname in the SNI extension. Without it, the server may return the wrong certificate (or reject the connection if it requires SNI). Always use -servername when testing.
TLS Inspection and MITM
TLS inspection (also called TLS interception or MITM proxy) terminates TLS connections and re-encrypts them. Corporate proxies use this to inspect encrypted traffic. Security tools use it to detect threats in TLS traffic.
# mitmproxy - intercept TLS traffic
mitmproxy --listen-port 8080
# Configure client to use proxy
export https_proxy=http://localhost:8080
curl https://example.com
# mitmproxy generates a CA cert on first run
# Install ~/.mitmproxy/mitmproxy-ca-cert.pem in your trust store
# Charles Proxy (GUI alternative)
# Configure proxy and enable SSL Proxying for the target domainFor debugging API traffic, TLS interception lets you see the full request and response. This is invaluable when you cannot add logging to the client or server. Use it only on your own traffic for debugging.
TLS inspection requires your CA to be in the client's trust store. This breaks certificate pinning and can cause issues with apps that validate certificate transparency. Only intercept your own traffic for debugging purposes.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.