Subject: [kitten] WGLC of draft-ietf-kitten-gss-loop-00

From: Nico Williams <[email-masked]>
Date: Sat, 1 Nov 2014 02:32:56 -0500

The ambiguity in GSS_Process_context_token() may be easily resolved,
perhaps: it returns GSS_S_COMPLETE when a context deletion token is
processed correctly, and a minor status indicating something about what
happend, and if the context was terminated by the async context token, then
the application will find out on the next GSS call, which should preferably
be one to GSS_Inquire_context(), or from the way the error token was framed
by the peer.

---

From: Greg Hudson <[email-masked]>
Date: Sat, 01 Nov 2014 10:55:26 -0400

Responding point-by-point is causing miscommunication (specifically, in
several places you assumed that I was arguing with you when I was
agreeing), so I am going to address just one point and then re-summarize
the gss_process_context_token issue.

On 11/01/2014 02:07 AM, Nico Williams wrote:
> If we're not out to improve the state of the world, then what are we
> doing.

This draft was conceived of as a document that application protocol
specs can refer to so that they don't have to go on at length about how
implementations should perform GSS context negotiation.  As such, it is
informational and does not update RFC 2743.  It sounds like you oppose
publication of a document with only that scope, and instead want a
normative document with the ability to clarify and perhaps even change
RFC 2743.  I do not have a strong opinion on this question.

I agree that better diagnostics would be possible if, when processing
the last message in an exchange, an endpoint could generate an error
token to be processed by the other endpoint after context establishment.
 However:

1. I believe that mechanisms are not currently doing that (though I only
have high certainty with regard to the krb5 mech).

2. I believe with high certainty that applications are not currently
doing that.  The search results for gss_process_context_token are all
provider, no consumer.

3. I believe that some--perhaps most--GSS-using protocols, do not even
have a way to transport such error tokens.

4. The RFC 2743 specification of gss_process_context_token is broken for
this purpose (and for any purpose), in the following ways:

* It suggests that the token might result in context termination, but
does not specify that this always occurs.  It does not give the caller a
way to know whether the context is still alive or not.  It does not
specify whether the caller should still release the handle with
gss_delete_sec_context afterwards.

* It does not admit a way to communicate error information from a token
to the caller.

We can reasonably amend the specification of gss_process_context_token
to address these flaws, and then document that future protocols should
allow it and future implementations should do it.  In order to do so
with the gss-loop document, we would need to expand its scope such that
it is standard-track and updates RFC 2743.

If we decide to do that, then there are a few options for how we fix it.
 Modifying the function signature in the C bindings is not reasonable,
so we must assume the current signature which does not allow us to null
out the caller's context handle.  Therefore, that handle must remain a
valid C pointer (or table index or whatever, but real-world
implementations use pointers), and the caller must eventually call
gss_delete_sec_context to release it.  The remaining questions are:

* Should the caller assume that the context is dead (except for needing
to be released), or should it make no such assumption?  If the former,
should it assume that for all major return codes or only for some?  I do
not have a strong preference yet.  If the latter, I think we all agree
that future calls on that context handle (other than
gss_delete_sec_context) should result in GSS_S_NO_CONTEXT.

* Should properly validated error tokens result in GSS_S_COMPLETE with a
minor code, in GSS_S_FAILURE specifically, or in perhaps any of the
major codes which gss_init/accept_sec_context could return on an error
token?  The first option is weird for GSSAPI.  The third option is the
most programmatically informative to the caller, and is no less cleanly
delineated than the error results for init/accept_sec_context, so that
would be my preference.

---

From: Nico Williams <[email-masked]>
Date: Sat, 1 Nov 2014 16:59:40 -0500

> informational and does not update RFC 2743.  It sounds like you oppose

I'm not proposing that we update RFC2743.

I'm pointing out where this I-D diverges from RFC2743.  You're not
ackowledging this.  Please address that point without reference to
anyone's desire, real or imagined, to update RFC2743.

