On Thu, 11 Jul 2013, Jeffrey Hutzelman wrote:
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.
That's okay, mine was a bit unpolished due to lateness as well.
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).
Okay. We should probably have some generic text on how the server should
fail the negotiation.
BTW, this may also mean that the server needs to do some sort of replay
protection with its opaque tokens. An exported partially-established
The GSS tokens, or the ones used to serialize server state across
nominally-stateless RPCs (the "opaque_out" and "opaque_in" arguments of
the GSSNegotiate RPC)? I assume the latter.
context ought to be re-importable only once. I don't really recall what
the API spec says about dealing with this.
The GSS tokens should only be usable once, I agree.
In practice, this probably means that you can't call GSSNegotiate against
one vlserver and then try to finish against a different vlserver.
My rough plan for implementing multi-round-trip mechanisms on the
server-side was to cache partially-constructed GSS security contexts, with
a cap on how many can be cached at once and an expiration timer on them.
That would eliminate any need to either export/import the
partially-constructed context or replay GSS tokens.
[server reporting failure covered below]
You are taking issue with the synthesis of GSS_S_BAD_QOP?
Yes.
I think I ran that by tlyu/ghudson and it seemed okay. I can
double-check.
I suppose this would be a reasonable thing to put in the errorcode field
of the ClientInfo, though part of the point of the exchange is that we are
relying on the contents of the ClientInfo to be integrity-protected.
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?
The most generic thing we have is RXGK_INCONSISTENCY, "Security module
structure inconsistent". This isn't really a BAD_TOKEN or a SEALED_INCON,
I think.
- 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.
It's a bootstrapping problem; we can't securely report an error until we
have a GSS context established, so any errors incurred during the
negotiation are in some sort of limbo.
The client will presumably need to retry a few times and then report
failure to the user.
- 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.
I guess (part of) the problem is that our story for reporting errors from
the server to the client is lousy (the bootstrapping problem abpve). I
think there probably will need to be some place for Rx aborts, and we'll
need to make the client do the least bad thing.
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
Okay.
(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.
The client will (must!) fail if there is no usable ClientInfo returned.
I'm not sure that we need to be terribly concerned about whether we call
this a negotiation failure or just a failure.
I'm not sure I understand your statement, though.
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 was afraid you were going to say that, when I was writing this up and
made the realization. Will fix.
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.
Do you think we should change all occurrences of "output token" to
"non-empty output token"?
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).
I don't think we should add a non-abort non-gss-status "error code" output
parameter other than the one already in the ClientInfo.
I will work on updates to the document.
-Ben
_______________________________________________
AFS3-standardization mailing list
[email protected]
http://lists.openafs.org/mailman/listinfo/afs3-standardization