[Prev][Next][Index][Thread]

Re: STLP and proposal




In message <c=US%a=_%p=msft%l=RED-92-MSG-960423204419Z-23495@tide21.microsoft.c
om>, Dan Simon writes:
> Taher claims that the mechanism proposed for the latter (pre-encrypted
> data) "breaks" the protocol, but I don't see that it poses any security
> (or other) problems.  (If it does, I would certainly like to see the
> details.)  In the absence of such problems, I believe that support for
> pre-encrypted data would be a useful efficiency feature of the protocol.
>  (I might add that there are most probably other ways of implementing
> the feature safely, if use of the "change cipher spec" message is
> unworkable.)

Now, Taher's message said:
> ...
> include other values, that actually has the potential of breaking the
> data stream since that signal is provided as a synchronization point
> between the client and the server to switch algorithms.

Note that identifying something as having "potential of breaking the
data stream" is very different from identifying it as something that
"'breaks' the protocol", esp in the usual cryptographic sense.  My
read of Taher's comment was that he claimed that there is the
possibility that the sender and the receiver would get out of
synchronization and render them unable to communicate.  (Taher, please
correct me if I'm wrong.)

The language used in the STLP draft document was not particularly
clear.  The original language (from SSLv3) explicitly described the
_pending_ and _current_ read/write cipher states and how
ChangeCipherSpec caused states to be copied among these state
variables; if the use of ChangeCipherSpec for handling pre-encrypted
data had followed that style more closely (i.e., named a set of cipher
state variables _saved_ state, etc, etc), the exposition would have
been clearer.  Also, as it reads currently, it appears that two
ChangeCipherSpec messages with empty new_key_infos is allowed if the
state had been saved once, which would be a stupid thing for the
sender to do since reverting the (uni-directional / half-) channel to
a previously state permits replay attacks; this should be explicitly
disallowed.

Aside for the need for cleaning up the text, however, I do not see a
real possibility for breaking either the protocol or the data stream
synchronization as a result of the proposed change.  If Taher or
somebody else has an existence proof of a break (either sense) or an
argument as to why this weakens the protocol, this is certainly the
right forum to discuss it.

(I broke down and shut down Linux to booted up Windoze to print out
the .doc file rather than trying to read the badly formatted ASCII
version. :)

There are several sections below that are more-or-less independent and
they are separated by several blank lines.



Another, more real problem is the interaction of the protocol design
with the SSLref API.  Recall that SSLref emulates the Unix read/write
interface, basically providing an SSLized version of read/write, but
still using the raw descriptor with select(2).  (This is after the
initial SSL handshake is complete.)  With this interface, the
application program blocks on a select and performs reads and writes
as select returns and FD_ISSET says a descriptor is readable or
writable -- just like most of all the other select-based I/O code
written under Unix.  The SSLref read/write routines, however, tries to
have standard Unix semantics of a zero return value meaning descriptor
closure (EOF/TCP connection close).  This means that if the peer
initiates another run of the handshake protocol or the change cipher
spec protocol or sends any of the non-user-payload records, the SSLref
read (or write) can not return -- there is no application data
available, and the SSLref read/write must block until the
non-user-payload protocol finishes and real user data arrives (can be
sent), or until a timeout occurs: the application code is ill prepared
to get a zero return value.  The protocol message processing would be
"exposed" to the application writer's code.

Having a ChangeCipherSpec message to copy cipher states from _pending_
to _current_ state variables was a partial solution the above problem
for SSLv3: if another handshake is initiated ala the PCTv1
redo-handshake mechanism, user data records may be interleaved with
the handshake protocol messages (unlike PCTv1).  If one assumes that
the kernel mbufs quantizes the granularity of datasizes that can be
read/written whenever select(2) returns so that complete handshake
records are always received/sent, then when the application code calls
SSL_write with payload data, the SSLref layer can send (also receive)
some handshake records prior to buffering up one byte of payload data
(when no more data can be sent) and return, keeping the application
layer code happy.

The above is not a problem with the various WinSock implementations of
SSL or PCT, since select is a deprecated interface there and most
WinSock clients use the event-notification model (just like XNextEvent
loops, for those unfamiliar with WinSock), which permits the emulation
library to hide protocol message processing from the application.

Also, note that even if we piggy-back a user data record in the same
write(2) as that for sending the last non-user-data record for the
non-user-data protocol initiator, the problem is not completely
solved.  While on good net connections the data will all get there in
a reasonable amount of time, if the peer is on a flakey connection --
and a small percentage of clients will be on such -- then the write
returns partially succeeds, and it may occur that no user data is
sent; in this case, the SSL_write code must fallback to doing a
blocking write, possibly timing out and aborting that connection in
order to servicing other connections.  This can cause the performance
of SSLref-based servers to degrade and may pose as a denial-of-service
attack.

Anyway, to make a long story shorter, when making pre-encrypted data a
useful feature we should keep the API design in mind -- and it would
be difficult to accomodate SSLref-based code if we insist on
preserving the exact SSLref API.  (Certainly several different APIs
may exist.  I just want to talk about migrating the existing codebase
at this pt tho.)  The cleanest method that I see is to provide an
SSL-ized version of select(2), which can then hide all the
SSL/PCT/TLS/TLA protocol processing from the application code, but
this means all SSLref (which is SSLv2 code) will need to be (slightly)
modified to link against a new library with an extended API.  I don't
know what Netscape's plans are for supporting SSLv3 (or if code
exists) or TLS (whatever we come up with) for Unix platforms.  If the
guts of Mozilla is anything like Mosaic with its
cheesy-threads-by-ugly-state-machines model, this addition of a
SSL_select would certainly result in an API that composes better with
the thread model than one that could randomly block.