(Perhaps you thought that my asides about the ambiguities I see in
RFC2743 were me calling for updating it.  They weren't.)

Nico
--

---

From: Greg Hudson <[email-masked]>
Date: Sat, 01 Nov 2014 18:39:20 -0400

On 11/01/2014 05:59 PM, Nico Williams wrote:
> ackowledging this.

I acknowledge that RFC 2743 does mention post-establishment error tokens
in its description of gss_process_context_token.  However, this part of
RFC 2743 is broken (not ambiguous, broken) and everyone ignores it.
According to the current spec, an application calling
gss_process_context_token (1) does not receive error information from
the token, and (2) does not know whether the context handle is still
active and whether it is allowed to make further calls on that handle to
find out.

---

From: Nico Williams <[email-masked]>
Date: Sun, 2 Nov 2014 16:06:00 -0600

> active and whether it is allowed to make further calls on that handle to

[Now we're communicating.]

I don't agree.

First, the application can get error token information in the minor
status code result from GSS_Process_context_token().  Nothing in the
two RFCs prohibits returning a non-zero minor status code when
returning GSS_S_COMPLETE as the major status code.

Second, both existing cases of asynchronous context tokens denote that
the context is no longer usable (though GSS_Process_context_token()
does not itself delete the security context).

I don't see the problem.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Sun, 2 Nov 2014 16:13:45 -0600

I.e, I think RFC2743 is not sufficiently specific as to how async
error tokens are handled, but it's clear that they can occur, and
there's enough text to strongly imply the missing details, and the
simplest interpretation turns out to be simple enough.

To ignore this would be akin to making this I-D update RFC2743.

Nico
--

---

From: Benjamin Kaduk <[email-masked]>
Date: Sun, 2 Nov 2014 19:09:10 -0500 (EST)

I'll try to trim bits that have been elucidated by later parts of the
thread.

On Fri, 31 Oct 2014, Nico Williams wrote:

> On Fri, Oct 31, 2014 at 05:58:05PM -0400, Benjamin Kaduk wrote:
> > On Mon, 27 Oct 2014, Nico Williams wrote:
>
> > >  - We should say, in the intro, something about the expectation that the
> > >    application will add such things as:
> > >
> > >     - authentication + authorization success/failure messages
> >
> > I'm not entirely convinced about this.  We don't even necessarily know
> > that there is a user to see such messages.
>
> The message could be a boolean (success/fail), but it's necessary in
> many (but not all) applications.

I've started leaning towards thinking that it's worth finding a place to
list some things that are required of an application (protocol) using the
GSS-API which are not otherwise mentioned in the rest of the document;
things like authorization checks and the ability to convey error
information.

> > >  - Section 2.3, what is a "synchronous TCP channel"?
>
> That's very non-obvious.  You want an antonym for "multiplexed", I
> think.

I went with "dedicated".

> > [...].  How
> > about:
> >           The application protocol may also include a facility for
> >           indicating errors from one party to the other, which can be
> >           used to convey errors resulting from GSS-API calls, when
> >           appropriate.  Note that GSS major and minor status codes
> >           are specified by language bindings, not the abstract API,
> >           so may not be directly interpretable by the other peer.

[lots of diatribe trimmed]

So, this text is supposed to be about what the application (protocol) does
*when it didn't get an error token from the GSS implementation*.
If you get a token, of course send it, but there can be situations where
the local state is in error but there is no token to send.  It's still
useful to convey some error information in this case, and that's most of
what the "when appropriate" is supposed to be saying.

>  "...should assume that the [peer's] state is invalid..." just strikes
>  me as really weird.  Developers understand "timeout".

How about "state is invalid (time out)"?

> You can list them if you like, but please say that all request flags
> must be kept the same throughout.

Currently this is like "the initiator specifies as part of its fixed set
of inputs to GSS_Init_sec_context() values for [the list of flags] (and
any additional request flags [...])".  The key part being the "fixed set
of inputs", i.e., yes, they should be kept the same throughout.

The email exchanges we've been having are making me wonder if that should
be made more prominent.

> >           Applications using per-message operations
> >           on a partially complete security context should take into
> >           consideration the fact that replay protection is not avaiable
> >           from the GSS-API for those messages, and take the appropriate
> >           protective measures.
>
> You also need to say that they shouldn't send data requiring
> confidentiality protection (since at the time the per-message token is
> sent the peer may not yet be authenticated).

A good point.  (I might not oppose just removing all treatment of
per-message operations on a partically complete context, since this
document is informational only...)

[discussion of error context token trimmed]

Some other messages in this thread (which I won't go find and quote) seem
to imply that you think applications will have trouble with GSS context
exchanges involving an odd number of tokens; the whole point of this
document is to provide clear guidance to application protocol designers
such that they can handle the fully generic case, whether it is an odd or
even number of tokens in the exchange.  I furthermore think that we are
agreed that new application protocols being developed should include
provision for sending error tokens occuring on processing of the last
regular context token (regardless of whether existing protocols do or
existing mechanism implementations generate such tokens).

The main disagreement centers around process_context_token, which I will
cover in a reply to a later message in the thread.

[GSS_ERROR()]

There are three occurrences of the string "GSS_ERROR" in this document;
two are in the sample code, and the third is:
        [sample code is written in C.]  It uses the macro GSS_ERROR() to
        help unpack the various sorts of information which can be stored in the
        major status field; supplementary information does not necessarily
        indicate an error.  Applications written in other languages will
        need to exercise care that checks against the major status value
        are written correctly.

I could add a note here that GSS_ERROR() should not be used for
per-message token operations (and say why that is the case in the
security considerations), or I could remove its use entirely.  I'm still
undecided what I think is best.  If I understand correctly, you prefer to
remove its use entirely.  In some sense, I guess this is a conflict
between being formally correct as per 2743 and 2744, and operating
securely with current best practices.

> > >     - Why not mention authorization (use a stub function) and
> > >       application-level status message in do_acceptor()?
> >
> > I believe there were previous discussions around this, and Greg convinced
> > me that such checks fit more naturally outside of do_acceptor(), which
> > should just be about establishing the context.  This may be another case
> > where guidance on the use of the GSS-API is lacking, but this document is
> > not the appropriate place to rectify that.
>
> This is asking for a security vulnerability.  We must teach proper use
> of the API.
>
> > The closest we get is to pass &client_name to gss_accept_sec_context(),
> > which we then proceed to not do anything with.
>
> Just add a call to a stub function.

Another issue with trying to cover this is that we get into the
rabbit-hole of whether to do "the right thing" and maintain a local
database of exported names, or just do string processing on the display
name.

> > >     - This:
> > >
> > >         } else {
> > >             /* This situation is forbidden by RFC 2743.  Bail out. */
> > >             warnx("major not complete or continue but not error\n");
> > >             goto cleanup;
> > >         }
> > >
> > >       would be an internal error, not behavior forbidden by RFC2743,
> > >       because you break out of the loop in this case before ever getting
> > >       here.  You should either assert() or ignore this.
> >
> > Hmm?  I think this case covers at least a major status code with
> > no fatal error codes set but a per-message-token informatory status code
> > set, which is indeed forbidden by 2743.
>
> Right, which answers your question about as to GSS_ERROR().  Don't use
> GSS_ERROR().  Instead treat any GSS_S_COMPLETE-with-supplementary-
> status-codes-other-than-GSS_S_CONTINUE_NEEDED as errors.  It's easier,
> it's less code, easier to explain.

I think I've realized why this makes me uncomfortable -- we only provide
sample code with the C bindings, but there are other language bindings
(Java is specified, and I hear there is work on python bindings in
progress); these other language bindings may not use the same
representation for the major status values, and the assumptions that are
valid in C may not remain valid if the sample code is translated to a
different language.

> > >  - What about mentioning the possible need to check -on the acceptor
> > >    side- the name of the acceptor as used by the initiator?  That's a
> > >    gss_inquire_context() call to get the name of the acceptor, then a
> > >    gss_compare_name() function call (or any of the other methods of
> > >    comparing names given in RFC2743).
> >
> > "What is the possible need for that check?"
>
> Consider an application with keys for many principals in its keytab...

Did you answer Greg's question about what it would be compared to?  Oh,
yes, you did (with several alternatives).

I think at present I'm inclined to not give a detailed treatment of this
subject, and rather mention that applications which can accept context
using different names (such as by using the default credential set) may
need to introspect the name of the acceptor as specified by the initiator
to enforce local policy (possibly with more details in the security
considerations).

-Ben

---

From: Benjamin Kaduk <[email-masked]>
Date: Sun, 2 Nov 2014 20:08:00 -0500 (EST)

> returning GSS_S_COMPLETE as the major status code.

I think that Martin's gsstest program complains about it, though :)

> does not itself delete the security context).

It seems somewhat debatable whether GSS_Process_context_token() deletes
the security context (viz. the last paragraph of page 5, which you noted
previously); the contraints of the C bindings' API means that it should
not do so, just ~render the context handle unusable.  Hmm, the Java
bindings don't have a process_context_token at all.

I think that the behavior we should recommend to applications is to call
GSS_Process_context_token(), followed immediatly by GSS_Inquire_context(),
and GSS_Delete_sec_context() as appropriate (at present: always), to
provide reasonable behavior and be future-proof.

That said, is it even within the scope of the gss-loop document?

-Ben

---

From: Nico Williams <[email-masked]>
Date: Mon, 3 Nov 2014 10:02:51 -0600

> things like authorization checks and the ability to convey error

:)

