curl and sni-enabled server

Solution 1:

The host header has nothing to do with SNI. To use SNI you have to use the hostname in the URL, i.e. use https://example.com/ instead of http://1.2.3.4/ (and of course use https:// not http://).

More details: SNI sends the hostname inside the TLS handshake (ClientHello). The server then chooses the correct certificate based on this information. Only after the TLS connection is successfully established it will send the HTTP-Request, which contains the Host header you specified.

Regarding your edit/comments:

  • I wonder how you've accessed the site successfully with the browser if there is no DNS entry for the host. If the browser does not know the hostname it cannot use SNI either.
  • If you add the host/ip mapping to /etc/hosts it will work when accessing https://example.com with curl because you know you have the hostname for SNI and the matching IP for the TCP connection.
  • Your ruby code sets ssl_client.hostname. This is not the same as the HTTP host header you've set with curl.
  • I don't see an option for curl where you could set hostname for TLS SNI and IP for TCP connection independently.

Solution 2:

Finally found the answer after referring to this.

curl --cacert CustomCA.crt --resolve example.com:443:1.2.3.4 https://example.com/foo