Subject: SPNEGO implementation issues

From: Wyllys Ingersoll <[email-masked]>
Date: Mon, 02 Dec 2002 15:24:57 -0500

Recently, I've been working on an SPNEGO implementation as described by
RFC 2478  that interoperates with Microsoft (Win2k Server).    I've come across some
problems/issues and was wondering if anyone else has tried to interoperate
with MS SPNEGO successfully or knows of these issues.

[ I raise these issues in this forum because it relates to RFC 2478 compliance
   and I think the CAT WG is dead, so this seems like the most appropriate forum.
   My apologies if its too far off-topic ]

Test Environment:
    * GSSAPI sample applications running in Solaris using SEAM software and native
       Solaris GSSAPI implementation (i.e. NOT using MIT KRB5 GSS stuff).
    * Microsoft's SSPI GSS client/server applications running on Windows 2000
       server.

Problems Discovered:
#1 - (Unix gss-client, Win2K gssserver) - All NegTokenTarg tokens sent from the SSPI
     based server include a field tagged as if the MechListMIC were present, but
     the data in that position is actually an exact copy of the 'responseToken'
     field, not a MIC of the original mech list that the client sent to the  server.
     In order to interoperate with MS as a GSS/SPNEGO client, the SPNEGO module
     must ignore the mechListMIC field in the response from the server, it cannot
     be verified since its not a valid MIC of anything.  This seems very wrong and
    will make interoperating with both MS *and* anyone elses implementation that
    actually includes a proper MIC difficult without some ugly hacks.  The RFC says
    the MIC field is optional, but including data in that field that is not a
    real MIC is clearly wrong.

#2 - (Unix gss-server, Win2K gssclient) -  When the "Negotiate" package is specified
    in the SSPI clients call to 'AcquireCredentialsHandle', the client sends a
    'NegTokenInit' packet with a list of possible SSPI mechanisms.    On my
    Win2K server (and probably most others) the OIDs for Kerberos and
    NTLMSSP are sent.
      1.2.840.48018.1.2.2
      1.2.840.113554.1.2.2
      1.2.840.113554.1.2.2.3
      1.3.6.1.4.1.311.2.2.10

The first OID sent is a unique Microsoft OID for Kerberos V5.  In order to
interoperate correctly (and use Kerberos V5), the Unix gss-server SPNEGO
code must use this bogus OID value.   If the server chooses to respond to the
client and indicate that the selected mechanism is the "correct" OID for Krb5
(1.2.840.113554.1.2.2), the MS client will complain - "Cannot contact the
LSA".   If the server responds to the client and uses the bogus Microsoft
KRB5 OID (1.2.840.48018.1.2.2), the client will accept this and continue
the conversation.     This is very odd.  If it can talk to the LSA for the wrong
OID, why can't it talk to the LSA when the correct OID is used, specially
considering that the "correct" OID was one of the values advertised by the
SSPI client in the first place ?

This seems badly broken, in order to interoperate, all non-MS GSS SPNEGO
implementations must understand that this bogus OID is supposed to be treated
the same as the correct KRB5 OID (1.2.840.113554.1.2.2) and make the proper
substitution in the NegTokenTarg packet generation (if Kerberos is to be selected).

#3 - (Unix gss-server, Win2K gssclient) - SSPI seems to completely ignore the
      contents of the MechListMIC field in the NegTokenTarg token.  This causes
      a problem with the GSS sequence numbering.   An RFC 2478 compliant server
     will call 'gss_get_mic' on the original mechListMIC in order to include the MIC
     in the response to the NegTokenInit packet (following the  RFC).  This
     increments  the internal GSS sequence number used when generating MICs
     within the KRB5 GSS mechanism.

      Later, after the SSPI client has successfully sent its actual data to the
     GSSAPI server,  the gss-server must send back a MIC of the message to the SSPI
     gssclient as a final verification that the data was transferred OK.  This 
causes
     the sequence number to be incremented again. The problem is that because the
     SSPI code never verified the MIC in the NegTokenInit packet, it is not 
expecting
     the sequence number to be incremented when the MIC of the final data is sent
     and an "incorrect sequence number" error occurs when the SSPI client tries to
     verify the final signature.
     Workaround - dont generate or sent a MechListMIC to Microsoft clients.

So, if you want to interoperate with MS, dont bother creating or sending MechListMIC
fields in either the initiator or target packets.  This would seem to weaken the
whole negotiation process since there is no way to verify that the originally
desired list of mechanisms was not altered.

Of course, one could say that a MechListMIC is useless when the list contains
mechanisms that do not support integrity protection (e.g NTLMSSP) since its
not possible to generate a MIC if one of those mechs is chosen.  However, it seems
that if the chosen mechanism does support integrity (like Kerberos V5), then
the MIC should be generated just to be safe.

Anyway, if anyone has any comments or can shed some light on these issues it would
be appreciated.

-Wyllys Ingersoll
  Sun Microsystems.

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 2 Dec 2002 12:56:20 -0800

Does MS support SPKM-1/2/3 or LIPKEY?

> Anyway, if anyone has any comments or can shed some light on these issues it would

