JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Developer's Guide to Oracle Solaris 11 Security     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Oracle Solaris Security for Developers (Overview)

2.  Developing Privileged Applications

3.  Writing PAM Applications and Services

4.  Writing Applications That Use GSS-API

Introduction to GSS-API

Application Portability With GSS-API

Security Services in GSS-API

Available Mechanisms in GSS-API

Remote Procedure Calls With GSS-API

Limitations of GSS-API

Language Bindings for GSS-API

Where to Get More Information on GSS-API

Important Elements of GSS-API

GSS-API Data Types

GSS-API Integers

Strings and Similar Data in GSS-API

Names in GSS-API

Comparing Names in GSS-API

GSS-API OIDs

Mechanisms and QOPs in GSS-API

Name Types in GSS-API

GSS-API Status Codes

GSS-API Tokens

Interprocess Tokens in GSS-API

Developing Applications That Use GSS-API

Generalized GSS-API Usage

Working With Credentials in GSS-API

Acquiring Credentials in GSS-API

Working With Contexts in GSS-API

Initiating a Context in GSS-API

Accepting a Context in GSS-API

Using Other Context Services in GSS-API

Delegating a Credential in GSS-API

Performing Mutual Authentication Between Peers in GSS-API

Performing Anonymous Authentication in GSS-API

Using Channel Bindings in GSS-API

Exporting and Importing Contexts in GSS-API

Obtaining Context Information in GSS-API

Sending Protected Data in GSS-API

Tagging Messages With gss_get_mic()

Wrapping Messages With gss_wrap()

Handling Wrap Size Issues in GSS-API

Detecting Sequence Problems in GSS-API

Confirming Message Transmission in GSS-API

Cleaning Up a GSS-API Session

5.  GSS-API Client Example

6.  GSS-API Server Example

7.  Writing Applications That Use SASL

8.  Introduction to the Oracle Solaris Cryptographic Framework

9.  Writing User-Level Cryptographic Applications

10.  Introduction to the Oracle Solaris Key Management Framework

A.  Secure Coding Guidelines for Developers

B.  Sample C-Based GSS-API Programs

C.  GSS-API Reference

D.  Specifying an OID

E.  Source Code for SASL Example

F.  SASL Reference Tables

Glossary

Index

Important Elements of GSS-API

This section covers the following important GSS-API concepts: principals, GSS-API data types, status codes, and tokens.

GSS-API Data Types

The following sections explain the major GSS-API data types. For information on all GSS-API data types, see GSS-API Data Types and Values.

GSS-API Integers

Because the size of an int can vary from platform to platform, GSS-API provides the following integer data type:OM_uint32which is a 32–bit unsigned integer.

Strings and Similar Data in GSS-API

Because GSS-API handles all data in internal formats, strings must be converted to a GSS-API format before being passed to GSS-API functions. GSS-API handles strings with the gss_buffer_desc structure:

typedef struct gss_buffer_desc_struct {
     size_t     length;
     void       *value;
}  gss_buffer_desc *gss_buffer_t;

gss_buffer_t is a pointer to such a structure. Strings must be put into a gss_buffer_desc structure before being passed to functions that use them. In the following example, a generic GSS-API function applies protection to a message before sending that message.

Example 4-1 Using Strings in GSS-API

char *message_string;
gss_buffer_desc input_msg_buffer;

input_msg_buffer.value = message_string;
input_msg_buffer.length = strlen(input_msg_buffer.value) + 1;

gss_generic_function(arg1, &input_msg_buffer, arg2...);

gss_release_buffer(input_msg_buffer);

Note that input_msg_buffer must be deallocated with gss_release_buffer() when you are finished with input_msg_buffer.

The gss_buffer_desc object is not just for character strings. For example, tokens are manipulated as gss_buffer_desc objects. See GSS-API Tokens for more information.

Names in GSS-API

A name refers to a principal. In network-security terminology, a principal is a user, a program, or a machine. Principals can be either clients or servers.

Some examples of principals are:

In GSS-API, names are stored as a gss_name_t object, which is opaque to the application. Names are converted from gss_buffer_t objects to the gss_name_t form by the gss_import_name() function. Every imported name has an associated name type, which indicates the format of the name. See GSS-API OIDs for more about name types. See Name Types for a list of valid name types.

gss_import_name() has the following syntax:

OM_uint32 gss_import_name (
       OM_uint32          *minor-status,
       const gss_buffer_t input-name-buffer,
       const gss_OID      input-name-type,
       gss_name_t         *output-name)
minor-status

Status code returned by the underlying mechanism. See GSS-API Status Codes.

input-name-buffer

The gss_buffer_desc structure containing the name to be imported. The application must allocate this structure explicitly. See Strings and Similar Data in GSS-API as well as Example 4-2. This argument must be deallocated with gss_release_buffer() when the application is finished with the space.