> *when it didn't get an error token from the GSS implementation*.

Oh, I guess I misunderstood that.  My apologies.

> what the "when appropriate" is supposed to be saying.

Sending a minor status code is never appropriate.  Major status codes
convey very little information.

My advice in that case is to optionally send the display form of the two
status codes, along with the major status code numeric value.

> How about "state is invalid (time out)"?

Fine.

> The email exchanges we've been having are making me wonder if that should

I'd noticed that text.  I'd a reason to ask for a change, but it may
have gotten lost.  My proposal:

OLD:
   The initiator specifies as part of its fixed set of inputs to
   GSS_Init_sec_context() values for the following booleans:
   deleg_req_flag, mutual_req_flag, replay_det_req_flag,
   sequence_req_flag, conf_req_flag, and integ_req_flag.  Upon ..

NEW:
   The initiator specifies as part of its fixed set of inputs to
   GSS_Init_sec_context() values for all defined request flag booleans,
   among them: deleg_req_flag, mutual_req_flag, replay_det_req_flag,
   sequence_req_flag, conf_req_flag, and integ_req_flag.  Upon ...

The point is that this is an open set.

> document is informational only...)

I wouldn't either!  PROT_READY is a neat feature, but it is optional and
difficult to use safely, therefore it seems best to not mention it here.

> existing mechanism implementations generate such tokens).

Agreed.

> securely with current best practices.

I believe that GSS_ERROR() was in fact intended for use with per-message
token functions (gss_unwrap() and gss_verify_mic()): otherwise why
ignore supplementary major status code bits that are only relevant to
those functions?

However, it was a bad idea.  Too many application protocol implementors
used GSS_ERROR() -without checking the supplementary status code bits-
when they intended to implement an octet stream.  Octet streams are
incompatible with any supplementary status code bits from those
functions.  In practice many application protocols using the GSS-API
want an octet stream.

The GSS_ERROR() macro should have had a second parameter indicating
whether an octet stream is intended.  Then it wouldn't have been
dangerous.

The best thing we can do is tell developers never to use GSS_ERROR()
when intending to consume an octet stream.

FYI, I've seen this bug in:

 - a couple of SASL GS1 implementations
 - at least two FTP w/ GSS implementations
 - at least one non-standard GSS application

> database of exported names, or just do string processing on the display

I think we can simply refer to the relevant sections of RFC2743 and
RFC6680.

> [...]

Good point.

> yes, you did (with several alternatives).

:)

At least two sshd implementations do something about this, IIRC.

> to enforce local policy (possibly with more details in the security

I agree.  A small amount of text and references to relevant sections in
RFC2743 should suffice.  Something like:

   When using the default credential handle to accept security contexts,
   the mechanism is free to accept contexts for any name for which the
   acceptor has credentials.  This might be problematic.  Acceptor
   applications can check what target name the initiator used, but the
   details are out of scope for this document.  See RFC2743 sections
   2.2.6 and 1.1.5, and RFC6680.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Mon, 3 Nov 2014 10:06:11 -0600

> I think that Martin's gsstest program complains about it, though :)

But is it normative? :)

> bindings don't have a process_context_token at all.

The C bindings gss_process_context_token() cannot delete the security
context.

For the abstract GSS_Process_context_token() it's a bit less clear, but
that's OK: this is the sort of detail that is OK to leave to the various
programming language bindings.

> provide reasonable behavior and be future-proof.

I agree.

> That said, is it even within the scope of the gss-loop document?

I think so.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Mon, 3 Nov 2014 12:02:09 -0600

> > I think that Martin's gsstest program complains about it, though :)

BTW, RFC2744 says that minor_status is always set, and it doesn't define
any numeric values for it, not even "no error", not even zero.

Therefore I think gsstest is wrong to complain about it.

---

From: [email-masked] (Martin Rex)
Date: Mon, 3 Nov 2014 22:33:26 +0100 (CET)

> token to be processed by the other endpoint after context establishment.

I assume you are referring to "last [context level] message in an exchange"
here?

> have high certainty with regard to the krb5 mech).

AFAIK, Microsoft Kerberos has been trying to do this for the last 14years,
and has been trying to mislead the context acceptor about the error
nature of the token by indicating the equivalent of CONTINUE_NEEDED
to get the calling server app to transfer the token to the client.

> doing that.  The search results for gss_process_context_token are all

Few apps, if any, do that.  Ours does not.  My gsskrb5 wrapper even
peeks inside kerbers context tokens to detect camouflaged kerberos
error tokens so that the calling (server) app gets to see that there
was an error.