I would argue that if the initiator's mechList includes at least one mech
which does not support integrity protection then the mechListMIC is
useless regardless of the acceptor's actual choice because the acceptor
could well choose a mech that does not support integrity and the
initiator must be ready for such an eventuality (otherwise it wouldn't
include weak mechs in its mechList).

The problem here is that the negotiation can't be protected if the
acceptor can select a mech that cannot protect the negotiation, even if
the acceptor could choose a mech that can.

Of course, arguably, given Kerberos which supports integrity and a mech
Foo which does not, if the initiator requests Kerberos and Foo and sends
an initial, optimistic Kerberos token, then the client knows that the
server ought to be able to choose Kerberos, and by all rights should, if
the initiator requests integrity protection, since Kerberos supports
integrity and Foo does not and so the client should not even include Foo
in the initial mechList.

This implies that the only time that the mechListMIC matters is when: a)
the initiator requests integrity or confidentiality and b) the
initiator's initial mechList contains two or more mechs and c) all of
the initiator's requested mechs support integrity protection.

If Microsoft's implementation does not violate the above then we can all
implement that behaviour and be fully interoperable wrt the mechListMIC.

>   Sun Microsystems.

Cheers,

Nico
--

---

From: Martin Rex <[email-masked]>
Date: Tue, 3 Dec 2002 20:01:30 +0100 (MET)

Wyllys Ingersoll wrote:
> RFC 2478  that interoperates with Microsoft (Win2k Server).
> I've come across some problems/issues and was wondering if anyone else
> has tried to interoperate with MS SPNEGO successfully or knows of
> these issues.
> 
> [I raise these issues in this forum because it relates to RFC 2478 compliance
>  and I think the CAT WG is dead, so this seems like the most appropriate
>  forum.  My apologies if its too far off-topic ]

Today, this might be the most appropriate forum for SPNEGO issues in the IETF
since it has discussions around SPNEGO every once in a while and you'll find
a few leftovers (like me) from the CAT WG here, although I hardly see
comments from other CAT experts like John Linn and Theodore Ts'o anymore.

> 
> Test Environment:
>     * GSSAPI sample applications running in Solaris using SEAM software and
>       native Solaris GSSAPI implementation (i.e. NOT using MIT KRB5 GSS stuff).
> #1 - (Unix gss-client, Win2K gssserver) - All NegTokenTarg tokens sent
>      from the SSPI based server include a field tagged as if the
>      MechListMIC were present, but the data in that position is actually
>      an exact copy of the 'responseToken' field, not a MIC of the original
>      mech list that the client sent to the server.
>      In order to interoperate with MS as a GSS/SPNEGO client, the SPNEGO
>      module must ignore the mechListMIC field in the response from the
>      server, it cannot be verified since its not a valid MIC of anything.
>      This seems very wrong and will make interoperating with both MS *and*
>      anyone elses implementation that actually includes a proper MIC
>      difficult without some ugly hacks.  The RFC says the MIC field is
>      optional, but including data in that field that is not a real MIC
>      is clearly wrong.

OUCH!  Should your oberservation be correct then Microsoft has really
fubar'ed their SPNEGO implementation.

Although the MIC field is optional as far as the ASN.1 structure of the
tokens is concerned, the MIC field is clearly and explicitly required
when the negotiated mechanism is capable of integrity protection
(such as a Kerberos 5 mechanism):

quoting from the SPNEGO spec (rfc 2478, second page 3rd paragraph):
:
:  The simple and protected GSS-API mechanism negotiation provides a
:  technique to protect the negotiation that must be used when the
:  underlying mechanism selected by the target is capable of integrity
:  protection.
:
:  When all the mechanisms proposed by the initiator support integrity
:  protection or when the selected mechanism supports integrity
:  protection, then the negotiation mechanism becomes protected since
:  this guarantees that the appropriate mechanism supported by both
:  peers has been selected.

Actually this looks like it's killing basically all of the remaining
"let's use SPNEGO for IAKERB" arguments -- even for those that didn't
grasp that a protected negitiation inside rfc1964bis Kerberos would
quite possible and exactly as secure as a **correct** SPNEGO.

>     Win2K server (and probably most others) the OIDs for Kerberos and

Indeed that looks BADLY broken.  The Kerberos context tokens emitted
by InitializeSecurityContext() and AcceptSecurityContext() in Microsoft's
SSPI contain the *correct* Kerberos GSS-API mechanism OID from rfc1964
(at least in the way I use them).  So it is really a mystery why this
OID shouldn't work (as required by rfc2478) at the SPNEGO level.

