On Mon, Jun 26, 2006 at 12:35:57PM +0100, Darryl Miles wrote:
> "Some of the calls to SSL_write() may read some of your data", I am
> still not such how the reading of data impacts the write operation. Are
> you saying that when WANT_READ is returned from SSL_write() the OpenSSL
> library has already committed some number of bytes from the buffer given
> but because its returning -1 WANT_READ it is failing to report that
> situation back to the application during the first SSL_write() call ?
Yes. During the first call to SSL_write(), OpenSSL may take as many
bytes as fit into one TLS record, and encrypt this for transport.
Then SSL_write() may fail with WANT_WRITE or WANT_READ both before and
after this first record has been written, until finally all the data
has been broken up into records and all these records have been sent.
> An under reporting of committed bytes if you want to call it that. This
> would also imply you can't reduce the amount of data to SSL_write()
> since a subsequent call that failed. Or implies that OpenSSL may access
> bytes outside of the range given by the currently executing SSL_write(),
> in that its somehow still using the buffer address given during a
> previous SSL_write() call.
>
> I still have not gotten to the bottom of the entire scope of
> situation(s) can cause an SSL_write() to return -1 WANT_READ. If its
> only renegotiation that can; then this is always instigated by a
> SSL_renegotiate() (from my side) or and SSL_read() that causes a
> re-negotiate request (from the remote side) to be processed.
Yes. The other party is always allowed to start renegotiation, so
your SSL_write() call might be during renegotiation; but OpenSSL won't
try to read data from the other party during SSL_write() unless it
already knows that a renegotiation is going on.
> It is still unclear how this would work, here is the strictest pseudo
> code case I can think up. This is where:
>
> * the exact address for the 4096th byte to send it always at the same
> address for every repeated SSL_write() call and
>
> * I don't change or reduce the amount of data to be written during
> subsequent SSL_write(), until all 4096 bytes of the first SSL_write()
> have been committed into OpenSSL.
Exactly. You should not change the amount of data (n), and you should
not change the contents of these n bytes. You may change the address
of that buffer (provided that the contents remain the same) if you
set the flag that you asked about. However ...
> char pinned_buffer[4096];
> int want_write_len = 4096;
> int offset = 0;
> int left = want_write_len;
>
> do {
> int n = SSL_write(ssl, &pinned_buffer[offset], left);
> if(n < 0) {
> sleep_as_necessary();
> } else if(n > 0) {
> offset += n;
> left -= n;
> }
> while(left > 0);
... once SSL_write() returns a positive number, this indicates that
this number of bytes, and *only* this number of bytes, has been
processed. So any subsequent SSL_write() is "detached" from this
SSL_write(); OpenSSL does not care what you change in the buffer
Note that you'll have to set SSL_MODE_ENABLE_PARTIAL_WRITE to cause
OpenSSL to return success before *all* of the application buffer has
been written. The default is that OpenSSL will write all the data,
using multiple records if necessary; with
SSL_MODE_ENABLE_PARTIAL_WRITE, SSL_write() will report success
once a single record has been written.
> In practice many applications may copy their data to a local stack
> buffer and give that stack buffer to SSL_write(). This means the data
> shuffles up and the next 4096 byte window is use for SSL_write().
>
> So what I am asking now is what is the _LEAST_ strict case that can be
> allowed too if the one above the what I see as the most strict usage.
>
>
>
> The need for this dumbfounds me. If SSL_write() is returning (<= 0)
> then it should not have taken any data from my buffer, nor be retaining
> my buffer address (or accessing data outside the scope of the function
> call).
If SSL_write() has started writing a first record, but delayed other
data to later records, then it may have to return -1 to indicate
a "WANT_WRITE" or "WANT_READ" condition.
> It is also valid for me to "change my mind" about exactly what
> application data I want to write at the next SSL_write() call. This
> maybe a change of application data contents or a change of amount of
> data to write (length).
Not if OpenSSL has already started handling the application data.
In that case you should buffer the application data so that you
can repeat the SSL_write() call properly.
> Infact I have an application that does exactly this, it implements a
> priority queue of packetized data and the decision about what to send
> next is made right at the moment it knows it can call write().
>
>
> >But sometimes, you might want to change the buffer location for some
> >reason, e.g. since the SSL_write() data buffer is just a window in a
> >larger buffer handled by the application. To tell OpenSSL that such
> >an address change is intentional in your application, and that the
> >application will make sure that any buffer contents will be preserved
> >until SSL_write() reports success, you can set the
> >SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER flag. This will not change
> >OpenSSL's operation in any way except disabling the sanity check,
> >since settings this flag indicates that your application does not
> >require this check.
>
> When you say "change the buffer location" do you mean the exact offset
> given to SSL_write() in 2nd argument ? Or do you mean for repeated
> calls to SSL_write() the last byte (4096th byte from example) address
> remains constant until OpenSSL gives indication that the last byte has
> been committed ?
>
> Here I am asking "which buffer when?" and "what location?" in relation
> to previous failed SSL_write() ?
I don't quite understand these questions. The second argument
to SSL_write provides a pointer to a buffer, the third argument
provides the length. Without the SSL_MODE_ENABLE_PARTIAL_WRITE,
a sanity check done by OpenSSL requires the buffer pointer to remain
unchanged until SSL_write returns a non-negative number, since
otherwise there might be unintended behaviour, as explained above.
> In the case of my example usage when copying to the stack, I have a much
> larger buffering system in place and a small temporary window on the
> stack is used to prepare data for SSL_write(). This is because
> SSL_write() doesn't support IOV/writev() scatter-gather buffers which I
> am using with unencrypted sockets.
>
>
> Its still unclear what guarantees my application needs to make for
> OpenSSL, the sanity check looks at first glance to be there for its own
> sake and redundant. Is there a direct relationship between
> SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER and SSL_MODE_ENABLE_PARTIAL_WRITE ?
Well, if you use SSL_MODE_ENABLE_PARTIAL_WRITE, then it doesn't really
matter if the write buffer changes between calls to SSL_write() since
OpenSSL won't break up the buffer into multiple records anyway. So in
that case, you probably won't encounter problems if you disable the
sanity check by using SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as well.
Bodo
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [email protected]
Automated List Manager [EMAIL PROTECTED]