[AFS3-std] rxgk implementation notes
Benjamin Kaduk
kaduk@MIT.EDU
Thu, 28 Feb 2013 19:05:27 -0500 (EST)
Thanks for the detailed replies.
On Thu, 28 Feb 2013, Simon Wilkinson wrote:
>
> On 28 Feb 2013, at 22:05, Benjamin Kaduk wrote:
>
>> We still have some places that refer to or imply an ordering of
>> security levels, such as "this MUST NOT be less than the security level
>> originally negotiated"; the OpenAFS rxkad implementation has this sort
>> of assumption baked in, in that the client and server track a "minimum
>> security level" in the security object private data, and make numeric
>> comparisons against that value. We used to have a channel-bound
>> security level, and conceivably one may get added in the future. It
>> would be nice to either settle on "a token only supports exactly the
>> level it was negotiated for" or some better ordering on the values of
>> security levels. Having the client and server explicitly track all
>> allowable security levels would be somewhat annoying.
>
> This is definitely an issue - in my implementation, we just use the
> various numeric values to provide an ordering in much the same way as
> rxkad. Whilst this is abstracted out from the rest of the code, I agree
> that in a world where we have many other security levels this will be a
> bit of a nightmare.
I'm a bit curious how things would fail if we required an exact match for
the security level. I don't think there are many places in the openafs
codebase that change the level, so it seems likely that almost everything
is using a single level anyway.
>> Having a mixture of RXGK_Data and plain XDR opaque types gets a bit
>> annoying; in some places I end up having one variable of each type that
>> alias the same storage.
>
> This is purely an implementation issue. There's no reason that RXGK_Data
> can't be a plain XDR opaque type. In fact, if you're using OpenAFS's
> rxgen properly, they can be. In my implementation, the header from the
> .xg file has just:
>
> typedef struct rx_opaque RXGK_Data;
Hmm, that would probably be convenient. More motivation to write rxgen.1!
>> It's hard to get the logic right for when to terminate a GSS
>> negotiation loop, especially when the same C variable is used to hold
>> major/minor status information from both the client and server calls.
>> I still owe us an update to the text in the document on this matter.
>
> The negotiation loop logic is exactly the same as that in OpenSSH when
> using GSSAPI - it seems to me to be a pretty standard GSSAPI negotiaton
> loop.
My point was more "everyone seems to have trouble getting the negotiation
loop right the first time they write a GSS application"; there's nothing
particularly special about our case (other than the current text in the
document being wrong).
>> Having publicly-visible routines that take a gssapi context or other
>> gssapi type is pretty annoying for the code structure, as it makes
>> gssapi.h a prerequisite for the rxgk header. This is rather
>> inevitable, but it may prove convenient to split that stuff off into a
>> separate header/library only used by the negotiation service.
>
> I don't think there's any need for any part of the rxgk API to take
> GSSAPI types. The YFS implementation definitely does not - the whole
> GSSAPI internals are completely hidden from the caller.
I agree that there's no need. Looking more carefully, the only routine I
currently export that takes a gss type is the one to take a GSS security
context and produce the master key k0; that could easily move to a private
header.
>> Additionally, the gssapi libraries shipped with some OSes do not
>> support the pseudo-random functions that we need. This is just
>> something that implementations will have to deal with.
>
> There are ways (some pretty, some less pretty) of working around this.
I guess we'll talk about that on openafs-devel when the time comes.
>> It takes a fair amount of code to prepare the several structures that
>> we specify as opaque or RXGK_Data typed objects that are the XDR
>> encoding of some more detailed type. Manually specifying bit layouts
>> would be differently annoying though, I'm sure.
>
> Specifying them as XDR does specify bit layouts. It's up to the
> implementor whether to encode them using the XDR functions, or by
> manually bit twiddling. In either case, the XDR specs within the draft
> do provide an exact account of which bits should be present on the wire.
Sure.
>> We say "rxgk challenges simply contain some versioning information and
>> a random nonce selected by the server", though the current RPC-L is
>> just a nonce. It sort of seems like it may be worth adding a version
>> field in case the challenge/response protocol ever needs to be rev'd.
>
> An earlier version of the draft did contain versioning information.
> However, until we have extended unions, that versioning information is
> useless - because any attempt to decode a structure with a form other
> than that expected by the receiver will produce a marshalling error. The
> only way (currently) to take advantage of a version number is to peek at
> the structure without decoding it, and then use the version byte to
> decide which structure decoder to use. This seemed to provide no
> additional elegance compared to making the decision based on the encoded
> length of the structure, and so the versioning byte was removed. If (and
> when) we standardise extended unions, this is definitely something that
> could be revisited for a later version of rxgk.
Oh, right, I remember now.
> At the moment, I think the reference to versioning information should
> just be removed.
Okay, I'll do that.
>> Endianness conversion routines for 64-bit quantities (i.e., rxgkTime)
>> do not seem to be universally available; an incorrect hand-rolled
>> implementation could lead to interoperability issues.
>
> These are specified as part of XDR, and are used throughout AFS -
> providing both ends of the connection are using correct XDR
> implementations, this shouldn't be an issue.
We have to manually generate NBO for the seed for the PRF+ used to
generate the transport key; I suppose we could leverage the XDR encoder
for parts of this but it seemed easier to just use htonl for the 32-bit
fields.
>> It's a bit awkward to include call number information in the
>> authenticator (read: feels like a layering violation), and it's not
>> clear to me what benefit is gained from doing so. I vaguely remember
>> seeing some discussion of this in an archive somewhere, but can't find
>> it now.
>
> I don't have a reference to hand, but the importance of this is
> discussed in one of the CITI RX security papers. Essentially, it removes
> an avenue by which an attacker can hijack an encrypted connection. Much
> of the design of rxgk (and the modifications to rxkad) come from the
> security work done by CITI on AFS-3. If you haven't read their RX papers
> already, I would strongly recommend doing so.
Thanks for the pointer, I have not read those papers.
>> All I see looking nowis discussion of using the maxcalls information
>> as a way to migrate to having more than 4 calls per connection, which
>> doesn't sound familiar. We also don't mention whether call numbers in
>> use are checked as part of verifying the authenticator -- I do not
>> currently do so.
>
> You should just provide the call number vector to the RX layer, which
> will take care of checking the call numbers within it (OpenAFS's RX
> currently just sets up the connection according to the provided
> authenticator, which will cause non-matching calls to fail as they are
> encountered)
Oh, hmm, I guess rxi_SetCallNumberVector is exported.
>> Strictly speaking, this affects the rxgk-afs document, but including
>> the client UUID in the authenticator's appdata field is pretty awkward.
>> This field "contains the UUID of the client", which sounds like it
>> should be the cache manager's idea of the UUID, but getting that from
>> the rx layer seems to be a layering violation,
>
> This is based on work that Tom Keiser was doing -
> draft-tkeiser-rxrpc-sec-clear provides a detailed account of his
> motivations.
Okay, I'll take a look.
>> and we may have situations (e.g., bos) where an rxgk client is not
>> running a cache manager.
>
> The intent of this document was that you would only be using rxgk-afs
> with fileserver-like protocols. That is, specifically not bos.
Hmm, I guess we can make an optional uuid field in the client security
object and only fill a uuid in the appdata if it's present.
-Ben