When I previously raised the issue of handling pre-encrypted data, I
got two responses, the first claiming that this sort of functionality
was inappropriate at the transport level, and, according to the
respondent's own experiments, the throughput difference "only"
amounted to a factor of two (pre-encrypted or no encryption versus
on-the-fly encryption).  The second message, from David Wagner
<daw@cs.berkeley.edu>, raised interesting security issues/questions
that I had neglected to address.

I'd like to discuss my take on this.  First message.

To address the latter point, I must say that, in the real world, a
mere factor of two matters.  If I can handle twice as many connections
(since there's significant public key overhead, this is more like 1/2
or 1/4 as many again or something like that, depending on the lifetime
of the cached session IDs and usage pattern of users) or use a cheaper
(or fewer) server(s), this is a win for the end user.  If we can get
more people to use good crypto and improve their security by
overcoming their performance concerns, this is a win for the security
community.

Now, as to whether handling pre-encrypted data "belongs" in a
transport level protocol: I believe that abstraction barriers are
useful, and that, yes, we should not bump our foreheads against them
too often.  That being said, however, I would also like to point out
that the choice of abstractions -- and consequently, APIs -- can often
bias our thinking.

Suppose instead of a secure pipe for raw bits being transferred from
memory to the pipe, we view the TLS pipe as more of an object-oriented
pipe, through which data objects may send themselves.  Instead of
thinking in terms of a
reading-from-file-descriptor-and-writing-to-socket loops, we can think
of sending in-memory data structures, GIFs, JPEGs, MPEGs, or (more
generically) flat files over a secure transport.  If our API design
permits these ideas, then just as databases can do query optimizations
and also automatically change the underlying data layout to optimize
for frequent accesses, we can also think of our API as permitting us
to "compile" the objects into a form that is more efficient for
transport, to save these pre-compiled objects, and to send these
pre-compiled objects down our pipe efficiently.

