openssl icon indicating copy to clipboard operation
openssl copied to clipboard

Non-blocking socket not handled correctly.

Open ioquatix opened this issue 2 years ago • 4 comments

https://github.com/ruby/openssl/blob/94fb921540fe49d3842b0ae562efbfea62a42901/ext/openssl/ossl_ssl.c#L2124

According to the documentation, SSL_shutdown can:

If the underlying BIO is nonblocking, SSL_shutdown() will also return when the underlying BIO could not satisfy the needs of SSL_shutdown() to continue the handshake. In this case a call to SSL_get_error() with the return value of SSL_shutdown() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_shutdown(). The action depends on the underlying BIO. When using a nonblocking socket, nothing is to be done, but select() can be used to check for the required condition. When using a buffering BIO, like a BIO pair, data must be written into or retrieved out of the BIO before being able to continue.

I don't know if we need to explicitly handle this when in non-blocking mode or not, but I'd assume so until otherwise confirmed/checked.

ioquatix avatar Mar 19 '23 19:03 ioquatix

The underlying socket is always set to non-blocking by us in SSLSocket#initialize.

That SSL_shutdown() is not retried on error is a known issue, but I'm not sure how we're supposed to fix it.

https://github.com/ruby/openssl/blob/94fb921540fe49d3842b0ae562efbfea62a42901/ext/openssl/ossl_ssl.c#L2130-L2136

Would it be acceptable for IOish#close to potentially block? I have an impression it could be surprising.

rhenium avatar Jun 06 '23 18:06 rhenium

I think it's okay. IO#close can block in some cases.

ioquatix avatar Jan 25 '24 04:01 ioquatix

I don't know about other IO, but as far as I understand TCP sockets' #close can only block with the setsockopt(SO_LINGER) option.

I think the blocking behavior (ensuring close_notify to be sent) needs the user's explicit request. Changing the default behavior can be a DoS issue as I think people usually call SSLSocket#close without a timeout.

Perhaps we can just expose SSL_shutdown() as a new method?

rhenium avatar Feb 05 '24 10:02 rhenium

Maybe in the first instance we can log when it fails, and then collect data about how frequently it happens?

I think we could consider exposing SSL_shutdown as part of https://github.com/ruby/openssl/issues/609

ioquatix avatar Feb 05 '24 11:02 ioquatix