49

I'm looking for a simple way to know if a server is using the Server Name Indication SSL extension for its HTTPS certificate on a website. A method that uses either a browser or Unix command line is fine.

Thanks!

spookylukey
  • 593
  • 1
  • 4
  • 6

3 Answers3

38

The one liner you are probably looking for to detect the presence of a SSL/TLS Server Name Indication extension header is:

openssl s_client -servername www.SERVERNAME.com -tlsextdebug -connect www.YOURSERVER.com:443 2>/dev/null | grep "server name"

where www.SERVERNAME.com is the SNI value you're testing and www.YOURSERVER.com is the domain name or IP address of the TLS-capable server you're testing.

The command line uses openssl's s_client (see s_client(1)) to connect to the server at www.YOURSERVER.com on port 443. The -tlsextdebug option turns on TLS extension debugging output. The -servername option tells the s_client program to pass www.SERVERNAME.com as the value of the SNI field in the ClientHello packet during the TLS handshake.

Finally, 2>/dev/null simply hides stderr output (which can be noisy), and the | grep "server name" pipeline filters stdout to display the TLS extension called "server name" in s_client's TLS extension debugging output.

If you see a line of output such as

TLS server extension "server name" (id=0), len=0

then the server is returning SNI header information in its ServerHello response. If you don't, then it's possible the server either does not support SNI or it has not been configured to return SNI information given the name you're asking for. In this case, double-check that you are using a domain name in the -servername option that the server should respond with SNI information about.

M12
  • 481
  • 4
  • 2
  • 1
    Output is the same whether I use correct `-servername` or not. `-servername sdfsdlkfjsdf23.somedomain.somewhere -connect realhost.somedomain.somewhere` = `TLS server extension "server name" (id=0), len=0` (And same output if they match.) How do you verify it doesn't match a host on server from output? – B. Shea Jan 09 '19 at 15:17
  • 1
    @bshea You need to pass `-msg` in addition to the paramters above and grep for "Alert". If the `-servername` is wrong you will get something like `TLS 1.2 Alert ... warning unrecognized_name` from the server. @Meitar I think if you add that to the answer will be useful for other people. – Viktor Nonov Feb 19 '19 at 22:02
  • @ViktorNonov The `-msg` switch simply adds a hexdump of TLS protocol messages. It is not required to observe a TLS handshake error, so would be incorrect to add to this answer. Moreover, TLS handshake errors like this are printed to STDOUT, which would mean that the `2>/dev/null` would need to be removed from the answer in order for it to be processed by `grep` in the first place. What @bshea is actually asking for is "How do I detect TLS errors?" which is a different question entirely to the question of "Does this server utilize the SNI feature of the TLS protocol?" which is the topic here. – M12 Feb 28 '19 at 06:01
  • @Meitar, I couldn't find another way to observe the TLS handshake messages. Also even if I redirect the `STDERR` to a text file, I'm not getting that error there. Without `-msg` I couldn't find other option that shows the handshake messages. (using openssl 1.0.2q). As long as the relevance to the answer you might be right. – Viktor Nonov Feb 28 '19 at 19:02
26

SNI is initiated by the client, so you need a client that supports it. Unless you're on windows XP, your browser will do. If your client lets you debug SSL connections properly (sadly, even the gnutls/openssl CLI commands don't), you can see whether the server sends back a server_name field in the extended hello. Note that the absence of this field only means that the server didn't use the server_name in the client hello to help pick a certificate, not that it doesn't support it.

So, in practice the easiest test is to simply try connecting. For this you need to know two names that resolve to the same IP, to which an ssl connection can be made. https is easiest as you can then simply browse to both names and see if you're presented with the correct certificate.

There are three outcomes:

  • You get a wildcard certificate (or one with a subjectAltName) which covers both names: you learn nothing
  • You get the wrong certificate for at least one of them: either the server does not support SNI or it has been configured wrong
  • You get two different certificates, both for the correct name: SNI is supported and correctly configured.

A slightly more complicated test which will yield more info is to have wireshark open and capturing while browsing. You can then find the relevant packets by filtering for ssl.handshake. The screenshots below are an example of a client hello/server hello pair where SNI is supported:

Client hello Server hello

Again, of course the absence of a server_name field in the server hello does not indicate that SNI is not supported. Merely that the client-provided server_name was not used in deciding which certificate to use.

Dennis Kaarsemaker
  • 18,793
  • 2
  • 43
  • 69
  • 11
    Dennis - disagree on `openssl`. Some details are available: `openssl s_client -servername alice.sni.velox.ch -tlsextdebug -msg -connect alice.sni.velox.ch:443` Some indication of using SNI is given during the Qualys [SSL test](https://www.ssllabs.com/ssltest/). – Deer Hunter May 09 '13 at 17:37
  • 1
    Ah, I missed that in the manpage. Thanks for the addition. – Dennis Kaarsemaker May 09 '13 at 17:40
-1

You can use openssl to fetch and query the certificate.

  • fetch the cert with openssl s_client -connect
  • parse the cert with openssl x509
  • grep to find the "DNS:" info

openssl s_client -connect alice.sni.velox.ch:443 | openssl x509 -noout -text | grep DNS:

% openssl s_client -connect alice.sni.velox.ch:443 | openssl x509 -noout -text | grep DNS:
depth=2 C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2
verify return:1
depth=1 C = BM, O = QuoVadis Limited, CN = QuoVadis Global SSL ICA G2
verify return:1
depth=0 C = CH, ST = Zuerich, L = Zuerich, O = Kaspar Brand, CN = alice.sni.velox.ch
verify return:1
                DNS:alice.sni.velox.ch, DNS:carol.sni.velox.ch

The last line shows all the SNI entries present in the certficate:

                DNS:alice.sni.velox.ch, DNS:carol.sni.velox.ch
spazm
  • 125
  • 3
  • What am I looking for in that output? The fact that multiple domains are present? – spookylukey May 16 '15 at 20:32
  • The `DNS:...` entries on the last line show all the valid SNI names in the certificate. – spazm May 21 '15 at 23:50
  • 4
    SANs in a certificate and SNI support on a server are different things, the use of SANs for HTTPS virtualhosting is something of hack that predates SNI. For SNI you don't need a certificate with SANs because the server is able to select an individual certificate that matches the clients naming expectations. – mr.spuratic Jan 19 '16 at 15:33