On Fri, May 29, 2020 at 7:28 PM Nico Williams <n...@cryptonector.com> wrote:

> On Fri, May 29, 2020 at 06:35:58PM -0400, Watson Ladd wrote:
> > In my experience the issues are thorniest when dealing with blocking
> > sockets. Libraries using nonblocking sockets have to signal to the
> > application that they want IO to happen during the handshake, and can
> > use that same mechanism at later times, particularly for rekeying.
> > Libraries with blocking behavior are unfortunately in a difficult
> > position if they imitate a POSIX API and have no means to drive I/O.
> >
> > One possible dirty trick is to set nonblocking on an owned socket and
> > translate the blocking call into a select or poll based loop that
> > issues both writes and reads until enough is read or written. Note
> > that the real corner case is unanticipated needs to read from the
> > socket: the library has control when it needs to write.
>

The signaling for nonblocking sockets is somewhat interesting. I don't
think it's as straightforward as that because these non-blocking APIs and
how callers use them becomes sequential anyway. Consider the
NewSessionTicket deadlock issue and a TLS implementation which wishes to
send it immediately after the handshake, rather than deferring to the
first write. Signaling to the application that I/O needs to happen during
handshake, read, and write may look something like...

enum tls_io_result {
    tls_io_success,
    tls_io_error,
    tls_io_want_read,
    tls_io_want_write,
};

tls_io_result tls_handshake(...);
tls_io_result tls_read(...)
tls_io_result tls_write(...)

An HTTP/1.1 server may then:

1. tls_handshake(). On tls_io_want_*, pop back to the select() loop and
retry until tls_io_success.
2. tls_read("GET HTTP/1.1 ..."). On tls_io_want_*, pop back to the select()
loop and retry until tls_io_success.
3. tls_write("HTTP/1.1 200 OK ...")). On tls_io_want_*, pop back to the
select() loop and retry until tls_io_success.

Conversely, an HTTP/1.1 client may tls_handshake(), tls_write(), and
tls_read(), in that order. It likewise would only advance to the next
TLS-level function when the previous one succeeded. You generally do
not read or write before the connection is established, and HTTP/1.1,
unlike HTTP/2, never reads and writes concurrently.

Now the TLS library implements TLS 1.3 and wishes the server to send
NewSessionTicket as soon as possible. It may think to send it right at the
end of tls_handshake(). That gets it out independent of the caller's I/O
patterns. If NewSessionTicket hits EWOULDBLOCK, it then returns
tls_io_want_write out of tls_handshake(). But now we have our deadlock.
This HTTP server will not proceed to tls_read() and thus not consume the
(potentially large) HTTP request until *after* NewSessionTicket is written.
Conversely, this client will not consume the NewSessionTicket via
tls_read() until *after* it has finished writing the HTTP request.

Deferring to the first write makes it all work out, but that is because it
removes the "out-of-turn" write altogether.


> Indeed.
>
> Another is to start a worker thread to do all (async) I/O on the
> connection and use inter-thread communications primitives on the
> blocking I/O API side.  Because the worker thread needs to do async I/O
> anyways, it might as well service multiple connections to reduce the
> amount of resources needed for the whole thing.
>

Right, what is happening here, blocking or non-blocking, is that a
non-deferred NewSessionTicket must not be in sequence with the handshake or
TLS read. A deferred one can be in sequence with TLS write since you're
"naturally" blocking on transport write anyway.

If your core TLS protocol implementation is at the same layer as the
component that can drive new sequences, that all works fine. If not, you
need the upper layer to drive that background work, which means this is
part of the TLS protocol implementation's API contract. (Often the layers
above have only a basic understanding of the TLS protocol, since the point
of the TLS library is to abstract that.)

Or, in the case of NewSessionTicket, just defer them to TLS writes because
it's so much simpler. :-)

David
_______________________________________________
TLS mailing list
TLS@ietf.org
https://www.ietf.org/mailman/listinfo/tls

Reply via email to