Here's a small, concrete example from every day C programming.  Before
GCC introduced the const type qualifier for functions to mean purely
functional functions, I worked on a Unix system that had the ntoh* and
hton* functions declared as macros.  This was important for
performance for some test codes: not only did it eliminate the
function call setup/teardown overhead (inlining), it also permitted
the compiler to evaluate the macros at compile time and do constant
folding, common subexpression elimination, and loop invariant code
motion -- even when the software's author wrote easily readable code
instead of assembly-style C.  Every unsigned long or short object
needs to be translated to network byte order, and it often didn't
matter (from a correctness point of view) whether it happened at
compile time or at run time.  For code tuning where a few percent
execution time speedup really matters, this was useful.

This example was just another case of doing compile-time data
transformation for efficiency.  Just as pre-compressing data is a
time-honored way to store files in FTP archives (albeit the dominant
reason is to save disk space rather than to save bandwidth).  Just as
we mostly use compilers rather than interpreters to run our programs
(well, except for Java, and even there we're moving to dynamic
compilation).  Does handing pre-encrypted data "belong" in TLS?  It
belongs as much as compression belongs.

Second response message.

The security issues raised by daw@cs.berkeley.edu are whether allowing
pre-encrypted data opens us up to replay attacks, and the privacy loss
because an eavesdropper now can link pre-encrypted data (e.g., news
article or JPEG) and learn that two users read the same things.
Similarly, an exhaustive search of a Web server will reveal the
pre-encrypted object, leaking out the actual data that was read by a
user.

First, the replay attacks.  The use of ChangeCipherSpec for
pre-encrypted data doesn't open us up to replay attacsk: the
ChangeCipherSpec message which switches the protocol engine to
temporary encryption/MAC keys is protected by the original session
keys.  Assuming that the temporary keys are of sufficient length, the
pre-encrypted data and the ending ChangeCipherSpec message to revert
the cipher / MAC states can not be tampered with.  Because the revert
message is independent of the original cipher / MAC states, it may be
pre-encrypted / pre-MACed just as the payload pre-encrypted/MACed data
are -- might as well, since this message is protected by the temporary
keys anyway -- and the only replay of old data that is possible is
what the server intended to transmit.

The issue of loss of privacy is more real.  However, note that by
using traffic analysis techniques, it is already trivial to recover
the same information, at least with very high probability, even if the
pre-encrypted data mechanism is not used: by observing the length of
the GET http request and the size of the response (since everybody
uses RC4, a stream cipher, which does not introduce uncertainty in the
lengths because it doesn't mask lengths modulo block size), it is easy
to determine when two users obtained the same object from the server
even if the connection is encrypted.  Even if DES were used, the
lengths mod 8 should be enough information leaked, albeit the
probability of a false match is higher.  A similar argument may be
made for exhaustively searching through a server's contents.

It is good, nevertheless, to be more explicit about all the security
properties (if any) that we may be sacrificing for efficiency and make
an informed decision on these tradeoffs.  Perhaps we might say that
the tradeoffs are too complicated for the typical server administrator
and we should not provide the pre-encrypted data option, perhaps not.
Allowing pre-encrypted data isn't worse than existing SSL practice,
and I think it's quite valuable for some applications.

One possiblity to make traffic analysis harder for non-pre-encrypted
data transfers -- as an ammendment to SSLv3 or PCTv2 or whatever -- is
to permit random non-user-data records that are simply discarded
(record type would have to be encrypted, of course, so as to be
indistinguishable from payload data).  This is probably not a real
concern for most people, it wastes bandwidth which is precious for
dialup users, and it may even be outside the scope of our charter.
Having it as an option doesn't really hurt, but it's another knob for
the user to play with (worry about) and potentially another option to
negotiate on, and I don't think it'd be worthwhile, but maybe some
discussion is in order.

Sorry about the lengthy missive / rambling.

-bsy

--------
Bennet S. Yee		Phone: +1 619 534 4614	    Email: bsy@cs.ucsd.edu

Web:	http://www-cse.ucsd.edu/users/bsy/
USPS:	Dept of Comp Sci and Eng, 0114, UC San Diego, La Jolla, CA 92093-0114


References: