Re: KITTEN BOF at IETF 60?

Martin Rex <[email protected]> Mon, 22 Mar 2004 22:17:40 +0100 (MET)
Newsgroups gmane.ietf.cat
Message-ID <[email protected]>
Ken Raeburn wrote:
> 
> Well, I haven't implemented a mechanism from scratch, mostly tweaked
> MIT's krb5 mechanism, but I can toss out a few nits I have to pick
> with RFC 2744:
> 
> - No GSS_C_AF_INET6 definition.  Some of the AF definitions that are
>   included are silly.  Does anyone on the planet care about
>   GSS_C_AF_CHAOS?

For me GSS_C_AF_CHAOS is just as useless ans GSS_C_AF_INET4.  :)

Seriously, the channel bindings are probably straight from GSS-API v1
which was published in 1993 (rfc-1508/1509) and someone was trying
to create a complete list of known networking protocols at that
time, I suppose.  That there is no GSS_C_AF_INET6 seems to indicate
that there weren't many implementors using channel bindings when
GSS-API v2 was discussed...


> 
> - No guidance concerning thread support.

Multi-threading is an extremely platform specific mess and thread support
will implementation specific anyway.  GSS-API v2 does *NOT* cover
threads at all, and it is quite good that it doesn't even try to
(because it would almost certainly have failed).

The discussion about multi-threading with GSS-API came up a few times
on CAT before GSS-API v2 was completed, but most of the participants
agreed that it would be a too radical change for a mature API and
better be saved for a GSS-API v3 revision that could decide to
break with interoperability.  The apparently most often mentioned
lack was an initialization and a final cleanup call.

