Subject: Re: updated GSSAPI draft and summary of the off-list discussions

From: Ken Raeburn <[email-masked]>
Date: Mon, 01 Sep 2003 22:03:46 -0400

This is kind of long, but much of it is nit-picky stuff.  We're
definitely getting closer....

Section 1: Change "obsoletes" to "updates"; calling it obsolete and
then using it as a normative reference would be inconsistent.  Or, do
consider RFC 1964 obsolete, but incorporate all the relevant
specifications so that a session using a DES session key can be done
compatibly.

Section 7.1: If we change anything in context initiation, we should
try to move away from this bogus conjured-up "checksum as arbitrary
octet string we can stuff data into" business.  In Clarifications (and
probably RFC 1510, but I haven't double-checked), the checksum field
of an authenticator is a checksum of associated application data, and
what RFC 1964 stuffs in there is no checksum.  (If we had AEAD, etc,
etc.)

Section 8.2: Is bit 0 the most significant bit in this field also?

Section 8.3, last paragraph: Should be, "When AES is used, for
example", to make it crystal clear that the paragraph is
demonstrating, not specifying, how the values are calculated.

I don't think we actually get any benefit from having EC in the token
header of Wrap-with-confidentiality, do we?  The useful copy is in the
encrypted data.

I'm not sure that including EC in the checksummed data for
Wrap-without-confidentiality gains us much either.  If the EC value is
supplied but not protected, and someone alters it such that the
checksum appears to be longer or shorter, the checksum verification
should fail.

So we could consider placing EC at the end and not in the real token
header, inside the encrypted data but not in the checksummed data.

It *might* be useful if you are trying to do scatter-gather type i/o,
to put the different bits of data into different buffers, but it would
require that you read EC from the token header before allocating space
to put the rest of the token, which will have its own performance
implications.

Section 8.4: In the non-encrypted Wrap token, the MIC is computed over
the plaintext data followed by the header.  This is done for
performance reasons when the supplied plaintext data is block-aligned.
But for an implementation that constructs the data to checksum in one
buffer, the token buffer, it isn't the optimal approach.  It would be
better for such implementations if the MIC were computed over the
theader and then the plaintext data -- in exactly the form you'd
already have them laid out in the buffer.  I'm not sure if the
alignment makes much difference for most checksum type operations, but
it seems to me we're optimizing for the scatter-gather implementation
by imposing an extra cost on the one-buffer implementation.

I'd like to see diagrams of the data layout in 8.4.

The use of EC for the size of the checksum in Wrap tokens without
confidentiality imposes other limits on kcrypto not covered in 8.4:

 * No checksum algorithm may ever produce an output greater than 65535
   bytes.

 * The application must be able to compute the checksum size without
   knowing exactly what the data is.  (In private discussions, we went
   around and around on encryption output size and encryption
   functions incorporating compression and thus producing output
   varying in size based on the data itself, but we didn't get into
   checksums as much.)  The length is known in this case, as is most
   of the data except for the EC bytes.

   I don't think we currently require that checksums in general have
   fixed sizes.

There isn't a description of how the size of the random filler is
chosen.  I'd suggest something like this in place of the third
paragraph:

  In Wrap tokens that provide for confidentiality, the first 16 bytes
  of the Wrap tokens (the "header") are appended to the plaintext data
  before encryption.  In order for the recipient to be guaranteed to
  be able to locate this header in the decrypted token, the resulting
  message should be expanded to a size for which the [KCRYPTO]
  encrypt/decrypt sequence will add no additional padding.  This
  expansion is done by inserting filler bytes into the constructed
  Wrap token after the plaintext application data and before the copy
  of the token header.  The values in these bytes are unspecified.

  The resulting Wrap token is ....

...and then don't describe the filler bytes as "random" in 8.3.  It
might add a very tiny amount of security to use a strong random number
generator, but I don't think we lose a lot by using a constant zero
filler either, given that it'll tend to be less than a block anyways.

Do we really need to require that the size used is always the smallest
suitable size?  Or can it just be *a* possibly-larger size, so long as
it's less than 64K above the current size?  Strictly speaking, we
probably only need the latter, and the 64K bound is needed either way.

