Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
1.  The GSS-API: An Overview Programming Using the GSS-API Overview  Previous   Contents   Next 
   
 

A general schema of this process is presented in Figure 1-6, which shows one way that the GSS-API can be used; other scenarios are possible.

Figure 1-6 Using the GSS-API: An Overview

Credentials

A credential is a data structure that provides proof of an application's claim to a principal name. An application uses a credential to establish its global identity. You can think of a credential as a principal's "identity badge," a set of information that proves that a person, machine, or program is who it claims to be and, often, what privileges it has.

The GSS-API does not provide credentials. Credentials are created by the security mechanisms that underly the GSS-API, before GSS-API functions are called. In many cases, for example, users receive credentials when they log in to a system.

A given GSS-API credential is valid for a single principal. A single credential can contain several elements for that principal, each created by a different mechanism, as shown in Figure 1-7. This means that a credential acquired on a machine with several security mechanisms will be valid if transferred to a machine that has only a subset of those mechanisms. The GSS-API accesses credentials through the gss_cred_id_t structure; this structure is called a credential handle. Credentials are opaque to applications; you don't need to know the specifics of a given credential.

Figure 1-7 Generalized GSS-API Credential

Credentials come in three forms:

  • GSS_C_INITIATE: A credential of this type identifies applications that only initiate security contexts.

  • GSS_C_ACCEPT: A credential of this type identifies applications that only accept security contexts.

  • GSS_C_BOTH: A credential of this type identifies applications that can initiate or accept security contexts.

Acquiring Credentials

Before a security context can be established, both the server and the client must acquire their respective credentials. Once acquired, credentials can be re-used until they expire, at which time they must be re-acquired. Credentials used by the client and those used by the server might have different lifetimes.

GSS-API-based applications acquire credentials in one of two ways:

  • By using the gss_acquire_cred() function (in some cases this will be the gss_add_cred() function), or

  • By specifying a default credential, represented by the value GSS_C_NO_CREDENTIAL, when establishing a context.

In most cases, gss_acquire_cred() is called only by a context acceptor (server), because the context initiator (client) is likely to have received its credentials at login. The initiator, therefore, can usually specify only the default credential. The context acceptor can also bypass using gss_acquire_cred() and use its default credential instead.

The initiator's credential proves its identity to other processes, while the acceptor acquires a credential to enable it to accept a security context. Consider the case of a client making an ftp request to a server. The client already has a credential, from login, and the GSS-API is automatically retrieves that credential when the client attempts to initiate a context. The server program, however, explicitly acquires credentials for the requested service (ftp).

gss_acquire_cred() takes the syntax shown below:

OM_uint32 gss_acquire_cred (
OM_uint32         *minor_status,
const gss_name_t  desired_name,
OM_uint32         time_req,
const gss_OID_set desired_mechs,
gss_cred_usage_t  cred_usage,
gss_cred_id_t     *output_cred_handle,
gss_OID_set       *actual_mechs,
OM_uint32         *time_rec)
minor_status

The status code given by the underlying mechanism upon return.

desired_name

The name of the principal whose credential should be acquired. In our example above, it would be "ftp." This argument would be created with gss_import_name() (see "Names").

Note that if desired_name is set to GSS_C_NO_NAME, then the credential returned is a generic one that causes the GSS-API context-initiation and context-acceptance routines to use their default behavior with regard to credentials. In other words, passing GSS_C_NO_NAME to gss_acquire_cred() returns a credential that, when passed to gss_init_sec_context() or gss_accept_sec_context(), is equivalent to passing them the default credential request (GSS_C_NO_CREDENTIAL). See "Context Initiation (Client)" and "Context Acceptance (Server)" for more information.

time_req

The length of time (in seconds) for which the credential should remain valid. Specify GSS_C_INDEFINITE to request the maximum permitted lifetime.

desired_mechs

The set of underlying mechanisms that the application wants to use with this credential. This is a gss_OID_set data structure containing one or more gss_OID structures, each representing an appropriate mechanism. If possible, specify GSS_C_NO_OID_SET to get a default set from the GSS-API.

cred_usage

A flag that indicates how this credential should be used: for context initiation (GSS_C_INITIATE), acceptance (GSS_C_ACCEPT), or both (GSS_C_BOTH).

output_cred_handle

The credential handle returned by this function.

actual_mechs

A set of mechanisms that can be used with this credential. If you don't need to know what the mechanisms are, set this to NULL.

time_rec

The actual number of seconds for which the credential is valid. Set to NULL if this value doesn't interest you.

gss_acquire_cred() returns GSS_S_COMPLETE if it completes successfully. If it cannot return a valid credential, it returns GSS_S_NO_CRED; see the gss_acquire_cred(3GSS) man page for other error codes. An example of acquiring a credential can be found in "Acquiring Credentials" (program listing in "server_acquire_creds()").

