From K5Wiki
Jump to: navigation, search
This project was completed in release 1.8.



The goals of this project are to:

  • change the behaviour of krb5_rd_req() to always verify known authorization data elements
  • provide an attribute-based GSS interface for inquiry and submission of authorization information (draft-ietf-kitten-gssapi-naming-exts)
  • provide an attribute-based plugin interface for verification and serialization of authorization information
  • encourage the use of positive authorization data by providing sample KDC and application plugins


A new opaque type, an authorization data context (krb5_authdata_context) provides an attribute-based accessor onto a set of authorization data elements. The operations which one can perform on this context roughly mirror those specified in draft-ietf-kitten-gssapi-naming-exts.

An authorization data context is always created and verified by krb5_rd_req(); one can also be submitted to krb5_mk_req(). Access to it is provided via the krb5_auth_con_get_authdata_context() API. The public interface is provided via draft-ietf-kitten-gssapi-naming-exts.

The authorization data context encapsulates a set of authorization data systems, each which provide support for one or more authorization data types. Each system is instantiated as a module, one for each authorization data type. This is modelled closely on the client-side preauthentication SPI. The set of systems is extensible at runtime through a plug-in interface.

If an authorization data system fails to verify an element, then krb5_rd_req() will fail; however, unknown elements are still ignored (behaviour which is backwards compatible but not compliant with RFC 4120). We may want to revisit this.

Windows PAC

