Subject: Re: [kitten] Kerberos extra round trips I-D revised

From: Benjamin Kaduk <[email-masked]>
Date: Fri, 7 Nov 2014 16:13:06 -0500 (EST)

On Mon, 27 Oct 2014, Nico Williams wrote:

> ----- Forwarded message from [email-masked] -----
>
> A new version of I-D, draft-williams-kitten-krb5-extra-rt-02.txt
> has been successfully submitted by Nicolas Williams and posted to the
> IETF repository.
>
> Name:		draft-williams-kitten-krb5-extra-rt
> Revision:	02
> Title:		Negotiation of Extra Security Context Tokens for Kerberos V5 Generic Security Services Mechanism
> Document date:	2014-10-27
> Group:		Individual Submission
> Pages:		15
> URL:            http://www.ietf.org/internet-drafts/draft-williams-kitten-krb5-extra-rt-02.txt
> Status:         https://datatracker.ietf.org/doc/draft-williams-kitten-krb5-extra-rt/
> Htmlized:       http://tools.ietf.org/html/draft-williams-kitten-krb5-extra-rt-02
> Diff:           http://www.ietf.org/rfcdiff?url2=draft-williams-kitten-krb5-extra-rt-02
>
> Abstract:
>    This Internet-Draft proposes an extension to the Kerberos V5 security
>    mechanism for the Generic Security Services Application Programming
>    Interface (GSS-API) for using extra security context tokens in order
>    to recover from certain errors.  Other benefits include: user-to-user
>    authentication, authenticated errors, replay cache avoidance, and
>    others.
>
> ----- End forwarded message -----

Hmm, I guess I was slow in getting to this, and you put out an -03
already.

I read the -03.

My summary is: create a KRB-ERROR2 structure that the acceptor can return
when the initiator has opted in by setting a flag; KRB-ERROR2 has several
nice features compared to KRB-ERROR, including (1) can be encrypted, if a
key is available; (2) can indicate to the acceptor to retry with a
modified request; (3) can include a challenge nonce/freshness indicator;
(4) can include a TGT for use with user-to-user.  (It can also be sent
from initiator to acceptor when the initiator fails to process a received
KRB-ERROR2.)

The initiator includes (3) in the follow-up AP-REQ, proving freshness and
allowing the replay cache to be safely omitted.

Most of the draft is just laying out the details surrounding these and how
they are to be used.

The core extension seems like a fine thing to have so I would be okay with
adopting this as a WG document if we think we have the energy to advance
it properly.

I have some concerns that some of the text could be written differently
and be more clear, most notably section 2.

There are a few open questions tagged in the document:

   [[anchor1: Perhaps we should use a checksum 0x8003 [RFC4121]
   extension instead of authorization data in the authenticator.]]

This is for incorporating the challenge-nonce back into the reply, if I
understand correctly.  I'm not sure how well that would work if we want to
allow for stateless acceptors that use nonces similar to the pkinit
freshness tokens we've been discussing.

   [[anchor2: Question: how should we address this?  We could say "give
   priority to the user-to-user mechanism", but in some cases that might
   require changes to the acceptor side.]]

This refers to the potential for conflict with
draft-swift-win2k-krb-user2user, which I haven't read, so I can't say much
about.

   [[anchor3: We could use the GSS_EXTS_FINISHED extension from
   draft-ietf-kitten-iakerb to implement a strong binding of all context
   tokens.]]

I haven't thought about things hard enough to decide whether the gain in
strength of binding is worth the extra work.

-Ben

---

From: Nico Williams <[email-masked]>
Date: Fri, 7 Nov 2014 15:43:50 -0600

On Fri, Nov 07, 2014 at 04:13:06PM -0500, Benjamin Kaduk wrote:
> My summary is: [...]

That's a fine summary.  (Except that I think we seem to agree that
there's no need for an initiator->acceptor error context token.)

> allowing the replay cache to be safely omitted.

Yes.