input-name-type

A gss_OID that specifies the format of input-name-buffer. See Name Types in GSS-API. Also, Name Types contains a table of valid name types.

output-name

The gss_name_t structure to receive the name.

A minor modification of the generic example shown in Example 4-1 illustrates how gss_import_name() can be used. First, the regular string is inserted into a gss_buffer_desc structure. Then gss_import_name() places the string into a gss_name_t structure.

Example 4-2 Using gss_import_name()

char *name_string;
gss_buffer_desc input_name_buffer;
gss_name_t      output_name_buffer;

input_name_buffer.value = name_string;
input_name_buffer.length = strlen(input_name_buffer.value) + 1;

gss_import_name(&minor_status, input_name_buffer, 
                    GSS_C_NT_HOSTBASED_SERVICE, &output_name);

gss_release_buffer(input_name_buffer);

An imported name can be put back into a gss_buffer_t object for display in human-readable form with gss_display_name(). However, gss_display_name() does not guarantee that the resulting string will be the same as the original due to the way the underlying mechanisms store names. GSS-API includes several other functions for manipulating names. See GSS-API Functions.

A gss_name_t structure can contain several versions of a single name. One version is produced for each mechanism that is supported by GSS-API. That is, a gss_name_t structure for user@company might contain one version of that name as rendered by Kerberos v5 and another version that was given by a different mechanism. The function gss_canonicalize_name() takes as input an internal name and a mechanism. gss_canonicalize_name() yields a second internal name that contains a single version of the name that is specific to that mechanism.

Such a mechanism-specific name is called a mechanism name (MN). A mechanism name does not refer to the name of a mechanism, but to the name of a principal as produced by a given mechanism. This process is illustrated in the following figure.

Figure 4-3 Internal Names and Mechanism Names

image:Diagram shows how mechanism names are derived.

Comparing Names in GSS-API

Consider the case where a server has received a name from a client and needs to look up that name in an access control list. An access control list, or ACL, is a list of principals with particular access permissions.

One way to do the lookup would be as follows:

  1. Import the client name into GSS-API internal format with gss_import_name(), if the name has not already been imported.

    In some cases, the server will receive a name in internal format, so this step will not be necessary. For example, a server might look up the client's own name. During context initiation, the client's own name is passed in internal format.

  2. Import each name in the ACL with gss_import_name().

  3. Compare each imported ACL name with the imported client's name, using gss_compare_name().

This process is shown in the following figure. In this case, Step 1 is assumed to be needed.

Figure 4-4 Comparing Names (Slow)

image:Diagram shows how internal client names are compared using the gss_compare_name function.

The previous approach of comparing names individually is acceptable when there are only a few names. When there are a large number of names, using the gss_canonicalize_name() function is more efficient.

This approach uses the following steps:

  1. Import the client's name with gss_import_name(), if the name has not already been imported.

    As with the previous method of comparing names, if the name is already in internal format, this step is unnecessary.

  2. Use gss_canonicalize_name() to produce a mechanism name version of the client's name.

  3. Use gss_export_name() to produce an exported name, which is the client's name as a contiguous string.

  4. Compare the exported client's name with each name in the ACL by using memcmp(), which is a fast, low-overhead function.

This process is shown in the following figure. Again, assume that the server needs to import the name that is received from the client.

Figure 4-5 Comparing Names (Fast)

image:Diagram shows how internal client names are compared using the memcmp function.

Because gss_export_name() expects a mechanism name (MN), you must run gss_canonicalize_name() on the client's name first.

See the gss_export_name(3GSS), gss_import_name(3GSS), and gss_canonicalize_name(3GSS) for more information.

GSS-API OIDs

Object identifiers (OIDs) are used to store the following kinds of data:

OIDs are stored in GSS-API gss_OID_desc structure. GSS-API provides a pointer to the structure, gss_OID, as shown in the following example.

Example 4-3 OIDs Structure

typedef struct gss_OID_desc_struct {
        OM_uint32   length;
        void        *elements;
     } gss_OID_desc, *gss_OID;

Further, one or more OIDs might be contained in a gss_OID_set_desc structure.

Example 4-4 OID Set Structure

typedef struct gss_OID_set_desc_struct {
        size_t    count;
        gss_OID   elements;
     } gss_OID_set_desc, *gss_OID_set;

Caution

Caution - Applications should not attempt to deallocate OIDs with free().


Mechanisms and QOPs in GSS-API

Although GSS-API allows applications to choose underlying security mechanisms, applications should use the default mechanism that has been selected by GSS-API if possible. Similarly, although GSS-API lets an application specify a Quality of Protection level for protecting data, the default QOP should be used if possible. Acceptance of the default mechanism is indicated by passing the value GSS_C_NULL_OID to functions that expect a mechanism or QOP as an argument.


