From K5Wiki
< Projects
Revision as of 15:04, 20 August 2009 by Lukeh (Talk | contribs)

Jump to: navigation, search
This is an early stage project for MIT Kerberos. It is being fleshed out by its proponents. Feel free to help flesh out the details of this project. After the project is ready, it will be presented for review and approval.

Working code is in the users/lhoward/s4u branch.



[MS-SFU] describes two extensions to the Kerberos protocol:

  • S4U2Self, or protocol transition, which enables a service to acquire a ticket from an arbitrary principal to itself (the service is trusted to have authenticated the principal)
  • S4U2Proxy, or constrained delegation, which enables a service to use a client's ticket to itself to request another ticket for delegation

Together, these extensions are referred to as Services4User, or S4U.

The KDC will typically make some authorization checks before permitting the above: for S4U2Self, a flag on the service indicating that it is "trusted to authenticate for delegation" and, for S4U2Proxy, a set of server principals to which the service is permitted to delegate to. There is already some KDC-side support for these protocols in MIT Kerberos 1.7 (although supporting S4U2Proxy requires explicit backend support that is not included with the standard distribution, and S4U2Self does not support some protocol extensions Microsoft made in Windows 2008).

This proposal is principally concerned with the client-side (or, more correctly, service-side) implementation of S4U, although we have also updated the KDC and kadmin to more completely support S4U2Self.

Protocol extensions


Readers are referred to [MS-SFU] for protocol details, but the premise behind S4U2Self is that a service requests a ticket from itself, to itself, presenting some additional preauthentication data containing the name of the user it has presumably authenticated. The KDC, after making any access checks, returns a ticket with the client-name rewritten to that in the preauthentication data. The server name is unchanged.

There are two types of PA data:

  • PA-FOR-USER, introduced in Windows 2003, which consists of the "user name" (client principal) and a checksum of the PA data with the TGT session key
  • PA_S4U_X509_USER, introduced in Windows 2008, which includes the TGS-REQ nonce to bind the S4U request to the TGS-REQ, as well as allowing the user to be identified with an X.509 certificate rather than a name.

The protocol itself is quite complicated, particularly where cross-realm authentication is concerned, so I refer the reader to [MS-SFU] for further details.

We introduce the following key usage types to krb5.h:

/* Defined in [MS-SFU] */
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST  26 /* XXX note conflict with above */
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY    27 /* XXX note conflict with above */

and the following PA data types (although PA-FOR-USER is present since 1.7):

#define KRB5_PADATA_FOR_USER            129 /* username protocol transition request */
#define KRB5_PADATA_S4U_X509_USER       130 /* certificate protocol transition request */

Flags for use with PA_S4U_X509_USER are also defined here, although as they are not exposed through any APIs they could be moved to k5-int.h:

#define KRB5_S4U_OPTS_CHECK_LOGON_HOURS         0400000000 /* check logon hour restrictions */
#define KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE       0x20000000 /* sign with usage 27 instead of 26 */

One important change from 1.7 is that the KDC no longer requires that the S4U2Self user principal be an enterprise principal name (UPN). KDCs that assumed this must be updated.


Again, refer to [MS-SFU] for protocol details, but in this case the service presents a ticket (from an AP-REQ) to the KDC in the additional tickets field, whilst requesting a ticket from itself to the service to which it wishes to delegate. (A new KDC option, CNAME-IN-ADDL-TKT, is used to disambiguate this from user-to-user authentication.) The KDC, after making any access checks, returns a ticket from the additional ticket client to the delegatee.

The CNAME-IN-ADDL-TKT option is present since 1.7:

#define KDC_OPT_CNAME_IN_ADDL_TKT       0x00020000

Proposed APIs

I propose that the only public APIs are at the GSS-API layer. We will need to export krb5 APIs for GSS to use, and possibly the kvno tool (for testing); it's probably not necessary to indirect these through an kaccess, though.


gss_krb5_create_sec_context_for_principal(OM_uint32 *minor_status,
	gss_ctx_id_t *context_handle,
	gss_cred_id_t verifier_cred_handle,
	gss_name_t principal,
	OM_uint32 req_flags,
	OM_uint32 time_req,
	gss_name_t *src_name,
	gss_OID *mech_type,
	OM_uint32 *ret_flags,
	OM_uint32 *time_ret,
	gss_cred_id_t *delegated_cred_handle);