> adopting this as a WG document if we think we have the energy to advance

Thanks.  I hope we do.  I think this is sorely needed.

>    extension instead of authorization data in the authenticator.]]

(FYI, this [[anchorN:...]] business is an artifact of lyx2rfc's
rendering of "revision remarks" -- comments intended for rendering,
effectively.  I should fix this to drop the anchorN business.)

> freshness tokens we've been discussing.

It works fine: the acceptor decrypts the Ticket from the AP-REQ, then
the Authenticator from the AP-REQ, recovers the challenge, and validates
it.

The challenge should probably have a timestamp and a counter at the very
least, and should be at least integrity protected.  I.e., it should be
very similar to the PKINIT freshness token.

> draft-swift-win2k-krb-user2user, which I haven't read, so I can't say much

Consider an initiator app with a mech with these extensions *and* an
implementation of draft-swift-win2k-krb-user2user.  Now imagine this app
talks to an acceptor app that also has both mechanisms but not these
extensions.  Can we accidentally end up failing to setup a security
context?

That was my question.

However, I'm now convinced that the answer is "no", therefore this
section and remark can be removed.

The reason the answer is "no" is that if the acceptor app has acceptor
credentials for RFC4121 and draft-swift-win2k-krb-user2user then it
should be able to use both, otherwise it should only have acceptor
credentials for one (if that) and only offer to negotiate those
mechanisms for which it has acceptor credentials.  It follows then that
the situation I feared cannot happen.

> strength of binding is worth the extra work.

I think it's not worth the extra work, but it's important that the
acceptor either insist that the cname/crealm of the two AP-REQs be the
same, or else ignore the cname/crealm from the first AP-REQ and then
rely only on the second AP-REQ's cname/crealm.  I feel uneasy about the
latter.  For PROT_READY purposes it would be convenient if the two
Authenticators asserted the same sub-session keys too.  I don't think
there's any need to bind any more of the exchange, but then, I like the
binding everything as a generic defensive design security principle.

Nico
--

---

From: Benjamin Kaduk <[email-masked]>
Date: Sat, 8 Nov 2014 20:41:12 -0500 (EST)

> there's no need for an initiator->acceptor error context token.)

Well, I think the acceptor application should be prepared to handle one if
it gets one, but maybe the initiator doesn't always need to make/send one.

> extensions.  Can we accidentally end up failing to setup a security

Right, that was clear to me from reading the draft; I just don't have an
answer.

> latter.  For PROT_READY purposes it would be convenient if the two

I also feel uneasy about the latter.

-Ben

---

From: Nico Williams <[email-masked]>
Date: Mon, 10 Nov 2014 10:34:13 -0600

On Sat, Nov 08, 2014 at 08:41:12PM -0500, Benjamin Kaduk wrote:
> Well, I think the acceptor application should be prepared to handle
> one if it gets one, but maybe the initiator doesn't always need to
> make/send one.

Agreed, acceptor apps should be required to beprepared to handle them.

Q: Should mechanisms specify outputting such error tokens as well?
A: Optionally, yes. (my answer)

Q: Should initiator apps be expected to send them?
A: Optionally, yes. (my answer)

> > [...]
> Right, that was clear to me from reading the draft; I just don't have
> an answer.

