Subject: SSHv2 GSS spec issue wrt gss error tokens

From: Nicolas Williams <[email-masked]>
Date: Tue, 5 Nov 2002 12:25:46 -0600

GSS_Accept_sec_context() can produce tokens when its major status code
is neither GSS_S_COMPLETE nor GSS_S_CONTINUE_NEEDED. RFC2743 doesn't
state this anywhere but by not prohibiting this it implies the
behaviour.

The Kerberos GSS mechanism (RFC1964) defines error tokens; it does not
state that gss_accept_sec_context() can produce these but strongly
implies it. RFC1964 also does not specify numeric forms of minor codes.

The MIT implementation of GSS-API and the Kerberos GSS mechanism *does*
produce error tokens in some circumstances.

The gsskeyex draft does not specify what to do with error tokens, though
it does provide an optional SSH_MSG_KEXGSS_ERROR message for transmitting
GSS error information to the client. The result of this and the fact
that RFC2743 does not specify major status codes for certain conditions
(leaving one to use GSS_S_FAILURE) is that there is no interoperable way
of communicating to the client certain GSS-API error conditions
occurring on the server side.

It turns out that sending the acceptor's major and minor status codes is
not an appropriate alternative to sending the actual error token to the
initiator. For one, RFC1964 does not define numeric forms of its minor
status codes (and MIT's implementations liberally uses codes not defined
in RFC1964 and not called KG_...). Second, in some cases the
major/minor codes produced by gss_accept_sec_context() may be different
from those produced by gss_init_sec_context() upon receipt of an error
token. GSS status codes, major and minor, are API-level concepts and
should really not be used on the wire - that's what the gss error tokens
are for, though, admittedly, if gss_accept_sec_context() returns an
error but produces no output token, then sending the major/minor codes
to the client is better than sending nothing at all.

I propose that the draft be modified to say that when GSS_Accept_sec_context()
returns an error but produces an output token, then the server MUST send
back a SSH_MSG_KEXGSS_CONTINUE message with the error token to the
client and it MUST continue to the next key exchange algorithm.

Alternatively we could add a new message for the server to indicate that
it had an error and in which to send the error token OR we could modify
the SSH_MSG_KEXGSS_ERROR message to include an optional error token.

RPCSEC_GSS (rfc2203) has a similar problem.

Cheers,

Nico
--

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Sun, 10 Nov 2002 08:41:12 -0500 (EST)

On Tue, 5 Nov 2002, Nicolas Williams wrote:

> client

So far, so good.  I'll have to think about the semantics of that; we
would want to make sure that once the server has gotten an error, the key
exchange cannot succeed.

 and it MUST continue to the next key exchange algorithm.

There is no "next key exchange algorithm".  If key exchange fails, the
connection is aborted.  There is no second chance.

> the SSH_MSG_KEXGSS_ERROR message to include an optional error token.

I'm not sure which of the three approaches is best.  But I do agree the
problem should be solved...

-- Jeff

---

From: "Nicolas Williams \[RU-CENTRAL\]" <[email-masked]>
Date: Mon, 11 Nov 2002 08:47:42 -0800

> would want to make sure that once the server has gotten an error, the key

IIRC GSS-API basically guarantees that if the acceptor sends an error
token to the initiator then the initiator's gss_init_sec_context() will
also return an error.  A misbehaved initiator may insist on sending
additional tokens, but wouldn't fool the acceptor, who should proceed to
terminate the key exchange immediately upon GSS_Accept_sec_context()
returning an error, thus leading to failure of the connection,
regardless of any further actions on the part of the client.

> connection is aborted.  There is no second chance.

Ah, yes, sorry.  This does apply to the GSS userauth part of the draft
however.

> problem should be solved...

Technically speaking no major/minor codes should ever be sent - the
fact that a token is sent and the subsequent result codes of processing
said token is all that is required for both sides to know what comes
next. I.e., if GSS_Accept_sec_context() returns GSS_S_CONTINUE_NEEDED
the acceptor doesn't have to tell the initiator, just sending the output
token (and there must be one, IIRC) should suffice.