The problems that I have encountered with multithreading on various
platforms are:

 - on most Unix/Posix platforms single-threaded objects/shared libs
   can *NOT* be used/linked with multi-threaded objects/shared libs

 - some Unix/Posix platforms offer two different incompatible threading
   models and code compiled for one cannot be used together with code
   compiled for the other (Reliant Unix 5.45 with DCE- vs Unix98-threads)
   
 - Win32 has a serious deficiency with cleaning up thread-local storage,
   since it lacks a destructor in TlsAlloc().  Hooking the THREAD_DETACH
   event in DllMain() might be a workaround, but you have to put your
   code into a DLL for this to work--but what about cleanup when
   UnloadLibrary() is used before the threads terminate ...

 - some platforms are still stuck on old draft4 Posix threads
   (IBM's OS/390 Open Edition alias z/OS, and OS/400) 


>
>   If a mechanism doesn't provide out-of-sequence detection, can I use
>   gss_get_mic in two threads with the same security context, without
>   ensuring that the calls aren't fully serialized?

In the portable sense: NOPE, never.

With most "multi-threading-capable" gssapi mechanism implementations
you will have to serialize calls on the same "handle", since these
handles have internal state which can be affected by gssapi calls
and by external events.

To offer such a functionality, an implementation would either use
a global locking or a handle-specific locking itself, and it would
have to always use it, even if the application did serialize or
wasn't multithreaded at all.

In the POSIX thread spec there is a rather low upper limit on the number
of Mutexes that a threads implementation must be able to support.


If a mechanism wanted to offer such functionality, then it would be
appropriate if the mechanism offered special locking calls that
would lock operations on the handle and can be used by the
application.  Similar to GetDC()/ReleaseDC() on Microsoft Windows platforms.

The more common situation than two independent threads calling
gss_get_mic() on the same context would be two independent threads
for each direction of the communication (incoming/outgoing) so that
one thread calls gss_get_mic() on the same context handle on which
the second thread calls gss_verify_mic()  (analogous with wrap/unwrap).

Personally, even with a multi-thread-capable gssapi mechanism I would
always serialize calls that used the same object handle (here context).


Btw. have you checked the constraints of OpenSSL when calling
SSL_Read and SSL_Write on the same SSL handle in two independent
threads (I haven't)?


> 
>   How about gss_inquire_cred on the same credentials in multiple
>   threads?  The description of that function suggests that cred_handle
>   is an input argument, but the description of gss_acquire_cred says
>   that gss_inquire_cred may implement delayed credential acquisition,
>   which suggests modification under the covers.

Again, in the portable sense: never.

With credentials it may be even worse.  On Microsoft Windows NT platforms
there usually are thread-local permissions (thread-local access tokens),
so when the application plays funny "impersonation" games this may cause
some gssapi mechanisms (not native to Windows NT) to run into problems
accessing credentials.

I haven't checked whether SSPI credentials (once the handle is acquired)
remain fully accessible while the application caller plays around
with context impersonation.


> 
>   How about general use of the GSS-API from multiple threads for
>   unrelated sessions?  If a mechanism has static data that it
>   modifies, must it use a mutex (or semaphore, or atomic-access
>   instructions) internally in a threaded environment?  Or is it up to
>   the application to avoid the simultaneous use of GSS-API functions
>   in different threads?

As you found out, there is no GSS-API definition for a multi-threaded
environment, so whatever you do it will be *specific* to the combination
of both, your multi-threaded app and your multi-threaded gssapi mechanism.

A portable application will assume a non-threadsafe gssapi mechanism
and therefore have to serialize *all* gssapi calls.

A gssapi mechanism implementation that wants to offer support for
multiple threads must at least offer concurrent use of independent
handles (correctly locking/serializing access to internally shared
resources).


> 
>   I'm actually working on thread safety for the MIT code right now,
>   and I'm pretty much having to guess.

Well, Good Luck!

When we had a discussion on multi-threading on CAT (but I think it
was rather a conversation


> 
> - The handling of "const" is confused.
> 
>   Several "pointer or arithmetic type" parameters are declared
>   "const".  This does *not* mean "any pointed-to data is not modified
>   by the function".  It means "the function implementation cannot
>   modify its local copy of the argument passed in", which is just
>   silly, since doing so doesn't influence the caller at all.
> 
>   I'd have to check the C spec, but I'm not sure if it would be
>   compliant with ISO C to actually define the specified OIDs as
>   "const", given the header file we're supposed to provide.  But
>   that's an "implementation detail", and implementations are on real
>   systems, not ISO C abstract machines.  The application isn't allowed
>   to write to the OIDs, so as long as the behavior is correct for a
>   compliant application, stuffing them in read-only storage and not
>   declaring them "const" in the available header is probably fine.

Bad luck.

I hardly use const even today.  I certainly didn't use it back then.
The GSS-API header file which we use for our application doesn't
have const anywhere, probably because it was nailed down early 1996  :)

Comment from Ted Ts'o on the CAT list about the use of "const":
: 
: From: "Theodore Y. Ts'o" <[email protected]>
: To: Marc Horowitz <[email protected]>
: Cc: [email protected], [email protected]
: Subject: Re: GSS Storage Issues
: Date: Fri, 30 Aug 1996 16:08:48 -0400
: 
:    Cc: [email protected]
:    From: Marc Horowitz <[email protected]>
: 
:    >> Perhaps we should add the keyword "const" where
:    >> appropriate too.
: 
:    I'd be for that.
: 
: So would I; right now, there are some people who are inserting "const"
: into their GSSAPI function prototypes, which I claim is in violation of
: the GSSV1 C Bindings specs --- it causes compilers to flame incessantly
: about type warnings, and that masks the real bugs.   :-)
: 
: The people who put in the "const" keywords claims that it's better C
: coding style.  I don't disagree with that, but I'd much rather see it
: into the C bindings specification first.
: 
:                                                 - Ted


> 
>   Maybe that's not completely true.  The spec says "should" in a lot
>   of places, including "GSS-API implementations *should* provide
>   constant gss_OID values" and "*should* treat...as read-only", but
>   not "must", and as far as I've found, it doesn't explicitly give the
>   implementation license to blow up if the application misbehaves in
>   this regard.

rfc-2743/2744 is actually GSS-API v2 update 1.

If you look at rfc-2078 there was the concept of dynamic OIDs over
a few years in GSS-API v2, but was dropped when it was realized that
there were several problems with dynamically allocated OIDs and
that it was backward-incompatible with GSS-API v1.

Rather than explicitly "outlawing" mechanism implementations that
had implemented the gss-api-v2 draft it was considered more appropriate
to list the requirements and constraints on OIDs once they're made
visible to the application.

One of the situations where OIDs might be initially dynamic is
plug-n-play multimechanism schemes where the glue layer figures
out OIDs and OID_sets at runtime.  But as there is no (more)
gss_release_oid() call, the OID needs to exhibit "const" behaviour
once it has been returned to the application caller via any of
the gssapi calls.


> 
> - How is the header file used?  <gssapi.h> or <foo/gssapi.h> or
>   something else?  At least some applications are testing the
>   environment in order to pick between <gssapi.h> and
>   <gssapi/gssapi.h>.  What's "portable" here?

For our application we're using our own header file (one single header
file for *ALL* of our platforms).  Hardly any platform that we use
for building our code comes with a gssapi mechanism on-board, and
neither do we install one.