I'm not convinced that the problem doesn't arise.  (An acceptor that
supports both mechanisms but not u2u in the krb5 mech will not offer the
latter if it doesn't have long-term principal keys with which to accept
sec contexts, and the KDC shouldn't return KDC_ERR_MUST_USE_USER2USER if
the acceptor has long-term keys.  But if this should result for some
reason, then we'd have a problem.  In practice this doesn't happen,
won't happen, and anyways, user2user is exceedingly rare.)

> I also feel uneasy about the latter.

It's trivial to go with the first.  I'll make it so.

Nico
--

---

From: Greg Hudson <[email-masked]>
Date: Tue, 11 Nov 2014 12:59:35 -0500

I support adopting this document.  My comments so far:

* Encrypting in the null enctype/key isn't a formalized RFC 3961
concept.  The RFC will need to explicitly say what goes into the
EncryptedData message when encryption isn't possible.

* In section 2, there are two bullet points about whether the initiator
should attempt to recover, the first for receiving any KRB-ERROR2 and
the second for receiving a KRB-ERROR2 with the ke-continue-needed flag
set.  In the first bullet point, what does "attempt to recover" imply?
If the acceptor sent a KRB-ERROR2 without ke-continue-needed, it's not
expecting another message, is it?

* Do we really need to address the case where the acceptor can decrypt
the Ticket but not the Authenticator?  If not, we can get rid of
KrbErrorEncPartFlags and the receiver can easily deduce the key from the
EncryptedData and whether it sent an authenticator subkey.

* My preference is not to specify KRB-ERROR2 messages going from the
initiator to the acceptor under any circumstances.  It seems like a fair
amount of implementation complexity for minimal gain; at best the
acceptor is going to write something about the error to a log file.

* Section 2 says that an initiator MAY produce a token (softened from a
MUST in earlier draft versions), but section 2.2 says it MUST produce a
KRB-ERROR2 if it rejects an additional round trip.  Which is it?  I
assume there was some concern about early abandonment of the GSSAPI
exchange by one of the parties.  In my experience, this isn't a serious
problem.  The MIT krb5 GSS acceptor was doing early abandonment for many
releases due to a bug, and while it could obscure error conditions by
failing to send an error packet to the client, it didn't seem to break
any application protocols.

* If the initiator is going to send KRB-ERROR2 messages to the acceptor,
we need to specify what key it uses for encryption.  (The simplest
answer is to use the same key as the acceptor did.)

* I don't see any reference to key usages in the draft.  If the
initiator sends KRB-ERROR2 messages to the acceptor using the same key
as the acceptor used, it should use a different key usage to prevent
reflection attacks.

* How useful is service name redirection if it can only work when the
acceptor was able to decrypt the ticket?  (The draft bars service name
redirection via unencrypted KRB-ERROR2 for fairly obvious security reasons.)

* Does it make any sense to put a fast-reauth ticket in a KRB-ERROR2?
Wouldn't we want it in an AP-REP instead?  (That would render it out of
scope for this draft.)

* In the U2U flow, is there a reason not to use zero-length octet strings?

* Is case 2 of the U2U flow useful?  If not, it presents additional
attack surface on the initiator implementation for no good reason.

* I don't yet have a strong opinion on whether to add a
GSS_EXTS_FINISHED binding.  There might be a reason for it, but if we
can't think of one then I would prefer to avoid the extra complexity.

* Do we need new redir-srealm/redir-sname fields for redirection or
could we just use srealm/sname?  Section 5 says that srealm/sname must
mirror those in the Ticket, but I don't see the point of that
requirement; an attacker can't replay a KRB-ERROR2 for a different
ticket because the key won't match.

* Is it right to specify new ASN.1 type definitions to be added to the
RFC 4120 ASN.1 module, or should we create a new module with its own OID
and import declarations?

* Defining KrbErrorEncPartFlags as KerberosFlags seems like a bad fit;
it is conceptually an enumeration, not a bitmask.

I also have several thoughts about replay cache avoidance, but will put
those in a separate message.

Editorial comments:

* "SHALL have a the" -> "SHALL have the"
* "without no fifth token" -> "without a fifth token"

---

From: Greg Hudson <[email-masked]>
Date: Tue, 11 Nov 2014 13:50:22 -0500

Here are further thoughts on replay cache avoidance as it affects this
draft.

Replay caches help in two cases:

1. They provide minimal protection when a krb5 exchange takes place over
an unprotected channel and is used for authentication only, with no use
of the resulting key.  This protection is minimal because a replay
attack assumes an active attacker, who could perhaps suppress the
original exchange, beat the original exchange with the replay, or
compromise the channel after authentication.  It is not totally
unreasonable to abandon case 1 as hopeless, but for the purpose of this
message I will assume we still care about it.