Microsoft runs its own TLS implementation under a GSS-API style interface,
and you notice from Microsoft IIS never sending fatal alerts upon
handshake failures before closing the network connections that apps
typically ignore error tokens.

> have a way to transport such error tokens.

Probably true.  Even mine does not have it. (While I do have a possibility
to run a new context handshake to replace an expiring or expired gss context).

> * It does not admit a way to communicate error information from a token

I read rfc2743 differently.

rfc2743 simply did _not_ want to limit future extensibility of
the purposes of gss_process_context_token().

Currently, there exist only two calls that can produce context-level
tokens that for which a necessity to call gss_process_context_token()
may arise:

   (1) an "unexpected" context level token from one of the security context
       establishment iterators (init_sec_context or accept_sec_context)
       which the intended receipient can therefore no longer feed into
       his context establishment iterator call.

   (2) a context deletion token as a result of a call to
       gss_delete_sec_context().  In principle, this token needs to always
       be passed to gss_process_context_token() by the recipient, but
       there is a small grey area about the situation where one side
       calls this without ever completing the context establishment
       handshake/loop.

In (1) the context never was usable for the creator of the token,
so it doesn't really matter whether the status changes for the recipient
of the token.  In (2), the context is _no_longer_ usable for the creator
of the token (because it has been deleted), so it also does not really matter
whether the status changes for the recipient of the token.

> gss_delete_sec_context) should result in GSS_S_NO_CONTEXT.

No, I would strongly discourage that.  GSS_S_NO_CONTEXT refers to
the validity of the context *handle*, not to the ability to use the
referenced context.  GSS_S_NO_CONTEXT would indicate that this handle
can also not be passed to gss_delete_sec_context(), which is wrong,
because it *needs* to be passed to gss_delete_sec_context() for release
of the associated resources.

> delineated than the error results for init/accept_sec_context, so that

Processing of a context deletion token should result in GSS_S_COMPLETE
(provided that the mechanism has/uses any such thing).

Processing of a context error token should probably result in
GSS_S_FAILURE accompanied by a meaningful minor_status.  There is
no other suitable error code defined in rfc2743.

GSS_S_DEFECTIVE_TOKEN would apply only to a defective error token,
not to convey information about a previously received defective
context token, and GSS_S_NO_CONTEXT refers to the context _handle_ state.

-Martin

---

From: Nico Williams <[email-masked]>
Date: Mon, 3 Nov 2014 15:39:33 -0600

> context token, and GSS_S_NO_CONTEXT refers to the context _handle_ state.

I agree with this interpretation.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Mon, 3 Nov 2014 15:48:02 -0600

> I agree with this interpretation.

Well, actually, this is one of two interpretations that I would agree with.

The other interpretation is that GSS_S_COMPLETE is to be returned for
the error token case, with the error information in the minor status.
The caller can then use GSS_Inquire_context() to determine the
context's current state.

The problem is that RFC2743 doesn't say that GSS_S_FAILURE is the case
that corresponds to an error token.

But I think your interpretation is the most correct one, the one that
makes most sense, and we should say that this is an error in RFC2743
(and file the erratum).

Nico
--

---

From: [email-masked] (Martin Rex)
Date: Tue, 4 Nov 2014 20:18:21 +0100 (CET)

Nico Williams wrote:
>
> Nico Williams <[email-masked]> wrote:
>>
>> Martin Rex <[email-masked]> wrote:
>>>

It's difficult to make a recommendation here.  Your suggestion to
return a non-zero minor_status along with GSS_S_COMPLETE would be OK
with the specification (rfc2743), but application callers typically
to not look at minor_status at all when major_status==GSS_S_COMPLETE,
and I'm not particularly enthusiastic to see a recommendation to give
meaning to minor_status!=0 when major_status==GSS_S_COMPLETE.

> that corresponds to an error token.

IMHO the highest probability to get to see any error message from
an (unsuspecting) app (if it calls gss_process_context_token() at all)
is when using GSS_S_FAILURE.  A non-zero minor_status values that
accompanies GSS_S_COMPLETE has a high likelyhood to get ignored entirely.

-Martin

---

From: Nico Williams <[email-masked]>
Date: Tue, 4 Nov 2014 13:25:12 -0600

> meaning to minor_status!=0 when major_status==GSS_S_COMPLETE.

Well, it'd be exceptional, but workable.  I prefer your
interpretation.  I've filed an erratum to that effect, FYI.

Agreed.

Nico
--

---

From: [email-masked] (Martin Rex)
Date: Tue, 4 Nov 2014 20:33:45 +0100 (CET)

> active and whether it is allowed to make further calls on that handle to

The mere existence of a context deletion or error token does not change
the status of the context handle.

Feeding a context deletion or error token to gss_process_context_token()
will probably impair message protection services, in case these have
been previously available, so there will may be a difference in
the output of gss_inquire_context() before and after the call to
gss_process_context_token().  If the prior value of the "open" boolean
was TRUE, then it will likely be FALSE after gss_process_context_token().

The final paragraph of the description of gss_inquire_context() in
rfc2743 reads:
   https://tools.ietf.org/html/rfc2743#page-57

   o  GSS_S_FAILURE indicates that the requested operation failed for
   reasons unspecified at the GSS-API level. Return values other than
   major_status and minor_status are undefined.

   This call is used to extract information describing characteristics
   of a security context.  Note that GSS-API implementations are
   expected to retain inquirable context data on a context until the
   context is released by a caller, even after the context has expired,
   although underlying cryptographic data elements may be deleted after
   expiration in order to limit their exposure.

so I believe that gss_inquire_context() should also remain possible after
calling gss_process_context_token(), i.e. should not fail.  I would
certainly prefer to have gss_process_context_token() rather than
gss_inquire_context() to report the error from an incoming error context
token. 

-Martin

---

From: Nico Williams <[email-masked]>
Date: Tue, 4 Nov 2014 14:44:38 -0600

> will probably impair message protection services, in case these have

Emphasis on 'probably'.  There's no requirement as to this.

