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

ssl: support IO-like object as the underlying transport #736

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

rhenium
Copy link
Member

@rhenium rhenium commented Mar 27, 2024

An implementation of #731. The test suite passes on my box, but it needs more testing especially around the error handling.

This adds support for IO-like object that is not backed by a file descriptor by defining a BIO_METHOD to wrap the following Ruby methods.

  • #read_nonblock(len, exception: false)
  • #write_nonblock(str, exception: false)
  • #wait_readable
  • #wait_writable
  • #flush
  • #closed?
  • #close

ext/openssl/ossl_bio.c Show resolved Hide resolved
ext/openssl/ossl_bio.c Show resolved Hide resolved
ext/openssl/ossl_bio.c Outdated Show resolved Hide resolved
ext/openssl/ossl_bio.c Show resolved Hide resolved
rb_io_set_nonblock(fptr);
}
else {
// Not meant to be a comprehensive check
Copy link
Contributor

Choose a reason for hiding this comment

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

as per the BIO impl, shouldn't this also verify "#flush"? (hypothetically, understand this wasn't as exhaustive check).

@@ -1735,6 +1805,11 @@ no_exception_p(VALUE opts)
static void
io_wait_writable(VALUE io)
{
if (!is_real_socket(io)) {
if (!RTEST(rb_funcallv(io, rb_intern("wait_writable"), 0, NULL)))
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't this be the same as the rb_io_maybe_wait_writable call below?

@HoneyryderChuck
Copy link
Contributor

@rhenium anything I can help with to move this forward?

@HoneyryderChuck
Copy link
Contributor

@rhenium friendly ping

The SSL ex_data index is used for storing the verify_callback Proc. The
only user of it, ossl_ssl_verify_callback(), can find the callback by
looking at the SSLContext object which is always known.
This is no longer necessary as of commit 22e601a (Remove usage of
IO internals. (ruby#627), 2023-05-29).
The result value is used for generating an informative error message.
Let's just say "unsupported" if it's not available.
The value is used to determine whether SSLSocket should skip buffering
in OpenSSL::Buffering or not. Defaulting to true (no buffering) should
be a safe option.
Implement a minimal BIO_METHOD required for SSL/TLS. The underlying
IO-like object must implement the following methods:

 - #read_nonblock(len, exception: false)
 - #write_nonblock(str, exception: false)
 - #flush

This will be used in a later commit with OpenSSL::SSL::SSLSocket.
OpenSSL::SSL::SSLSocket currently requires a real IO (socket) object
because it passes the file descriptor to OpenSSL.

OpenSSL internally uses an I/O abstraction layer called BIO to interact
with the underlying socket. BIO is pluggable; the implementation can be
supplied by a user application as long as it implements the necessary
BIO functions. We can make our own BIO implementation ("BIO method")
that wraps any Ruby IO-like object using normal Ruby method calls.

Support for such an IO-like object is useful for establishing TLS
connections on top of non-OS sockets, such as another TLS connection or
an HTTP/2 tunnel.

For performance reason, this patch continues to use the original socket
BIO if the user passes a real IO object.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants