Skip to content

rustls: handle EOF during initial handshake#21242

Closed
kpcyrd wants to merge 3 commits into
curl:masterfrom
kpcyrd:rustls-handshake-eof
Closed

rustls: handle EOF during initial handshake#21242
kpcyrd wants to merge 3 commits into
curl:masterfrom
kpcyrd:rustls-handshake-eof

Conversation

@kpcyrd
Copy link
Copy Markdown
Contributor

@kpcyrd kpcyrd commented Apr 6, 2026

I noticed curl built with vtls-rustls gets stuck if the server closes the connection immediately without writing anything.

This adds a check if rustls_connection_read_tls had returned 0, which is also interpreted as EOF in the demo client:

https://github.com/rustls/rustls-ffi/blob/3f6476095541972da158226746a5d73e70842056/librustls/tests/client.c#L747-L752

Things I'm not sure about regarding this patch:

  • Should I set peer_closed in this case or leave it unmodified?
  • Is there a style guide for "check == 0 or < 0 first"?
  • Is "Connection closed abruptly" the correct/best error message for this situation?
    • Changed to TLS connect error: Connection closed abruptly
  • Is CURLE_RECV_ERROR the best error code for this?
    • Changed to CURLE_SSL_CONNECT_ERROR

Also happy to add a unit/integration test for this when pointed in the right direction.

cc: @cpu

Steps to reproduce

socat TCP-LISTEN:4443,fork /dev/null

Before this patch

% curl -v https://localhost:4443      
* Host localhost:4443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:4443...
* connect to ::1 port 4443 from ::1 port 37120 failed: Connection refused
*   Trying 127.0.0.1:4443...
* ALPN: curl offers h2,http/1.1

[hangs]

With this patch

% ./src/curl -v https://localhost:4443
* Host localhost:4443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:4443...
* connect to ::1 port 4443 from ::1 port 35140 failed: Connection refused
*   Trying 127.0.0.1:4443...
* ALPN: curl offers h2,http/1.1
* Connection closed abruptly
* closing connection #0
curl: (56) Connection closed abruptly
%

@github-actions github-actions Bot added the TLS label Apr 6, 2026
@kpcyrd kpcyrd force-pushed the rustls-handshake-eof branch 3 times, most recently from 10e1be4 to c1360c7 Compare April 6, 2026 17:42
Copy link
Copy Markdown
Contributor

@cpu cpu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This diff looks good to me from the rustls-ffi API usage perspective.

I have less input to offer w.r.t the error choice + message, or the right place to consider test coverage (though I do agree it feels like there's a gap here!). Hopefully one of the friendly neighborhood curl gurus has some opinions on these topics.

@kpcyrd
Copy link
Copy Markdown
Contributor Author

kpcyrd commented Apr 7, 2026

There is one failing test on windows, but I'm not sure why, I can't identify the error and there should be no side-effect on schannel.

@bagder bagder requested a review from icing April 8, 2026 11:01
Copy link
Copy Markdown
Contributor

@icing icing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

@kpcyrd
Copy link
Copy Markdown
Contributor Author

kpcyrd commented Apr 8, 2026

I noticed openssl curl has the following output:

% /usr/bin/curl -v 'https://localhost:4443/'
* Host localhost:4443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:4443...
* connect to ::1 port 4443 from ::1 port 54966 failed: Connection refused
*   Trying 127.0.0.1:4443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust Anchors:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
* TLSv1.3 (OUT), TLS alert, decode error (562):
* TLS connect error: error:0A000126:SSL routines::unexpected eof while reading
* closing connection #0
curl: (35) TLS connect error: error:0A000126:SSL routines::unexpected eof while reading

I guess adding TLS connect error: and status code 35 seems sensible?

@cpu
Copy link
Copy Markdown
Contributor

cpu commented Apr 8, 2026

In case it's helpful, I tried to take a crack at writing a regression unit test: cpu@eb4ae39 I verified locally that it failed with c1360c7 reverted, as expected. Feel free to cherry-pick it in here, or otherwise fiddle with it further if folks don't like the location/approach used.

kpcyrd and others added 3 commits April 9, 2026 13:59
Test that connecting to a server that immediately closes the connection
produces an error instead of hanging/timing out.
@kpcyrd kpcyrd force-pushed the rustls-handshake-eof branch from c1360c7 to e3e18a9 Compare April 9, 2026 12:10
@github-actions github-actions Bot added the tests label Apr 9, 2026
@bagder bagder closed this in ce05754 Apr 10, 2026
@bagder
Copy link
Copy Markdown
Member

bagder commented Apr 10, 2026

Thanks!

@kpcyrd kpcyrd deleted the rustls-handshake-eof branch April 30, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

4 participants