My take is that currently[*] all possible tokens that can only be
processed with GSS_Process_context_token() necessarily denote that the
sender no longer has a security context with which to process any
further tokens, either because of context establishment error or because
of a call to GSS_Delete_sec_context().

[*] One could imagine future re-keying/re-establishment extensions (a la
    TLS renego) that would change this, but we're not there, no one is
    proposing such extensions, and if anyone ever does it won't be the
    end of the world if today's GSS applications don't support it
    since... they couldn't anyways.

> was TRUE, then it will likely be FALSE after gss_process_context_token().

We all seem to agree as to this.  But still ISTM that your proposal,
that error tokens elicit GSS_S_FAILURE from GSS_Process_context_token(),
is the right interpretation since there's no other case that could
legitimately yield GSS_S_FAILURE from GSS_Process_context_token().

> calling gss_process_context_token(), i.e. should not fail.  I would

Yes.  Besides, it's clear that GSS_Process_context_token() does not
delete the context, and it's even more clear that this is true in the C
bindings.

Agreed.

Nico
--

---

From: [email-masked] (Martin Rex)
Date: Wed, 5 Nov 2014 00:32:43 +0100 (CET)

> Therefore I think gsstest is wrong to complain about it.

The relevant gsstest plausibility tests look like this:

   if ( minor_status==BOGUS_VALUE ) {
      XVEB((V_ERR, "%s() FAILED to clear minor_status!\n", call_name));
      rc++;
      minor_status = 0;
   }

   if ( major_status==0 && minor_status!=0 ) {
      rc++;
      XVEB((V_ERR, "%s() unexpected non-zero minor_status (%08lx)!\n",
                   call_name, (Ulong) minor_status));
   }

So gsstest complains only about _bogus_ return values for min_stat,
which is a conformance test suggested by rfc2744 section 3.9.2:

  https://tools.ietf.org/html/rfc2744#page-15

   3.9.2. Mechanism-specific status codes

   GSS-API routines return a minor_status parameter, which is used to
   indicate specialized errors from the underlying security mechanism.
   This parameter may contain a single mechanism-specific error,
   indicated by a OM_uint32 value.

   The minor_status parameter will always be set by a GSS-API routine,
   even if it returns a calling error or one of the generic API errors
   indicated above as fatal, although most other output parameters may
   remain unset in such cases.  However, output parameters that are
   expected to return pointers to storage allocated by a routine must
   always be set by the routine, even in the event of an error, although
   in such cases the GSS-API routine may elect to set the returned
   parameter value to NULL to indicate that no storage was actually
   allocated.  Any length field associated with such pointers (as in a
   gss_buffer_desc structure) should also be set to zero in such cases.

For unexpected non-zero minor_status values, it only returns an
indication that -- whatever this value is supposed to mean -- it will
go entirely unnoticed by applications (and therefore admin/users)
when it accompanies a GSS_S_COMPLETE status.

While it is technically true that there is no official designation
in the GSS-API v2 C-Bindings (rfc2744) for a minor_status value with
the meaning of "absent" / "not available", using "0" for this purpose
looked like an intuitive natural fit (for C-bindings), and my app code
on top of GSS-API will not even try to obtain a description for
a 0 minor_status value.

-Martin

---

From: Benjamin Kaduk <[email-masked]>
Date: Tue, 4 Nov 2014 21:51:20 -0500 (EST)

I'm working on a summary of the options and their downsides, but

> legitimately yield GSS_S_FAILURE from GSS_Process_context_token().

Well, there are always mundane things like ENOMEM.
But we are kind of stuck with no good options, so we may have to ignore
those cases.

-Ben

---

From: Benjamin Kaduk <[email-masked]>
Date: Tue, 4 Nov 2014 22:21:29 -0500 (EST)

I think we are approaching consensus about the right behavior for these
error tokens and GSS_Process_context_token(), so I will try to summarize
the options that have been considered and the arguments for and against
them.  (Initially I favored a different approach than proposed by Martin,
but upon closer reading of 2743 I believe I am in agreement with his
proposal.)

Upon receiving a context-level token after its call to
GSS_{Accept,Init}_sec_context() has succeeded, a peer may end up calling
some or all of GSS_Process_context_token(), GSS_Inquire_context(), and/or
GSS_Delete_sec_context(), in that order.  Options that have been
considered include:

(0) Do nothing with the token; call GSS_Delete_sec_context() because the
token must mean that the context is no longer usable.

This is bad both because it does not verify the authenticity of the token
and because it has no way to convey the actual error information to the
user.

(1a) Pass the token to GSS_Process_context_token(), which returns success
and deletes the context data.  Do not call GSS_Delete_sec_context() and
assume that GSS_Process_context_token() has done that work for us.

This is not supported by RFC 2743; furthermore, the C bindings in RFC 2744
do not provide a way for the context handle to be fully invalidated, so
this clearly cannot be correctly implemented.

(1b) Pass the token to GSS_Process_context_token(), which returns a
different value depending on whether the token was an error token or a
deletion token.  Whether Delete_sec_context is necessary depends on the
particular return.

Simlar to (1a); additionally this is too complicated a contract to
reasonably impose on applications.

(1c) Pass the token to GSS_Process_context_token(), which returns success
and marks the context as unusable.  Call GSS_Inquire_context() to
determine whether the context is still valid (returning success and
looking at its outputs), and GSS_Delete_sec_context() when we're done.

This is appealing to me because process_context_token() succeeds at what
it is doing (processing the token), and it seems natural for something
with the name Inquire_context() to tell me whether my handle is still
valid or not.  However, Inqure_context() is not really designed to produce
this kind of information; it gives names, a lifetime, the mech, and some
booleans corresponding roughly to the request flags, and 'open'.  'open'
is described as TRUE if fully established, and FALSE if partly established
(in CONTINUE_NEEDED) state.  Neither one is appropriate for "deleted" (or
similar).  While it's true that the conf_avail and similar booleans are
likely to be false after the processing of an extra token, that's a
terrible way for applications to be able to tell that the context has been
invalidated and should be deleted.  Furthermore, GSS_S_COMPLETE "indicates
that the referenced context is valid", and the only error returns are
GSS_S_NO_CONTEXT (the supplied handle was not valid) and GSS_S_FAILURE
(the (inquire) operation failed).