> 
> - Tying anything to whether or not X/Open header files are available
>   is pretty clear, but unfortunate.  (Especially where a lot of
>   systems have optional add-on packages these days.)  Updating to C
>   '99 would be nice, if it can be done compatibly.

Our application explicitly does NOT use the X/Open stuff, since that
is a royal PITA, and unfortunately on 64-bit platforms tend to be
incompatible the OID/OID_set "fallback definitions" in the
gssapi v2 sample header file.


> 
> - Is an implementation allowed to define any of these functions as
>   macros as well (a la C '89, which generally allows it but requires
>   that an addressable function be available as well).
> 
>   For example:
>   #define gss_wrap(a,b,c,d,e,f,g)                            \
>     ({ /* statement expression - gcc extension */            \
>        gss_ctx_id_t _ctx = (b); /* no multiple evaluation */ \
>        (_ctx->ops->wrap(a,_ctx,c,d,e,f,g));                  \
>     })

YUCK!

Besides that wouldn't work with binary plug'n'play mechanisms
(using shared libraries) it is also distasteful.

I consider every code seriously broken which reveals internal implementation
detail in the API header file or which performs recursion through its external
programming API so that inside the function you cannot immediately distinguish
a genuine call from the application from an internal use or recursion.


> 
> - Appendix A: "C-language GSS-API implementations should include a
>   copy of the following header-file."
> 
>   Ignoring the fact that platform-specific substitutions need to be
>   done first, and the preprocessor test using sizeof is completely
>   useless (the preprocessor doesn't evaluate sizeof), this also
>   suggests that no other changes (e.g., declaring extension functions
>   or additional name-type OIDs) are allowed.

The definitions at the beginning of the gssapi_2.h Header file
that I've been using since 1995 for *ALL* platforms
looks like the following, and I do ignore <xom.h> which still
isn't available on many of our build platforms.

/*
 * Determine platform-dependent configuration.
 */
#include <limits.h>

#if USHRT_MAX > 0x10000
#  define GSS_SIZEOF_SHORT    4
#else
#  define GSS_SIZEOF_SHORT    2
#endif

#if UINT_MAX > 0x10000
#  define GSS_SIZEOF_INT      4
#else
#  define GSS_SIZEOF_INT      2
#endif

#if ULONG_MAX > 0xffffffff
#  define GSS_SIZEOF_LONG     8
#else
#  define GSS_SIZEOF_LONG     4
#endif

/*
 * Define APIENTRY, NEAR & FAR
 * plus LOCAL_APIENTRY (for WIN16 to avoid __loadds)
 */

#ifndef APIENTRY
#  if defined(_WINDOWS)
#    define APIENTRY        __far __export __pascal
#    define LOCAL_APIENTRY  __far __pascal
#  elif defined(WIN32)
#    define APIENTRY        __stdcall
#  else
#    define APIENTRY
#  endif
#endif

#ifndef LOCAL_APIENTRY
#  define LOCAL_APIENTRY  APIENTRY
#endif

#ifndef FAR
#  if defined(_WINDOWS)
#    define FAR   __far
#    define NEAR  __near
#  else
#    define FAR
#    define NEAR
#  endif
#endif


> 
> - The description of equality comparisons in section B.3 makes me
>   shudder.  I'm not even sure what it means.  As far as I can tell, if
>   your machine lets you have two objects (pointers, integers, floats)
>   that compare equal with "==" despite having some bits that are not
>   identical, then you have to fix up those bits to always be equal.

B.3 says:
   For binary portability, additional constraints are required. The
   following is an attempt at defining platform-independent constraints.

Why does this make you shudder?  The decription that follows this is
more-or-less the assumptions that must be met so that the *independent*
header files of the application programmer and the gssapi mechanism
programmer will smoothly interoperate when the two binaries
(exe-application and shared lib-mechanism) meet in the wild.

> 
> - If you want to make recommendations about ABI compatibility, how
>   about suggesting *either* pointer or arithmetic type for handles,
>   and not giving the implementation the choice.  Not only is it valid
>   for pointers and arithmetic types to be passed and returned
>   differently, there is at least one platform where pointers and
>   numbers *are* returned differently.  Also, floating-point values are
>   "arithmetic", and are often passed differently from both integers
>   and pointers.

It really doesn't matter how it is passed.

It is about interoperability when the two binaries (exe-app and
shared lib-mechansim) have been *independently* built with differing
definitions for e.g. gss_ctx_id_t.

So even if the application treats it as a pointer and the gssapi
mechanism actually uses an "int" they both should interoperate!
However if the gssapi mechanism uses an integer (and a union to
get size/alignment of void*), then the gssapi mechanism must clear
bits in gss_ctx_id_t when setting the integer part of the union
in case that sizeof(void*)>sizeof(int), e.g. on a 64-bit platform.


> 
>   (And I'd have to research it, but suggesting incomplete struct
>   pointer types might be a better option.)

I agree.  Instead of just discouraging (void*) the spec would have
better suggested to use imcomplete struct pointers -- I didn't know
how simple that is and how good it works for quite a while...


> 
> - Should the ABI discussion touch on shared library names?  I'm not
>   sure.  Perhaps not.

Nope.  There are definitely going to be several independent gssapi mechanisms
available.  So either its fine when an application is directly linked
with an implementation-specific library, or the application should be
able to load one (or more) of arbitrarily named libaries dynamically
at runtime.

> 
> - No discussion of C namespace issues.
> 
>   Are names starting with "gss_" and "GSS_" reserved for
>   implementation internal use, future updates and extensions?  Or
>   should applications feel free to use them?  If they're reserved,
>   then under what conditions?  (See the C library spec's description
>   of this sort of thing, IIRC there are at least two classes of
>   reserved names.)
> 
>   Inclusion of gssapi.h on an ANSI C system is required to define
>   ptrdiff_t and offsetof(), right?  After all, Appendix A, which
>   apparently is normative, says it includes stddef.h, and C '89 says
>   stddef.h defines those.  So using some system-specific header than
>   only provides a __size_t for the implemenation's use, and avoiding
>   stddef.h, is not allowed?
> 
>   What's added to the namespace on an X/Open system?
> 
>   Can I use gss_uint32 in my code?  (True, there's no guarantee that
>   it's the same as OM_uint32.)

Actually I'm using OM_uint32 everywhere in the header and my application
code, but I do *NOT* use the X/Open definitions or header files anywhere
-- actually the X/Open definitions would cause serious incompatibilities
on some platforms...

> 
> (Taking off my "amateur language lawyer" hat now....)
> 
> > Channel bindings are actually non-portable anyway, many gss-api mechanisms
> > don't implement them (even Microsoft's Kerberos doesn't) and portable
> > applications don't use them anyway.  Routing&multihoming issues,
> > NATs and all that interfere in all sorts of ways.
> 
> And the non-portability makes it okay for the specification to be
> confusing?  Does the GSS-API spec say that you shouldn't use channel
> bindings?  Should it?

I think that a GSS-API v2 spec that wants to advance to draft standard
(which may well be independent of KITTEN going for GSS-API v3),
then the refined spec should clearly outline that channel bindings
are optional for the gssapi mechanism to implement and optional
for the application to use and it should give a warning what
mechanisms should do if one peer supplied/supports channel bindings
and the other doesn't... (in order to document existing practice).


> 
> > So far I've primarily seen clear breaches of the abstraction when
> > IPv4 channel bindings where used with Kerberos and the Kerberos
> > gssapi mechanism did not only verify the channel bindings at both
> > ends with the application provided values, but also peeked inside
> > the channel bindings and matched them up against credentials.
> 
> What abstraction?  I thought RFC 2743 section 1.1.6 allowed for this
> sort of use?

I would consider that heavily underspecified.  I think it is a flawed
assumption that the network interface that the application is
using is for communication will always be available/visible/accessible
to the gssapi implementation when it acquires/creates credentials,
even if both are using IPv4.  This seems to be more obvious when the
application is *NOT* using IPv4.

I know little about IPv6, but the situation of adhoc-creation of
network addresses unknown to the gssapi mechanism may be more
common with IPv6.


-Martin

-++**==--++**==--++**==--++**==--++**==--++**==--++**==
This message was posted through the Stanford campus mailing list
server.  If you wish to unsubscribe from this mailing list, send the
message body of "unsubscribe ietf-cat-wg" to [email protected]