When old becomes new
which have been in existence for many years. One of such multiplexors is C
select() statement which has been around forever. Securing software communication channels is one of the major issues
in today’s world, and, in this tutorial, we will examine how to read OpenSSL records using
select() multiplexor, should we decide to create our own secure event-driven library or the hot new
web server from ground up.
Traditional select() loop
The above code shows one way to implement a
select() read on non-encrypted socket connection. Basically, what happens above is we run select() statement, check if the file descriptor ready to be read in the
select set is a listening socket or an existing connected socket, and either accept new connection or read data on the existing connection. The actual read data operation is simple: for instance, we can
read bytes into
buffer_array from socket using
read statement as shown below.
OpenSSL can of worms
Let’s say we had to secure the above connection. We would probably use OpenSSL library and use
SSL_read statement instead to read and decrypt SSL record. Our read data operation could look like:
But implementing the above code,
select() could actually mislead the application and signal that SSL data is ready to read when, in fact, it is not ready. Why is that?
select() is solely concerned with the contents of the encrypted network buffer, while the
SSL_read reads the SSL buffer into which OpenSSL places the decrypted data.
SSL_read has to read the entire SSL record in order to deliver the first decrypted byte to the program, while
select() returns immediately after the first encrypted byte is ready,
creating the following situation:
select()call returns signalling encrypted data is ready to read.
SSL_readempties network buffer, but is not ready to deliver the decrypted data in the SSL buffer to the application due to decryption overhead.
select()call does not return since network buffer is empty.
And the solution
We need another SSL read loop to make
select() wait until SSL record is completely placed into SSL buffer and decrypted data becomes available:
And Voila! In the above code, we obtain number of readable bytes buffered in an SSL object through
SSL_pending function, and loop while there is still bytes to read. This loop makes select() wait
until we have the complete decrypted SSL record. For a more complete description, please read this excellent RTFM Inc. paper part 1 and
part 2 by Eric Rescorla which helped me solve this particular problem.
Activity diagram of SSL sockets + select()