gss_add_cred() is similar to gss_acquire_cred(), but allows an application to either create a new credential handle based on an existing credential or to add a new credential element to the existing one. If GSS_C_NO_CREDENTIAL is specified as the existing credential, then gss_add_cred() will create a new credential based on default behavior. See the gss_add_cred(3GSS) man page for more information.

Context Establishment

As stated earlier, the two most significant things that the GSS-API does in providing security are to create security contexts and to protect data. After an application has the credential(s) it needs, it's time to establish a security context. To do this, one application (typically a client) initiates the context, and another (usually a server) accepts it. Multiple contexts between peers are allowed.

The communicating applications establish a joint security context by exchanging authentication tokens. The security context is a pair of GSS-API data structures that contain information shared between the two applications. This information describes the state of each application (in terms of security). A security context is required for protection of data.

Context Initiation (Client)

Security context initiation between an application and a remote peer is done using the gss_init_sec_context() function. If successful, this function returns a context handle for the context being established and a context-level token to send to the acceptor. Before calling gss_init_sec_context(), however, the client should:

  1. Acquire credentials, if necessary, with gss_acquire_cred(). Commonly, however, the client has received credentials at login, and can skip this step.

  2. Import the name of the server into GSS-API internal format with gss_import_name(). See "Names" for more about names and gss_import_name().

When calling gss_init_sec_context(), the client typically passes the following argument values:

  • GSS_C_NO_CREDENTIAL for the cred_handle argument, to indicate the default credential.

  • GSS_C_NULL_OID for the mech_type argument, to indicate the default mechanism.

  • GSS_C_NO_CONTEXT for the context_handle argument, to indicate an initial null context. Because gss_init_sec_context() is usually called in a loop, subsequent calls should pass the context handle returned by previous calls.

  • GSS_C_NO_BUFFER for the input_token argument, to indicate an initially empty token. Alternatively, the application can pass a pointer to a gss_buffer_desc object whose length field has been set to zero.

  • The name of the server, imported into internal GSS-API format with gss_import_name().

Applications are not bound to use these default values. Additionally, the client will specify its requirements for other security parameters with the req_flags argument. The full set of gss_init_sec_context() arguments is described below.

The context acceptor can require several "handshakes" in order to establish a context; that is, it can require the initiator to send more than one piece of context information before it considers the context fully established. Therefore, for portability, context initiation should always be done as part of a loop that checks whether the context has been fully established.

If the context is not complete, gss_init_sec_context() returns a major-status code of GSS_C_CONTINUE_NEEDED. Thus a loop should use gss_init_sec_context()'s return value to test whether to continue the initiation loop.

The client passes context information to the server in the form of the output token returned by gss_init_sec_context(). The client receives information back from the server as an input token, which can then be passed as an argument to subsequent calls of gss_init_sec_context(). If the received input token has a length of zero, however, then no more output tokens are required by the server.

Therefore, in addition to checking for the return status of gss_init_sec_context(), the loop should check the input token's length to see if a further token needs to be sent to the server. (Before the loop begins, the input token's length should be initialized to zero, either by setting the input token to GSS_C_NO_BUFFER or by setting the structure's length field to a value of zero.)

This is what such a loop can look like, highly generalized:

context = GSS_C_NO_CONTEXT
input token = GSS_C_NO_BUFFER

do

     call gss_init_sec_context(credential, context, name, input token, 
                                           output token, other args...)

     if (there's an output token to send to the acceptor)
          send the output token to the acceptor
          release the output token

     if (the context is not complete)
          receive an input token from the acceptor

     if (there's a GSS-API error)
          delete the context

until the context is complete

Naturally, a real loop will be more complete, with, for example, much more extensive error-checking. See "Establishing a Context" (program listing in "client_establish_context()") for a real example of such a context-initiation loop. Additionally, the gss_init_sec_context(3GSS) man page gives a less generic example than this.

Again, the GSS-API does not send or receive tokens; these must be handled by the application. Examples of token-transferring functions are found in "send_token()" and "recv_token()".

Here is a synopsis of gss_init_sec_context(). For more information, see the gss_init_sec_context(3GSS) man page.


Example 1-5 gss_init_sec_context()

     OM_uint32 gss_init_sec_context (
       OM_uint32                    *minor_status,
       const gss_cred_id_t          initiator_cred_handle,
       gss_ctx_id_t                 *context_handle,
       const gss_name_t             target_name,
       const gss_OID                mech_type,
       OM_uint32                    req_flags,
       OM_uint32                    time_req,
       const gss_channel_bindings_t input_chan_bindings,
       const gss_buffer_t           input_token
       gss_OID                      *actual_mech_type,
       gss_buffer_t                 output_token,
       OM_uint32                    *ret_flags,
       OM_uint32                    *time_rec )

 
 
 
  Previous   Contents   Next