[AFS3-std] rxgk: Rekeying
Marcus Watts
mdw@umich.edu
Wed, 14 Oct 2009 17:50:17 -0400
> Date: Wed, 14 Oct 2009 08:56:40 EDT
> To: Simon Wilkinson <sxw@inf.ed.ac.uk>
> cc: afs3-standardization@openafs.org
> From: Chaskiel Grundman <cg2v@andrew.cmu.edu>
> Subject: Re: [AFS3-std] rxgk: Rekeying
>
> Does there necessarily have to be a transparent rekeying operation? Why
> not just have the application layer return VICETOKENDEAD or some such and
> have the client create a new connection (the cm already has code for
> this...)
>
> > When the other end receives packets with a later version
> > number, it should start sending using a key with that version number,
> > too.
> Since my earlier suggestion will undoubtedly lose out....
> This should only happen if packets bearing new key version numbers are
> successfully validated. an attacker should not be able to change which key
> one side is using... Also, the size of the key version number space and
> what happens when all available key versions are exhausted should be
> documented.
1/
By "application layer" - do you mean the application (ie, fileserver,
ptserver) instead of the security mechanism? I can't speak for the
rxgk side of things, but speaking from the rxk5 side of things this
is something I was specifically seeking to avoid: application/mechanism
specific glop. Or, in a world, "yuck". But, ignoring that problem...
>From the rx side of things, there is a problem: there may be handling multiple
calls, they may be in different stages of completion, and there is no
guarantee on how long any given call might last. On the server side, it's
not possible to know what calls the client might have sent, are in-flight,
but haven't been received on the server. This means there is no
logical "good" place timing-wise for the server to return "VICETOKENDEAD".
Waiting for idle moments on a connection on the server may not be possible
for a sufficiently busy connection. Adding slop in will reduce problems,
but not eliminate them.
On the client side, the client code could "know" more closely when it
might generate a call or combination of calls that might exceed
the key byte limit. This means all client side calls would need to
be able to closely estimate the max. number of bytes they might generate,
and additional logic to track when the combination of current proposed
calls exceeds the byte limit for the connection, and to restart the
connection in that event. This is more restrictive and less elegant
than the current design for rx.
So, for instance, if the client is in the middle of a bulk data write,
and the server decides to return "VICETOKENDEAD", then on the client
there is a problem. The client has no way to know how much of the
write was accepted by the server before the error was returned, so has
no real choice but to start the entire write over, from the beginning.
Presumably, redoing a write is harmless, provided the redo completes.
However, this has worse implications for operations that are not
idempotent. And, of course, if a bulk data write is larger than the
"byte window" in rxgk, things get worse.
2/
For key version numbers, wraparound should not be a real problem.
You don't need to send the whole version number, you only need to send
the least significant bits - enough to distinguish between "old" and
"new". Of course you still need to store the whole thing at both ends,
and if it's small enough to make wrap around possible, as you say, it
should be defined what happens there. In any case, the response (for c/r) must
contain sufficient information to generate the whole key version number.
On the wire, one bit is probably sufficient unless you anticipate changing
the key more than once within some given window size. The server (and
client) must be prepared to deal with packets encrypted under the old
key for some set period after a new key is signaled.
Presumably the client or server would not accept a key change signalled
by a bogus packet that cannot be decrypted successfully. So why would
an attacker be able to cause a key change?
-Marcus Watts