(1d) Pass the token to GSS_Process_context_token(), which returns success.
Error reporting is deferred until a call to GSS_Inquire_context(), which
returns an error corresponding to the information in the token.  (Whether
or not GSS_Delete_context() is called is not relevant for the discussion.)

2743 implies that Inquire_context() really should be able to succeed in
this situation, so errors from it are not an appropriate way to convey
status information.

(2a) Pass the token to GSS_Process_context_token(), which returns success
with a minor code indicating the error.  Inquire_context is optional;
Delete_sec_context is required.

This is probably not the right thing to do for a deletion token; we mostly
should just be ignoring those, these days, I think.

(2b) Pass the token to GSS_Process_context_token(), which returns success
with a minor code indicating the nature of the error in the token for
error tokens, and just success for deletion tokens.

Nico would accept this, but it's really weird within the GSS-API to have
information in the minor status when the major status is GSS_S_COMPLETE.

(3a) Pass the token to GSS_Process_context_token(), which returns
GSS_S_COMPLETE for deletion tokens and GSS_S_FAILURE for error tokens.
Inquire_context() is still usable, and we always must call
Delete_sec_context().

Martin and Nico are okay with this one.  The only downside is that 2743
doesn't document GSS_S_FAILURE as meaning quite this; rather "the context
is recognized, but that the GSS_Process_context_token() operation could
not be performed for reasons unspecified at the GSS-API level."  It's not
really clear what that is supposed to mean, so maybe it's okay if we feel
free to interpret as something that results in a mostly usable API.  (It
is still possible for confusion with local errors like ENOMEM, but maybe
the minor code will be enough to disambiguate.)  Returning GSS_S_FAILURE
is a decent way to get applications to report an error to the user which
is consistent with expectations for error reporting elsewhere in the
GSS-API.

(3b) Pass the token to GSS_Process_context_token(), which returns
GSS_S_FAILURE for both kinds of tokens.  As in (3a), Inquire_context()
works and Delete_sec_context() is required.

As mentioned previously, we probably should just be ignoring deletion
tokens.  This is otherwise similar to (3a), and thus probably tolerable.

(4) Pass the token to GSS_Process_context_token(), which returns some
other major code than GSS_S_FAILURE which would be returned from
GSS_{Init,Accept}_sec_context upon receipt of an error token.

Not supported by the return codes documented in RFC 2743, which are just
GSS_S_DEFECTIVE_TOKEN, which would apply to the token itself, not its
contents; and GSS_S_NO_CONTEXT, which refers to the supplied handle's
state.  There is some potential, but the meanings of the errors would not
be very clear, and would be a large change from the published spec.  Just
returning the same error that the other side emitted when the error token
was produced is probably not okay, as that would collide with some of the
existing documented return values for Process_context_token().

So, it looks like the least bad option is (3), and we are leaning towards
the (3a) variant based on Martin's preference.

Does that seem like a reasonable summary?

-Ben

---

From: Nico Williams <[email-masked]>
Date: Tue, 4 Nov 2014 22:12:15 -0600

> GSS_Delete_sec_context(), in that order.  Options that have been

I don't think it was ever the case that not calling Delete_sec_context()
was OK in the case of context tokens arriving after full security
context establishment.

> and because it has no way to convey the actual error information to the

Agreed, though it's not necessarily as bad as all that (the error token,
for example, may not be integrity protected, in which case a DoS would
be possible even if we bother calling GSS_Process_context_token()).

(1a) was never proper.

> deletion token.  Whether Delete_sec_context is necessary depends on the

As of today and per-RFCs 2743 and 2744, GSS_Delete_sec_context() must
always eventually be called upon processing an error/deletion token
_except_ when processing returns GSS_S_DEFECTIVE_TOKEN (i.e., the token
may well not have been an error/deletion token).  But even here, the
application might well find that the peer is no longer responsive or
closes the connection/whatever.

With that note, (1b) is almost indistinguishable from (3a).

> looking at its outputs), and GSS_Delete_sec_context() when we're done.

This works for me as a second choice.  It may leave more room for future
extensibility, but I don't think so: if, for example, we were to add
something like TLS renego I'd expect a new req_flag/ret_flag and/or
function call to indicate application support for the feature.

> similar).  [...]

The context *must* have been open if we got to this point -- otherwise
the token would have been passed to one of GSS_Init/Accept_sec_context().
The context no longer being open (if Inquire_context() says so) is
indicative that the context is now to be deleted.  It can't already be
deleted at this point.  Therefore there's nothing weird about the 'open'
output being FALSE at this point.

> (1d) [...]

I think I might have offered (1d) at some point.  If I did I retract it
now.

> should just be ignoring those, these days, I think.

We can't externally and securely tell if it is a deletion token.  Having
GSS_S_COMPLETE for both, error _and_ deletion tokens would mean we never
could tell.  That would be mildly dissatisfying, but I could live with
it.

> error tokens, and just success for deletion tokens.

Remember, there's no defined no-error minor status.  (2b) is
indistinguishable from (2a) unless we also codify that the zero minor
status value is no-error.

(2b) is better than (2a) because it allows error and deletion tokens to
be distinguished.

> information in the minor status when the major status is GSS_S_COMPLETE.

It's not necessarily all that weird.  For one, the RFCs never say this
can't happen...

> Martin and Nico are okay with this one.  The only downside is that 2743

Yes.  I think it's fair to say that Martin prefers this.  I do prefer
this.

> is consistent with expectations for error reporting elsewhere in the

I agree, but since either way it was curtains for the context, this
slight ambiguity between exceptional local errors and every day remote
errors is acceptable to me.

> works and Delete_sec_context() is required.

This contradicts RFC2743 as to deletion tokens.

> tokens.  This is otherwise similar to (3a), and thus probably tolerable.

I'm not so sure that obsoleting deletion tokens was a good idea...  But
let's leave that thought for some other day; we're having enough fun
with this problem as it is.