If, otoh, GSS-API allows a mechanism's initiators and acceptors to get
out of sync, then exchanging GSS_S_CONTINUE_NEEDED/COMPLETE/FAILURE
clearly becomes necessary.  But it is clear to me that this is not the
case, otherwise GSS-API would explicitly require that such status codes
be sent along with GSS tokens or in their stead when none are produced.

But sending GSS_S_CONTINUE_NEEDED/COMPLETE/FAILURE does not hurt and I
see no reason to break backwards compatibility by revising the draft in
such a way as to exchange only tokens, not tokens and status codes,
particularly given that at least one implementation of this draft, to my
knowledge, has been widely deployed.

If the existing messages are not replaced and backwards compatibility is
preserved, then the minor status code field should be deprecated and the
major status code field should be constrained to carry only these three
status codes: GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE and GSS_S_FAILURE
(for backwards compatibility, but otherwise the major status code field
should be ignored by clients); and the SSH_MSG_KEXGSS_ERROR message
should be deprecated.  Similarly for GSS userauth.

Cheers,

Nico
--

---

From: "Nicolas Williams \[RU-CENTRAL\]" <[email-masked]>
Date: Mon, 11 Nov 2002 09:01:20 -0800

Ugh, there are no major and minor status field in any messages other the
ones I think should be deprecated, so please ignore that part of the
below.

So, to rework this:

 - The SSH_MSG_KEXGSS_ERROR message should be deprecated

 - SSH_MSG_KEXGSS_CONTINUE should continue to be used as specified in
   the draft

 - SSH_MSG_KEXGSS_CONTINUE should also be used to send any GSS "error"
   tokens

 - SSH_MSG_KEXGSS_COMPLETE should continue to be used as specified in
   the draft

 - similarly for the SSH_MSG_USERAUTH_GSSAPI_* messages (why are they
   not named in a manner consistent with the SSH_MSG_KEXGSS_* messages?)

These changes should preserve backwards compatibility, though it is
conceivable that brittle clients speaking to servers implementing the
protocol in this way may well panic or crash.

Cheers,

Nico

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Mon, 18 Nov 2002 11:07:34 -0500 (EST)

>  - The SSH_MSG_KEXGSS_ERROR message should be deprecated

No.  I think you misunderstand the purpose of this message, and the reason
it was added to the document.  The reason for sending this message is not
to signal to the client that there was an error, or to provide the client
with status codes that it can use to decide how to proceed -- as you note,
the status code values are implementation-dependent and not standardized.
Rather, it is there to allow the server to provide status codes and/or a
textual error message to the user which may be useful in determining why
key exchange failed and correcting the problem.  It was added specifically
because we have discovered in the past that not having this information
significantly impedes debugging when something breaks.

If the document is unclear on this issue, we could add some clarifying
text.

>    not named in a manner consistent with the SSH_MSG_KEXGSS_* messages?)

They are named in a manner consistant with the names used in the core SSH
drafts.  I believe this is appropriate and should not be changed.

-- Jeffrey T. Hutzelman (N3NHS) <[email-masked]>
   Sr. Research Systems Programmer
   School of Computer Science - Research Computing Facility
   Carnegie Mellon University - Pittsburgh, PA

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Nov 2002 11:16:13 -0600

