[AFS3-std] New Version Notification for draft-wilkinson-afs3-rxgk-06.txt (fwd)

Jeffrey Hutzelman jhutz@cmu.edu
Thu, 11 Jul 2013 01:17:06 -0400


Forgive me if this is a little unpolished; it's getting late and I'm
trying to get a new fileserver set up by several hours ago.


On Thu, 2013-07-11 at 00:19 -0400, Benjamin Kaduk wrote:

> > - In step 3, you don't say anything about the case where the major
> >  status code from GSS_Accept_sec_context indicates an error.
> 
> This was something of a conscious decision, as the client need not know 
> the server's gss_accept_sec_context() return value directly.

Sure.  But the negotiation must fail.  Remember that although this is
structured as a client making a bunch of RPCs, it's not good enough to
describe the process from the client's point of view.  If
GSS_Accept_sec_context returns an error, then the _server_ has to fail
the exchange, no matter what the client does from then on (of course,
the client is free to start over).

BTW, this may also mean that the server needs to do some sort of replay
protection with its opaque tokens.  An exported partially-established
context ought to be re-importable only once.  I don't really recall what
the API spec says about dealing with this.


>   Even in 
> RFC4462, it is only "the server MAY send a message informing the client of 
> the details of the error" and "SHOULD send the error token [if it 
> exists]".

Sure, but just above that, RFC4462 says "... the key exchange fails."
In SSH, that means we're going to terminate the connection, no matter
what the client wants to do.

The userauth section is a bit more handwavy about the GSS exchange,
which in retrospect is unfortunate, because it's structurally more
similar to what you're doing here.  That section notes that a
server-side error results in the server failing the userauth by sending
SSH_MSG_USERAUTH_FAILURE, which here would be the equivalent of an Rx
abort, or some other error-reporting mechanism.



> > - If the server decides that negotation has failed for a reason other
> >  than GSS_Accept_sec_context returning an error status, , it should
> >  indicate this to the client by returning an error from the RPC or
> >  by some other indicator.  It should not synthesize a GSS-API status
> >  code that was not actually returned by the GSS-API.
> 
> You are taking issue with the synthesis of GSS_S_BAD_QOP?

Yes.


> To represent this error case (GSS_Accept_sec_context returns 
> GSS_S_COMPLETE but ret_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG) != 
> GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG) as a com_err error, I believe we would 
> need to introduce a new RXGK error code.  Do you have suggestions for this 
> error code name and text?

We don't already have a semi-general "bad context" error?


> > - In step 4, if the GSSNegotiate() fails for any reason, the client
> >  should consider the negotiation to have failed.
> 
> Well, the client should not decide to downgrade to rxkad because 
> GSSNegotiate returns -1!  I can add explicit text for what to do if the 
> RPC fails if you want, though I think the intent was that the last 
> paragraph of 6.2 would cover this case.

Oh, hm, I see.



> > - Don't conflate GSS_S_CONTINUE_NEEDED with an output token.  The
> >  GSS_S_CONTINUE_NEEDED flag indicates that another call with an input
> >  token is expected, not that an output token was provided.  So...
> 
> Right.
> 
> >  + If GSS_Init_sec_context produced a token when the server wasn't
> >    expecting one, or failed to produce one when it was, that is an
> >    error, and negotiation fails.
> >
> >  + If GSS_Accept_sec_context produced a token when the client was
> >    not expecting one, or failed to produce one when it was, that is
> >    an error, and negotiation fails.
> 
> These will both be caught by the counterparty's next GSS call and need not 
> be handled explicitly.

I'm not convinced.  This is an authentication exchange with an untrusted
party; if something fails locally, you have to fail it locally, not
depend on the other party to fail.


> Hmm, saying "the major status code" here is a bit ambiguous as to whether 
> it is from initiator or acceptor (it's supposed to be the acceptor, if I 
> remember correctly.

Only the initiator should make control flow decisions based on the
status returned by GSS_Init_sec_context, and only the acceptor should
make decisions based on the status returned by GSS_Accept_sec_context.
RPC or not, the initiator isn't calling GSS_Accept_sec_context; the
acceptor is.

Among other things, the abstract GSS-API doesn't nail down the values of
status codes, so they cannot be sent over the wire portably and thus the
client cannot directly make decisions based on the status returned on
the server.  Note that SSH doesn't require the client to interpret the
server's status codes directly; instead, the server effectively sends a
boolean flag (in the form of its choice of message types) indicating
whether another token is required.




> >  (a) The server returned GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED, with
> >  an output token, and the client was expecting a token.  In this case,
> >  the client begins the next cycle.
> >
> >  (b) The server returned GSS_S_COMPLETE without an output token, and
> >  the client was not expecting a token.  In this case, negotiation
> >  succeeds.
> >
> >  (c) All other combinations are failures.
> 
> This is a valid decomposition, but I would prefer to not introduce the 
> notion of the client "expecting" a token; instead, I like to refer only to 
> what has already happened.  Thus, "the most recent call to 
> GSS_Init_sec_Context() returned the major status code GSS_S_COMPLETE" 
> instead of "the client was not expecting a token".

OK; I don't have a problem with that.  I found my formulation a bit less
wordy, which made it a useful shorthand for discussion, but using the
more precise form in the document makes sense.


> Are you claiming that the breakdown in step 4 is an invalid decomposition?

I believe it's incorrect.  In that breakdown, if the server asserts that
another cycle is needed but the client's last call returns
GSS_S_COMPLETE, then the loop terminates successfully.  But this is
actually a failure condition.



> If the server is not GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED, it is in 
> error, of course (as your (c), my first bullet point).  If the client was 
> not expecting a token (second bullet point) and gave one to the server, 
> the server cannot be setting GSS_S_CONTINUE_NEEDED (right?)

Sure it can.  The server is an untrusted adversary; its responses are
not bound by the client's state machine.


> I believe I used to have an explicit case for the client expecting a token 
> and the server not returning one, but Simon noted that we can just 
> continue the loop and the next Init_sec_context call will detect the 
> error.

If the server asserts CONTINUE_NEEDED and does not send a token, that's
always an error.  The SSH text appears to presume that an empty token is
the same as no token at all.  I can't remember offhand if that's true,
but we tried to be fairly careful writing that particular bit of text
(well, actually, it was pretty bad at first, and then there was a round
of careful editing and rewriting), so it probably is.



> > GSSNegotiate is intended to be called over an unprotected channel.
> > So, there is no security reason to favor reporting results via an
> > output parameter instead of via an Rx abort.
> 
> That text at the end of 6.2 was intended to call to mind the security 
> considerations 12.1.  I guess the description as written is not really 
> consistent with the class of errors for which the security consideration 
> applies, though.

Indeed, looking at it, I think the text in 12.1 is a bit strong.  I
imagine OpenAFS clients will have been told which security classes to
expect a cell to support, but that may not be true for every client
implementation ever and it may not be true for applications other than
AFS (which do exist, even if none are widely deployed).  In fact, the
sort of fallback 12.1 seeks to prohibit is fairly normal, and usually OK
provided it is to a mechanism the client was willing to use to begin
with.

FWIW, there may be _non-security_ reasons to favor an output parameter
over an abort, and I have no problem with that (but avoid synthesizing
GSS errors, especially since the client can't actually interpret them
anyway).

-- Jeff