2. They prevent an entire session from being replayed, causing a
properly authenticated request to be processed twice within the replay
window.  This is not a concern when an acceptor subkey is used.  (I
assume that legitimate initiators don't use prot-ready messages or send
wrap tokens using the initiator subkey.  I think in practice RFC 4121
implementations don't set the prot-ready flag and initiators never use
the initiator subkey.)

A krb5 acceptor implementation generally does not know whether the
application protocol will use the context key or whether there is a
different case 1 acceptor using the same long-term acceptor keys.
Because of this, it is intrinsically difficult for an implementation to
know that it is safe not to use a replay cache for case 1.

The extra round trips draft allows the acceptor to ask an initiator to
encrypt a nonce, which would defeat a replay attack if everyone had to
do it.  However:

* There is an easy downgrade attack on the extra round trip.  Until
client implementations are ubiquitous enough for acceptors to turn off
support for basic RFC 4121, an attacker can simply suppress the extra
round trip.

* The first authenticator must still be added to the replay cache if it
might be used for a case 1 acceptor--and if this acceptor would be a
case 1 acceptor without the extra round trip, allowing basic RFC 4121
means it is still a case 1 acceptor.

So this doesn't really seem to give us replay cache avoidance until
basic RFC 4121 can be turned off.

Specific notes:

* The MUST in section 4 is not necessary for interoperability or
security, and as such ought to be a SHOULD.

* Section 2.2.1 states that after a recoverable error, a fifth token is
not required because of the nonce in the second token.  I am not sure
this is true--the nonce in the second token was not necessarily
encrypted; if it wasn't, an attacker could feed it to a legitimate
initiator in a separate exchange.

* For pedagogical purposes, section 4 should probably be explicit about
what the initiator does in response to a KRB-ERROR2 with a KDC_ERR_NONE
code.

---

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

> I support adopting this document.  My comments so far:

Thanks.

> EncryptedData message when encryption isn't possible.

I thought we ended up saying that the null enctype does have a purpose
after all (was it about KRB-CRED?  I forget).  But yes.

> set.  In the first bullet point, what does "attempt to recover" imply?

That's covered in section 2.1.

> expecting another message, is it?

Ah, this is an editing error.  Thanks for catching this.

> KrbErrorEncPartFlags and the receiver can easily deduce the key from
> the EncryptedData and whether it sent an authenticator subkey.

I was wondering about this.  If the acceptor can decrypt the Ticket but
not the Authenticator then there was a transmission error, and the
question is whether it's worth trying to recover from that.  My guess
now is "no".

> acceptor is going to write something about the error to a log file.

What I'd like to say is that initiator _apps_ shouldn't bother sending
error tokens to acceptors.  Allowing the initiator _mech_ to produce
them (and the acceptor _mech_ to consume them) is an exercise in
completeness that would enable role reversal applications.

Perhaps we shouldn't care about role reversal applications (since we
have none).  But since this has been needed in the past (ISMS or some
such), I'd want a bit more discussion before discounting them
altogether.

> any application protocols.

Yeah, it's about abandonment.  There may well be no value to it because
apps always have to deal with timeouts anyways.  Not forcing a peer to
timeout is a matter of courtesy, but if the peer minimizes state kept
(as it should), it may not matter much.

> answer is to use the same key as the acceptor did.)

Right (or more likely a dk in the same key hierarchy).

> as the acceptor used, it should use a different key usage to prevent

Yep, this is missing.

> redirection via unencrypted KRB-ERROR2 for fairly obvious security reasons.)

I thought I ripped that out completely in the latest version.  Did I
leave stray text about it?

> Wouldn't we want it in an AP-REP instead?  (That would render it out of

Two reasons: a) the server might still want rcache avoidance, b) I
wanted to avoid having to extend AP-REP (though I'd be happy to extend
it anyways).  (b) is lame; (a) is not.