[BTW, I will not be attending this week's IETF.]

Jeff,

How do you propose to fix the problem at hand, that gsskeyex does not
provide a method to send GSS error tokens, and therefore has no
interoperable mechanism for conveying acceptor-side errors to
initiators?  (forgive me, GSS-API demands that we speak of initiators
and acceptors for what every other API/standard refers to as clients and
servers - I'll use the terms interchangeably as SSHv2 clients will only
be GSS initiators and so on).

This issue does affect the user experience.  Take OpenSSH w/ Simon
Wilkinson's patches + krb5, for example, and slightly misconfigure
Kerberos on the server side, so that it cannot accept GSS/Kerberos key
exchange, then run the client (with valid Kerberos credentials
available) and see what happens: the one and only message the client
will have for the user is "Connection closed."

(One need not even have to misconfigure Kerberos - if the server is
multi-homed, with multiple canonical hostnames [one for each set of
interfaces] then gsskeyex will work only when user against the
interfaces whose canonical hostname matches the host's "nodename".  This
is because the existing open source implementations of GSS/Kerberos do
not support the better GSS_C_NO_CREDENTIAL semantics in
GSS_Accept_sec_context().  This scenario happens every day in at least
one environment that I know of, so it is not far-fetched; having useful
error messages for this and other scenarios would be great and sending
the acceptor's error token is the correct way to achieve that.)

At my previous job I wrote patches to implement SSH_MSG_KEXGSS_ERROR
with OpenSSH and Simon's patches.  This sure helped the situation, but,
as you know, the minor status codes are specific to the side where they
are produced, and may not be appropriate for the other side ("wrong
acceptor cred" on the acceptor side may be "wrong acceptor name" on the
client side; BTW, RFC1964 explicitly does not constrain implementations
to the list of minor status codes listed therein, nor is MIT's
implementation so constrained).  Sending the GSS error token truly fixes
the problem and does so in a way that is in keeping with the spirit of
RFC2743 and the letter of RFC2744.

The draft modifications that I propose would fix this problem in a
backwards compatible way (except where clients have broken GSS-API
implementations which cannot properly deal with GSS error tokens, of
which I know not one).  Alternatively the draft could be modified in a
non-backwards compatible manner, but I believe it's too for that.

More comments below.

> If the document is unclear on this issue, we could add some clarifying

I think this is somewhat disingenuous.  The draft does not provide for
sending of GSS error tokens, thus leaving SSH_MSG_KEXGSS_ERROR as the
only, but inadequate alternative.  This leads me to suspect that the
draft's authors failed to understand that GSS_Accept_sec_context()
can produce an output token and a final error at the same time, thus the
desire for an explicit error message that conveys the major/minor status
code produced by GSS_Accept_sec_context().  Had the authors understood
GSS error tokens I doubt they would have bothered to define
SSH_MSG_KEXGSS_ERROR.  In any case, the draft says nothing about the
message being for debug purposes or about minor status codes possibly
being implementation specific.

Having implemented SSH_MSG_KEXGSS_ERROR before (see above) I know I too
missed the significance of GSS error tokens, even their existence, for
some time.  RFC2743 is not explicit about GSS error tokens at all, and
RFC2743 being more general than RFC2744 (the C-bindings of RFC2743) one
would not expect RFC2744 to be explicit about them either (but it is).
Thus it would seem that it is not uncommon to find this misunderstanding
of the GSS-API - and it has occurred in other protocols that ustilize
the GSS-API as well.

Having SSH_MSG_KEXGSS_ERROR as a debug message is fine, but it will
still only help when the client and server are of similar origins
(meaning that they share definitions for the minor status codes of their
supported mechanisms).  This limited utility makes SSH_MSG_KEXGSS_ERROR
less than useful, and, given that sending GSS error tokens interoperably
provides the relevant information to the client anyways I see no reason
to bother with SSH_MSG_KEXGSS_ERROR and its userauth friend.

That said, it is not absolutely necessary that SSH_MSG_KEXGSS_ERROR be
deprecated and I am not wedded to its deprecation as a practical matter
(i.e., the message is optional already), only as a matter of principle
(why send the client infomartion it may not be able to decode).

> >  - SSH_MSG_KEXGSS_CONTINUE should also be used to send any GSS "error"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >    tokens
^^^^^^^^^^^^^

Do you object to this?  This is the actual, backwards compatible draft
change needed to have interoperable communications about GSS errors.

This fix is interoperable because as soon as the client processes any
GSS error token sent by the server the client will fail gsskey ex just
as the server knows to fail it as well - SSH_MSG_KEXGSS_CONTINUE may
seem inappropriate for this purpose, but only because of its name; given
the need for a backwards compatible solution this additional use of
SSH_MSG_KEXGSS_CONTINUE is just fine.

> drafts.  I believe this is appropriate and should not be changed.

How do you propose that GSS error tokens be sent back?  Or do you
propose that they not be sent back at all?

Cheers,

Nico
--

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Mon, 18 Nov 2002 13:36:33 -0500 (EST)

> be GSS initiators and so on).

Sorry; I guess I was unclear.  I have no problem with recommending that
the SSH_MSG_KEXGSS_CONTINUE message be used to send error back error
tokens, provided that the party sending the error token (which, I believe,
could be the initiator or acceptor) remembers that it is in an error state
and does not then allow key exchange to succeed.

I only oppose dropping the SSH_MSG_KEXGSS_ERROR message, which I believe
provides useful debugging information that may not be available any other
way -- particularly if the mechanism in use does not generate interesting
error tokens.

All of the relevant messages should be optional or recommended, and we
should be consistent about it.  See the last paragraph of the security
considerations section, in which we recommend that it be possible to
configure servers _not_ to send the error message, in order to avoid
giving an attacker information that may help him to break in.

> being implementation specific.

You're right; we did fail to understand that.  We understand it now, and
we can certainly add text to address the issue of error tokens, since it
seems the right thing to do is not entirely obvious.  This is not
surprising, since the GSSAPI specs are notoriously difficult to fully
understand.

> to bother with SSH_MSG_KEXGSS_ERROR and its userauth friend.

I disagree.  The intent was never that the client would attempt to
interpret the status codes, but that it would display them to the user
(possibly only if an appropriate debugging option is enabled).  When a
user says "I tried to ssh into your machine and it didn't work", being
able to get them to report the status codes can be quite useful --
especially given that users are likely to report a code accurately when
they would attempt to interpret the meaning of a message.

> > >  - SSH_MSG_KEXGSS_CONTINUE should also be used to send any GSS "error"

For clarity:  No, I do not object to this.

-- Jeff

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Nov 2002 12:45:20 -0600

On Mon, Nov 18, 2002 at 11:16:13AM -0600, Nicolas Williams wrote:
> [...]

That should read "One need not misconfigure Kerberos ..." and
"... only when used against ..."

> [...]
>                         Alternatively the draft could be modified in a

That should read "... but I believe it's too late for that."

> [...]

Nico
--

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Nov 2002 13:20:30 -0600

[...]
> and does not then allow key exchange to succeed.

Ah.  Good.  Then there is no disagreement.  See below.

> way -- particularly if the mechanism in use does not generate interesting

My reading of the GSS-API RFCs is that both sides of a context setup
token exchange should be "synchronized," as it were, in that neither
side should produce an output token-less status when the other side
still expects a token (i.e., had GSS_S_CONTINUE_NEEDED).  The specs do
allow for one side to complete and then receive an unexpected error
token from the other side that was not expected (thus the spec provides
GSS_Process_context_token()).

Nothing else makes sense.

It would not be good for both sides to both produce GSS_S_CONTINUE_NEEDED
but both also produce no output tokens, for example.  I don't think that
the protocol using GSS-API ought to send messages saying "[still] waiting
for your token" unless GSS-API explicitly allowed for such deadlocks
which could then only be detected and broken with "waiting for your
token" messages defined by the application using GSS-API.

So I think that we should never see a situation, no matter what the
mechanism, where GSS_Init_sec_context() returns GSS_S_CONTINUE_NEEDED
and GSS_Accept_sec_context() returns a failure and no output error
token, as this should generally lead to the initiator "hanging."
Consider the gss-sample that comes with MIT krb5.  (Gotta go check the
SPKM/LIPKEY mech RFCs...).

> giving an attacker information that may help him to break in.

I don't think not sending a GSS error token should be optional, under
any circumstance, unless the alternative is to close the connection
without further ado.

I do agree that SSH_MSG_KEXGSS_ERROR should be optional, if it even
exist.  The complete/continue_needed messages must be required though.

[...]
> surprising, since the GSSAPI specs are notoriously difficult to fully

I agree. E.g., see above - I'm not sure I can "prove" my contention that
GSS mechs must be "synchronized" internally, not anymore than I could
"prove" that GSS error tokens exist...  If those RFCs are ever updated
there's several items that need clarification - here we have two.

> they would attempt to interpret the meaning of a message.

Why couldn't this be accomplished with debug messages on the server
side? Or with the server sending debug messages to the client? (there's
no debug messages during key exchange, are there?)

Regardless, the draft should be clear that the minor status code is
implementation specific and that the client should not attempt to
interpret it (the message in question has a field for a human readable
error message string anyways).

> For clarity:  No, I do not object to this.

Cool.  Problem solved.

> -- Jeff

Thanks,

Nico
--

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Mon, 18 Nov 2002 16:01:49 -0500 (EST)

> any circumstance, unless the alternative is to close the connection

Effectively, that is the alternative.  If there is an error, the server
sends up to three messages:

- optional SSH_MSG_KEXGSS_CONTINUE with the error token
- optional SSH_MSG_KEXGSS_ERROR with error status and message
- recommended SSH_MSG_DISCONNECT with SSH_DISCONNECT_KEY_EXCHANGE_FAILED.
- close the connection

For user auth the exchange is slightly different:
- optional SSH_MSG_USERAUTH_GSSAPI_TOKEN with the error token
- optional SSH_MSG_USERAUTH_GSSAPI_ERROR with error status and message
- required SSH_MSG_USERAUTH_FAILURE

Once the client receives SSH_MSG_USERAUTH_FAILURE, it aborts the GSSAPI
exchange and may either close the connection or try again.

> no debug messages during key exchange, are there?)