Caution

Caution - Specifying a security mechanism or QOP explicitly defeats the purpose of using GSS-API. Such a specific selection limits the portability of an application. Other implementations of GSS-API might not support that QOP or mechanism in the intended manner. Nonetheless, Appendix D, Specifying an OID briefly discusses how to find out which mechanisms and QOPs are available, and how to choose one.


Name Types in GSS-API

Besides QOPs and security mechanisms, OIDs are also used to indicate name types, which indicate the format for an associated name. For example, the function gss_import_name(), which converts the name of a principal from a string to a gss_name_t type, takes as one argument the format of the string to be converted. If the name type is, for example, GSS_C_NT_HOSTBASED_SERVICE, then the function knows that the name being input is of the form service@host. If the name type is GSS_C_NT_EXPORT_NAME, then the function expects a GSS-API exported name. Applications can find out which name types are available for a given mechanism with the gss_inquire_names_for_mech() function. A list of name types used by GSS-API is provided in Name Types.

GSS-API Status Codes

All GSS-API functions return two types of codes that provide information on the function's success or failure. Both types of status codes are returned as OM_uint32 values.

The two types of return codes are as follows:

GSS-API Tokens

The basic unit of “currency” in GSS-API is the token. Applications that use GSS-API communicate with each other by using tokens. Tokens are used for exchanging data and for making security arrangements. Tokens are declared as gss_buffer_t data types. Tokens are opaque to applications.

Two types of tokens are context-level tokens and per-message tokens. Context-level tokens are used primarily when a context is established, that is, initiated and accepted. Context-level tokens can also be passed afterward to manage a context.

Per-message tokens are used after a context has been established. Per-message tokens are used to provide protection services on data. For example, consider an application that wants to send a message to another application. That application might use GSS-API to generate a cryptographic identifier to go along with that message. The identifier would be stored in a token.

Per-message tokens can be considered with regard to messages as follows. A message is a piece of data that an application sends to a peer. For example, the ls command could be a message that is sent to an ftp server. A per-message token is an object generated by GSS-API for that message. A per-message token could be a cryptographic tag or the encrypted form of the message. Note that this last example is mildly inaccurate. An encrypted message is still a message and not a token. A token is only GSS-API-generated information. However, informally, message and per-message token are often used interchangeably.

An application is responsible for the following activities:

  1. Sending and receiving tokens. The developer usually needs to write generalized read and write functions for performing these actions. The send_token() and recv_token() functions in Miscellaneous GSS-API Sample Functions.

  2. Distinguishing between types of tokens and manipulating the tokens accordingly.

    Because tokens are opaque to applications, the application does not distinguish between one token and another. Without knowing a token's contents, an application must be able to distinguish the token's type to pass that token to an appropriate GSS-API function.

    An application can distinguish token types through the following methods:

    • By state. Through the control-flow of a program. For example, an application that is waiting to accept a context might assume that any received tokens are related to context establishment. Peers are expected to wait until the context is fully established before sending message tokens, that is, data. After the context is established, the application assumes that new tokens are message tokens. This approach to handling tokens is a fairly common way to handle tokens. The sample programs in this book use this method.

    • By flags. For example, if an application has a function for sending tokens to peers, that application can include a flag to indicate the kind of token. Consider the following code:

      gss_buffer_t token;     /* declare the token */
      OM_uint32 token_flag       /* flag for describing the type of token */
      
      <get token from a GSS-API function>
      
      token_flag = MIC_TOKEN;     /* specify what kind of token it is */
      send_a_token(&token, token_flag);

      The receiving application would have a receiving function, for example, get_a_token(), that would check the token_flag argument.

    • Through explicit tagging. Applications can use meta-tokens. A meta-token is a user-defined structure that contain tokens that have been received from GSS-API functions. A meta-token includes user-defined fields that signal how the tokens that are provided by GSS-API are to be used.

Interprocess Tokens in GSS-API

GSS-API permits a security context to be passed from one process to another in a multiprocess application. Typically, a application has accepted a client's context. The application then shares the context among that application's processes. See Exporting and Importing Contexts in GSS-API for information on multiprocess applications.

The gss_export_context() function creates an interprocess token. This token contains information that enables the context to be reconstituted by a second process. The application is responsible for passing the interprocess token from one process to the other. This situation is similar to the application's responsibility for passing tokens to other applications.

The interprocess token might contain keys or other sensitive information. Not all GSS-API implementations cryptographically protect interprocess tokens. Therefore, the application must protect interprocess tokens before an exchange takes place. This protection might involve encrypting the tokens with gss_wrap(), if encryption is available.


Note - Do not assume that interprocess tokens are transferable across different GSS-API implementations.