1. Library
  2. Tools and Commands
  3. Http Testing

Updated 10 hours ago

When an HTTPS connection fails, most tools just say "connection failed." They can't show you why. The encryption is a black box.

openssl s_client opens that box. It establishes an SSL/TLS connection to any server, performs the handshake, shows you every certificate in the chain, tells you what cipher was negotiated—and then hands you the keyboard. You're not observing a connection. You're making one. You become the client, speaking directly to the server, seeing exactly what it sends back.

Basic Usage

Connect to an HTTPS server:

openssl s_client -connect example.com:443

This establishes an SSL/TLS connection to port 443 and displays everything about the negotiation: certificate chain, TLS version, cipher suite, verification status.

What the Output Tells You

A successful connection shows:

CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Example, CN = example.com
verify return:1
---
Certificate chain
 0 s:C = US, ST = California, L = Los Angeles, O = Example, CN = example.com
   i:C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
 1 s:C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
   i:C = US, O = DigiCert Inc, CN = DigiCert Global Root CA
---
SSL handshake has read 3847 bytes and written 444 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384

The depth lines show certificate chain validation—depth 0 is the server's certificate, higher numbers are the chain leading to the root CA. verify return:1 means each certificate passed validation.

Speaking Protocols by Hand

Once connected, you can type protocol commands directly. For HTTPS:

openssl s_client -connect example.com:443

Then type:

GET / HTTP/1.1
Host: example.com

(Press Enter twice after the Host line.)

You'll see the raw HTTP response—headers and body—proving the encrypted connection works end-to-end.

Inspecting Certificates

Check expiration dates:

openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -dates
notBefore=Dec 15 00:00:00 2023 GMT
notAfter=Dec 14 23:59:59 2024 GMT

View full certificate details:

openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -text

Shows subject, issuer, validity period, public key, Subject Alternative Names (SANs), extensions, and signature algorithm.

Extract certificate to a file:

openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > cert.pem

Check Subject Alternative Names:

openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

Shows all domains covered by the certificate.

Essential Options

-servername (SNI)

Server Name Indication tells the server which certificate to present—critical when multiple sites share an IP:

openssl s_client -servername example.com -connect 93.184.216.34:443

Without this, you might get the wrong certificate or a handshake failure.

-showcerts

Display every certificate in the chain, not just the server's:

openssl s_client -showcerts -connect example.com:443

Essential for debugging "unable to get local issuer certificate" errors.

-starttls

For protocols that upgrade to TLS mid-connection:

# SMTP
openssl s_client -starttls smtp -connect mail.example.com:587

# IMAP
openssl s_client -starttls imap -connect mail.example.com:143

# POP3
openssl s_client -starttls pop3 -connect mail.example.com:110

-tls1_2, -tls1_3

Force a specific TLS version:

# Verify TLS 1.3 support
openssl s_client -tls1_3 -connect example.com:443

# Verify TLS 1.0 is disabled (should fail on secure servers)
openssl s_client -tls1 -connect example.com:443

-cipher

Test if a server supports a specific cipher:

openssl s_client -cipher 'ECDHE-RSA-AES256-GCM-SHA384' -connect example.com:443

Connection succeeds if supported, fails if not.

-CAfile

Use a custom CA certificate for validation:

openssl s_client -CAfile custom-ca.crt -connect internal.example.com:443

-cert and -key

For mutual TLS (client certificate authentication):

openssl s_client -cert client.crt -key client.key -connect example.com:443

-brief and -quiet

# Minimal output
openssl s_client -brief -connect example.com:443

# Suppress handshake info, show only protocol interaction
openssl s_client -quiet -connect example.com:443

Testing Different Protocols

# HTTPS
openssl s_client -connect example.com:443

# SMTPS (implicit TLS)
openssl s_client -connect mail.example.com:465

# SMTP with STARTTLS
openssl s_client -starttls smtp -connect mail.example.com:587

# IMAPS
openssl s_client -connect mail.example.com:993

# POP3S
openssl s_client -connect mail.example.com:995

# LDAPS
openssl s_client -connect ldap.example.com:636

Debugging Common Failures

"unable to get local issuer certificate"

The certificate chain doesn't reach a trusted root. Either the server isn't sending intermediate certificates, or you need to specify a CA file:

openssl s_client -showcerts -connect example.com:443

Check if intermediates are present. If not, the server is misconfigured.

"Hostname mismatch"

The certificate's CN or SANs don't include the hostname you're connecting to. Use -servername to specify the correct hostname for SNI.

"SSL handshake failure"

TLS negotiation failed—usually a cipher or version mismatch. Try forcing a specific version:

openssl s_client -tls1_2 -connect example.com:443

"wrong version number"

You connected with SSL to a plaintext port, or vice versa.

"Cipher is (NONE)"

No mutually supported cipher. The server and client have no cipher suites in common.

Testing Before DNS Changes

Validate a certificate on a new server before cutting over:

openssl s_client -servername example.com -connect 203.0.113.50:443

Connects to the IP directly while presenting the correct hostname for SNI and certificate validation.

Scripting Examples

Alert on expiring certificates:

#!/bin/bash
EXPIRY=$(openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 30 ]; then
  echo "WARNING: Certificate expires in $DAYS_LEFT days"
fi

Test TLS version support:

#!/bin/bash
for version in tls1 tls1_1 tls1_2 tls1_3; do
  echo -n "$version: "
  if openssl s_client -$version -connect example.com:443 </dev/null 2>/dev/null | grep -q "Cipher is"; then
    echo "supported"
  else
    echo "not supported"
  fi
done

Security Auditing

Test for weak ciphers:

# 3DES is weak—should fail on secure servers
openssl s_client -cipher 'DES-CBC3-SHA' -connect example.com:443

Check for Certificate Transparency:

openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep -A5 "CT Precertificate SCTs"

Verify HSTS header:

Connect with openssl s_client, send an HTTP request, and look for:

Strict-Transport-Security: max-age=31536000

Frequently Asked Questions About OpenSSL s_client

Was this page helpful?

😔
🤨
😃