> * In the U2U flow, is there a reason not to use zero-length octet

Not sure.

> attack surface on the initiator implementation for no good reason.

I think it might be.  Think of authz-data in the u2u TGT affecting what
appears in the service ticket in the end.

> can't think of one then I would prefer to avoid the extra complexity.

It's that or authz-data.

> ticket because the key won't match.

Again, I thought I'd ripped that out.

> RFC 4120 ASN.1 module, or should we create a new module with its own OID

Either is fine with me.

> it is conceptually an enumeration, not a bitmask.

Sure.  I was following tradition :)

> those in a separate message.

OK.  Thanks!

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Tue, 11 Nov 2014 14:57:33 -0600

On Tue, Nov 11, 2014 at 01:50:22PM -0500, Greg Hudson wrote:

FYI, I had a separate replay cache avoidance I-D that I'm looking to
abandon and replace with this one.  I didn't adopt all of the content of
that older I-D.

> of the resulting key.  This protection is minimal [...]

This affects SSHv2 in particular because it shares a service name with
things like rsh/rlogin/telnet, and those aren't always configured to
protect the entirety of their sessions.

It also affects every service in environments where every host-based
service shares a single long-term key on the same host.

It might be nice to simply make this go away by using 1.5rt for the AP
exchange wherever possible.

> implementations don't set the prot-ready flag and initiators never use

PROT_READY is nice to have, but only for data that is not too sensitive.
E.g., if the first message sent will be something like "list new
messages", then that's OK, but if it's going to be "list activity in
bank account #..." then it may not be.

> different case 1 acceptor using the same long-term acceptor keys.

That and the above point about multiple host-based services sharing a
single long-term key on any given host in some environments.

Yes.

> support for basic RFC 4121, an attacker can simply suppress the extra

Speaking of which, I'd meant to also have an authz-data element for
indicating willingness to use extra round trips.

> means it is still a case 1 acceptor.

See above comment about authz-data.

> basic RFC 4121 can be turned off.

Or, rather, until all mechanism acceptor implementations on a host can
be upgraded.

> initiator in a separate exchange.

The nonce should be tied to a single partially-established security
context.  It should not be accepted on other new contexts.

> what the initiator does in response to a KRB-ERROR2 with a KDC_ERR_NONE

OK.

Nico
--

---

From: Greg Hudson <[email-masked]>
Date: Wed, 12 Nov 2014 11:35:18 -0500

On 11/11/2014 01:54 PM, Nico Williams wrote:
> I thought I ripped [service name redirection] out completely in the latest
> version.  Did I leave stray text about it?

My bad.  I started reviewing -01 by mistake, then attempted to update my
comments for -03, and missed that service name redirection was gone in -03.

> it anyways).  (b) is lame; (a) is not.

This brings up a larger point that I previously missed: in the rcache
avoidance flow with an odd number of tokens, there is no AP-REP token in
the exchange.

So, should rcache avoidance should use a modified KRB-ERROR or a
modified AP-REP?  I think using a modified AP-REP is more natural, but
it does mean adding a second new message type and adding the nonce to
both messages.

If we do use a modified KRB-ERROR in this flow, then we need to make
sure that we get all of the security properties we would get from the
AP-REP.  The AP-REP provides:

* Mutual authentication through use of the authenticator subkey (or
ticket session key if none was used).  An encrypted KRB-ERROR provides
this, but section 4 needs to say that an unencrypted KRB-ERROR with code
KDC_ERR_NONE MUST be treated as an error by the initiator.

* An acceptor subkey, which prevents whole-session replays even without
a replay cache (assuming the legitimate initiator uses it for all
important messages).  It might be okay to omit the acceptor subkey since
the nonce provides the same property, but we would definitely need some
rationale.

* A mirror of the authenticator timestamps, to prevent AP-REP replays.
This does not seem important if an authenticator subkey was used.  We
could require that the initiator use an authenticator subkey.

We also need to consider how this all interacts with
draft-vanrein-krb5-kdh.