gss_krb5_create_sec_context_for_principal() synthesises an acceptor-side security context for an arbitrary principal. (There's probably a better name for this. The word "impersonate" seems good, but it has a different meaning on Windows, which could be confusing.)

verifier_cred_handle must be both an initiator- and acceptor-side credentials handle, because a TGT is required to perform S4U2Self.

Essentially this function acquires Kerberos credentials using S4U2Self, wraps them up as GSS credentials, and then calls gss_init_sec_context() and gss_accept_sec_context(). This provides a simple interface for developers, at the expense perhaps of some transparency. I do suspect that if we provide complex APIs they won't be used, or giant slabs of sample code will be copied and pasted.

That said, alternatives to this API are:

  • one which returns a GSS initiator credential (gss_krb5_acquire_creds_for_principal())
  • one which returns a GSS initial context token (gss_init_sec_context_for_principal())

The current API has no provision for certificate-based protocol transition.


gss_krb5_add_sec_context_delegatee() creates or updates a skeletal context that can be passed to gss_accept_sec_context(), such that delegated_cred_handle will contain credentials for delegating to the specified principals. The existing GSS-API delegation model is maintained; the only difference being that the delegated credentials handle contains a set of service tickets, instead of a TGT.

This takes advantage of the new behaviour of gss_accept_sec_context() introduced in 1.7 (although there was a bug in that implementation), where gss_set_sec_context_option() can be used to create a context with some parameters which is passed to gss_accept_sec_context() with the initial context token. Prior to that, the context handle on the first call to gss_accept_sec_context() was always GSS_C_NO_CONTEXT.

Some changes were required to gss_accept_sec_context() and gss_init_sec_context() to accept and validate these skeletal contexts. (Note that such a context should never be passed to gss_init_sec_context().)

Implementation details

Most of the implementation can be found in src/lib/krb5/krb/s4u_creds.c.



krb5_error_code KRB5_CALLCONV
krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
                              krb5_ccache ccache, krb5_creds *in_creds,
                              krb5_data *subject_cert,
                              krb5_creds **out_creds)

krb5_get_credentials_for_user() does the following:

  • checks the credentials cache for an existing ticket
  • identifies the user's realm using an AS-REQ, if a certificate or enterprise principal name is being used
  • acquires a TGT to the user's realm
  • makes the S4U2Self request, following any referrals
  • stores the ticket in the credentials cache

Both variants of S4U2Self are supported.

A new flag, KRB5_GC_NO_STORE, has been added to all the krb5_get_credentials APIs, which causes the retrieved credentials to be not stored in the credentials cache.

The following data types are introduced into k5-int.h, along with their complementary encode/decode/free routines. Note that these types are not exposed via exported APIs.

typedef struct _krb5_pa_for_user {
    krb5_principal      user;
    krb5_checksum       cksum;
    krb5_data           auth_package;
} krb5_pa_for_user;

typedef struct _krb5_s4u_userid {
    krb5_int32          nonce;
    krb5_principal      user;
    krb5_data           subject_cert;
    krb5_flags          options;
} krb5_s4u_userid;

typedef struct _krb5_pa_s4u_x509_user {
    krb5_s4u_userid     user_id;
    krb5_checksum       cksum;
} krb5_pa_s4u_x509_user;


  • S4U2Self client names are no longer required to be an enterprise principal name, as they were in 1.7
  • the Windows 2008 variant of S4U2Self is supported
  • kadmin has been updated to support the ok_to_auth_as_delegate (and, for completeness) no_auth_data_required attributes. Services with ok_to_auth_as_delegate are allowed to use S4U2Self



krb5_error_code KRB5_CALLCONV
krb5_get_credentials_for_proxy(krb5_context context,
                               krb5_flags options,
                               krb5_ccache ccache,
                               krb5_creds *in_creds,
                               krb5_ticket *evidence_tkt,
                               krb5_creds **out_creds)

krb5_get_credentials_for_proxy() does the following:

  • checks the credentials cache for an existing ticket
  • makes the S4U2Proxy request
  • stores the ticket in the credentials cache

A new flag, KRB5_GC_NO_STORE, has been added to all the krb5_get_credentials APIs, which causes the retrieved credentials to be not stored in the credentials cache.

Note: most of the logic for this is now in krb5_get_credentials(), so we could probably remove this function entirely. The one difference is that, because krb5_get_credentials() doesn't have access to the decrypted second ticket, verifying the KDC response correctly is not possible.


There are no changes from 1.7. Note that the backend must validate that the evidence ticket was issued by the KDC. In the Windows case, this is done by validating the KDC signature on the PAC. (The MIT KDC will reject constrained delegation requests unless the backend implements a SIGN_AUTH_DATA method.)

Open issues

  • Do we actually want to store the returned S4U2Self/S4U2Proxy tickets in the credentials cache, or should we just return them as krb5_creds? Presently we do the latter (via KRB5_GC_NO_STORE).
  • What level of abstraction do we wish to expose at the GSS-API layer?
  • Do we wish to offer APIs for certificate based S4U2Self?
  • Would it be interesting/useful to offer a SAML variant of S4U2Self?


The kvno utility has been updated to support the -U user option (for S4U2Self) and the -P option (for S4U2Proxy, which changes the meaning of the additional service arguments to be delegatees).


Implementation-wise, S4U2Self and S4U2Proxy are presently working against Windows 2008. A test program can be found in src/tests/gssapi/t_s4u.c. I have tested both a single- and two-realm (child domain) setup. Also, S4U2Self has been tested against a MIT 1.8 KDC.

Personal tools