Purely from a presentation point of view, it might be an easier read
if the proposed changes to [KCRYPTO] were described first, perhaps
indented and narrowed, or otherwise made to appear "special", and then
the "normal" description of how the thus-modified kcrypto operations
are used in this mechanism.

Section 8.4, last paragraph: Say "for example", as I remarked for 8.3
above.

Section 8.5: So, RRC is treated as an unsigned value?  The rotation
can't go the other way?  (No, I don't have a good example at the
moment why you might want to do it that way.)  I don't remember if we
decided anything in our off-list discussions.

Section 8.6: The "flags" byte has an extra blank line in the middle of
its description in each message, as does the RRC description in the
Wrap token.

Section 9.1.2: "Principal in credential cache does not match desired
name" has assumptions about the implementation details.  How about
"Client principal in credentials does not match specified name"?
Likewise for some of the other messages....  "No key available for
specified service principal"; "No Kerberos ticket-granting ticket
available"; etc.

Can an implementation acting as initiator use a keytab for storing the
client's long-term key?  If so, do you return KEYTAB_NOMATCH if the
client principal name doesn't match anything in the keytab?

Section 10: Probably could use some clarification.  Use some text from
[3DES] if it helps.

Section 11: If this is to go on the standards track, it shouldn't
refer to the draft for 3DES that I allowed to expire.  Copy the text
you need.

Ken

---

From: Sam Hartman <[email-masked]>
Date: Tue, 02 Sep 2003 14:01:47 -0400

>>>>> "Ken" == Ken Raeburn <[email-masked]> writes:

    Ken> This is kind of long, but much of it is nit-picky stuff.  We're
    Ken> definitely getting closer....

    Ken> Section 1: Change "obsoletes" to "updates"; calling it obsolete and
    Ken> then using it as a normative reference would be inconsistent.  Or, do
    Ken> consider RFC 1964 obsolete, but incorporate all the relevant
    Ken> specifications so that a session using a DES session key can be done
    Ken> compatibly.
I'd prefer it to update RFC 1964, referencing 1964 for DES but only defining the token formats for new ciphers.

The idea is that it is sufficient for an all-new implementation, but
if you need to implement DES you need to go back to 1964.

    Ken> Section 7.1: If we change anything in context initiation, we should
    Ken> try to move away from this bogus conjured-up "checksum as arbitrary
    Ken> octet string we can stuff data into" business.  In Clarifications (and
    Ken> probably RFC 1510, but I haven't double-checked), the checksum field
    Ken> of an authenticator is a checksum of associated application data, and
    Ken> what RFC 1964 stuffs in there is no checksum.  (If we had AEAD, etc,
    Ken> etc.)

I would not object to moving away from that format but do not actually
think it is necessary to do.
    Ken> I don't think we actually get any benefit from having EC in the token
    Ken> header of Wrap-with-confidentiality, do we?  The useful copy is in the
    Ken> encrypted data.

It might be worth keeping things as they are for better parallelism.
The same comment applies to your concerns about checksums and EC.

    Ken> Section 8.4: In the non-encrypted Wrap token, the MIC is computed over
    Ken> the plaintext data followed by the header.  This is done for
    Ken> performance reasons when the supplied plaintext data is block-aligned.
    Ken> But for an implementation that constructs the data to checksum in one
    Ken> buffer, the token buffer, it isn't the optimal approach.  It would be
    Ken> better for such implementations if the MIC were computed over the
    Ken> theader and then the plaintext data -- in exactly the form you'd
    Ken> already have them laid out in the buffer.  I'm not sure if the
    Ken> alignment makes much difference for most checksum type operations, but
    Ken> it seems to me we're optimizing for the scatter-gather implementation
    Ken> by imposing an extra cost on the one-buffer implementation.

Is there actually a performance benefit for the MIC?  It seems much
less of an issue than the block alignment for encryption.

    Ken> I'd like to see diagrams of the data layout in 8.4.
    Ken> Purely from a presentation point of view, it might be an easier read
    Ken> if the proposed changes to [KCRYPTO] were described first, perhaps
    Ken> indented and narrowed, or otherwise made to appear "special", and then
    Ken> the "normal" description of how the thus-modified kcrypto operations
    Ken> are used in this mechanism.

While I agree improving presentation clarity is desirable, we
presumably expect to have that text removed by the time we go to RFC,
right?

---

