Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ALPN problem: IIS aborts the TLS handshake for HTTP 1.0 requests #12259

Closed
mkauf opened this issue Nov 3, 2023 · 9 comments
Closed

ALPN problem: IIS aborts the TLS handshake for HTTP 1.0 requests #12259

mkauf opened this issue Nov 3, 2023 · 9 comments
Labels

Comments

@mkauf
Copy link
Contributor

mkauf commented Nov 3, 2023

I did this

Connect to a Microsoft IIS 10 server with HTTP 1.0:

$ curl -v --http1.0 https://my-iis-server/
* Host my-iis-server:443 was resolved.
* IPv6: (none)
* IPv4: 172.18.6.91
*   Trying 172.18.6.91:443...
* Connected to my-iis-server (172.18.6.91) port 443
* ALPN: curl offers http/1.0
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* Recv failure: Connection reset by peer
* OpenSSL SSL_connect: Connection reset by peer in connection to my-iis-server:443 
* Closing connection
curl: (35) Recv failure: Connection reset by peer

IIS aborts the TLS handshake with a TCP reset (RST) after the "client hello" message.

This is a regression, it works with curl 7.87.0 and earlier.

The root cause of the problem is the ALPN protocol that curl sends to the server. curl 7.88.0 has started to send "http/1.0" (commit df856cb, discussion #10183). Earlier curl versions use the ALPN protocol "http/1.1", even for HTTP 1.0 requests.

My guess is that the IIS server does not know the ALPN protocol "http/1.0". The original ALPN specification does not contain "http/1.0", but it contains "http/1.1".

Side note: Firefox also uses the ALPN protocol "http/1.1" even if the setting "network.http.version" is set to "1.0".

This hack fixes the problem:

diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h
index 2e65e6303..a7d76fcc9 100644
--- a/lib/vtls/vtls_int.h
+++ b/lib/vtls/vtls_int.h
@@ -33,7 +33,7 @@
 #define ALPN_HTTP_1_1_LENGTH 8
 #define ALPN_HTTP_1_1 "http/1.1"
 #define ALPN_HTTP_1_0_LENGTH 8
-#define ALPN_HTTP_1_0 "http/1.0"
+#define ALPN_HTTP_1_0 "http/1.1"
 #define ALPN_H2_LENGTH 2
 #define ALPN_H2 "h2"
 #define ALPN_H3_LENGTH 2

Workaround: Use the parameter --no-alpn.

I expected the following

Successful transfer

curl/libcurl version

curl 8.5.0-DEV (x86_64-pc-linux-gnu) libcurl/8.5.0-DEV OpenSSL/3.0.9 nghttp2/1.52.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTP2 HTTPS-proxy IPv6 Largefile NTLM SSL threadsafe TLS-SRP UnixSockets

operating system

Fedora Linux 38

@bagder
Copy link
Member

bagder commented Nov 3, 2023

The IANA registry clearly says that ALPN for HTTP/1.0 is http/1.0.

I think this rather indicates that the server is wrong and curl is right.

@bagder bagder added the TLS label Nov 3, 2023
@mkauf
Copy link
Contributor Author

mkauf commented Nov 3, 2023

Is the ALPN protocol "http/1.0" mentioned in any RFC? I don't understand why it's in the IANA registry.

It's a backwards compatibility issue. At the time ALPN was invented, the only known ALPN protocols were "http/1.1", "spdy/1", "spdy/2" and "spdy/3", so there was no other choice but to also use "http/1.1" for HTTP 1.0.

From https://httpd.apache.org/docs/2.4/en/mod/core.html#protocols :

By default, only the http/1.1 protocol (which includes the compatibility with 1.0 and 0.9 clients) is allowed.

So in practice the ALPN protocol "http/1.1" probably means "HTTP 1.x".

@bagder
Copy link
Member

bagder commented Nov 3, 2023

Is the ALPN protocol "http/1.0" mentioned in any RFC? I don't understand why it's in the IANA registry.

That's not how it works. ALPN is an RFC and a mechanism to negotiate the underlying protocol. any protocol. They are negotiated using "Protocol IDs". The IANA registry lists all those valid and official protocol ids. http/1.0 is one of those. As you can se in the list, there are plenty. The registry is mentioned in the RFC.

So in practice the ALPN protocol "http/1.1" probably means "HTTP 1.x".

Possibly, for some legacy servers sure. The question is still what curl should do about it. Willingly just send the wrong Id just because there might be some wrong servers out there or simply let users use --no-alpn or stick to HTTP/1.1...

After all, going HTTP/1.0 is a very special situation to begin with.

@bagder
Copy link
Member

bagder commented Nov 3, 2023

We can very well imagine that there are also servers that will reject HTTP/1.0 requests if we used the http/1.1 ALPN protocol, as that is a discrepancy and such are usually frowned upon in protocols as they often lead to security issues down the line.

@bagder
Copy link
Member

bagder commented Nov 5, 2023

@icing any thoughts on what the best way forward could be here?

@icing
Copy link
Contributor

icing commented Nov 6, 2023

A HTTP server supporting HTTP/1.1 and HTTP/1.0 will always have to detect the version in play from the request parsed. It is a property of the request, not the connection while ALPN is a property of the connection.

One could say that after seeing ALPN http/1.1 a server may reject HTTP/1.0 requests on that connection. But in practice, I do not see anyone doing that. Instead, all http/1.* ALPN values will switch to HTTP/1.* processing on that connection. And that was the intended behaviour when introducing ALPN, to differentiate between h2 and "use HTTP/1.* processing" when seeing http/1.1.

That IIS is rejecting http/1.0 seems a consequence of them saying "we support h2 and http/1.1 here and this is neither of those, so we disengage. Apache chose another path with anything not specifically recognised being fed to HTTP/1.* - same as when no ALPN is used by the client. It can be debated which is the better approach.

I think for curl it would suit users better to send http/1.1 ALPN even if it knows the request itself is formulated as HTTP/1.0. The addition of http/1.0 to IANA's ALPNs was not a good idea, IMO.

@bagder
Copy link
Member

bagder commented Nov 6, 2023

Thank you both. @mkauf, will you make that into a PR?

@mkauf
Copy link
Contributor Author

mkauf commented Nov 6, 2023

@bagder Yes, I will create a PR

mkauf added a commit to mkauf/curl that referenced this issue Nov 6, 2023
Some servers don't support the ALPN protocol "http/1.0" (e.g. IIS 10),
avoid it and use "http/1.1" instead.

This reverts commit df856cb (curl#10183).

Fixes curl#12259
Closes #...
mkauf added a commit to mkauf/curl that referenced this issue Nov 6, 2023
Some servers don't support the ALPN protocol "http/1.0" (e.g. IIS 10),
avoid it and use "http/1.1" instead.

This reverts commit df856cb (curl#10183).

Fixes curl#12259
Closes #...
@mkauf
Copy link
Contributor Author

mkauf commented Nov 7, 2023

Note that IIS responds with HTTP/1.1 to a HTTP/1.0 request. This is expected, see https://serverfault.com/a/1059873

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

3 participants