> GSS_{Init,Accept}_sec_context upon receipt of an error token.

A lot of common errors have those two functions return GSS_S_FAILURE.
The other errors probably don't cover all errors that the error token
might be reporting.

ASIDE: I see that I was wrong about the other supplementary major status
       codes: the two RFCs do list them for GSS_Init/Accept_sec_context().
       If you could see me now, you'd see me wiping egg from my face.

> the (3a) variant based on Martin's preference.

I'm pulling for (3a), yes.

My preferences, from most- to least-preferred:

3a, 2b, 2a.  I reject the others.

> Does that seem like a reasonable summary?

Yes.

Nico
--

---

From: [email-masked] (Martin Rex)
Date: Wed, 5 Nov 2014 23:14:50 +0100 (CET)

Thanks Ben for the summary.

I hadn't seen as many options/variants in the discussion,
but I'm also not missing anything, and I also only jumped into the
discussion very late.

I'm following up to Nico's response for brevity.

Nico wrote:
> Ben wrote:
> Yes.  I think it's fair to say that Martin prefers this.  I do prefer this.

Confirmed. My preference is (3a).

When trying to extend an existing spec that seems incomplete or
ambiguous, it may help to follow the general guideline of
"the principle of least surprise" and look at similar *known*
situations that either already exist or can easily be constructed.

Kerberos should be a suitable mechanism to describe what we have
and figure out what should be.

rfc1964 defines two variants of the Kerberos authentication:

1) initiator-to-target authentication with a single context token

2) initiator-to-target plus target-to-initiator authentication
   ("GSS_C_MUTUAL_FLAG") with two context tokens, one from initiator
   to acceptor and one from acceptor to initiator.

A number of possible error situations that can occur during the
acceptors call to gss_accept_sec_context() will equally be possible
in either of these authentication variants, and could therefore result
in the exact same KRB_ERROR token.

The difference is, that in (1), there is no expected context level token,
so if gss_accept_sec_context() returns a context level token at all,
and if it is sent back to the initiator at all (in spite of
that token being accompanied by a FATAL major_status from
gss_accept_sec_context()), the initiator will have to pass it to
gss_process_context_token(), because his initial call to
gss_init_sec_context() completed with GSS_S_COMPLETE, and the
initiator does not really expect another context level token.

I firmly believe, that the same error cause should result in mostly
the same "look and feel" for the initiator (and the user/caller on
top of the initiator side) for both situations (1) and (2).

In (2), the KRB_ERROR token will be processed by gss_accept_sec_context()
and should cause a fatal major status along with a helpful minor_status
that conveys the reason from the KRB_ERROR token.

In (1), the closest matching behaviour would be that
gss_process_context_token() behaves much like gss_accept_sec_context()
behaves when processing that very KRB_ERROR token.

The only well-defined means how a gss-api mechanism can get a
mechanism-specific error shown to a user/caller is by making a
gssapi call return a fatal major_status along with a helpful minor_status.

The context-iterators (gss_init_sec_context/gss_accept_sec_context)
are very close relatives to gss_process_context_token() with respect
to processing error tokens, because error tokens that are transfered
as a substitute to a regular, expected context level token will be
processed by a context-iterator, whereas error tokens that are going
to be "unexpected" context level tokens will have to be processed
by gss_process_context_token().

Having gss_process_context_token() return an error upon processing
a context deletion would look strange to me.  This certainly does not
fit the meaning of failure for that call and if a pair of application
callers uses a context deletion token to "smoothly" close down
a communication channel, why should they receiver be facing a
fatal error message that is _not_ suggested anywhere in the existing
specification.

> was OK in the case of context tokens arriving after full security

Agreed.  There are only two calls that may delete a context (handle):
gss_delete_sec_context() and gss_export_sec_context().

gss_init_sec_context() and gss_accept_sec_context() can only fail to
create&return a valid context handle (on the initial call) but should
not delete a context handle that was created by an earlier iterator call.
(from the perspective of formal correctness proofing).

> closes the connection/whatever.

Whether receipt of a context level token that is rejected with
GSS_S_DEFECTIVE_TOKEN by the gssapi mechanism is to be seen as
a fatal termination of the communication depends on the specific
application an protocol.  There certainly should be some _low_ threshold
how often the application caller on top of gssapi should allow that
to happen and be ignored, or it may open a security vulnerability
(access to an "Oracle").  This is how DTLS was made practically
susceptible to LuckyThirteen, whereas the same attack isn't practical
for TLS, where integrity failures of the communication always fatally
terminate the connection.

> function call to indicate application support for the feature.

I'm not aware of any currently well-defined situation/behaviour where
an application that (a) receives a context level token after context
establishment, and (b) properly hands the token to gss_process_context_token()
could expect to continue using the security context.

