Inspect TLS
Connect with openssl s_client
Open a TLS connection, send the intended server name, and separate handshake output from application data.
openssl s_client is a TLS client for debugging. It opens a real TLS connection to a server and prints what happened during the handshake: which certificates the server sent, which protocol version and cipher were picked, and whether verification passed.
I reach for it every time a browser or an app gives me a vague TLS error. The browser hides the details. s_client shows them.
Let’s connect to a public HTTPS site:
openssl s_client -connect flaviocopes.com:443 -servername flaviocopes.com </dev/null
Two options matter here. -connect is the TCP target, host and port. -servername sends SNI (Server Name Indication), the hostname the client asks for during the handshake.
Why do we need to send the name twice? Because many servers host several sites on one IP address. They use SNI to pick the right certificate. Skip -servername and you can get a default certificate for a site you never asked about, or no certificate at all. Try -noservername against a site behind Cloudflare and the handshake fails with alert handshake failure.
The </dev/null part closes standard input right away. Without it, s_client sits there after the handshake, waiting for you to type an HTTP request. With it, the command exits as soon as the handshake is done.
What to read in the output
The output is long. These are the lines I look for:
Certificate chain
0 s:CN=flaviocopes.com
i:C=US, O=Google Trust Services, CN=WE1
1 s:C=US, O=Google Trust Services, CN=WE1
i:C=US, O=Google Trust Services LLC, CN=GTS Root R4
...
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
...
Verify return code: 0 (ok)
The Certificate chain block lists what the server sent. s: is the subject, the identity of the certificate. i: is the issuer, who signed it. The Protocol and Cipher lines tell you what the two sides agreed on.
Verify return code: 0 (ok) is the line that matters most. It means the chain validated against the trust store on your machine. Any other number names a specific failure. 10 is an expired certificate. 20 means OpenSSL could not find the issuer. We’ll meet both later in this course.
Be careful with what a 0 proves. It proves TLS works. The application behind it can still be down, return errors, or serve the wrong content. Treat s_client as a transport check, nothing more.
One habit to build from day one: s_client output ends up pasted in tickets and chat. Never put private keys or real client credentials in a diagnostic command. The output travels further than you think.
Lesson completed