How to use openSSL with memory BIOs and non blocking sockets
Asked Answered
M

1

7

I'm new to openSSL and I trying to figure out what the best / good solution is to create a https connection when using non blocking sockets, and libraries such as libevent, libev or libuv in combination with memory BIOs.

I'm trying to figure out how to manage openSSL calls/data and application data. In short my understanding of how a ssl client application should work is something like this:

  • create SSL_CTX
  • create a new socket connection (e.g. I'm using libuv)
  • create two memory BIOs:
    • one is filled with data I receive from the server (readBio)
    • the other one is used to in the application code to read from. (writeBio)
  • create a SSL* and set state to SSL_connect_state
  • start the handshake process with SSL_do_handshake
  • [loop] receive / send data

As I'm using libuv (but this could be any other async/non-blocking library), I have a read callback that gets called when data is received on the socket. When I have data which must be written to the socket, I pass this data into a write function of the library (in this uv_write()), but in between this I need to put the calls to SSL.

So after calling SSL_do_handshake(...), SSL stores some data into the writeBIO which I must read and pass into the socket. One question I was thinking about, how do I know that SSL stores data into this BIO, and secondly how do I know when I should send this over the socket.

After looking at some code, I figured out that I had to consume from the writeBIO after calling SSL_do_handshake(). But the next steps are not clear to me. After s ending the first bytes from the handshake the 'event' loop of libuv sets everything in motion; when new data arrives on the socket my 'onread() callback is called. But how do I handle this incoming data? (e.g. do I keep SSL state myself (<-- something which some people have advised me not do to)).

Although I've seen lots of examples which use blocking sockets and the core SSL functions to make a connection I haven't found a good clean/minimalistic example which shows how to use memory BIOs as a client.

I've pasted some code I'm using to test openSSL here: https://gist.github.com/3989091

Someone around who can describe the process of using async/non-blocking sockets and memory BIOs with SSL?

Thanks R

Meader answered 31/10, 2012 at 18:57 Comment(1)
Is there some reason you can't use a socket BIO?Spindle
G
6

I've also put together a basic example of using memory BIO's with non-blocking sockets and a poll based event loop.

ssl_server_nonblock.c

I don' think it makes sense to post all the source code of that example here. But here is the outline of what the example code does.

Flow of encrypted & unencrypted bytes

This diagram shows how the read and write memory BIO's (rbio & wbio) are associated with the socket read and write respectively. On the inbound flow (data into the program) bytes are read from the socket and copied into the rbio via BIO_write. This represents the the transfer of encrypted data into the SSL object. The unencrypted data is then obtained through calling SSL_read. The reverse happens on the outbound flow to convey unencrypted user data into a socket write of encrypted data.

  +------+                                    +-----+
  |......|--> read(fd) --> BIO_write(rbio) -->|.....|--> SSL_read(ssl)  --> IN
  |......|                                    |.....|
  |.sock.|                                    |.SSL.|
  |......|                                    |.....|
  |......|<-- write(fd) <-- BIO_read(wbio) <--|.....|<-- SSL_write(ssl) <-- OUT
  +------+                                    +-----+

          |                                  |       |                     |
          |<-------------------------------->|       |<------------------->|
          |         encrypted bytes          |       |  unencrypted bytes  |
Gabrielegabriell answered 21/3, 2017 at 19:22 Comment(3)
A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.Trivalent
@Paul. There were no other answers to this question, and the link I provided gives a well documented code example that exactly answers the question. In fact, I developed the example code because I had the same question, and its wasn't answered anywhere on stack overflow. While I cannot guarentee the link will persist forever (its on github), while it does exist it provides value. And I don't think posting several sets of files here is feasible or the most helpful. Also, the example code has already evolved due to other contributors, so being on somewhere like github is preferable.Gabrielegabriell
very good example ... I'm especially unsure of how to deal with BIO errors ... it seems there's not much we can doJoeannjoed

© 2022 - 2024 — McMap. All rights reserved.