Dmytro Shteflyuk created THRIFT-6120:
----------------------------------------
Summary: Ruby SSLServerSocket client timeout does not cover the
TLS handshake
Key: THRIFT-6120
URL: https://issues.apache.org/jira/browse/THRIFT-6120
Project: Thrift
Issue Type: Bug
Components: Ruby - Library
Reporter: Dmytro Shteflyuk
Assignee: Dmytro Shteflyuk
h3. Problem
{{Thrift::SSLServerSocket}} applies {{client_timeout}} only after
{{OpenSSL::SSL::SSLServer#accept}} has completed. That accept call performs the
TLS handshake before the accepted connection is wrapped in a
{{Thrift::Socket}}, so the configured timeout cannot interrupt a client that
opens TCP but does not finish TLS negotiation.
h3. Client impact
A client that connects and then sends no TLS handshake data, or sends only a
partial handshake, can leave the server blocked in {{accept}} beyond the
configured client timeout. In {{SimpleServer}}, accepting connections happens
on the server thread, so no later client can be accepted until that handshake
completes or the peer disconnects.
Successful TLS connections are unaffected; the problem is that the timeout
begins too late to cover the TLS setup it is expected to bound.
h3. Reproduction
>From {{lib/rb}}, run the following against the current implementation:
{code:ruby}
require "openssl"
require "socket"
require "thrift"
context = OpenSSL::SSL::SSLContext.new
context.cert = OpenSSL::X509::Certificate.new(
File.read("../../test/keys/server.crt")
)
context.key = OpenSSL::PKey::RSA.new(
File.read("../../test/keys/server.key")
)
server = Thrift::SSLServerSocket.new(
"127.0.0.1",
0,
context,
client_timeout: 0.05
)
server.listen
client = TCPSocket.new(
"127.0.0.1",
server.to_io.local_address.ip_port
)
accept_thread = Thread.new { server.accept }
sleep 0.2
puts(
"configured_client_timeout=0.05 " \
"accept_still_blocked_after=0.2 " \
"timed_out=#{accept_thread.alive?}"
)
client.close
accept_thread.join
server.close
{code}
The configured timeout is 50 milliseconds, but after 200 milliseconds the
accept operation is still blocked:
{code}
configured_client_timeout=0.05 accept_still_blocked_after=0.2 timed_out=true
{code}
The same behavior occurs when the peer sends an incomplete TLS handshake and
then stops.
h3. Expected behavior
The configured client timeout should apply to TLS negotiation as one monotonic
deadline. If the handshake does not complete in time, the accepted socket
should be closed and {{accept}} should raise a typed TLS error so the server
can continue accepting other connections. A completed TLS handshake should
still return a normal {{Thrift::Socket}} with the configured timeout.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)