I have a x.example
which serves traffic for both a.example
and b.example
.
x.example
has certificates for both a.example
and b.example
. The DNS for a.example
and b.example
is not yet set up.
If I add an /etc/hosts
entry for a.example
pointing to x.example
's ip and run curl -XGET https://a.example
, I get a 200.
However if I run curl --header 'Host: a.example' https://x.example
, I get:
curl: (51) SSL: no alternative certificate subject name matches target host name x.example
I would think it would use a.example as the host. Maybe I'm not understanding how SNI/TLS works.
Because a.example
is an HTTP header the TLS handshake doesn't have access to it yet? But the URL itself it does have access to?
Indeed SNI in TLS does not work like that. SNI, as everything related to TLS, happens before any kind of HTTP traffic, hence the Host
header is not taken into account at that step (but will be useful later on for the webserver to know which host you are connecting too).
So to enable SNI you need a specific switch in your HTTP client to tell it to send the appropriate TLS extension during the handshake with the hostname value you need.
In case of curl
, you need at least version 7.18.1 (based on https://curl.haxx.se/changes.html) and then it seems to automatically use the value provided in the Host
header. It alo depends on which OpenSSL (or equivalent library on your platform) version it is linked to.
See point 1.10 of https://curl.haxx.se/docs/knownbugs.html that speaks about a bug but explains what happens:
When given a URL with a trailing dot for the host name part: "https://example.com./", libcurl will strip off the dot and use the name without a dot internally and send it dot-less in HTTP Host: headers and in the TLS SNI field.
The --connect-to
option could also be useful in your case. Or --resolve
as a substitute to /etc/hosts
, see https://curl.haxx.se/mail/archive-2015-01/0042.html for am example, or https://makandracards.com/makandra/1613-make-an-http-request-to-a-machine-but-fake-the-hostname
You can add --verbose
in all cases to see in more details what is happening. See this example: https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header ; you will also see there how to test directly with openssl
.
If you have a.example
in your /etc/hosts
you should just run curl with https://a.example/
and it should take care of the Host
header and hence SNI (or use --resolve
instead)