TLS

TLS protocol operations — handshake inspection, cipher management, and certificate chain validation.

Testing with openssl s_client

Connect and show the certificate chain
openssl s_client -connect docs.domusdigitalis.dev:443 -showcerts </dev/null 2>/dev/null
Extract just the server certificate — PEM format
openssl s_client -connect docs.domusdigitalis.dev:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > server.pem
Check certificate expiry — the most common TLS failure
openssl s_client -connect docs.domusdigitalis.dev:443 </dev/null 2>/dev/null | openssl x509 -noout -dates
Show Subject, Issuer, SANs, and serial — the four things you check first
openssl s_client -connect docs.domusdigitalis.dev:443 </dev/null 2>/dev/null | \
    openssl x509 -noout -subject -issuer -ext subjectAltName -serial
Test a specific TLS version — verify server rejects old protocols
# Should FAIL — TLS 1.0 and 1.1 must be disabled
openssl s_client -connect docs.domusdigitalis.dev:443 -tls1 </dev/null 2>&1 | head -5
openssl s_client -connect docs.domusdigitalis.dev:443 -tls1_1 </dev/null 2>&1 | head -5

# Should succeed — TLS 1.2 minimum
openssl s_client -connect docs.domusdigitalis.dev:443 -tls1_2 </dev/null 2>&1 | head -5
Connect with SNI — required when multiple sites share an IP
openssl s_client -connect 10.50.1.100:443 -servername docs.domusdigitalis.dev </dev/null
Test with a specific CA bundle — verify chain against your CA
openssl s_client -connect internal.domusdigitalis.dev:443 -CAfile /etc/ssl/certs/domus-ca-chain.pem </dev/null

Certificate Chain Verification

Verify a certificate against a CA chain
openssl verify -CAfile ca-chain.pem server.pem
Verify with intermediate — explicit chain building
openssl verify -CAfile root-ca.pem -untrusted intermediate-ca.pem server.pem
Download and verify the full chain from a live server
openssl s_client -connect docs.domusdigitalis.dev:443 -showcerts </dev/null 2>/dev/null | \
    awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' > full-chain.pem
openssl verify full-chain.pem
Check if private key matches certificate — the modulus must be identical
diff <(openssl x509 -noout -modulus -in server.pem) <(openssl rsa -noout -modulus -in server.key)

If the diff outputs nothing, they match. If it outputs content, you have a key/cert mismatch — the most common TLS deployment failure.

Cipher Suites

List ciphers supported by a server
nmap --script ssl-enum-ciphers -p 443 docs.domusdigitalis.dev
List ciphers your OpenSSL supports for TLS 1.3
openssl ciphers -v -tls1_3
List ciphers for TLS 1.2
openssl ciphers -v 'TLSv1.2' | awk '{print $1}' | sort
Test a specific cipher
openssl s_client -connect docs.domusdigitalis.dev:443 -cipher ECDHE-RSA-AES256-GCM-SHA384 </dev/null

OCSP Stapling

Check if a server supports OCSP stapling
openssl s_client -connect docs.domusdigitalis.dev:443 -status </dev/null 2>/dev/null | grep -A5 "OCSP Response"

If the output says OCSP Response Status: successful, stapling is working. If you see no response sent, the server is not stapling — clients will need to query the OCSP responder directly, adding latency.

Manual OCSP check — verify certificate revocation status
# Extract OCSP responder URL from the certificate
openssl x509 -in server.pem -noout -ocsp_uri

# Query the OCSP responder
openssl ocsp -issuer intermediate-ca.pem -cert server.pem \
    -url http://ocsp.example.com -resp_text

Certificate Transparency

Check CT logs for certificates issued for your domain
curl -s "https://crt.sh/?q=%.domusdigitalis.dev&output=json" | jq -r '.[] | "\(.not_before)\t\(.issuer_name)\t\(.common_name)"' | sort -r | head -20

This catches misissued or unauthorized certificates. Run periodically or set up monitoring.

Common TLS Errors and Fixes

Error: certificate verify failed — missing CA in trust store
# Diagnose: what CA signed this cert?
openssl s_client -connect internal.domusdigitalis.dev:443 </dev/null 2>/dev/null | openssl x509 -noout -issuer

# Fix: add your CA to the system trust store (Arch)
sudo cp domus-root-ca.pem /etc/ca-certificates/trust-source/anchors/
sudo update-ca-trust
Error: hostname mismatch — cert SAN doesn’t include the hostname
# Diagnose: what names does the cert cover?
openssl s_client -connect internal.domusdigitalis.dev:443 </dev/null 2>/dev/null | \
    openssl x509 -noout -ext subjectAltName
Error: certificate has expired — check both server and intermediate
openssl s_client -connect internal.domusdigitalis.dev:443 -showcerts </dev/null 2>/dev/null | \
    awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' | \
    while openssl x509 -noout -subject -dates 2>/dev/null; do echo "---"; done
Error: unable to get local issuer certificate — incomplete chain
# Server is not sending the intermediate. Fix: concatenate cert + intermediate
cat server.pem intermediate-ca.pem > fullchain.pem

HSTS Check

Verify HSTS header is present
curl -sI https://docs.domusdigitalis.dev | grep -i strict-transport-security

Expected: Strict-Transport-Security: max-age=31536000; includeSubDomains. The max-age should be at least 1 year (31536000 seconds).