Hi there,
I was lurking on this thread without replying until now because I'm damned
busy at the moment, and wasn't really sure what the beef was that started
all this ...
On Mon, 21 Aug 2000, Jeffrey Altman wrote:
> > Maybe, but I'm not sure what you mean exactly. Could you describe
> > in terms of an approximate example API?
>
> I think what he would like is the ability to do what the Microsoft
> SSPI does. Instead of OpenSSL being a layer between the I/O channel
> and the app, he would like the app to provide all I/O functions and
> have OpenSSL provide routines that encode and decode buffers provided
> to it by the application. After OpenSSL has done its work, the
> application transmits the outgoing data to the peer. After receiving
> data from the peer it calls OpenSSL to process it.
>
> Its a different model which has its advantages when working with
> applications that may not have direct access to the network socket and
> instead have its I/O handle by message passing.
This is already rather trivial, even if it doesn't immediately appear to
be so, with OpenSSL's API ... why people think they need to start writing
new wrappers or rearchitecting things is beyond me. I know this because I
have done, and continue to do, exactly what you've outlined - namely using
OpenSSL as a state-machine for "grinding the bytes" and providing all the
network operations from the calling application (here "network" can even
be virtual, ie using shared memory, message posting, whatever).
(1) Set up your SSL_CTX (client or server, doesn't particularly matter)
(2) Create a new SSL from that SSL_CTX
(3) Create new memory BIOs to represent the "dirty" side of the SSL stream
(4) set the read and write memory BIOS for the SSL
(5) call the SSL_set_connect/accept function you need depending on whether
it's an SSL server or client.
then new traffic arriving on your network sockets can be pumped into the
SSL state machine using SSL_write() from the clean side (usually this is
the locally generated data to send out) and BIO_write to the SSL's read
BIO from the dirty side (usually is the encrypted traffic from the
network). Likewise, data can be retrieved on either side (if there is
any available) by using SSL_read() on the clean side or BIO_read on the
SSL's write BIO.
The trick (well one of them anyway) is to remember that although an SSL
structure has bi-directional activity on both the "clean" and "dirty"
sides, data arriving on one side does not automatically mean there will be
data available to go out on the other, and vice-versa. *Also*, data may be
generated to write out on the dirty side of the SSL even if no data
arrived on the clean side (this happens during the SSL handshake and any
renegotiations that happen during streaming) - a read on the dirty side
can result in data waiting to go back out on the dirty side as well.
Another trick is to remember that it can be confusing to determine in
which order you should attempt to read and write on both sides of the SSL
when you are buffering it from the outside yourself (eg by providing
network encapsulations yourself) ... the safest and simplest way I found
of doing this was to run the following loop twice;
(i) take any data arrived on the "dirty side" and BIO_write() it to the
SSL's read BIO - ignore any negative return value, a positive return value
tells you how much data the SSL actually consumed (this could be less than
you offered it).
(ii) SSL_read() into a buffer you use to send out on the "clean side" -
ignore negative return values, and any positive return value indicates how
much data was provided.
(iii) take any data that arrived on the "clean side" and SSL_write() it -
ignore any negative return value, and a positive return value tells you
how much the SSL actually consumed (this could be less than you offered
it).
(iv) BIO_read() the SSL's write BIO to a buffer you use to send out on the
"dirty side" - again, ignore negative return values, and a positive return
value indicates how much data it provided for you to send out.
This loop, when done twice, should effectively leave the SSL in a state
where it can achieve no more processing based on the network abstraction's
current state - there may be new data now waiting to go out, and data that
had arrived on either side before may not yet have been fully consumed by
the SSL (eg it could be waiting for a renegotiate on the dirty side to
complete before it can consume any more data on the clean side). There's
no great inefficiency in doing this loop twice as any "redundant calls"
return immediately - and the cost of trying to make a optimal set of calls
in the right order would be far higher and more bug-prone than letting
OpenSSL's own internal logic just escape out when you attempt a call it
can't deal with yet.
The negative return values BTW are there to try and indicate to you in a
complicated way why the given operation can't yet be completed. It can be
that the SSL itself has crashed out due to data corruption, certificate
verification problems, or just general "not yet, need something else to
take place first" conditions. Checking the SSL's status, providing your
own callbacks, and ignoring them are the respective ways of dealing with
those eventualities. :-)
Does this generally answer the issues? I detailed this technique on the
list (or was it openssl-users?) a while ago, and I may have been more
methodical about it at that time, in fact I think I recall using some
ASCII art too ... oh to have that much time on my hands these days ... You
can also use BIO pairs as Bodo mentioned (and also detailed a while back
on one of the lists) - they may or may not be more useful to you, but it
is certainly not true that OpenSSL *must* do your networking for you ...
I've more often done the networking myself than I letting OpenSSL do it
for me.
Anyway, I'm out of here - hope that actually made some sense.
Cheers,
Geoff
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]