GSS-APIv3 sketch

Nicolas Williams <Nicolas.Williams@sun.com> Wed, 11 November 2009 18:22 UTC

Return-Path: <Nicolas.Williams@sun.com>
X-Original-To: kitten@core3.amsl.com
Delivered-To: kitten@core3.amsl.com
Received: from localhost (localhost [127.0.0.1]) by core3.amsl.com (Postfix) with ESMTP id AADDE3A6AE0 for <kitten@core3.amsl.com>; Wed, 11 Nov 2009 10:22:51 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -6.03
X-Spam-Level:
X-Spam-Status: No, score=-6.03 tagged_above=-999 required=5 tests=[AWL=0.016, BAYES_00=-2.599, HELO_MISMATCH_COM=0.553, RCVD_IN_DNSWL_MED=-4]
Received: from mail.ietf.org ([64.170.98.32]) by localhost (core3.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vpmtex4VebY8 for <kitten@core3.amsl.com>; Wed, 11 Nov 2009 10:22:50 -0800 (PST)
Received: from sca-ea-mail-2.sun.com (sca-ea-mail-2.Sun.COM [192.18.43.25]) by core3.amsl.com (Postfix) with ESMTP id 08A373A687D for <kitten@ietf.org>; Wed, 11 Nov 2009 10:22:50 -0800 (PST)
Received: from dm-central-01.central.sun.com ([129.147.62.4]) by sca-ea-mail-2.sun.com (8.13.7+Sun/8.12.9) with ESMTP id nABINFE4022964 for <kitten@ietf.org>; Wed, 11 Nov 2009 18:23:15 GMT
Received: from binky.Central.Sun.COM (binky.Central.Sun.COM [129.153.128.104]) by dm-central-01.central.sun.com (8.13.8+Sun/8.13.8/ENSMAIL, v2.2) with ESMTP id nABINF84063017 for <kitten@ietf.org>; Wed, 11 Nov 2009 11:23:15 -0700 (MST)
Received: from binky.Central.Sun.COM (localhost [127.0.0.1]) by binky.Central.Sun.COM (8.14.3+Sun/8.14.3) with ESMTP id nABIBf9n013775 for <kitten@ietf.org>; Wed, 11 Nov 2009 12:11:41 -0600 (CST)
Received: (from nw141292@localhost) by binky.Central.Sun.COM (8.14.3+Sun/8.14.3/Submit) id nABIBeZP013774 for kitten@ietf.org; Wed, 11 Nov 2009 12:11:40 -0600 (CST)
X-Authentication-Warning: binky.Central.Sun.COM: nw141292 set sender to Nicolas.Williams@sun.com using -f
Date: Wed, 11 Nov 2009 12:11:40 -0600
From: Nicolas Williams <Nicolas.Williams@sun.com>
To: kitten@ietf.org
Subject: GSS-APIv3 sketch
Message-ID: <20091111181140.GC10501@Sun.COM>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
User-Agent: Mutt/1.5.7i
X-BeenThere: kitten@ietf.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: Common Authentication Technologies - Next Generation <kitten.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/listinfo/kitten>, <mailto:kitten-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/kitten>
List-Post: <mailto:kitten@ietf.org>
List-Help: <mailto:kitten-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/kitten>, <mailto:kitten-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 11 Nov 2009 18:22:51 -0000

As I mentioned yesterday, I started with a goal of writing a new, model
mechglue based on GSS-APIv2u1, with some extensions, and with the
"PGSSAPI" idea fully incorporated.  For those who don't remember, the
PGSSAPI proposal was to add a [non-security] context handle to all GSS
functions, and which I'd refined to "turn the minor_context argument
into that context handle" proposal.

Well, I realized at one point that there were a number of other problems
with the GSS-APIv2u1 that I wanted to solve, and that my solutions were
less than ideal.  For example: memory management, which involved lots of
interning of things in my scheme.  That led me to consider a close-to-
wipe-the-slate approach -- the slate can't be wiped entirely clean, both
because the effort to update existing applications of the GSS-API to the
new-thing must be minimal, and because protocol aspects of the GSS-API
cannot change.

Here, then, is my proposal for a GSS-APIv3 (from memory, and not
necessarily complete -- it's still a work in progress).  My approach to
implementation is described below.

 - Problems to be solved:

    - memory management
    - extensibility
    - credentials limitations
    - application/instance-specific configuration
    - error reporting
    - QoP issues
    - C-Bindings ABI issues (primarily: remove ABI non-determinism
      caused by certain aspects of the v2u1 API that are left open to
      implementors)

 - At the abstract level the API changes very little:

    - minor_status indeed becomes a "call context handle"

       - functions are added to deal with that (more on this below)
       - this provides for better error reporting
       - this provides for application-specific mechglue configuration
       - for portability: a function to get from a call context handle
	 what used to be a discrete minor status number (providers need
	 not support this)

    - must distinguish between input and output buffers (more on this
      below)

    - sundry extensions

       - including a credential store handle and related functions (more
	 on this below), mechglue/provider configuration control, some
	 amount of reflection, ...

       - see below

    - optional output arguments, of functions where an output is not
      essential and can be obtained via inquiry functions, are
      eliminated (e.g., context expiration time is no longer output by
      init/accept_sec_context functions)

    - extensibility: new flags can be added that are critical or
      non-critical (see below)

    - credentials are more set-like objects
       - add_cred() function is revamped, simplified
	  - it only adds elements to an existing credential
	  - the requirement that desired_name be the same for add_cred()
	    calls that add elements to existing creds is gone
       - allows for better control over what creds are used for
	 accept_sec_context()
       - default initiator principal for a credential set can be
	 inquired/set (but this is cred handle-specific -- a credential
	 store's default initiator principal notion is distinct)
       - see below about credential stores

    - All existing extensions will be included

 - C-Bindings:

    - new symbol/macro prefix name, either gss3_ or gs3_ (capitalized,
      for macros)

    - requires C99

    - requires uint64_t

       - all uses of OM_uint32 become uses of uint64_t

       - for flags arguments, half the word contains critical and legacy
	 flags, while the other half contains non-critical flags

    - requires that all opaque types be declared as pointers to
      incomplete structures, and that the opaque types all be distinct
      (for static type safety)

    - memory management:

       - option for simple, single-threaded apps: sec context and
	 per-msg output tokens automatically release when either the
	 next token is output or the sec context is deleted

       - buffer types:

	  - struct gss3_in_buffer_desc
	  - gss3_in_buffer_t
	  - gss3_out_buffer_t

	 The gss3_out_buffer_t type is opaque, but accessor macros are
	 provided (these may expand to function calls or to casts and
	 derefences; accessor functions provided so one can take their
	 addresses and pass them around, if desired).

	 gss3_release_buffer() releases only output buffers.  No more
	 accidentally calling it to release application buffers!
	 (Static type safety ensures this.)

	 (Internally the gss3_out_buffer_t need only track length,
	 value, and provider release function pointer.)

	  - a function to allocate provider-specific input buffers for
	    optimizing context/per-msg input token processing (returned
	    as both, an output buffer, for releasing, and an input
	    buffer, for the app to place tokens into)

	     - think of crypto HW where using a buffer allocated for the
	       purpose can be used to reduce overhead in using the
	       crypto HW (the newest UltraSPARC crypto units support
	       this, for example)

       - OID, OID set, and output buffer set types

	  - no input buffer set type yet
	  - OID type is opaque
	  - all set types are opaque, manipulated only via functions and
	    accessed only via accessor getter macros/functions

	  - str_to_oid() and oid_to_str() revived

	     - OID description functions are provided, outputting symbol
	       name, the type of thing the OID refers to, stringified
	       OID (with and without arcs resolved to names),
	       description

	  - release_oid() revived

	 (Internally these types need only track count/length,
	 value/elements and provider ops vectors.)

    - all opaque _objects_ (creds, cred stores, contexts, names, call
      contexts), but not buffers, OIDs, OID sets, can be duplicated and
      refcounted.

      There's a function per-object type to duplicate, and a function
      per-object type to get an additional reference to an object.  The
      traditional release functions decrement reference counts,
      destroying the object when the last reference is gone.

    - minor_status indeed becomes a call context handle
      (gss3_call_ctx_id_t)

       - there's a default handle, GSS3_C_DEFAULT_CALL_CONTEXT, that can
	 be duplicated to get a call context handle that refers to the
	 default mechglue/provider configuration

       - new call contexts can be allocated, with a given configuration
	 file, or with manual mechglue configuration (add provider, add
	 provider, ...)

	  - and these can be duplicated, of course

	  - memory management functions can be specified, if desired

       - configuration is frozen when one call indicate_mechs() or one
	 of the extended mech inquiry functions

       - display_status() clearly has more information now
	  - internally the mechglue maintains a cache of
	    provider-specific call contexts in each mechglue call
	    context; this allows providers to track more error/status
	    information in a context-specific manner
	  - on next call to anything other than display_status() or
	    release_call_context() the previous error information is
	    cleared
	  - mechglue vs. provider errors better delineated (there's a
	    mechanism OID for the mechglue itself)

    - thread safety

       - v3 API is thread-safe provided that: only one thread is
	 accessing any given object at any given time

	  - for buffers and sets, what matters is destructive calls

	  - security contexts can allow concurrent per-msg token
	    functions if the app requests this (rationale: the mechanism
	    may be able to produce better concurrency than the
	    application could by locking around these functions)

    - well-defined SPI

       - the API is the SPI, _mostly_, but there's a function that each
	 provider must provide by which a mechglue above it can
	 configure the provider

	  - among other things, the mechglue passes a dlsym()-like
	    function and handle to providers that providers can use to
	    re-enter the mechglue (for pseudo-mechanisms, such as SPNEGO
	    and stackable mechanisms); re-entrance must be done this way

       - mechglues can be stacked; this is only interesting for testing
	 purposes, and for accessing providers with a v2u1 interface
	 only (see below)

       - I've several approaches for the delegated credential issue

    - credential stores

       - opaque object
       - anonymous credential stores (think MEMORY ccache type) can be
	 created at any time
       - notion of "current credential store" associated with call
	 contexts
       - a credential store has a notion of "default initiator
	 principal"
       - external credential stores supported for: process, session,
	 user
	  - a reference to such a cred store can be obtained if it
	    exists
	  - credential stores can be set for a process, session, user,
	    but creation of those things is not provided for (i.e., the
	    API is agnostic as to how processes, sessions, or users are
	    created; a login program still has to create such items in
	    an OS-specific manner)
	     - when the input cred store is anonymous it becomes
	       non-anonymous (think taking a MEMORY ccache and copying
	       it to a FILE ccache)
	  - note: no per-thread stores -- not needed because there's
	    always a call context and call contexts have a "current
	    credential store" notion
       - optional cred store argument for credential acquisition and
	 credential listing functions (not really needed, but makes API
	 easier to use, I think)
       - _of course_, there's a store_cred() function

    - QoP issues fixed

       - QoP integer argument for per-msg token functions replaced with
	 optional policy names
       - able to inquire what QoP _policies_ a credential supports
       - able to set what QoP _policies_ a credential can/must not use
       - able to inquire what QoP _policies_ a sec context supports
       - able to set what QoP _policies_ a sec context can/must not use,
	 and what QoP policy is the default for per-msg token functions
       - policies are named with well-known names with well-known
	 semantics or locally-controllable semantics
	  - Fixed semantics
	     - FIPS-140-2		(fixed semantics)
	     - NIST something or other	(fixed semantics)
	  - Fixed relative semantics, but with locally-definable exact
	    semantics
	     - strong	(strong algs only)
	     - fast	(fast algs only; may or may not be strong)
	     - interop	(required-to-implement algs included)
	     - weak	(weak algs included)
	     - notweak	(same as interop but with weak algs excluded;
			 may not be as strong as 'strong' policy)

	    I.e., sysadmin can say "'strong' means AES enctypes for krb5
	    mech, ...".

	  - locally-definable policy names (and semantics)?  locally-
	    definable policy names complicate the API...

    - Sundry extensions
       - I don't remember them all, but...
       - a per-msg token normalized-to-zero-start sequence number, for
	 mechanisms/sec contexts that can support it (the rationale:
	 apps like RPCSEC_GSS have had to build their own -- what a
	 waste!)

Implementation approach:

 - There's a file format for describing GSS-API functions:

    - function name, acronym (for internal purposes)
    - function attributes
       - versions of the API where the function is present
       - mechglue core (code can't be generated) or not core (code can
	 be generated)
       - stackable mech core or not core
       - whether it deals with call context allocation/release
       - whether providers include this function (whether to generate
	 function pointer typedef)
    - function arguments and per-argument attributes
       - type
       - input/output (optional, as often this can be inferred)
       - whether present in v2u1 and/or v3 APIs
       - ...
    - function description
    - header comments

 - A compiler reads the above and generates:

    - header file contents:
       - C function prototypes
       - file C function pointer typedefs (named <function_name>_fct)

    - code:
       - mechglue core function stubs
       - mechglue non-core functions, including code
	  - there are several patterns, inferred from function
	    name/attrs and argument list
       - stackable mechanism core function stubs
       - "null" stackable mechanism non-core functions, including code
	  - to be used as basis for constructing a variety of stackable
	    mechanisms
	  - there are several patterns, inferred from function
	    name/attrs and argument list
       - ssh-agent-like shell interface to GSS-API (to make it possible
	 to write most tests as shell scripts!)

    - compatibility shim code:
       - v2u1->v3 provider shim (so you can use existing v2u1 mechglues
	 and providers as providers for a v3 mechglue)
       - v3->v2u1 shim (so you can use a v3 mechglue implementation in
	 v2u1 applications)
	  - this uses interning to solve memory management issues (i.e.,
	    output buffers are interned)

    - documentation:
       - xml2rfc stubs (including generic abstract and C-bindings
	 argument descriptions + function description supplied in input
	 file); these can be accessed from a larger xml2rfc document as
	 XML entities
       - POD (or whatever) manpage stubs (including generic abstract and
	 C-bindings argument descriptions + function description
	 supplied in input file, SEE ALSOs, ...)

Currently my compiler is written as a ksh script.  Ideally the input
file should be XML and the compiler would be mostly a collection of XSLT
transformations of the input, but I've no clue as to how to write XSLT
transforms, so for me ksh it is for now.

Also, since I switched to a v3 design mid-stream, my compiler is not
entirely updated, and the mechglue core is incomplete and busted.

For me this is a weekends-only project, which means it's progressing
_slowly_.  I intend to ask our legal department for permission to open
source this with a permissive license, as I want to have a reference
implementation to speed standardization and adoption, but I make no
guarantees.  There's no IPR here that I know of (I've not applied for
any patents covering any aspect of the above; I have described this
project to others before; I believe most of this obvious enough).

Note too that the above approach can easily be re-purposed to generate a
SASL API.  I've considered having a SASL-as-GSS API, but there are too
many minor impedance mismatches for me to be comfortable with that
approach.  (The same problem applies to TLS, IMO, though a reasonable
subset of TLS/DTLS can be made available as a "non-standard" GSS
mechanism, in the GGF way.)

Nico
--