---

From: Nico Williams <[email-masked]>
Date: Wed, 12 Nov 2014 14:05:54 -0600

> avoidance flow with an odd number of tokens, there is no AP-REP token in

I removed too much when I removed sname/srealm.  The intention is to use
the KRB-ERROR2 as an AP-REP in the three-token flow, which means that it
needs to have an optional sub-session key field (and which must be
present when the initiator's AP-REQ was fine but the acceptor wants that
third token).

I added this back for -04 (not yet submitted).

> it does mean adding a second new message type and adding the nonce to

Right.  To me KRB-ERROR2 can fill both roles.

> AP-REP.  The AP-REP provides:

Agreed.

I'll be re-adding the acceptor sub-session key, I'll add the mirrored
timestamp, and I'll add authz-data (not just typed-data) so that this
message really can serve as both, KRB-ERROR2 and AP-REP2.  (Authz-data,
for example, could be useful here in the user-to-user case, for
symmetry, but also so we don't have to define both, authz-data and
typed-data elements for things like kDH pubkeys.)

> We also need to consider how this all interacts with

A typed-hole in KRB-ERROR2, and the authz-data in AP-REQ, allow for
ephemeral DH keys.  We then only need to specify the relevant elements
for carrying them.

We'll also need to support acceptor key confirmation for the DH key in
the case where the initiator's optimistic DH group/curve choice fails.

The kDH flows might look like this:

 - 2-token flow (optimistic negotiation succeeds, no acceptor key
   confimation):

   C->S: AP-REQ with ad-kdh-groups, ad-kdh-pubkey (one or more even)
         (initiator is PROT_READY here)
   S->C: KRB-ERROR2 or extended AP-REP with ad-kdh-pubkey and key
         confirmation typed-data/authz-data

 - 3-token flow (optimistic negotiation succeeds, no acceptor key
   confimation, acceptor wants rcache avoidance):

   C->S: AP-REQ with ad-kdh-groups, ad-kdh-pubkey (one or more even)
         (initiator is PROT_READY here)
   S->C: KRB-ERROR2 or extended AP-REP with acceptor pubkey and key
         confirmation
   C->S: AP-REQ with challenge

 - 4-token flow (optimistic negotiation fails, acceptor key confirmation
   desired):

   C->S: AP-REQ with ad-kdh-groups, ad-kdh-pubkey (one or more even)
   S->C: KRB-ERROR2 or extended AP-REP with ad-kdh-pubkey
   C->S: AP-REQ with ad-kdh-pubkey (and with challenge if the acceptor
                                    wanted it)
         (initiator is PROT_READY here)
   S->C: AP-REP

Obviously, it'd be nice if the KDC had some idea what groups/curves the
acceptor supports, then we could more often avoid the 4-token flow.

BTW, the TLS crowd is very keen on 0-RTT, which in GSS-speak means being
prot_ready after producing the first context token^W^W handshake message.

I'm not sure that prot_ready is a such terribly good idea because in
many, many cases the very first app data either needs PFS/established
authentication state, or else the layer right above TLS/whatever doesn't
know if the app data needs that.

But, there's a reason that 0-RTT is desired, and I think it'd be worth
formalizing and modernizing the prot_ready concept.  I also think it'd
be a good idea to de-conflate (in GSS) acceptor key confirmation from
authentication of the acceptor to the initiator.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Wed, 12 Nov 2014 14:12:33 -0600

>  - 2-token flow (optimistic negotiation succeeds, no acceptor key

I should explain that in this case the acceptor does confirm the non-kDH
symmetric sub-session key, but not the DH shared secret.  I think that's
a reasonable approach.

>  - 4-token flow (optimistic negotiation fails, acceptor key confirmation

And here I screwed up, there's no need for a fourth token because the
acceptor does confirm the non-kDH symmetric sub-session key, which is
good enough.

However, maybe we do need to confirm the DH shared secret?  I hope not.

Nico
--