On Fri, Aug 01, 2008 at 03:49:01PM +0200, Lutz Jaenicke wrote:
> Thor Lancelot Simon wrote:
>
> The record size of the SSL record is predetermined by the sender with
> 16k being the maximum size specified by the protocol.

32K for SSLv2, no?

> In order to return the (decrytped and authenticated) data to the
> application, the full record must have been received as the MAC
> (Message Authentication Code) is at the end of the record and
> checking it requires to calculate the hash over the complete record
> anyway. Hence, SSL_read() will only return and provide data once
> the full record has been recevied from the underlying socket.

Yes, I understand this.  The problem is that since the API doesn't include
SSL_select() or SSL_poll(), there's no way for an application to sleep
once SSL_read() consumes the data out of the socket buffer.  This means
SSL_read() can't work quite like read(2) here -- it requires the "read to
completion" behavior you mention.

This leads to another problem, actually:

A malicious peer which sends data as fast as it can can get _more_ data
into the socket buffer while the application is trying to "read to
completion".  This can deny service to _other_ peers.

Basically an event-driven application which had an event loop like this
(which worked with the Unix model):

        while (1)
        {
            select(....)
        
            for(selected writable) {
                write(it all);
            }
            for(selected readable) {
                read(fixed size for fairness);
            }
        }

Now has to do something like this:

        while (1)
        {
            select(....)

            for(selected writable) {
                SSL_write(it all);
            }
            for(SSL_pending() was true after last read) {
                SSL_read(another fixed size chunk);
                if (SSL_pending(this SSL)) {
                    flag as "more coming" in private datastructure;
                }
            }
            for(selected readable) {
                SSL_read(fixed size for fairness);
                if (SSL_pending(this SSL)) {
                    flag as "more coming" in private datastructure;
                }
            }
        }

This will work, but it will require restructuring the event loops of
many applications written to expect the Unix was (which is not great, but
so long as it's documented, it's better).

The SSL_read() manual page should at least mention that it's unsafe to
call select again if SSL_pending() comes true.  At present, it doesn't
mention SSL_pending() at all.

And this will work only as long as we're guaranteed SSL_pending() will
never actually read from the socket buffer, which someone might want to
make a note of somewhere!

> Hence the scenario you describe here (returned 8k and
> SSL_ERROR_WANT_READ at the same time) is technically impossible as
> long as you did call SSL_get_error() with the correct return value of
> SSL_read().

Yes.  That's not what occurred, as I determined when I traced through a
run of the application.  Rather, the application put the fd in its select
set for read without SSL_get_error() returning WANT_READ, because it was
trying to enforce fairness among clients (see above).  It looks like this
can be done via use of SSL_pending().

> Note: I did not invent the API, I just wrote the manual pages :-)

So noted!  And thanks for taking the time to explain this to me!

Thor
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [email protected]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to