From: Ken Raeburn <[email-masked]>
Date: Tue, 02 Sep 2003 17:10:38 -0400

> less of an issue than the block alignment for encryption.

I would be inclined to agree.  SHA-1 and MD5 operate on 16 32-bit
quantities at a time, so 4-byte alignment is likely to help, and
stricter alignment might save you a cache miss here and there, but I
think that's about it.

If the checksum scheme is something like a CBC-MAC, it's likely to
make about as much difference as for encryption.

> presumably expect to have that text removed by the time we go to RFC,

Yes, definitely.  I'm just talking about making the draft easier to
read in the meantime.

Ken

---

From: Sam Hartman <[email-masked]>
Date: Wed, 03 Sep 2003 18:40:38 -0400

Ken> Sam Hartman <[email-masked]> writes:
    >> Is there actually a performance benefit for the MIC?  It seems
    >> much less of an issue than the block alignment for encryption.

    Ken> I would be inclined to agree.  SHA-1 and MD5 operate on 16
    Ken> 32-bit quantities at a time, so 4-byte alignment is likely to
    Ken> help, and stricter alignment might save you a cache miss here
    Ken> and there, but I think that's about it.

Note I actually find Larry's argument that we want the wrap and
non-wrap token formats to be the same somewhat compelling.

---

From: Ken Raeburn <[email-masked]>
Date: Wed, 03 Sep 2003 22:12:02 -0400

"Liqiang\(Larry\) Zhu" <[email-masked]> writes:

>       20..23  Flags   Bit vector of context-establishment flags, 
>                       as defined next. The resulting bit vector is  
>                       encoded into bytes 20..23 in little-endian form. 

In this section and the next, there are lots of descriptions of bit
order or byte order, bit vectors and integers, bit numbers, etc.  I
think I can make a case that they're not entirely consistent.

RFC 1964 was kind of unclear on this too.

Storing a bit vector in little-endian order suggests to me that bit 0
of the vector should be first.  But bit 0 is the most significant bit
(section 7.1.1), so I guess bit 31 comes first.  Converting bit
strings to octets normally involves breaking them into groups of 8,
and in each set of 8, generally the first becomes the "high" bit, but
that doesn't seem to be the case here.

If I get this mostly straight, GSS_C_MUTUAL_FLAG, with a value of 2,
corresponds to bit 30, and would be expressed in the flags field as:

  02 00 00 00

right?

And you can make the bit vector make sense if you express each byte in
little-endian bit order:

 LSB=7  MSB=0 (octet)
  v      v
  01000000 00000000 00000000 00000000
  ^ bit 31                    bit 0 ^ (bit vector)

but that doesn't seem very natural.

It shouldn't be this hard to figure out.  I suggest dropping the byte
order description in 7.1, and putting a more useful diagram into
7.1.1.  If you want, I'll try to write up that description myself.

We have an interesting mix of big-endian and little-endian values in
this mechanism, but I think most of the non-bit-vector cases are
pretty clear.

Section 7.1.1:
>       Bit         Name          Description                  
>     ---------------------------------------------------- 
>       0..11     Mandatory     Critical extension flags 
>       12..15    Optional      Non-critical extension flags 
>       16..31    Standard      Context establishment flags 

I'm not sure I like this.  RFC 2744 doesn't provide for a distinction
between mandatory and optional flag bits to be specified in the future
at the API level, and the Kerberos mechanism so far has been using
values consistent with the API.  So if a v3 GSSAPI defines new
optional flags, and they happen to land in the "mandatory" field
above, we would need to specify a new encoding to pass such flags
across.

And, in any case, what do these "standard" flags mean, anyways?

>    An extension or context establishment flag can either be critical or 
>    non-critical.  When the context initiator desires a particular 
>    extension or context establishment flag (either critical or non-
>    critical) it sets the appropriate checksum flag.  The context 
>    acceptor MUST ignore unsupported non-critical extensions or flags in 
>    the initiator's context token (i.e., acceptors MUST NOT return an 
>    error just because there were unsupported non-critical extensions or 
>    flags in the initiator's token).  The acceptor MUST return 
>    GSS_S_UNAVAILABLE [RFC-2743] if there are unsupported critical 
>    extensions or flags in the initiator's context token. 

What do you mean by "acceptor MUST return" here?  Some particular
function on the acceptor side should return this error?  Is it
compatible with RFC 2743 or 2744 specifications for that function?

