I have a website, accessible with HTTP over TLS. It is multi-homed, so there are several A DNS entries for the hostname. Additionally, there are several websites, with several hostnames, on the same set of IP addresses, so this is all setup with a few NameVirtualHost in Apache 2.
Accessing the website with a browser, or a WebDAV client, etc works like a charm.
But when I try to connect with "openssl s_client", I cannot for the life of me get it to work. Apache throws a 400 "Bad Request" error at me. Apache selects the correct X.509 certificate, so the SNI must have been set correctly by openssl. This happens as soon as I press "enter" on the "GET" line, even before I can add any header. The HTTP syntax I use (basically "GET / HTTP/1.1\nHost: hostname" works on the non-TLS version of the website (which only redirects to the TLS version), so that should not be the problem. The same HTTP syntax also works to connect to e.g. www.google.com over TLS (port 443), so again it looks correct.
Logs of the Apache server show a request with a trailing newline, maybe that's a hint. The log entry goes to the one for the default VirtualHost for that IP/port although Apache sent the X.509 certificate for the hostname I connect to, which is different from the default.
I have checked with wireshark that SNI is set in the ClientHello.
Here's an example session:
INPUT $ openssl s_client -connect hostname:443
OUTPUT
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = hostname verify return:1 --- Certificate chain 0 s:CN = hostname i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 i:O = Digital Signature Trust Co., CN = DST Root CA X3 --- Server certificate -----BEGIN CERTIFICATE----- (...) -----END CERTIFICATE----- subject=CN = hostname issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 --- No client certificate CA names sent Peer signing digest: SHA256 Peer signature type: RSA-PSS Server Temp Key: X25519, 253 bits --- SSL handshake has read 3121 bytes and written 388 bytes Verification: OK --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 2048 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) --- --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 Session-ID: FBFD6172E3C659D4071B68A36BD5983A8571906C00190A745B5DAA1359D4087C Session-ID-ctx: Resumption PSK: 21957A3C267DAA25CE2D7F6BFD3C3593CCFA1E6FC45C4DC5D0CE35C29175F7E9BBDD59EE6C213DC53B8291B7BD055238 PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 300 (seconds) TLS session ticket: 0000 - 18 4b 25 ae 49 61 e8 f3-73 b5 bb 3b 50 2f 1d c4 .K%.Ia..s..;P/.. 0010 - 7e 02 e9 41 01 9e ed 8b-a1 b6 ec 48 4d 12 11 f2 ~..A.......HM... Start Time: 1602857943 Timeout : 7200 (sec) Verify return code: 0 (ok) Extended master secret: no Max Early Data: 0 --- read R BLOCK --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 Session-ID: 627DF7810556DB2918484F393E66DEA7BF22DD3A42288B47E46FCDCDEF176125 Session-ID-ctx: Resumption PSK: 851978077C93284CB3D69B541B77844A48D1CFC8800F60B6F7CF3D297911D0D93E0E935017B78777E2BD51A29E13329F PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 300 (seconds) TLS session ticket: 0000 - c0 1a 60 23 36 80 bf 27-83 0e 1f 26 4b 04 f2 53 ..`#6..'...&K..S 0010 - a0 8a 2d 6e 41 44 17 c7-9b 11 5d dc 7f 08 71 fc ..-nAD....]...q. Start Time: 1602857943 Timeout : 7200 (sec) Verify return code: 0 (ok) Extended master secret: no Max Early Data: 0 --- read R BLOCK INPUT (note no blank line after the first one) GET / HTTP/1.1
OUTPUT
Date: Fri, 16 Oct 2020 14:19:11 GMT Server: Apache/2.4.38 (Debian) Content-Length: 322 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> <hr> <address>Apache/2.4.38 (Debian) Server at default_hostname Port 443</address> </body></html> closed Note: the error message mentions default_hostname, not hostname!
The corresponding Apache log entry is: default_hostname:443 1.2.3.4 - - [16/Oct/2020:16:19:11 +0200] "GET / HTTP/1.1\n" 400 3279 "-" "-"
Note that default_hostname IS NOT hostname and that Apache sent the correct server certificate, so it has identified the correct VirtualHost! If I connect without SNI (openssl s_client -connect 4.3.2.1:443) then it sends the server certificate for default_hostname.