Skip to content

Diagnosing a failed TLS handshake

The connection opened. The port is right, the routing is right, DNS is right — and the request still fails, with an error nobody can act on:

curl: (60) SSL certificate problem: unable to get local issuer certificate

Browsers make this worse by hiding the detail behind a friendly warning page and an "Advanced" link. curl and openssl don't, which is why every TLS investigation should start at a terminal.

The handshake article covered what the two sides exchange. This one is about the six ways it fails and how to identify which one you're looking at in a single command.

The command that shows you everything

openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null

Two flags carry the weight:

  • -connect names the host and port to open a TCP connection to.
  • -servername sets the SNI extension in the ClientHello — the field that tells a server which of the many sites it hosts you're asking for. openssl populates it from -connect when that looks like a DNS name, but setting it explicitly is the habit to build, because the moment you connect by IP address it stops being set and the server hands you the wrong certificate.

`