A number of "application protocols" that embed gssapi tokens may not
have a mechanism to label/tag tokens with their token type (context vs.
message protection token), and instead, the nature of the token is
implied (everything sent&received before the local context iterator
call returns GSS_S_COMPLETE is a context level token, everything after
it is a message protection token.

To positively indicate the end of a data transfer, FTP Security extensions
(rfc2228) uses a zero-length protected message:

  http://tools.ietf.org/html/rfc2228#page-15

   When the end of the file is reached, the sender must encode a block
   of zero bytes, and send this final block to the recipient before
   closing the data connection.

(Side note: Microsoft botched the processing of zero-length message
 tokens in the Microsoft Kerberos SSP in Windows 7 and keeps refusing
 to fix it.  It is still botched in Windows 8.  DecryptMessage()
 will fail with SEC_E_MESSAGE_ALTERED when trying to unprotect
 a received zero-length message and passing it to DecryptMessage()
 in SECBUFFER_STREAM after reading it from the network.)

> could tell.  That would be mildly dissatisfying, but I could live with

While the factual result for the connection would be the same (no more data
transfer), having gss_process_context_token() return GSS_S_COMPLETE would
make creation, transfer and processing of an error token a silly&useless
operation.  And the difference in processing an error token in
kerberos 1-token (unidirectional) authentication and 2-token (mutual)
authentication does not look appealing/desirable to me.

> status value is no-error.

While it is true that rfc2744 fails to explicitly define a "no-error"
minor status code, the spec implicitly requires that one exist (because
the gssapi mechanism is explicitly required to _set_ minor_status on
each return of a gssapi function.  So not saying that minor_status==0
is a no-error looks like a specification defect of the omission kind
where the fix is obvious and natural.

> It's not necessarily all that weird.  For one, the RFCs never say this

As describe above, this is an implied requirement. YMMV.

Expertise&experience is unevenly distributed across implementors,
and often time pressure / deadlines pre-empt the necessary think-time
for common sense to kick in before code gets shipped.

>        If you could see me now, you'd see me wiping egg from my face.

I would be OK with making the behaviour of gss_process_context_token()
when processing an error token match that of the context iterator call
(gss_init_sec_context(),gss_accept_sec_context()) when processing this
error token.

-Martin

---

From: [email-masked] (Martin Rex)
Date: Wed, 5 Nov 2014 23:51:56 +0100 (CET)

Fixing two typos ( s/gss_accept_sec_context/gss_init_sec_context/ ):
I'm sorry.

  In (2), the KRB_ERROR token will be processed by gss_init_sec_context()
  and should cause a fatal major status along with a helpful minor_status
  that conveys the reason from the KRB_ERROR token.
  
  In (1), the closest matching behaviour would be that
  gss_process_context_token() behaves much like gss_init_sec_context()
  behaves when processing that very KRB_ERROR token.

-Martin

---

From: Nico Williams <[email-masked]>
Date: Wed, 5 Nov 2014 16:54:24 -0600

> where the fix is obvious and natural.

We could file an erratum for this too.

(I don't think we have the energy for a complete update of either RFC.
We could do one-off updates of them for this and that minor problem, but
even that seems like a lot of energy to put into fixing minor issues
that would best be dedicated to other work.)

> (gss_init_sec_context(),gss_accept_sec_context()) when processing this

It would create an ambiguity as to GSS_S_DEFECTIVE_TOKEN: is it that the
async context token is defective, or that a token we sent was seen as
defective by the peer?

It would also mean extending the list of major status codes that
GSS_Process_context_token() can return.  I have absolutely no problem
doing that in this case.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Wed, 5 Nov 2014 17:31:39 -0600

Incidentally, neither RFC1964 nor RFC4121 say whether the mechanism on
the acceptor side should output an error token when there is an error
accepting a context w/o mutual auth.

I believe most implementations don't.

What applications use GSS w/o mutual auth?

Aside from test apps (e.g., gss-client), the only one I can think of
(proprietary or otherwise) is HTTP/Negotiate [RFC4559], which doesn't
say whether to request mutual auth or not (not that it matters much,
security-wise, since HTTP/Negotiate doesn't actually use per-message
tokens...).

[Apologies for the length of this.  What follows is a discussion of
initiator->acceptor error tokens that can mostly be ignored.  We
probably shouldn't care about those; if you do, read on.]

Also, in general error tokens are most useful when they convey useful
information to a user.  Users are usually on the initiator side.  For
acceptors the value in unexpected error tokens is that they indicate
that the context should be deleted -- for some apps and/or mechanisms
there may be no way to securely indicate this in such a situation.

E.g., imagine krb5 outputting a KRB-ERROR when the acceptor's AP-REP is
defective.  Since the acceptor was [presumably] able to decrypt the
initiator's AP-REQ's Ticket and Authenticator (and especially if we had
an integrity-protected KRB-ERROR), the acceptor could take the error
token as an indication that the gig is up for this context.

In the case of Kerberos the initiator application could always use
PROT_READY per-message tokens to secure an application-layer delete/
close message, if the application protocol has one.  But if this
situation was common we'd want to have the initiator output an error
token.  In practice we just don't care about this situation.  Worst case
scenario acceptor apps have to deal with timeouts, but all network
applications have to anyways.

I think asking for initiator->acceptor error tokens would be going bit
too far for now.  We should want initiator apps to know to use
gss_process_context_token() though, for the reasons I gave much earlier
in this thread.

Nico
--

---

From: Benjamin Kaduk <[email-masked]>
Date: Wed, 5 Nov 2014 23:04:49 -0500 (EST)

I'm not replying to the previous messages in the subthread after I listed
a summary of options; I basically agree with all statements by both Nico
and Martin, and don't see anything that clearly needs a reply.  Please let
me know if you want me to comment on anything in particular.

> but I'm also not missing anything, and I also only jumped into the

I was probably overzealous when compiling it, but it doesn't seem harmful
to consider extra options.

Agreed.

> gssapi call return a fatal major_status along with a helpful minor_status.

This is also basically true.  Some of the numbered proposals offered
different options for conveying this sort of information, but they violate
the principle of least surprise.

> fatal error message that is _not_ suggested anywhere in the existing

Okay.

> gss_delete_sec_context() and gss_export_sec_context().

Yes, it was always the case.  Some confused statements may have been made
during previous discussions on this thread, but they were wrong.

> could expect to continue using the security context.

I agree.  Nico is pointing out that we might want to create such
situations in the future.

> (gss_init_sec_context(),gss_accept_sec_context()) when processing this

Martin pointed out in an off-list message that many of the error codes are
explicitly called out in RFC 2743 are referring to a specific input
variable to the GSS call in question (e.g., "GSS_S_DEFECTIVE_TOKEN
indicates that consistency checks performed on the input_token failed")

> GSS_Process_context_token() can return.  I have absolutely no problem

I don't think we can make that extension in gss-loop, and it seems rather
silly to make a one-off document just to do that.

Given the restrictions alluded to above, there would probably only be a
handful of error codes other than GSS_S_FAILURE that would be permitted,
so maybe it is simplest to just use that one.

-Ben

---

From: Benjamin Kaduk <[email-masked]>
Date: Wed, 5 Nov 2014 23:05:00 -0500 (EST)

I agree.

Yes.

-Ben