Thor Lancelot Simon

> On Sat, May 23, 2009 at 05:30:54AM -0700, David Schwartz wrote:

> Let me start out by saying I think you're correct on most of your
> points, and I was incorrect.  But I do want to clarify one issue.

> > Set SSL_ACCEPT_MOVING_WRITE_BUFFER. The only requirement then
> > is that you
> > not try to "unwrite" data.

> Here is the additional unpleasant requirement I believe I've observed.

> I have two basically independent directions of data flow, which is unlike
> most applications that run on top of SSL, since most of those seem to be
> request/response protocols (e.g. HTTP or IMAP).  So at any time, I might
> initiate either an SSL_read() or an SSL_write() towards the peer.

That is the case I am in as well. My code has to support request-response
protocols but also protocols that are not include RFC1459-like chat
protocols and bidirectional request-response protocols where requests can
originate on either end at any time.

> Here is what I have seen go wrong at renegotiation time, which led me to
> try to apply my (incorrect, as you've pointed out) rule:
>
> 1) I SSL_read().  It returns -1, WANT_READ.
>
> 2) Independently, I SSL_write().  Since a renegotiation is in progress,
>    it *also* returns -1, WANT_READ.
>
> 3) I select for read-ready, since OpenSSL told me to do so.

In this case, there is no known failure scenario because you have read
before write. However, in the other order, there are documented failure
scenarios. Imagine if instead:

1) You call SSL_write. It returns -1, WANT_READ, because a renegotiation is
in progress.

1A) The renegotiation data arrives.

2) Independently, you SSL_read. It reads the renegotiation data but no
application data, so it returns WANT_READ.

3) You select for read, since OpenSSL told you to do so. The select will
take forever, because the renegotiation data has already arrived and been
read. Your SSL_write would succeed immediately now.

When SSL_read returns *anything* it invalidates any prior WANT_* return from
SSL_write because the SSL_read may have made forward progress. Any call to
an SSL_* function may consume data. You cannot assume that because the data
hadn't been read when you called SSL_read it still hasn't been read after
you called SSL_write.

This will screw you on renegotiations.

> 4) Now I reissue the SSL_read() (I intend to next do the SSL_write() of
>    course, since it is waiting for read too).

> At this point, I have observed each of:
>
>       A) Protocol violations on the wire (bad SSL records).
>       B) SSL_ERROR_SSL from subsequent SSL_read() or SSL_write()
>          calls on my side.

Now that's baffling. Are you sure you can't ever call SSL_read and SSL_write
at the same time for the same SSL *? That's the only thing I can think of
that would cause the specific failure you are describing.

> With older versions of OpenSSL -- I haven't tested lately.  I think now
> I need to go write some simple test cases.
>
> I know that in ordinary operation, if I get WANT_READ from SSL_read()
> it's safe to continue to call SSL_write().  But it appears to me that
> if the WANT_READ from SSL_read() was caused by a renegotiation, if I
> do some other API call next, chaos ensues.

That shouldn't happen, and read-before-write should be safe. (As I noted,
write-before-read can fail.)

> And I cannot tell WANT_READ caused by a renegotiation apart from
> WANT_READ caused by no-data-ready, so whatever heuristic I use to work
> around this, I have to apply it all the time.  Obviously the same thing
> applies with SSL_write() and an initial WANT_WRITE.
>
> I take it it's not _supposed to_ be this way.  Do you agree?

It's not ever supposed to cause the kind of failures you are seeing. I would
check your locking.

DS


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

Reply via email to