| From f6e57c402688f4bc386d1a39512657a30f0bafd3 Mon Sep 17 00:00:00 2001 |
| From: Nicolas Williams <nico@twosigma.com> |
| Date: Mon, 14 Sep 2015 12:28:36 -0400 |
| Subject: [PATCH 2/4] Fix IAKERB context aliasing bugs [CVE-2015-2696] |
| |
| The IAKERB mechanism currently replaces its context handle with the |
| krb5 mechanism handle upon establishment, under the assumption that |
| most GSS functions are only called after context establishment. This |
| assumption is incorrect, and can lead to aliasing violations for some |
| programs. Maintain the IAKERB context structure after context |
| establishment and add new IAKERB entry points to refer to it with that |
| type. Add initiate and established flags to the IAKERB context |
| structure for use in gss_inquire_context() prior to context |
| establishment. |
| |
| CVE-2015-2696: |
| |
| In MIT krb5 1.9 and later, applications which call |
| gss_inquire_context() on a partially-established IAKERB context can |
| cause the GSS-API library to read from a pointer using the wrong type, |
| generally causing a process crash. Java server applications using the |
| native JGSS provider are vulnerable to this bug. A carefully crafted |
| IAKERB packet might allow the gss_inquire_context() call to succeed |
| with attacker-determined results, but applications should not make |
| access control decisions based on gss_inquire_context() results prior |
| to context establishment. |
| |
| CVSSv2 Vector: AV:N/AC:M/Au:N/C:N/I:N/A:C/E:POC/RL:OF/RC:C |
| |
| [ghudson@mit.edu: several bugfixes, style changes, and edge-case |
| behavior changes; commit message and CVE description] |
| |
| ticket: 8244 |
| target_version: 1.14 |
| tags: pullup |
| |
| Backport upstream commit: |
| https://github.com/krb5/krb5/commit/e04f0283516e80d2f93366e0d479d13c9b5c8c2a |
| |
| Upstream-Status: Backport |
| --- |
| src/lib/gssapi/krb5/gssapiP_krb5.h | 114 ++++++++++++ |
| src/lib/gssapi/krb5/gssapi_krb5.c | 105 +++++++++-- |
| src/lib/gssapi/krb5/iakerb.c | 351 +++++++++++++++++++++++++++++++++---- |
| 3 files changed, 529 insertions(+), 41 deletions(-) |
| |
| diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h |
| index a0e8625..05dc321 100644 |
| --- a/src/lib/gssapi/krb5/gssapiP_krb5.h |
| +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h |
| @@ -620,6 +620,21 @@ OM_uint32 KRB5_CALLCONV krb5_gss_accept_sec_context_ext |
| ); |
| #endif /* LEAN_CLIENT */ |
| |
| +OM_uint32 KRB5_CALLCONV krb5_gss_inquire_sec_context_by_oid |
| +(OM_uint32*, /* minor_status */ |
| + const gss_ctx_id_t, |
| + /* context_handle */ |
| + const gss_OID, /* desired_object */ |
| + gss_buffer_set_t* /* data_set */ |
| +); |
| + |
| +OM_uint32 KRB5_CALLCONV krb5_gss_set_sec_context_option |
| +(OM_uint32*, /* minor_status */ |
| + gss_ctx_id_t*, /* context_handle */ |
| + const gss_OID, /* desired_object */ |
| + const gss_buffer_t/* value */ |
| +); |
| + |
| OM_uint32 KRB5_CALLCONV krb5_gss_process_context_token |
| (OM_uint32*, /* minor_status */ |
| gss_ctx_id_t, /* context_handle */ |
| @@ -1301,6 +1316,105 @@ OM_uint32 KRB5_CALLCONV |
| krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token, |
| gss_cred_id_t *cred_handle); |
| |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_process_context_token(OM_uint32 *minor_status, |
| + const gss_ctx_id_t context_handle, |
| + const gss_buffer_t token_buffer); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + OM_uint32 *time_rec); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_inquire_context(OM_uint32 *minor_status, |
| + gss_ctx_id_t context_handle, gss_name_t *src_name, |
| + gss_name_t *targ_name, OM_uint32 *lifetime_rec, |
| + gss_OID *mech_type, OM_uint32 *ctx_flags, |
| + int *locally_initiated, int *opened); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_qop_t qop_req, gss_buffer_t message_buffer, |
| + gss_buffer_t message_token); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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 KRB5_CALLCONV |
| +iakerb_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, int iov_count); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_buffer_t msg_buffer, gss_buffer_t token_buffer, |
| + gss_qop_t *qop_state); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + int conf_req_flag, gss_qop_t qop_req, |
| + gss_buffer_t input_message_buffer, int *conf_state, |
| + gss_buffer_t output_message_buffer); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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 KRB5_CALLCONV |
| +iakerb_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 KRB5_CALLCONV |
| +iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_buffer_t input_message_buffer, |
| + gss_buffer_t output_message_buffer, int *conf_state, |
| + gss_qop_t *qop_state); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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 KRB5_CALLCONV |
| +iakerb_gss_wrap_size_limit(OM_uint32 *minor_status, |
| + 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); |
| + |
| +#ifndef LEAN_CLIENT |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_export_sec_context(OM_uint32 *minor_status, |
| + gss_ctx_id_t *context_handle, |
| + gss_buffer_t interprocess_token); |
| +#endif /* LEAN_CLIENT */ |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status, |
| + const gss_ctx_id_t context_handle, |
| + const gss_OID desired_object, |
| + gss_buffer_set_t *data_set); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_set_sec_context_option(OM_uint32 *minor_status, |
| + gss_ctx_id_t *context_handle, |
| + const gss_OID desired_object, |
| + const gss_buffer_t value); |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + int prf_key, const gss_buffer_t prf_in, |
| + ssize_t desired_output_len, gss_buffer_t prf_out); |
| + |
| /* Magic string to identify exported krb5 GSS credentials. Increment this if |
| * the format changes. */ |
| #define CRED_EXPORT_MAGIC "K5C1" |
| diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c |
| index 77b7fff..9a23656 100644 |
| --- a/src/lib/gssapi/krb5/gssapi_krb5.c |
| +++ b/src/lib/gssapi/krb5/gssapi_krb5.c |
| @@ -345,7 +345,7 @@ static struct { |
| } |
| }; |
| |
| -static OM_uint32 KRB5_CALLCONV |
| +OM_uint32 KRB5_CALLCONV |
| krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, |
| const gss_ctx_id_t context_handle, |
| const gss_OID desired_object, |
| @@ -459,7 +459,7 @@ static struct { |
| }; |
| #endif |
| |
| -static OM_uint32 KRB5_CALLCONV |
| +OM_uint32 KRB5_CALLCONV |
| krb5_gss_set_sec_context_option (OM_uint32 *minor_status, |
| gss_ctx_id_t *context_handle, |
| const gss_OID desired_object, |
| @@ -904,20 +904,103 @@ static struct gss_config krb5_mechanism = { |
| krb5_gss_get_mic_iov_length, |
| }; |
| |
| +/* Functions which use security contexts or acquire creds are IAKERB-specific; |
| + * other functions can borrow from the krb5 mech. */ |
| +static struct gss_config iakerb_mechanism = { |
| + { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID }, |
| + NULL, |
| + iakerb_gss_acquire_cred, |
| + krb5_gss_release_cred, |
| + iakerb_gss_init_sec_context, |
| +#ifdef LEAN_CLIENT |
| + NULL, |
| +#else |
| + iakerb_gss_accept_sec_context, |
| +#endif |
| + iakerb_gss_process_context_token, |
| + iakerb_gss_delete_sec_context, |
| + iakerb_gss_context_time, |
| + iakerb_gss_get_mic, |
| + iakerb_gss_verify_mic, |
| +#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE) |
| + NULL, |
| +#else |
| + iakerb_gss_wrap, |
| +#endif |
| +#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE) |
| + NULL, |
| +#else |
| + iakerb_gss_unwrap, |
| +#endif |
| + krb5_gss_display_status, |
| + krb5_gss_indicate_mechs, |
| + krb5_gss_compare_name, |
| + krb5_gss_display_name, |
| + krb5_gss_import_name, |
| + krb5_gss_release_name, |
| + krb5_gss_inquire_cred, |
| + NULL, /* add_cred */ |
| +#ifdef LEAN_CLIENT |
| + NULL, |
| + NULL, |
| +#else |
| + iakerb_gss_export_sec_context, |
| + NULL, |
| +#endif |
| + krb5_gss_inquire_cred_by_mech, |
| + krb5_gss_inquire_names_for_mech, |
| + iakerb_gss_inquire_context, |
| + krb5_gss_internal_release_oid, |
| + iakerb_gss_wrap_size_limit, |
| + krb5_gss_localname, |
| + krb5_gss_authorize_localname, |
| + krb5_gss_export_name, |
| + krb5_gss_duplicate_name, |
| + krb5_gss_store_cred, |
| + iakerb_gss_inquire_sec_context_by_oid, |
| + krb5_gss_inquire_cred_by_oid, |
| + iakerb_gss_set_sec_context_option, |
| + krb5_gssspi_set_cred_option, |
| + krb5_gssspi_mech_invoke, |
| + NULL, /* wrap_aead */ |
| + NULL, /* unwrap_aead */ |
| + iakerb_gss_wrap_iov, |
| + iakerb_gss_unwrap_iov, |
| + iakerb_gss_wrap_iov_length, |
| + NULL, /* complete_auth_token */ |
| + NULL, /* acquire_cred_impersonate_name */ |
| + NULL, /* add_cred_impersonate_name */ |
| + NULL, /* display_name_ext */ |
| + krb5_gss_inquire_name, |
| + krb5_gss_get_name_attribute, |
| + krb5_gss_set_name_attribute, |
| + krb5_gss_delete_name_attribute, |
| + krb5_gss_export_name_composite, |
| + krb5_gss_map_name_to_any, |
| + krb5_gss_release_any_name_mapping, |
| + iakerb_gss_pseudo_random, |
| + NULL, /* set_neg_mechs */ |
| + krb5_gss_inquire_saslname_for_mech, |
| + krb5_gss_inquire_mech_for_saslname, |
| + krb5_gss_inquire_attrs_for_mech, |
| + krb5_gss_acquire_cred_from, |
| + krb5_gss_store_cred_into, |
| + iakerb_gss_acquire_cred_with_password, |
| + krb5_gss_export_cred, |
| + krb5_gss_import_cred, |
| + NULL, /* import_sec_context_by_mech */ |
| + NULL, /* import_name_by_mech */ |
| + NULL, /* import_cred_by_mech */ |
| + iakerb_gss_get_mic_iov, |
| + iakerb_gss_verify_mic_iov, |
| + iakerb_gss_get_mic_iov_length, |
| +}; |
| + |
| #ifdef _GSS_STATIC_LINK |
| #include "mglueP.h" |
| static int gss_iakerbmechglue_init(void) |
| { |
| struct gss_mech_config mech_iakerb; |
| - struct gss_config iakerb_mechanism = krb5_mechanism; |
| - |
| - /* IAKERB mechanism mirrors krb5, but with different context SPIs */ |
| - iakerb_mechanism.gss_accept_sec_context = iakerb_gss_accept_sec_context; |
| - iakerb_mechanism.gss_init_sec_context = iakerb_gss_init_sec_context; |
| - iakerb_mechanism.gss_delete_sec_context = iakerb_gss_delete_sec_context; |
| - iakerb_mechanism.gss_acquire_cred = iakerb_gss_acquire_cred; |
| - iakerb_mechanism.gssspi_acquire_cred_with_password |
| - = iakerb_gss_acquire_cred_with_password; |
| |
| memset(&mech_iakerb, 0, sizeof(mech_iakerb)); |
| mech_iakerb.mech = &iakerb_mechanism; |
| diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c |
| index f30de32..4662bd9 100644 |
| --- a/src/lib/gssapi/krb5/iakerb.c |
| +++ b/src/lib/gssapi/krb5/iakerb.c |
| @@ -47,6 +47,8 @@ struct _iakerb_ctx_id_rec { |
| gss_ctx_id_t gssc; |
| krb5_data conv; /* conversation for checksumming */ |
| unsigned int count; /* number of round trips */ |
| + int initiate; |
| + int established; |
| krb5_get_init_creds_opt *gic_opts; |
| }; |
| |
| @@ -695,7 +697,7 @@ cleanup: |
| * Allocate and initialise an IAKERB context |
| */ |
| static krb5_error_code |
| -iakerb_alloc_context(iakerb_ctx_id_t *pctx) |
| +iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate) |
| { |
| iakerb_ctx_id_t ctx; |
| krb5_error_code code; |
| @@ -709,6 +711,8 @@ iakerb_alloc_context(iakerb_ctx_id_t *pctx) |
| ctx->magic = KG_IAKERB_CONTEXT; |
| ctx->state = IAKERB_AS_REQ; |
| ctx->count = 0; |
| + ctx->initiate = initiate; |
| + ctx->established = 0; |
| |
| code = krb5_gss_init_context(&ctx->k5c); |
| if (code != 0) |
| @@ -732,7 +736,7 @@ iakerb_gss_delete_sec_context(OM_uint32 *minor_status, |
| gss_ctx_id_t *context_handle, |
| gss_buffer_t output_token) |
| { |
| - OM_uint32 major_status = GSS_S_COMPLETE; |
| + iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle; |
| |
| if (output_token != GSS_C_NO_BUFFER) { |
| output_token->length = 0; |
| @@ -740,23 +744,10 @@ iakerb_gss_delete_sec_context(OM_uint32 *minor_status, |
| } |
| |
| *minor_status = 0; |
| + *context_handle = GSS_C_NO_CONTEXT; |
| + iakerb_release_context(iakerb_ctx); |
| |
| - if (*context_handle != GSS_C_NO_CONTEXT) { |
| - iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle; |
| - |
| - if (iakerb_ctx->magic == KG_IAKERB_CONTEXT) { |
| - iakerb_release_context(iakerb_ctx); |
| - *context_handle = GSS_C_NO_CONTEXT; |
| - } else { |
| - assert(iakerb_ctx->magic == KG_CONTEXT); |
| - |
| - major_status = krb5_gss_delete_sec_context(minor_status, |
| - context_handle, |
| - output_token); |
| - } |
| - } |
| - |
| - return major_status; |
| + return GSS_S_COMPLETE; |
| } |
| |
| static krb5_boolean |
| @@ -802,7 +793,7 @@ iakerb_gss_accept_sec_context(OM_uint32 *minor_status, |
| int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT); |
| |
| if (initialContextToken) { |
| - code = iakerb_alloc_context(&ctx); |
| + code = iakerb_alloc_context(&ctx, 0); |
| if (code != 0) |
| goto cleanup; |
| |
| @@ -854,11 +845,8 @@ iakerb_gss_accept_sec_context(OM_uint32 *minor_status, |
| time_rec, |
| delegated_cred_handle, |
| &exts); |
| - if (major_status == GSS_S_COMPLETE) { |
| - *context_handle = ctx->gssc; |
| - ctx->gssc = NULL; |
| - iakerb_release_context(ctx); |
| - } |
| + if (major_status == GSS_S_COMPLETE) |
| + ctx->established = 1; |
| if (mech_type != NULL) |
| *mech_type = (gss_OID)gss_mech_krb5; |
| } |
| @@ -897,7 +885,7 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status, |
| int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT); |
| |
| if (initialContextToken) { |
| - code = iakerb_alloc_context(&ctx); |
| + code = iakerb_alloc_context(&ctx, 1); |
| if (code != 0) { |
| *minor_status = code; |
| goto cleanup; |
| @@ -983,11 +971,8 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status, |
| ret_flags, |
| time_rec, |
| &exts); |
| - if (major_status == GSS_S_COMPLETE) { |
| - *context_handle = ctx->gssc; |
| - ctx->gssc = GSS_C_NO_CONTEXT; |
| - iakerb_release_context(ctx); |
| - } |
| + if (major_status == GSS_S_COMPLETE) |
| + ctx->established = 1; |
| if (actual_mech_type != NULL) |
| *actual_mech_type = (gss_OID)gss_mech_krb5; |
| } else { |
| @@ -1010,3 +995,309 @@ cleanup: |
| |
| return major_status; |
| } |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_buffer_t input_message_buffer, |
| + gss_buffer_t output_message_buffer, int *conf_state, |
| + gss_qop_t *qop_state) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer, |
| + output_message_buffer, conf_state, qop_state); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + int conf_req_flag, gss_qop_t qop_req, |
| + gss_buffer_t input_message_buffer, int *conf_state, |
| + gss_buffer_t output_message_buffer) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req, |
| + input_message_buffer, conf_state, |
| + output_message_buffer); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_process_context_token(OM_uint32 *minor_status, |
| + const gss_ctx_id_t context_handle, |
| + const gss_buffer_t token_buffer) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_DEFECTIVE_TOKEN; |
| + |
| + return krb5_gss_process_context_token(minor_status, ctx->gssc, |
| + token_buffer); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + OM_uint32 *time_rec) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_context_time(minor_status, ctx->gssc, time_rec); |
| +} |
| + |
| +#ifndef LEAN_CLIENT |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_export_sec_context(OM_uint32 *minor_status, |
| + gss_ctx_id_t *context_handle, |
| + gss_buffer_t interprocess_token) |
| +{ |
| + OM_uint32 maj; |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + /* We don't currently support exporting partially established contexts. */ |
| + if (!ctx->established) |
| + return GSS_S_UNAVAILABLE; |
| + |
| + maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc, |
| + interprocess_token); |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) { |
| + iakerb_release_context(ctx); |
| + *context_handle = GSS_C_NO_CONTEXT; |
| + } |
| + return maj; |
| +} |
| + |
| +/* |
| + * Until we implement partial context exports, there are no SPNEGO exported |
| + * context tokens, only tokens for the underlying krb5 context. So we do not |
| + * need to implement an iakerb_gss_import_sec_context() yet; it would be |
| + * unreachable except via a manually constructed token. |
| + */ |
| + |
| +#endif /* LEAN_CLIENT */ |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_inquire_context(OM_uint32 *minor_status, |
| + gss_ctx_id_t context_handle, gss_name_t *src_name, |
| + gss_name_t *targ_name, OM_uint32 *lifetime_rec, |
| + gss_OID *mech_type, OM_uint32 *ctx_flags, |
| + int *initiate, int *opened) |
| +{ |
| + OM_uint32 ret; |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (src_name != NULL) |
| + *src_name = GSS_C_NO_NAME; |
| + if (targ_name != NULL) |
| + *targ_name = GSS_C_NO_NAME; |
| + if (lifetime_rec != NULL) |
| + *lifetime_rec = 0; |
| + if (mech_type != NULL) |
| + *mech_type = (gss_OID)gss_mech_iakerb; |
| + if (ctx_flags != NULL) |
| + *ctx_flags = 0; |
| + if (initiate != NULL) |
| + *initiate = ctx->initiate; |
| + if (opened != NULL) |
| + *opened = ctx->established; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_COMPLETE; |
| + |
| + ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name, |
| + targ_name, lifetime_rec, mech_type, |
| + ctx_flags, initiate, opened); |
| + |
| + if (!ctx->established) { |
| + /* Report IAKERB as the mech OID until the context is established. */ |
| + if (mech_type != NULL) |
| + *mech_type = (gss_OID)gss_mech_iakerb; |
| + |
| + /* We don't support exporting partially-established contexts. */ |
| + if (ctx_flags != NULL) |
| + *ctx_flags &= ~GSS_C_TRANS_FLAG; |
| + } |
| + |
| + return ret; |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_wrap_size_limit(OM_uint32 *minor_status, |
| + 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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag, |
| + qop_req, req_output_size, max_input_size); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_qop_t qop_req, gss_buffer_t message_buffer, |
| + gss_buffer_t message_token) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer, |
| + message_token); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + gss_buffer_t msg_buffer, gss_buffer_t token_buffer, |
| + gss_qop_t *qop_state) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer, |
| + token_buffer, qop_state); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status, |
| + const gss_ctx_id_t context_handle, |
| + const gss_OID desired_object, |
| + gss_buffer_set_t *data_set) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_UNAVAILABLE; |
| + |
| + return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc, |
| + desired_object, data_set); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_set_sec_context_option(OM_uint32 *minor_status, |
| + gss_ctx_id_t *context_handle, |
| + const gss_OID desired_object, |
| + const gss_buffer_t value) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle; |
| + |
| + if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_UNAVAILABLE; |
| + |
| + return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc, |
| + desired_object, value); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req, |
| + conf_state, iov, iov_count); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state, |
| + iov, iov_count); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag, |
| + qop_req, conf_state, iov, iov_count); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle, |
| + int prf_key, const gss_buffer_t prf_in, |
| + ssize_t desired_output_len, gss_buffer_t prf_out) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in, |
| + desired_output_len, prf_out); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov, |
| + iov_count); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov, |
| + iov_count); |
| +} |
| + |
| +OM_uint32 KRB5_CALLCONV |
| +iakerb_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, int iov_count) |
| +{ |
| + iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; |
| + |
| + if (ctx->gssc == GSS_C_NO_CONTEXT) |
| + return GSS_S_NO_CONTEXT; |
| + |
| + return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov, |
| + iov_count); |
| +} |
| -- |
| 1.9.1 |
| |