An authorization data system for the Windows 2000 PAC is built into libkrb5, as a wrapper around the krb5_pac APIs introduced in MIT Kerberos 1.7. Each PAC buffer is surfaced as a separate attribute. A vendor that wished to surface fields within buffers (for example, SIDs representing a user's group membership) could do so by registering the appropriate plug-in, avoiding the overhead of building a NDR parser into libkrb5. Indeed, as long as all authorization data systems are re-entrant, the plug-in could call into krb5_authdata_get_attribute() to build upon the existing PAC parsing code.

Initiator/acceptor data

Systems that implement the AD_USAGE_AP_REQ usage can serialize attributes for inclusion in an AP-REQ. The "greet_client" plugin is one such system: it conveys a single string from initiator to acceptor in the authorization data of the AP-REQ authenticator. (AD_USAGE_TGS_REQ is also supported.) Plugins that only need to verify and inquiry about KDC issued authorization data, such as the Windows 2000 PAC, advertise the AD_USAGE_KDC_ISSUED usage.


The existing KDC authorization data SPI contributed by Apple and Novell is unchanged by this project (except for a minor change to support AD-KDCIssued plug-ins). However, in order to encourage the use of positive authorization data, we have provided helper routines for marshalling and verifying AD-KDCIssued, as well sample application- and KDC-side plugins. A few hundred lines of code in total, they may be easily adapted to vendor-specific requirements such as NFSv4, POSIX, or SAML. Further, an enterprising developer might choose to build a KDC authorization data plugin on top of the authorization data ontexts APIs (and perform the majority of work in a "client" plug-in).



Naming extension APIs

The reader is referred to draft-ietf-kitten-gssapi-naming-exts for details. The following new APIs are defined in gssapi_ext.h:

  • gss_display_name_ext()
  • gss_inquire_name()
  • gss_get_name_attribute()
  • gss_set_name_attribute()
  • gss_delete_name_attribute()
  • gss_export_name_composite()
  • gss_map_name_to_any()
  • gss_release_any_name_mapping()

The following changes were made from draft-ietf-kitten-gssapi-naming-exts-05 (obviously, until the draft becomes an RFC, we may expect further changes):

  • the output argument of gss_map_name_to_any() is a pointer to gss_any_t (presumably this is a typo in the document)
  • the signature of gss_inquire_name() is:
OM_uint32 KRB5_CALLCONV gss_inquire_name
    OM_uint32 *,        /* minor_status */
    gss_name_t,         /* name */
    int *,              /* name_is_MN */
    gss_OID *,          /* MN_mech */
    gss_buffer_set_t *  /* attrs */

That is, there is a single output parameter enumerating attributes (rather than authenticated, asserted, and all_attrs), and it is a gss_buffer_set_t.

Changes to mechanism glue

The mechglue exports the naming extension functions named above. New files have been added to implement them, and the gss_mechanism type updated accordingly. Note that the mechglue does not provide its own attribute store: as such, the naming extensions APIs must be used with mechanism names. This may require the caller to explicitly canonicalize the name first.

Changes to SPNEGO

Wrappers for the naming extension APIs have been added to SPNEGO.

Changes to Kerberos 5 mechanism

All of the naming extension APIs, save for gss_display_name_ext(), have been implemented in the Kerberos 5 mechanism. Most of the code is to be found in naming_exts.c.

Previously, a Kerberos 5 mechanism name was represented by the type krb5_principal. This is now a structure containing an authorization data context as well as the principal name:

typedef struct _krb5_gss_name_rec {
    krb5_principal princ; /* immutable */
    k5_mutex_t lock; /* protects ad_context only for now */
    krb5_authdata_context ad_context;
} krb5_gss_name_rec, *krb5_gss_name_t;

Note that the lock protects ad_context only; the principal name is immutable. The initialization of ad_context is deferred until an attribute it set or authorization data imported. Some helper APIs are provided to manage the creation, copying and destruction of Kerberos 5 mechanism names.

A summary of changes to existing functions follows, excluding changes required to use the new krb5_gss_name_t data structure:


Note: the terms "flatten" and "export" are used interchangeably below and hereafter.

  • If the initiator name has an authorization data context, then the authorization data for all AD_USAGE_TGS_REQ systems is flattened, and included in the TGS request and stored in the credentials cache
  • If the initiator name has an authorization data context, then the authorization data for all AD_USAGE_AP_REQ systems is flattened, and included in the AP request
  • Support is added for importing composite names that include authorization data elements (note that re-imported names will lose their authenticated state)

This new function is a wrapper around krb5_authdata_get_attribute_types().


This new function is a wrapper around krb5_authdata_get_attribute().


This new function is a wrapper around krb5_authdata_set_attribute().


This new function is a wrapper around krb5_authdata_delete_attribute().


This new function is a wrapper around krb5_authdata_export_internal().


This new function is a wrapper around krb5_authdata_free_internal().


This new function is a wrapper around krb5_authdata_export_attributes().


This is not yet implemented.

  • Update to use kg_XXX_name() helper functions
  • Extract authorization data context from authentication context and store in source name



The following fixes were made to existing functions in libkrb5:

  • The file-based credentials cache did not support negative authorization data types
  • krb5_get_cred_from_kdc_opt() did not handle TGS-REQ submitted authorization data correctly: it should be submitted in the first service ticket request only (because in the referral case, the TGS will copy it into the returned ticket), and any returned referral tickets must be marked as containing authorization data so they are not inappropriately re-used

Public APIs

krb5_error_code KRB5_CALLCONV
krb5_make_authdata_kdc_issued(krb5_context context,
    const krb5_keyblock *key,
    krb5_const_principal issuer,
    krb5_authdata *const *authdata,
    krb5_authdata ***ad_kdcissued);

This function both encodes and signs AD-KDCIssued authorization data (RFC 4120 section A set of authorization data containing a single AD-KDCIssued element is returned to the caller.

krb5_error_code KRB5_CALLCONV
krb5_verify_authdata_kdc_issued(krb5_context context,
    const krb5_keyblock *key,
    const krb5_authdata *ad_kdcissued,
    krb5_principal *issuer,
    krb5_authdata ***authdata);

This function both decodes and verifies AD-KDCIssued authorization data (RFC 4120 section The issuer and unwrapped authorization data are returned to the caller.

Exported, private APIs

void KRB5_CALLCONV krb5int_free_data_list
(krb5_context context, krb5_data *data);

Frees an array of krb5_data objects, terminated by the last element's data member being NULL.

krb5_error_code KRB5_CALLCONV
krb5_authdata_context_init(krb5_context kcontext,
                           krb5_authdata_context *pcontext);

Initialises an authorization data context, loading both built- and plug-in authorization data systems. Note that in the present implementation, the plug-in list is not cached between calls to this function; this may change in the future.

krb5_authdata_context_free(krb5_context kcontext,
                           krb5_authdata_context context);

Releases and authorization data context.

krb5_error_code KRB5_CALLCONV
krb5_authdata_get_attribute_types(krb5_context kcontext,
                                  krb5_authdata_context context,
                                  krb5_data **verified_attrs,
                                  krb5_data **asserted_attrs,
                                  krb5_data **all_attrs);

Returns the union of attributes supported by all registered authorization data systems. Note that the meaning of all_attrs is unclear from draft-ietf-kitten-gssapi-naming-exts; we may remove this in the future.

krb5_error_code KRB5_CALLCONV
krb5_authdata_get_attribute(krb5_context kcontext,
                            krb5_authdata_context context,
                            const krb5_data *attribute,
                            krb5_boolean *authenticated,
                            krb5_boolean *complete,
                            krb5_data *value,
                            krb5_data *display_value,
                            int *more);

Retrieves an attribute named by attribute from the set of authorization data systems. Note that presently a single attribute type cannot be federated amongst multiple systems. more must be set to -1 on the first call; this function should be called repeatedly until more is 0, or an error returned.

krb5_error_code KRB5_CALLCONV
krb5_authdata_set_attribute(krb5_context kcontext,
                            krb5_authdata_context context,
                            krb5_boolean complete,
                            const krb5_data *attribute,
                            const krb5_data *value);

Sets/adds an attribute value. Whether an attribute is multi-valued or not is left to the authorization data system. To replace an attribute's every value delete the attribute's values first with krb5_authdata_delete_attribute().

Return values: EEXIST indicates the attribute already exists, EINVAL indicates an invalid argument, ENOENT indicates that the attribute type is not recognised by any authorization data system.

krb5_error_code KRB5_CALLCONV
krb5_authdata_delete_attribute(krb5_context kcontext,
                               krb5_authdata_context context,
                               const krb5_data *attribute);

Deletes an attribute.

krb5_error_code KRB5_CALLCONV
krb5_authdata_import_attributes(krb5_context kcontext,
                                krb5_authdata_context context,
                                krb5_flags usage,
                                krb5_authdata **authdata_to_import);

Imports a set of authorization data with the given usage. Typically usage will be AD_USAGE_MASK, to indicate to all registered authorization data systems to import the authorization data. There is no way to convey the authorization data's authentication state using this function.

krb5_error_code KRB5_CALLCONV
krb5_authdata_export_attributes(krb5_context kcontext,
                                krb5_authdata_context context,
                                krb5_flags usage,
                                krb5_authdata ***pauthdata);

Exports, or flattens, the authorization data context's systems' attributes into a set of Kerberos authorization data. The usage argument is used to determine which systems will be called, so that only the authorization data appropriate to the type of request being made is exported.

krb5_error_code KRB5_CALLCONV
krb5_authdata_export_internal(krb5_context kcontext,
                              krb5_authdata_context context,
                              krb5_boolean restrict_authenticated,
                              const char *module_name,
                              void **ptr);

Exports an internal representation of the authorization data state. This might, for example, be used to retrieve an operating system-specific representation of authorization information, such as a struct ucred.

krb5_error_code KRB5_CALLCONV
krb5_authdata_free_internal(krb5_context kcontext,
                            krb5_authdata_context context,
                            const char *module_name,
                            void *ptr);

Frees an internal representation exported by krb5_authdata_export_internal().

krb5_error_code KRB5_CALLCONV
krb5_authdata_context_copy(krb5_context kcontext,
                           krb5_authdata_context src,
                           krb5_authdata_context *pdst);

Duplicates an authorization data context. In the present implementation this involves reloading the authorization data plug-in list, which could be expensive, so this should be used sparingly.

krb5_error_code KRB5_CALLCONV
krb5_auth_con_get_authdata_context(krb5_context context,
                                   krb5_auth_context auth_context,
                                   krb5_authdata_context *ad_context);

Retrieves the authorization data context associated with an authentication context. This is a weak reference; if the caller wishes to retain a reference to this after the authentication context has been destroyed, it should make a copy or take ownership by calling krb5_auth_con_set_authdata_context(... NULL).

krb5_error_code KRB5_CALLCONV
krb5_auth_con_set_authdata_context(krb5_context context,
                                   krb5_auth_context auth_context,
                                   krb5_authdata_context ad_context);

Sets the authorization data context associated with an authentication context. The context will be freed by krb5_auth_con_free(), so if the caller wishes to retain ownership it should call krb5_auth_con_set_authdata_context(... NULL). This API usage is in line with the management of other pointer types associated with an authentication context.


ASN.1 encoder for AD-KDCIssued.


ASN.1 decoder for AD-KDCIssued.

krb5_free_ad_kdcissued(krb5_context context, krb5_ad_kdcissued *val);

Free a krb5_ad_kdcissued structure; this structure is only used within libkrb5.

Non-exported, private APIs

krb5int_authdata_verify(krb5_context context,
                        krb5_flags usage,
                        const krb5_auth_context *auth_context,
                        const krb5_keyblock *key,
                        const krb5_ap_req *ap_req);

Verifies and imports authorization data from an AP-REQ.


This section describes the service provider interface (SPI) used by the authorization data context functions. Presently plug-ins are initialised upon creation of an authorization data context, however that may not be always the case; plug-ins should be careful to distinguish between plug-in initialisation and request initialisation. State associated with a specific set of authorization data should be managed by the latter.

The dispatch table is below:

typedef struct krb5plugin_authdata_client_ftable_v0 {
    char *name;
    krb5_authdatatype *ad_type_list;
    authdata_client_plugin_init_proc init;
    authdata_client_plugin_fini_proc fini;
    authdata_client_plugin_flags_proc flags;
    authdata_client_request_init_proc request_init;
    authdata_client_request_fini_proc request_fini;
    authdata_client_get_attribute_types_proc get_attribute_types;
    authdata_client_get_attribute_proc get_attribute;
    authdata_client_set_attribute_proc set_attribute;
    authdata_client_delete_attribute_proc delete_attribute;
    authdata_client_import_attributes_proc import_attributes;
    authdata_client_export_attributes_proc export_attributes;
    authdata_client_export_internal_proc export_internal;
    authdata_client_free_internal_proc free_internal;
    authdata_client_copy_context_proc copy_context;
    authdata_client_verify_proc verify;
} krb5plugin_authdata_client_ftable_v0;

ad_type_list is a zero terminated list of authorization data types supported by the system; a system's methods will be invoked once for each type, however they all share the same request context (state).

All methods are optional unless otherwise indicated.


typedef krb5_error_code
(*authdata_client_plugin_init_proc)(krb5_context context,
                                   void **plugin_context);

This is the plug-in initialisation function. It is called at plug-in initialisation. It is called no more than once for each constructed authorization data context, and may be called fewer times (if plug-in information is cached); however, plug-ins should not leak if this function is called multiple times. There is a matching call to fini() for each call to init().

This function is mandatory to implement.


typedef void
(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
                                   void *plugin_context);

This is the plug-in finalizer.

This function is mandatory to implement.


typedef void
(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
                                    void *plugin_context,
                                    krb5_authdatatype ad_type,
                                    krb5_flags *flags);

This function is called to indicate the usages supported by the authorization data system for a particular authorization data type. Usages are as follows:

#define AD_USAGE_AS_REQ       0x01
#define AD_USAGE_TGS_REQ      0x02
#define AD_USAGE_AP_REQ       0x04
#define AD_USAGE_KDC_ISSUED   0x08
#define AD_USAGE_MASK         0x0F
#define AD_INFORMATIONAL      0x10

If AD_INFORMATIONAL is unset, then a plug-in failure will cause an error to be returned to the caller and other systems not invoked (except for non-fatal errors such as an attribute not being found, in which case all systems are tried).

This function is not mandatory to implement, but a module that does not return flags will never be called.


typedef krb5_error_code
(*authdata_client_request_init_proc)(krb5_context kcontext,
                                    struct _krb5_authdata_context *context,
                                    void *plugin_context,
                                    void **request_context);

Initialises state for a new authorization data context.

This function is mandatory to implement.


typedef void
(*authdata_client_request_fini_proc)(krb5_context kcontext,
                                    struct _krb5_authdata_context *context,
                                    void *plugin_context,
                                    void *request_context);

Releases state associated with an authorization data context.

This function is mandatory to implement.


typedef krb5_error_code
(*authdata_client_import_attributes_proc)(krb5_context kcontext,
                                         struct _krb5_authdata_context *context,
                                         void *plugin_context,
                                         void *request_context,
                                         krb5_authdata **authdata,
                                         krb5_boolean kdc_issued_flag,
                                         krb5_const_principal issuer);

Instructs the authorization data system to load its state from serialised authorization data. plugin_context and request_context point to initialised values. The system can assume that authdata only contains authorization data that it recognises.

If kdc_issued_flag is TRUE, then the imported authorization data was extracted from authenticated KDC issued authorization data. issuer is an optional argument indicating


typedef krb5_error_code
(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
                                           struct _krb5_authdata_context *context,
                                           void *plugin_context,
                                           void *request_context,
                                           krb5_data **verified,
                                           krb5_data **asserted,
                                           krb5_data **all_attrs);

Enumerates attribute types supported by the authorization data system. verified, asserted, and all_attrs have the same meaning as defined in draft-ietf-kitten-gssapi-naming-exts-05 (except that verified should be read as authenticated).


typedef krb5_error_code
(*authdata_client_get_attribute_proc)(krb5_context kcontext,
                                     struct _krb5_authdata_context *context,
                                     void *plugin_context,
                                     void *request_context,
                                     const krb5_data *attribute,
                                     krb5_boolean *authenticated,
                                     krb5_boolean *complete,
                                     krb5_data *value,
                                     krb5_data *display_value,
                                     int *more);

Retrieves a single attribute value from an authorization data system. If the attribute is unrecognised, ENOENT should be returned. Note that federation of a single attribute across multiple authorization data systems is not supported at present. Authorization data systems must be re-entrant so that more granular systems can be built on top of less granular systems.


typedef krb5_error_code
(*authdata_client_set_attribute_proc)(krb5_context kcontext,
                                     struct _krb5_authdata_context *context,
                                     void *plugin_context,
                                     void *request_context,
                                     krb5_boolean complete,
                                     const krb5_data *attribute,
                                     const krb5_data *value);

Sets or adds a single attribute value to an authorization data system. If the attribute is unrecognised, ENOENT should be returned. If the attribute cannot accept any more values (either because it is single-valued or the same value is already present), then EEXIST should be returned.


typedef krb5_error_code
(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
                                        struct _krb5_authdata_context *context,
                                        void *plugin_context,
                                        void *request_context,
                                        const krb5_data *attribute);

Removes an attribute from an authorization data system.


typedef krb5_error_code
(*authdata_client_export_attributes_proc)(krb5_context kcontext,
                                         struct _krb5_authdata_context *context,
                                         void *plugin_context,
                                         void *request_context,
                                         krb5_flags usage,
                                         krb5_authdata ***authdata);

Flattens authorization data for the requested usage, for use in a KDC or AP request.


typedef krb5_error_code
(*authdata_client_export_internal_proc)(krb5_context kcontext,
                                       struct _krb5_authdata_context *context,
                                       void *plugin_context,
                                       void *request_context,
                                       krb5_boolean restrict_authenticated,
                                       void **ptr);

Exports some internal representation of authorization data. If restrict_authenticated is TRUE, only authenticated attributes will be included.


typedef void
(*authdata_client_free_internal_proc)(krb5_context kcontext,
                                     struct _krb5_authdata_context *context,
                                     void *plugin_context,
                                     void *request_context,
                                     void *ptr);

Releases representation returned by export_internal().


typedef krb5_error_code
(*authdata_client_copy_context_proc)(krb5_context kcontext,
                                    struct _krb5_authdata_context *context,
                                    void *plugin_context,
                                    void *request_context,
                                    void *dst_plugin_context,
                                    void *dst_request_context);

Copies state from request_context to dst_request_context. dst_request_context is a newly initialised context.

The plug-in should not assume that plugin_context and dst_plugin_context are different values.

This function is mandatory to implement.


typedef krb5_error_code
(*authdata_client_verify_proc)(krb5_context kcontext,
                              struct _krb5_authdata_context *context,
                              void *plugin_context,
                              void *request_context,
                              const krb5_auth_context *auth_context,
                              const krb5_keyblock *key,
                              const krb5_ap_req *req);

Verifies authorization data from an AP request. This function need not be implemented by negative authorization systems or systems that expect authorization data to be marked AD-KDCIssued (although is likely that in either case, some validation of the content of the authorization data may be required; this is better done in the import_attributes method).


The only changes to the KDC are as follows:

  • Add a session_key argument to kdb_sign_auth_data_req, for database backends that wish to use AD-KDCIssued
  • In do_tgs_req(), ensure that the session key is made available to handle_authdata()
  • In handle_authdata(), give preference to plug-ins over internal systems
  • Rename krb5plugin_authdata_ftable_vX to krb5plugin_server_authdata_ftable_vX (typedefs to the old types are retained)



Note the "greet:greeting" attribute; rather than being issued by the KDC, this was set on the claimant credential's name using gss_set_name_attribute(), and conveyed in the AP-REQ. The acceptor retrieves it like any other attribute, but note it is not marked "Authenticated". (By changing the flags in the greet plug-in, it's also possible to have the data conveyed in the TGS-REQ, and thus the service ticket.)

% ./t_namingexts test.keytab
init module "greet", ad_type -42, flags 00000014
init module "mspac", ad_type 128, flags 00000008
Source name:	host/test.de.padl.com@DE.PADL.COM

Attribute urn:mspac: Authenticated Complete 


Attribute urn:logon-info Authenticated Complete 


Attribute urn:mspac:client-info Authenticated Complete 


Attribute urn:mspac:upn-dns-info Authenticated Complete 


Attribute urn:mspac:server-checksum Authenticated Complete 


Attribute urn:mspac:privsvr-checksum Authenticated Complete 


Attribute greet:greeting  Complete 

Exported name:



This plug-in is a simple demonstration of the generation and verification of positive (KDC issued) authorization data.



A new option, -d, has been added to klist which enumerates the authorization data types submitted with the TGS request. It does not include authorization data added by the KDC (because that is only available to the service).

$ klist -d
Ticket cache: FILE:/tmp/krb5cc_1002
Default principal: Administrator@BERLIN.DE.PADL.COM

Valid starting     Expires            Service principal
09/01/09 14:49:15  09/02/09 00:49:15  krbtgt/BERLIN.DE.PADL.COM@BERLIN.DE.PADL.COM
	renew until 09/02/09 14:49:15
09/01/09 14:49:20  09/02/09 00:49:15  krbtgt/DE.PADL.COM@BERLIN.DE.PADL.COM
	renew until 09/02/09 14:49:15, AD types: -50
09/01/09 14:49:20  09/02/09 00:49:15  host/kreuz.de.padl.com@BERLIN.DE.PADL.COM
	renew until 09/02/09 14:49:15, AD types: -50
09/01/09 14:49:20  09/02/09 00:49:15  host/kreuz.de.padl.com@DE.PADL.COM
	renew until 09/02/09 14:49:15, AD types: -50
09/01/09 14:49:38  09/02/09 00:49:15  krbtgt/DE.PADL.COM@BERLIN.DE.PADL.COM
	renew until 09/02/09 14:49:15
09/01/09 14:49:38  09/02/09 00:49:15  host/kreuz.de.padl.com@BERLIN.DE.PADL.COM
	renew until 09/02/09 14:49:15
09/01/09 14:49:38  09/02/09 00:49:15  host/kreuz.de.padl.com@DE.PADL.COM
	renew until 09/02/09 14:49:15

Open issues

  • Should we force RFC 4120 compliance and have krb5_rd_req() fail if any authorization data element not enclosed in AD-IF-RELEVANT is unknown?
  • Should we refactor the server side auth data plugin interface to more closely mirror this one?


Code is in the users/lhoward/authdata branch.


This section documents the review of the project according to Project policy. It is divided into multiple sections. First, approvals should be listed. To list an approval type


on its own line. The next section is for summarizing discussion, which should take place on krbdev@mit.edu. Provide links to the archive at http://mailman.mit.edu/pipermail/krbdev/ if appropriate. Blocking objections can be noted with {{project-block}}.


Steve 16:18, 21 September 2009 (UTC)


Personal tools