>    All existing context establishment flags are non-critical, and it is 
>    possible that a new context establishment flag can be added as a 
>    critical flag. 

I'm not sure that's true.  At least, I don't know if the v2 API allows
for it.

> 8.2. Flags Field 

Clarify the bit order.  Does bit 0 correspond to 0x80 or 0x01?

If I got 7.1 right, and if 8.2 uses the same scheme, it would be 0x80.

>    The rest of available bits are reserved for future use. 

And?  Presumably they should always be set to zero by the sender for
now.  If they're set, should the receiver ignore them or reject the
message?

Ken

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 8 Sep 2003 14:36:10 -0700

> this mechanism, but I think most of the non-bit-vector cases are

I would be happy with consistency.  I also prefer big endianness (but
this is not because SPARC is big endian, that doesn't save us any
endianness conversions in source code because Solaris runs on x86 as
well).

> above, we would need to specify a new encoding to pass such flags

I think we should specify a single flags field where all currently
defined flags are non-critical as per GSS-APIv2.

We should also have a typed hole where we can later add a critical flags
extension, should the GSS-APIv3 ever add such a thing.

> And, in any case, what do these "standard" flags mean, anyways?

We should carry over the flags from rfc1964, which in turn derive from
the req_flags/ret_flags from the GSS-API.

> compatible with RFC 2743 or 2744 specifications for that function?

I think we can support acceptor-side option criticality with an error
code in the reply (but without having to force the use of KRB-ERROR,
since such errors would be at the mech level, not at the Kerberos AP
exchange level).  See recent posts of mine on the list.

> I'm not sure that's true.  At least, I don't know if the v2 API allows

You're right.  I think we should only specify the criticality of
reserved flags, and we should say that they are not critical.

> now.  If they're set, should the receiver ignore them or reject the

The receiver should ignore reserved flags it does not know about.

Nico
--

---

From: Martin Rex <[email-masked]>
Date: Thu, 11 Sep 2003 20:29:18 +0200 (MET DST)

> And, in any case, what do these "standard" flags mean, anyways?

I also find this concept strange.
The idea in GSS-API was that an application indicates which
attributes it would like on a security context, a mechanism
would try to match that as good as possible, but with the
emphasis on trying to establish a security context, and
finally it would be up to the application to look at the
resulting context attributes and make its decisions whether
the result was good enough.

The motivation of GSS-API is clear: GSS-API is a mere service
provider, policy decisions are up to the application altogether.

> compatible with RFC 2743 or 2744 specifications for that function?

Probably he meant gss_accept_sec_context(), there's no other
API call for which this description fits.

> I'm not sure that's true.  At least, I don't know if the v2 API allows

It would be clearly against the spirit of the current GSS-API spec,
and I wouldn't like it either, but the most significant problem
is that gss_accept_sec_context() doesn't even have a context_flags
input parameter, so any policy decision about context attributes
on the acceptor side can only be done after the security context
has been successfully established, and it can only be done by
the application, not by the gssapi mechanism.

Personally, I hate it when a gssapi mechanism tries to
enforce policy upon my application, and actually I doubt that
this could work reliably anyway.

A while ago an implementor of a proprietary gssapi mechanism
showed up for interoperability testing with out application.
I was a little surprised when I saw in the logs of our GSSTEST
that the performance for gss_wrap()/gss_unwrap() was about
the same, whether confidentiality was requested or not.
He told me that for that user they had a policy setting in their
central server that would enforce encryption for gss_wrap().
I laughed at him.  Our application can be configured with
three distinct message protection levels: authentication only,
data integrity and data confidentiality. The application
uses either no gssapi message protection, gss_get_mic/gss_verify_mic
or gss_wrap/gss_unwrap with confidentiality requested.
There simply is no possibility for a gss-api mechanism to
enforce a data protection level on an application.  And
we still allow the traditional use of the application without
gssapi based security if the customer so desires.

Really, a gssapi mechanism should focus on providing a service
as good as it can.  But the decision whether to use gssapi at all,
and how much of the service should be completely up to the application.

I know that most application designers are notoriously bad at
making security decisions, but that should be a reason to give
application writers a middleware (like RPC with GSS-API)
rather than straight GSS-API.

-Martin