diff options
author | Greg Hudson <ghudson@mit.edu> | 2013-09-16 13:04:27 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2013-09-18 18:22:17 -0400 |
commit | 42614eb0354afa08c4e2f03be561017b773a80ae (patch) | |
tree | 815694d9ff2471b4d5a0154af5019a6698344ccf /doc | |
parent | d750ef3130b76dd079e863ed395eb3620a37386b (diff) | |
download | krb5-42614eb0354afa08c4e2f03be561017b773a80ae.tar.gz krb5-42614eb0354afa08c4e2f03be561017b773a80ae.tar.xz krb5-42614eb0354afa08c4e2f03be561017b773a80ae.zip |
Document AEAD and IOV GSSAPI extensions
Diffstat (limited to 'doc')
-rw-r--r-- | doc/appdev/gssapi.rst | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/doc/appdev/gssapi.rst b/doc/appdev/gssapi.rst index a8c731bd7b..8e01ac080b 100644 --- a/doc/appdev/gssapi.rst +++ b/doc/appdev/gssapi.rst @@ -218,6 +218,301 @@ case, the contents of the credential cache are serialized, so that the resulting token may be imported even if the original memory credential cache no longer exists. + +AEAD message wrapping +--------------------- + +The following GSSAPI extensions (declared in +``<gssapi/gssapi_ext.h>``) can be used to wrap and unwrap messages +with additional "associated data" which is integrity-checked but is +not included in the output buffer:: + + OM_uint32 gss_wrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, gss_qop_t qop_req, + gss_buffer_t input_assoc_buffer, + gss_buffer_t input_payload_buffer, + int *conf_state, + gss_buffer_t output_message_buffer); + + OM_uint32 gss_unwrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t input_assoc_buffer, + gss_buffer_t output_payload_buffer, + int *conf_state, + gss_qop_t *qop_state); + +Wrap tokens created with gss_wrap_aead will successfully unwrap only +if the same *input_assoc_buffer* contents are presented to +gss_unwrap_aead. + + +IOV message wrapping +-------------------- + +The following extensions (declared in ``<gssapi/gssapi_ext.h>``) can +be used for in-place encryption, fine-grained control over wrap token +layout, and for constructing wrap tokens compatible with Microsoft DCE +RPC:: + + typedef struct gss_iov_buffer_desc_struct { + OM_uint32 type; + gss_buffer_desc buffer; + } gss_iov_buffer_desc, *gss_iov_buffer_t; + + OM_uint32 gss_wrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, int iov_count); + + OM_uint32 gss_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, int iov_count); + + OM_uint32 gss_wrap_iov_length(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count); + + OM_uint32 gss_release_iov_buffer(OM_uint32 *minor_status, + gss_iov_buffer_desc *iov, + int iov_count); + +The caller of gss_wrap_iov provides an array of gss_iov_buffer_desc +structures, each containing a type and a gss_buffer_desc structure. +Valid types include: + +* **GSS_C_BUFFER_TYPE_DATA**: A data buffer to be included in the + token, and to be encrypted or decrypted in-place if the token is + confidentiality-protected. + +* **GSS_C_BUFFER_TYPE_HEADER**: The GSSAPI wrap token header and + underlying cryptographic header. + +* **GSS_C_BUFFER_TYPE_TRAILER**: The cryptographic trailer, if one is + required. + +* **GSS_C_BUFFER_TYPE_PADDING**: Padding to be combined with the data + during encryption and decryption. (The implementation may choose to + place padding in the trailer buffer, in which case it will set the + padding buffer length to 0.) + +* **GSS_C_BUFFER_TYPE_STREAM**: For unwrapping only, a buffer + containing a complete wrap token in standard format to be unwrapped. + +* **GSS_C_BUFFER_TYPE_SIGN_ONLY**: A buffer to be included in the + token's integrity protection checksum, but not to be encrypted or + included in the token itself. + +For gss_wrap_iov, the IOV list should contain one HEADER buffer, +followed by zero or more SIGN_ONLY buffers, followed by one or more +DATA buffers, followed by a TRAILER buffer. The memory pointed to by +the buffers is not required to be contiguous or in any particular +order. If *conf_req_flag* is true, DATA buffers will be encrypted +in-place, while SIGN_ONLY buffers will not be modified. + +The type of an output buffer may be combined with +**GSS_C_BUFFER_FLAG_ALLOCATE** to request that gss_wrap_iov allocate +the buffer contents. If gss_wrap_iov allocates a buffer, it sets the +**GSS_C_BUFFER_FLAG_ALLOCATED** flag on the buffer type. +gss_release_iov_buffer can be used to release all allocated buffers +within an iov list and unset their allocated flags. Here is an +example of how gss_wrap_iov can be used with allocation requested +(*ctx* is assumed to be a previously established gss_ctx_id_t):: + + OM_uint32 major, minor; + gss_iov_buffer_desc iov[4]; + char str[] = "message"; + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer.value = str; + iov[1].buffer.length = strlen(str); + iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + + major = gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL, + iov, 4); + if (GSS_ERROR(major)) + handle_error(major, minor); + + /* Transmit or otherwise use resulting buffers. */ + + (void)gss_release_iov_buffer(&minor, iov, 4); + +If the caller does not choose to request buffer allocation by +gss_wrap_iov, it should first call gss_wrap_iov_length to query the +lengths of the HEADER, PADDING, and TRAILER buffers. DATA buffers +must be provided in the iov list so that padding length can be +computed correctly, but the output buffers need not be initialized. +Here is an example of using gss_wrap_iov_length and gss_wrap_iov: + + OM_uint32 major, minor; + gss_iov_buffer_desc iov[4]; + char str[1024] = "message", *ptr; + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer.value = str; + iov[1].buffer.length = strlen(str); + + iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING; + iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER; + + major = gss_wrap_iov_length(&minor, ctx, 1, GSS_C_QOP_DEFAULT, + NULL, iov, 4); + if (GSS_ERROR(major)) + handle_error(major, minor); + if (strlen(str) + iov[0].buffer.length + iov[2].buffer.length + + iov[3].buffer.length > sizeof(str)) + handle_out_of_space_error(); + ptr = str + strlen(str); + iov[0].buffer.value = ptr; + ptr += iov[0].buffer.length; + iov[2].buffer.value = ptr; + ptr += iov[2].buffer.length; + iov[3].buffer.value = ptr; + + major = gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL, + iov, 4); + if (GSS_ERROR(major)) + handle_error(major, minor); + +If the context was established using the **GSS_C_DCE_STYLE** flag +(described in :rfc:`4757`), wrap tokens compatible with Microsoft DCE +RPC can be constructed. In this case, the IOV list must include a +SIGN_ONLY buffer, a DATA buffer, a second SIGN_ONLY buffer, and a +HEADER buffer in that order (the order of the buffer contents remains +arbitrary). The application must pad the DATA buffer to a multiple of +16 bytes as no padding or trailer buffer is used. + +gss_unwrap_iov may be called with an IOV list just like one which +would be provided to gss_wrap_iov. DATA buffers will be decrypted +in-place if they were encrypted, and SIGN_ONLY buffers will not be +modified. + +Alternatively, gss_unwrap_iov may be called with a single STREAM +buffer, zero or more SIGN_ONLY buffers, and a single DATA buffer. The +STREAM buffer is interpreted as a complete wrap token. The STREAM +buffer will be modified in-place to decrypt its contents. The DATA +buffer will be initialized to point to the decrypted data within the +STREAM buffer, unless it has the **GSS_C_BUFFER_FLAG_ALLOCATE** flag +set, in which case it will be initialized with a copy of the decrypted +data. Here is an example (*token* and *token_len* are assumed to be a +pre-existing pointer and length for a modifiable region of data):: + + OM_uint32 major, minor; + gss_iov_buffer_desc iov[2]; + + iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM; + iov[0].buffer.value = token; + iov[0].buffer.length = token_len; + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2); + if (GSS_ERROR(major)) + handle_error(major, minor); + + /* Decrypted data is in iov[1].buffer, pointing to a subregion of + * token. */ + + +IOV MIC tokens +-------------- + +The following extensions (declared in ``<gssapi/gssapi_ext.h>``) can +be used in release 1.12 or later to construct and verify MIC tokens +using an IOV list:: + + OM_uint32 gss_get_mic_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_qop_t qop_req, + gss_iov_buffer_desc *iov, + int iov_count); + + OM_uint32 gss_get_mic_iov_length(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_qop_t qop_req, + gss_iov_buffer_desc *iov, + iov_count); + + OM_uint32 gss_verify_mic_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count); + +The caller of gss_get_mic_iov provides an array of gss_iov_buffer_desc +structures, each containing a type and a gss_buffer_desc structure. +Valid types include: + +* **GSS_C_BUFFER_TYPE_DATA** and **GSS_C_BUFFER_TYPE_SIGN_ONLY**: The + corresponding buffer for each of these types will be signed for the + MIC token, in the order provided. + +* **GSS_C_BUFFER_TYPE_MIC_TOKEN**: The GSSAPI MIC token. + +The type of the MIC_TOKEN buffer may be combined with +**GSS_C_BUFFER_FLAG_ALLOCATE** to request that gss_get_mic_iov +allocate the buffer contents. If gss_get_mic_iov allocates the +buffer, it sets the **GSS_C_BUFFER_FLAG_ALLOCATED** flag on the buffer +type. gss_release_iov_buffer can be used to release all allocated +buffers within an iov list and unset their allocated flags. Here is +an example of how gss_get_mic_iov can be used with allocation +requested (*ctx* is assumed to be a previously established +gss_ctx_id_t):: + + OM_uint32 major, minor; + gss_iov_buffer_desc iov[3]; + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer.value = "sign1"; + iov[0].buffer.length = 5; + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.value = "sign2"; + iov[1].buffer.length = 5; + iov[2].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN | GSS_IOV_BUFFER_FLAG_ALLOCATE; + + major = gss_get_mic_iov(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 3); + if (GSS_ERROR(major)) + handle_error(major, minor); + + /* Transmit or otherwise use iov[2].buffer. */ + + (void)gss_release_iov_buffer(&minor, iov, 3); + +If the caller does not choose to request buffer allocation by +gss_get_mic_iov, it should first call gss_get_mic_iov_length to query +the length of the MIC_TOKEN buffer. Here is an example of using +gss_get_mic_iov_length and gss_get_mic_iov: + + OM_uint32 major, minor; + gss_iov_buffer_desc iov[2]; + char data[1024]; + + iov[0].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN; + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer.value = "message"; + iov[1].buffer.length = 7; + + major = gss_wrap_iov_length(&minor, ctx, 1, GSS_C_QOP_DEFAULT, + NULL, iov, 2); + if (GSS_ERROR(major)) + handle_error(major, minor); + if (iov[0].buffer.length > sizeof(data)) + handle_out_of_space_error(); + iov[0].buffer.value = data; + + major = gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL, + iov, 2); + if (GSS_ERROR(major)) + handle_error(major, minor); + + .. _gss_accept_sec_context: http://tools.ietf.org/html/rfc2744.html#section-5.1 .. _gss_acquire_cred: http://tools.ietf.org/html/rfc2744.html#section-5.2 .. _gss_export_name: http://tools.ietf.org/html/rfc2744.html#section-5.13 |