GSS-API Programming Guide

Data Protection

After a context has been established between two peers — say, a client and a server — messages can be protected before being sent.

If you only establish a context and then send a message, you are utilizing the most basic GSS-API protection: authentication, wherein the recipient knows that the message comes from the principal claiming to be the sender. Depending on the underlying security mechanism being used, the GSS-API provides two other levels of protection:

The difference between the two functions is shown in Figure 1–11.

Figure 1–11 gss_get_mic() vs. gss_wrap()

Graphic

Which function you use depends on your needs. Because gss_wrap() includes the integrity service, many programs use gss_wrap(). They can test for the availability of the confidentiality service, calling gss_wrap() with or without it, depending on whether it's available. An example is Sending the Data (program listing in call_server()). However, since messages protected with gss_get_mic() don't need to be unwrapped by a recipient, there is a savings in CPU cycles over using gss_wrap(). Thus a program that doesn't need confidentiality may prefer to protect messages with gss_get_mic().

Message Tagging With gss_get_mic()

Programs can use gss_get_mic() to add a cryptographic MIC to a message; the recipient can check this MIC to see if the received message is the same as the one that was sent by calling gss_verify_mic(). gss_get_mic() has the following form:


OM_uint32 gss_get_mic (
OM_uint32          *minor_status,
const gss_ctx_id_t context_handle,
gss_qop_t          qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t       msg_token)

minor_status

The status code returned by the underlying mechanism.

context_handle

The context under which the message will be sent.

qop_req

A requested QOP (Quality of Protection). This is the cryptographic algorithm used in generating the MIC. For portability's sake, applications should specify the default QOP by setting this argument to GSS_C_QOP_DEFAULT whenever possible. (See Appendix C, Specifying an OID on specifying a non-default QOP.)

message_buffer

The message to be tagged with a MIC. This argument must be in the form of a gss_buffer_desc object; see Strings and Similar Data. Must be freed up with gss_release_buffer() when you have finished with it.

msg_token

The token containing the message and its MIC. This must be freed up with gss_release_buffer() when you have finished with it.

Note that gss_get_mic() produces separate output for the message and the MIC. (This is different from gss_wrap(), which bundles them together as output.) This separation means that a sender application must arrange to send both the message and its MIC. More significantly, the receiving application must be able to receive and distinguish the message and the MIC. Ways to ensure the proper processing of message and MIC include:

gss_get_mic() returns GSS_S_COMPLETE if it completes successfully. If the specified QOP is not valid, it returns GSS_S_BAD_QOP. For more information, see the gss_get_mic(3GSS) man page.

Message Wrapping With gss_wrap()

Messages can also be “wrapped” by the gss_wrap() function. Like gss_get_mic(), gss_wrap() provides a MIC; it also encrypts a given message, if confidentiality is requested (and permitted by the underlying mechanism). The message receiver “unwraps” the message with gss_unwrap(). gss_wrap() looks like this:


OM_uint32 gss_wrap (
OM_uint32          *minor_status,
const gss_ctx_id_t context_handle,
int                conf_req_flag,
gss_qop_t          qop_req
const gss_buffer_t input_message_buffer,
int                *conf_state,
gss_buffer_t       output_message_buffer )

minor_status

The status code returned by the underlying security mechanism.

context_handle

The context under which this message will be sent.

conf_req_flag

A flag for requesting the confidentiality service (encryption). If non-zero, both confidentiality and integrity are requested; if zero, only the integrity service is requested.

qop_req

A requested QOP (Quality of Protection). This is the cryptographic algorithm used in generating the MIC and doing the encryption. For portability's sake, applications should specify the default QOP by setting this argument to GSS_C_QOP_DEFAULT whenever possible. (See Appendix C, Specifying an OID on specifying a non-default QOP.)

input_message_buffer

The message to be wrapped. This argument must be in the form of a gss_buffer_desc object; see Strings and Similar Data. Must be freed up with gss_release_buffer() when you have finished with it.

conf_state

A flag that, on the function's return, indicates whether confidentiality was applied or not. If non-zero, confidentiality, message origin authentication, and integrity services were applied. If zero, only message-origin authentication and integrity were applied. Specify NULL if not required.

output_message_buffer

The buffer for the wrapped message. After the application is done with the message, it must release this buffer with gss_release_buffer().

Unlike gss_get_mic(), gss_wrap() wraps the message and its MIC together in the outgoing message, so the function that transmits them need be called only once. On the other end, gss_unwrap() will extract the message (the MIC is not visible to the application).

gss_wrap() returns GSS_S_COMPLETE if the message was successfully wrapped. If the requested QOP was not valid, it returns GSS_S_BAD_QOP. Sending the Data (listing in call_server()) shows an example of gss_wrap() being used. For more information, see the gss_wrap(3GSS) man page.

Wrap Size

Wrapping a message with gss_wrap() increases its size. Because the protected message packet must not be too big to “fit through” a given transportation protocol, the GSS-API provides a function, gss_wrap_size_limit(), that calculates the maximum size of a message that can be wrapped without becoming too large. The application can break up messages that exceed this size before calling gss_wrap(). It's a good idea to check the wrap-size limit before actually wrapping the message.

The amount of the size increase depends on two things:

gss_wrap_size_limit() looks like this:


OM_uint32 gss_wrap_size_limit (
OM_uint32          *minor_status,
const gss_ctx_id_t context_handle,
int                conf_req_flag,
gss_qop_t          qop_req,
OM_uint32          req_output_size,
OM_uint32          *max_input_size)

minor_status

The status code returned by the underlying mechanism.

context_handle

The context under which the data is transmitted.

conf_req_flag

A flag for requesting the confidentiality service (encryption). If non-zero, both confidentiality and integrity are requested; if zero, only the integrity service is requested.

qop_req

A requested QOP (Quality of Protection). This is the cryptographic algorithm used in generating the MIC and doing the encryption. For portability's sake, applications should specify the default QOP by setting this argument to GSS_C_QOP_DEFAULT whenever possible. (See Appendix C, Specifying an OID on specifying a non-default QOP.)

req_output_size

The maximum size (as an int) of a data chunk that a given transport protocol can handle. You must provide this information yourself; since the GSS-API is protocol-independent, it has no way of knowing which protocol is being used.

max_input_size

Returned by the function, this is the maximum size of an unwrapped message that, when wrapped, will not exceed req_output_size.

gss_wrap_size_limit() returns GSS_S_COMPLETE if it completes successfully. If the specified QOP was not valid, it returns GSS_S_BAD_QOP. call_server() includes an example of gss_wrap_size_limit() being used to return the maximum original message size, both if confidentiality is used and if it is not used.

Successful completion of this call does not necessarily guarantee that gss_wrap() will be able to protect a message of length max_input_size bytes, since this ability can depend on the availability of system resources at the time that gss_wrap() is called. For more information, see the gss_wrap_size_limit(3GSS) man page.