I don't see anything specific that prohibits debug messages during key
exchange.  However, the use of a separate "error" message makes it clear
that we are describing the reason for an error, which could have an effect
on whether the client displays the result to the user (for example, the
client may choose to try multiple user auth methods, and only display the
error information if all fail).

> error message string anyways).

Yes, I agree we should add some clarifying text.

-- Jeff

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Nov 2002 15:59:21 -0600

Ok, one more go around:

> - optional SSH_MSG_KEXGSS_CONTINUE with the error token

Why is this optional?  (To provide for error obfuscation?)  It should be
recommended, not merely optional.

BTW, GSS-API ought to provide a feature for error token obfuscation.
Better to let the mechanism determine what error information to send
than to let the GSS application get away with not sending error tokens.

In the meantime, I'd agree to making SSH_MSG_KEXGSS_CONTINUE w/ error
tokens optional, but recommended - SHOULD, in fact, and the error code
shrouding rationale should be described in the security considerations
section, say.

That brings up another question: do the various SSHv2 drafts
consistently provide for error code obfuscation where errors are sent on
the wire?  Should GSS-keyex be consistent with the other SSHv2 drafts on
this?

> error information if all fail).

Ok.

> Yes, I agree we should add some clarifying text.

Thanks.

Thanks,

Nico

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Mon, 18 Nov 2002 17:15:33 -0500 (EST)

