1

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.

2 Answers 2

2

... "GET / HTTP/1.1\n" 400 3279 "-" "-"

The line ending in a HTTP request should be \r\n and not \n. Try the -crlf option of s_client to translate an Enter into \r\n instead of only \n.

Also the server might have some limit in which time the request should be fully sent and it might not be fast enough to just type everything. Try cut+paste a pre-created request from a text file instead.

1
  • Yes, the -crlf option did it. Thanks. (Speed of typing was not the issue.) Commented Oct 17, 2020 at 18:02
1

You did actually send a malformed request. HTTP/1.1 requires the presence of the Host: header, and further with SNI, the content of the Host: header must match the SNI hostname.

Try again and this time provide the correct Host: header.

3
  • I cannot add any header. The error comes before I can put any header, as soon as I press "enter" after "HTTP/1.1". AFAIK, there must be a newline between the HTTP request and its headers. I don't mean an empty line! a newline to terminate the request line. The error appears as soon as I add that terminating newline. I apologise if I wasn't clear enough about that in my question, I thought I had explained it. Commented Oct 16, 2020 at 15:09
  • @LionelElieMamane That is rather strange. I can't reproduce it here. I don't get a response until I press enter twice. Check your keyboard, your terminal emulator, and maybe your openssl version? Commented Oct 16, 2020 at 15:15
  • The extra-double strange thing is that I can connect to e.g. www.google.com over TLS just alright with exactly the same setup (same openssl on the same machine with same keyboard and same terminal emulator). I type "GET / HTTP/1.1" then enter, then "Host: www.google.com" then enter twice, works right. Connecting to my Apache 2 on two different machines (different websites), I get the error as soon as I press enter after "GET / HTTP/1.1". Commented Oct 16, 2020 at 15:32

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.