Non-blocking SSL handshake

T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Hello. I'm attempting to use SSL within my Fiber-based Actor framework (
http://revactor.org) and running into problems incorporating SSL.

As far as I can discern, OpenSSL::SSL::SSLSocket#sysread and #syswrite are
non-blocking (please correct me if this is wrong) if the socket is in the
read/write ready state to begin with, which is great.

However, #connect and #accept, which (I believe) do the SSL handshaking,
both block.

Is there any way to do a non-blocking SSL handshake?
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

After investigating the issue some more, it appears that this is impossible
without a C extension.

The ossl_start_ssl() function in ossl_ssl.c, which is used by both
OpenSSL::SSL::SSLSocket#connect and #accept, contains a loop which calls
SSL_connect() or SSL_accept() repeatedly. If either of these functions
needs the socket to be in a readable or writable state,
rb_io_wait_readable() or rb_io_wait_writable() is called, blocking the
application.

Has there been any consideration as to adding something like
OpenSSL::SSL::SSLSocket#connect_nonblock and #accept_nonblock to go along
with Socket#connect_nonblock and Socket#accept_nonblock?
 
M

MenTaLguY

Has there been any consideration as to adding something like
OpenSSL::SSL::SSLSocket#connect_nonblock and #accept_nonblock to go along
with Socket#connect_nonblock and Socket#accept_nonblock?

I would favor this solution myself.

-mental
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

I would favor this solution myself.

-mental

Well, I managed to create a subclass of OpenSSL::SSL::SSLSocket in a C
extension which implements #connect_nonblock and #accept_nonblock. It was
quite a hack: #connect and #accept both call the static C function
ossl_ssl_setup(), which for whatever reason is not called from #initialize.

I managed to do it by finding a third method, #session=, which also calls
ossl_ssl_setup(). I couldn't really figure out what this is for... there's
a whole OpenSSL::SSL::Session class defined in ossl_ssl_session.c, but the
Init function for this file is never called, so while it's linked into the
OpenSSL C extension, it's not accessible in the Ruby environment.

I fed #session= a bogus parameter (nil), and fortunately the method calls
ossl_ssl_setup() before doing any typechecking on its arguments. This meant
I could catch the exception it threw due to the bogus argument, but
ossl_ssl_setup() was still called.

Changing the ossl_start_ssl() function that #connect and #accept call into a
non-blocking one was pretty trivial: I just had it raise exceptions for when
it needed more data to complete the connection, rather than calling
rb_io_wait_readable() / rb_io_wait_writable(). If there's any interest I
can contribute the code back to the OpenSSL extension, but since it's so
trivial I'd encourage someone on the OpenSSL team to implement it
themselves.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,233
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top