>       contents of the MechListMIC field in the NegTokenTarg token.
>      This causes a problem with the GSS sequence numbering.
>      An RFC 2478 compliant server will call 'gss_get_mic' on the original
>      mechListMIC in order to include the MIC in the response to the
>      NegTokenInit packet (following the  RFC).  This increments the
>      internal GSS sequence number used when generating MICs
>       Later, after the SSPI client has successfully sent its actual data
>      to the GSSAPI server, the gss-server must send back a MIC of the
>      message to the SSPI gssclient as a final verification that the data
>      was transferred OK.  This causes the sequence number to be incremented
>      again. The problem is that because the SSPI code never verified the
>      MIC in the NegTokenInit packet, it is not expecting the sequence number
>      to be incremented when the MIC of the final data is sent and an
>      "incorrect sequence number" error occurs when the SSPI client tries to
> So, if you want to interoperate with MS, dont bother creating or sending
> MechListMIC fields in either the initiator or target packets.
> This would seem to weaken the whole negotiation process since there is
> no way to verify that the originally desired list of mechanisms was
> not altered.
> 
> not possible to generate a MIC if one of those mechs is chosen.
> However, it seems that if the chosen mechanism does support integrity
> (like Kerberos V5), then the MIC should be generated just to be safe.
> 
> Anyway, if anyone has any comments or can shed some light on these issues
> it would be appreciated.

It strikes me as odd that Microsoft's implementation of SPNEGO should
be so totally flawed considering their involvement in the actual
SPNEGO spec and the large amount of time they had from when SPNEGO
was finalized and when W2K finally shipped.  Unfortunately it is similar
to my own experiences with Microsoft's implementations in other areas
of standardization (including their very own documentation/standards).

-Martin

---

From: Martin Rex <[email-masked]>
Date: Tue, 3 Dec 2002 20:52:45 +0100 (MET)

> include weak mechs in its mechList).

There's absolutely nothing to argue about, the SPNEGO spec is
crystal clear (minus one typo where the text uses a may for the mechListMIC,
however the spec provides enough "ECC" at all four other places in the
document where the requirement for presence of mechListMIC is explicitly
described as a must whenever the negotiated mechanism supports message
integrity).

> the acceptor could choose a mech that can.

That is not a problem at all, but a recognized and well-described
compromise in order to allow mechanisms that do not support message
integrity at all.

> the initiator's requested mechs support integrity protection.

You forgot the case when the server requires a mechanism with
message integrity independent of whether the initiator includes
a authentication-only mechanism on its list or not.

> implement that behaviour and be fully interoperable wrt the mechListMIC.

If Wyllys observations are correct then Microsoft's SPNEGO implementation
is fubar and will be definitely non-interoperable with each and every
CORRECT SPNEGO implementation when a mechanism supporting message
integrity is being negotiated.  And apparently even the negotiation of
rfc-1964 with the correct OIDs is broken as well ...

Considering the document quality, clarity and completeness SPNEGO
(rfc-2478) seems to be very good/high, it's just a little complex
and probably overkill for several scenarios in my opinion.

Even though Microsoft seems to have messed up their implementation
so badly that correct and/or independent implementations of SPNEGO
will not interoperate.  Considering the bloat, vagueness, incompleteness
ugliness and unresolved mysteries in the current IAKERB proposal,
I'm pretty sure that this will end up in disaster if we put it on
standards track and wait for Microsoft to implement it ...

Repeating myself: What's worse that a bad/broken spec?  An large installed
base of severly broken implementations.  What Microsoft has done to SPNEGO
(where the spec was actually quite good) seems to be quite devastating. 

-Martin

---

From: Nicolas Williams <[email-masked]>
Date: Tue, 3 Dec 2002 12:22:01 -0800

> a authentication-only mechanism on its list or not.

The client cannot know a priori that the server won't select auth-only
mechs.  Of course, if that's the case then if the server sends the
mechListMIC then no downgrade attack is possible.  Ok, fair enough.

Nico
--

---

From: Ken Raeburn <[email-masked]>
Date: Tue, 03 Dec 2002 16:42:44 -0500

> include weak mechs in its mechList).

If your mechList includes two mechanisms:

 mechA - no integrity protection, but takes a zillion years to crack
         the encryption
 mechB - integrity protection provided, but the key can be determined
         in a few days of offline attack of the recorded data stream

then a forced downgrade to mechB would be detectable through the
mechListMIC (assuming the negotiation weren't allowed to take long
enough to for the key to be cracked), and if it were not detectable,
would be desirable to an attacker.

BTW, RFC 1964 (without updates -- i.e., using plain DES) probably
qualifies as "mechB" these days.

Ken

---

From: Martin Rex <[email-masked]>
Date: Wed, 4 Dec 2002 10:35:10 +0100 (MET)

>          in a few days of offline attack of the recorded data stream

In case that you think of a mechA that offers message confidentiality
*without* message integrity -- that combination is *NOT* allowed by
the GSS-API standard (and would confuse or break a lot of applications).

GSS-API offers a strictly incremental set the following services,
- the absolute minimum is authentication
- the next step is authentication plus message integrity
- and finally there is authentication plus message integrity plus message
  confidentiality.

which makes two conceivable combinations non-conforming:
encryption-only (i.e. without authentication) and
authentication plus encryption without integrity protection.

However, a reckless spec weasel could masquerade encryption-only as
a unidirectional authentication with "the anonymous principal",
and a integrity-less authentication+encryption scheme by
simulating an integrity protection that isn't (because gss_getmic()
and gss_verifymic() must be implemented and provide the correct
look-and-feel).

-Martin