Yes, option 2 is the right way to go. Create a BIO pair with BIO_make_bio_pair()
, and assign them to the SSL object with SSL_set_bio()
.
You then read the encrypted-side SSL data with BIO_read()
and write it to the libssh tunnel, and read from the libssh tunnel and write it with BIO_write()
.
Addendum:
When you use this method, your SSL object doesn't have a file descriptor of its own - the BIOs replace the file descriptor / socket. Instead of reading and writing from a file descriptor, OpenSSL will read and write from the BIOs you provided.
The BIOs are simply an interface that sit between the OpenSSL library and your own code. They're a way for you to implement the actual shipping of the encrypted-side SSL data to and from the other side (instead of OpenSSL directly using a socket).
When you do a BIO_read()
on the BIO you provided as wbio
to SSL_set_bio()
, you will read the encrypted-side SSL data, and you must then send this on to the other side yourself (presumably using some libssh2
function). Similarly, when you recieve encrypted-side SSL data from the other side (again, from some libssh2
function), you pump it into SSL by using BIO_write()
on the BIO you provided as the rbio
.
Perhaps this illustration will help. When you read and write from the SSL object, OpenSSL will just read and write from the underlying BIO, leaving the data there for you to deal with later:
+------+ +-----+ +-----+
| Your | SSL_write() | SSL | BIO_read() | BIO |
| code | ------------> | | <------------ | |
| | | | | |
| | | | BIO_write() | |
| | | | ------------> | |
+------+ +-----+ +-----+
+------+ +-----+ +-----+
| Your | SSL_read() | SSL | BIO_read() | BIO |
| code | <----------- | | <------------ | |
| | | | | |
| | | | BIO_write() | |
| | | | ------------> | |
+------+ +-----+ +-----+
(Note, though, that an SSL_write()
may cause a read from the underlying BIO, and vice-versa).
When there is data in the wbio
, you must read it and ship it to the other side:
+------+ +-----+
| Your | BIO_read() | BIO |
| code | <----------- | |
| | +-----+
| | +---------+
| | libssh2_channel_write() | libssh2 |
| | ------------------------> | | -> (... to other side)
| | +---------+
+------+
Conversely, when there is data available from the other side, you should read it and pass it into the rbio
:
+------+
| Your | +---------+
| code | libssh2_channel_read() | libssh2 |
| | <----------------------- | | -> (... from other side)
| | +---------+
| | +-----+
| | BIO_write() | BIO |
| | -----------> | |
| | +-----+
+------+