Developer's Guide to Oracle® Solaris 11 Security

Exit Print View

Updated: July 2014
 
 

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:

  • A user, such as user@machine, who logs into another machine

  • A network service, such as nfs@machine

  • A machine, such as myHost@example.com, that runs an application

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:

  • Security mechanisms

  • QOPs – Quality of Protection values

  • Name types

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.