> recommended, not merely optional.

Yes, that's the idea.  We can argue about which messages should be
recommended vs optional.  I'm inclined to make sending the error token via
a continue message recommended but not required, and make the error
message optional.

> than to let the GSS application get away with not sending error tokens.

Not necessarily.  The application may be in a much better position to
detect an ongoing attack than is the GSSAPI mechanism.  In any event, the
GSSAPI currently does not have such a feature, and this is not the forum
in which to discuss fixing GSSAPI.

> the wire?  Should GSS-keyex be consistent with the other SSHv2 drafts on

I think if you read over the drafts, you'll find that in most cases, no
mechanism is provided for passing specific error information back.

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Nov 2002 16:28:52 -0600

> a continue message recommended but not required, and make the error

Ok.  I vote for recommended (SHOULD).  A note should be made about not
sending error tokens for error obfuscation.

> in which to discuss fixing GSSAPI.

Indeed.  I mentioned that apropos the subject in question.  Arguably the
fact that GSS-API does not provide for error obfuscation does not
license applications to violate the spirit and letter of the GSS specs.
That said this is a minor, tolerable violation, provided it is
intentional (thus my vote for recommending that error tokens be sent).

> mechanism is provided for passing specific error information back.

Yeah, ok.

Thanks,
  
Nico
--