From 31355119edb3a282ab302c05e33e23430af67603 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Thu, 23 Sep 2010 16:54:10 +0200 Subject: [PATCH] Use AD-KDCIssued to protect RADIUS authdata. Cleanup. --- Makefile.am | 35 ++++-- accept_sec_context.c | 123 ++++++++++--------- authdata_plugin.h | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++ gssapiP_eap.h | 12 +- init_sec_context.c | 91 +++++++------- mech | 10 +- radius_ad.exports | 1 + unwrap.c | 3 + unwrap_iov.c | 22 ++-- util.h | 4 +- util_adshim.c | 237 ++++++++++++++++++++++++++++++++++++ util_reauth.c | 99 ++++++++++++++- util_reauth.h | 10 ++ wrap.c | 19 ++- wrap_iov.c | 16 +-- wrap_iov_length.c | 4 +- 16 files changed, 855 insertions(+), 162 deletions(-) create mode 100644 authdata_plugin.h create mode 100644 radius_ad.exports create mode 100644 util_adshim.c diff --git a/Makefile.am b/Makefile.am index 5347b06..b59b57c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,21 +1,21 @@ AUTOMAKE_OPTIONS = foreign gssdir = $(libdir)/gss +gss_LTLIBRARIES = mech_eap.la -gss_LTLIBRARIES = libmech_eap.la +mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" +mech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \ + @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@ +mech_eap_la_CXXFLAGS = -g -Wall \ + @EAP_CFLAGS@ @KRB5_CFLAGS@ @SHIBSP_CXXFLAGS@ \ + @SHIBRESOLVER_CXXFLAGS@ @TARGET_CFLAGS@ +mech_eap_la_LDFLAGS = -avoid-version -module \ + -export-symbols mech_eap.exports -no-undefined \ + @EAP_LDFLAGS@ @KRB5_LDFLAGS@ @TARGET_LDFLAGS@ +mech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ \ + @SHIBRESOLVER_LIBS@ -lfreeradius-client -libmech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -libmech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \ - @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@ -libmech_eap_la_CXXFLAGS = -g -Wall \ - @EAP_CFLAGS@ @KRB5_CFLAGS@ @SHIBSP_CXXFLAGS@ \ - @SHIBRESOLVER_CXXFLAGS@ @TARGET_CFLAGS@ -libmech_eap_la_LDFLAGS = -export-symbols mech_eap.exports -version-info 0:0:0 \ - -no-undefined \ - @EAP_LDFLAGS@ @KRB5_LDFLAGS@ @TARGET_LDFLAGS@ -libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ @SHIBRESOLVER_LIBS@ -lfreeradius-client - -libmech_eap_la_SOURCES = \ +mech_eap_la_SOURCES = \ accept_sec_context.c \ acquire_cred.c \ acquire_cred_with_password.c \ @@ -82,3 +82,12 @@ libmech_eap_la_SOURCES = \ wrap_iov_length.c \ wrap_size_limit.c +krb5pluginsdir = $(libdir)/krb5/plugins/authdata +krb5plugins_LTLIBRARIES = radius_ad.la + +radius_ad_la_CFLAGS = -g -Wall -fno-strict-aliasing \ + @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@ +radius_ad_la_LDFLAGS = -avoid-version -module \ + -export-symbols radius_ad.exports -no-undefined +radius_ad_la_LIBADD = @KRB5_LIBS@ +radius_ad_la_SOURCES = util_adshim.c diff --git a/accept_sec_context.c b/accept_sec_context.c index f223cc5..eb1a07c 100644 --- a/accept_sec_context.c +++ b/accept_sec_context.c @@ -326,7 +326,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; - ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS; + ctx->state = EAP_STATE_EXTENSIONS_REQ; } major = GSS_S_CONTINUE_NEEDED; @@ -339,54 +339,41 @@ cleanup: } static OM_uint32 -eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, - gss_ctx_id_t ctx, - gss_cred_id_t cred, - gss_buffer_t inputToken, - gss_channel_bindings_t chanBindings, - gss_buffer_t outputToken) +acceptGssChannelBindings(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t inputToken, + gss_channel_bindings_t chanBindings) { - OM_uint32 major; + OM_uint32 major, tmpMinor; gss_iov_buffer_desc iov[2]; - outputToken->length = 0; - outputToken->value = NULL; - - if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) { - if (inputToken->length < 14) { - return GSS_S_DEFECTIVE_TOKEN; - } - - iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[0].buffer.length = 0; - iov[0].buffer.value = NULL; - - if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) - iov[0].buffer = chanBindings->application_data; + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[0].buffer.length = 0; + iov[0].buffer.value = NULL; - iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER; - iov[1].buffer.length = 16; - iov[1].buffer.value = (unsigned char *)inputToken->value - 2; + iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM; + iov[1].buffer = *inputToken; - assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB); - - iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER; - iov[2].buffer.length = inputToken->length - 14; - iov[2].buffer.value = (unsigned char *)inputToken->value + 14; + major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, + iov, 2, TOK_TYPE_WRAP); + if (GSS_ERROR(major)) + return major; - major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, - iov, 3, TOK_TYPE_GSS_CB); - if (GSS_ERROR(major)) - return major; + if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS && + !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) { + major = GSS_S_BAD_BINDINGS; + } else { + major = GSS_S_CONTINUE_NEEDED; } - ctx->state = EAP_STATE_KRB_REAUTH_CRED; + gss_release_buffer(&tmpMinor, &iov[0].buffer); - return GSS_S_CONTINUE_NEEDED; + return major; } static OM_uint32 -eapGssSmAcceptKrbReauthCred(OM_uint32 *minor, +eapGssSmAcceptExtensionsReq(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred, gss_buffer_t inputToken, @@ -395,12 +382,44 @@ eapGssSmAcceptKrbReauthCred(OM_uint32 *minor, { OM_uint32 major; - major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken); + outputToken->length = 0; + outputToken->value = NULL; + + major = acceptGssChannelBindings(minor, ctx, cred, inputToken, + chanBindings); + if (GSS_ERROR(major)) + return major; + + ctx->state = EAP_STATE_EXTENSIONS_RESP; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmAcceptExtensionsResp(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t inputToken, + gss_channel_bindings_t chanBindings, + gss_buffer_t outputToken) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc credsToken = GSS_C_EMPTY_BUFFER; + + major = gssEapMakeReauthCreds(minor, ctx, cred, &credsToken); if (GSS_ERROR(major)) return major; ctx->state = EAP_STATE_ESTABLISHED; + major = duplicateBuffer(minor, &credsToken, outputToken); + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, &credsToken); + return major; + } + + gss_release_buffer(&tmpMinor, &credsToken); + return GSS_S_COMPLETE; } @@ -425,39 +444,25 @@ acceptReadyKrb(OM_uint32 *minor, const gss_OID mech, OM_uint32 timeRec) { - OM_uint32 major, tmpMinor; - gss_buffer_desc authData = GSS_C_EMPTY_BUFFER; + OM_uint32 major; major = gssEapGlueToMechName(minor, initiator, &ctx->initiatorName); if (GSS_ERROR(major)) - goto cleanup; - - major = gssKrbExtractAuthzDataFromSecContext(minor, ctx->kerberosCtx, - KRB5_AUTHDATA_RADIUS_AVP, - &authData); - if (GSS_ERROR(major)) - goto cleanup; - - major = gssEapImportAttrContext(minor, &authData, ctx->initiatorName); - if (GSS_ERROR(major)) - goto cleanup; + return major; if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) { major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName); if (GSS_ERROR(major)) - goto cleanup; + return major; } major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec); if (GSS_ERROR(major)) - goto cleanup; + return major; ctx->state = EAP_STATE_ESTABLISHED; -cleanup: - gss_release_buffer(&tmpMinor, &authData); - - return major; + return GSS_S_COMPLETE; } static OM_uint32 @@ -514,8 +519,8 @@ static struct gss_eap_acceptor_sm { } eapGssAcceptorSm[] = { { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptIdentity }, { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptAuthenticate }, - { TOK_TYPE_GSS_CB, TOK_TYPE_NONE, eapGssSmAcceptGssChannelBindings }, - { TOK_TYPE_NONE, TOK_TYPE_KRB_CRED, eapGssSmAcceptKrbReauthCred }, + { TOK_TYPE_EXT_REQ, TOK_TYPE_NONE, eapGssSmAcceptExtensionsReq }, + { TOK_TYPE_NONE, TOK_TYPE_EXT_RESP, eapGssSmAcceptExtensionsResp }, { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished }, { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth }, }; diff --git a/authdata_plugin.h b/authdata_plugin.h new file mode 100644 index 0000000..32bff2f --- /dev/null +++ b/authdata_plugin.h @@ -0,0 +1,331 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * krb5/authdata_plugin.h + * + * Copyright (C) 2007 Apple Inc. All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * AuthorizationData plugin definitions for Kerberos 5. + */ + +/* + * This is considered an INTERNAL interface at this time. + * + * Some work is needed before exporting it: + * + * + Documentation. + * + Sample code. + * + Test cases (preferably automated testing under "make check"). + * + Hook into TGS exchange too; will change API. + * + Examine memory management issues, especially for Windows; may + * change API. + * + * Other changes that would be nice to have, but not necessarily + * before making this interface public: + * + * + Library support for AD-IF-RELEVANT and similar wrappers. (We can + * make the plugin construct them if it wants them.) + * + KDC could combine/optimize wrapped AD elements provided by + * multiple plugins, e.g., two IF-RELEVANT sequences could be + * merged. (The preauth plugin API also has this bug, we're going + * to need a general fix.) + */ + +#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED +#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED +#include + +/* + * While arguments of these types are passed-in, for the most part a + * authorization data module can treat them as opaque. If we need + * keying data, we can ask for it directly. + */ +struct _krb5_db_entry_new; + +/* + * The function table / structure which an authdata server module must export as + * "authdata_server_0". NOTE: replace "0" with "1" for the type and + * variable names if this gets picked up by upstream. If the interfaces work + * correctly, future versions of the table will add either more callbacks or + * more arguments to callbacks, and in both cases we'll be able to wrap the v0 + * functions. + */ +/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */ +typedef struct krb5plugin_authdata_server_ftable_v0 { + /* Not-usually-visible name. */ + char *name; + + /* + * Per-plugin initialization/cleanup. The init function is called + * by the KDC when the plugin is loaded, and the fini function is + * called before the plugin is unloaded. Both are optional. + */ + krb5_error_code (*init_proc)(krb5_context, void **); + void (*fini_proc)(krb5_context, void *); + /* + * Actual authorization data handling function. If this field + * holds a null pointer, this mechanism will be skipped, and the + * init/fini functions will not be run. + * + * This function should only modify the field + * enc_tkt_reply->authorization_data. All other values should be + * considered inputs only. And, it should *modify* the field, not + * overwrite it and assume that there are no other authdata + * plugins in use. + * + * Memory management: authorization_data is a malloc-allocated, + * null-terminated sequence of malloc-allocated pointers to + * authorization data structures. This plugin code currently + * assumes the libraries, KDC, and plugin all use the same malloc + * pool, which may be a problem if/when we get the KDC code + * running on Windows. + * + * If this function returns a non-zero error code, a message + * is logged, but no other action is taken. Other authdata + * plugins will be called, and a response will be sent to the + * client (barring other problems). + */ + krb5_error_code (*authdata_proc)(krb5_context, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply); +} krb5plugin_server_authdata_ftable_v0; + +typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0; + +typedef struct krb5plugin_authdata_server_ftable_v2 { + /* Not-usually-visible name. */ + char *name; + + /* + * Per-plugin initialization/cleanup. The init function is called + * by the KDC when the plugin is loaded, and the fini function is + * called before the plugin is unloaded. Both are optional. + */ + krb5_error_code (*init_proc)(krb5_context, void **); + void (*fini_proc)(krb5_context, void *); + /* + * Actual authorization data handling function. If this field + * holds a null pointer, this mechanism will be skipped, and the + * init/fini functions will not be run. + * + * This function should only modify the field + * enc_tkt_reply->authorization_data. All other values should be + * considered inputs only. And, it should *modify* the field, not + * overwrite it and assume that there are no other authdata + * plugins in use. + * + * Memory management: authorization_data is a malloc-allocated, + * null-terminated sequence of malloc-allocated pointers to + * authorization data structures. This plugin code currently + * assumes the libraries, KDC, and plugin all use the same malloc + * pool, which may be a problem if/when we get the KDC code + * running on Windows. + * + * If this function returns a non-zero error code, a message + * is logged, but no other action is taken. Other authdata + * plugins will be called, and a response will be sent to the + * client (barring other problems). + */ + krb5_error_code (*authdata_proc)(krb5_context, + unsigned int flags, + struct _krb5_db_entry_new *client, + struct _krb5_db_entry_new *server, + struct _krb5_db_entry_new *tgs, + krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_keyblock *tgs_key, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply); +} krb5plugin_authdata_server_ftable_v2; + +typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2; + +typedef krb5_error_code +(*authdata_client_plugin_init_proc)(krb5_context context, + void **plugin_context); + +#define AD_USAGE_AS_REQ 0x01 +#define AD_USAGE_TGS_REQ 0x02 +#define AD_USAGE_AP_REQ 0x04 +#define AD_USAGE_KDC_ISSUED 0x08 +#define AD_USAGE_MASK 0x0F +#define AD_INFORMATIONAL 0x10 + +struct _krb5_authdata_context; + +typedef void +(*authdata_client_plugin_flags_proc)(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags); + +typedef void +(*authdata_client_plugin_fini_proc)(krb5_context kcontext, + void *plugin_context); + +typedef krb5_error_code +(*authdata_client_request_init_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void **request_context); + +typedef void +(*authdata_client_request_fini_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context); + +typedef krb5_error_code +(*authdata_client_import_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer); + +typedef krb5_error_code +(*authdata_client_export_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***authdata); + +typedef krb5_error_code +(*authdata_client_get_attribute_types_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_data **attrs); + +typedef krb5_error_code +(*authdata_client_get_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more); + +typedef krb5_error_code +(*authdata_client_set_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value); + +typedef krb5_error_code +(*authdata_client_delete_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute); + +typedef krb5_error_code +(*authdata_client_export_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean restrict_authenticated, + void **ptr); + +typedef void +(*authdata_client_free_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *ptr); + +typedef krb5_error_code +(*authdata_client_verify_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *req); + +typedef krb5_error_code +(*authdata_client_size_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + size_t *sizep); + +typedef krb5_error_code +(*authdata_client_externalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_internalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_copy_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context); + +typedef struct krb5plugin_authdata_client_ftable_v0 { + char *name; + krb5_authdatatype *ad_type_list; + authdata_client_plugin_init_proc init; + authdata_client_plugin_fini_proc fini; + authdata_client_plugin_flags_proc flags; + authdata_client_request_init_proc request_init; + authdata_client_request_fini_proc request_fini; + authdata_client_get_attribute_types_proc get_attribute_types; + authdata_client_get_attribute_proc get_attribute; + authdata_client_set_attribute_proc set_attribute; + authdata_client_delete_attribute_proc delete_attribute; + authdata_client_export_authdata_proc export_authdata; + authdata_client_import_authdata_proc import_authdata; + authdata_client_export_internal_proc export_internal; + authdata_client_free_internal_proc free_internal; + authdata_client_verify_proc verify; + authdata_client_size_proc size; + authdata_client_externalize_proc externalize; + authdata_client_internalize_proc internalize; + authdata_client_copy_proc copy; /* optional */ +} krb5plugin_authdata_client_ftable_v0; + +#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */ diff --git a/gssapiP_eap.h b/gssapiP_eap.h index c9c785c..846c3ed 100644 --- a/gssapiP_eap.h +++ b/gssapiP_eap.h @@ -104,8 +104,8 @@ struct gss_cred_id_struct { enum gss_eap_state { EAP_STATE_IDENTITY = 0, EAP_STATE_AUTHENTICATE, - EAP_STATE_GSS_CHANNEL_BINDINGS, - EAP_STATE_KRB_REAUTH_CRED, + EAP_STATE_EXTENSIONS_REQ, + EAP_STATE_EXTENSIONS_RESP, EAP_STATE_ESTABLISHED, EAP_STATE_KRB_REAUTH_GSS }; @@ -201,6 +201,14 @@ gssEapWrapIovLength(OM_uint32 *minor, int *conf_state, gss_iov_buffer_desc *iov, int iov_count); +OM_uint32 +gssEapWrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer); unsigned char rfc4121Flags(gss_ctx_id_t ctx, int receiving); diff --git a/init_sec_context.c b/init_sec_context.c index 0709b1f..f1f260a 100644 --- a/init_sec_context.c +++ b/init_sec_context.c @@ -428,7 +428,7 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); major = GSS_S_CONTINUE_NEEDED; - ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS; + ctx->state = EAP_STATE_EXTENSIONS_REQ; } else if (ctx->flags & CTX_FLAG_EAP_FAIL) { major = GSS_S_DEFECTIVE_CREDENTIAL; } else if (code == 0 && initialContextToken) { @@ -462,59 +462,28 @@ cleanup: } static OM_uint32 -eapGssSmInitGssChannelBindings(OM_uint32 *minor, - gss_cred_id_t cred, - gss_ctx_id_t ctx, - gss_name_t target, - gss_OID mech, - OM_uint32 reqFlags, - OM_uint32 timeReq, - gss_channel_bindings_t chanBindings, - gss_buffer_t inputToken, - gss_buffer_t outputToken) +initGssChannelBindings(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_channel_bindings_t chanBindings, + gss_buffer_t outputToken) { OM_uint32 major; - gss_iov_buffer_desc iov[2]; - gss_buffer_desc buf; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; - iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[0].buffer.length = 0; - iov[0].buffer.value = NULL; - - iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; - iov[1].buffer.length = 0; - iov[1].buffer.value = NULL; if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) - iov[0].buffer = chanBindings->application_data; + buffer = chanBindings->application_data; - major = gssEapWrapOrGetMIC(minor, ctx, FALSE, FALSE, iov, 2, - TOK_TYPE_GSS_CB); + major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT, + &buffer, NULL, outputToken); if (GSS_ERROR(major)) - goto cleanup; - - /* Skip past token ID */ - assert(iov[1].buffer.length > 2); - assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB); - - buf.length = iov[1].buffer.length - 2; - buf.value = (unsigned char *)iov[1].buffer.value + 2; - - major = duplicateBuffer(minor, &buf, outputToken); - if (GSS_ERROR(major)) - goto cleanup; + return major; - major = GSS_S_CONTINUE_NEEDED; - ctx->state = EAP_STATE_KRB_REAUTH_CRED; - -cleanup: - gssEapReleaseIov(iov, 2); - - return major; + return GSS_S_CONTINUE_NEEDED; } static OM_uint32 -eapGssSmInitKrbReauthCred(OM_uint32 *minor, +eapGssSmInitExtensionsReq(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, gss_name_t target, @@ -525,6 +494,38 @@ eapGssSmInitKrbReauthCred(OM_uint32 *minor, gss_buffer_t inputToken, gss_buffer_t outputToken) { + OM_uint32 major, tmpMinor; + gss_buffer_desc cbToken = GSS_C_EMPTY_BUFFER; + + major = initGssChannelBindings(minor, ctx, chanBindings, &cbToken); + if (GSS_ERROR(major)) + return major; + + ctx->state = EAP_STATE_EXTENSIONS_RESP; + + major = duplicateBuffer(minor, &cbToken, outputToken); + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, &cbToken); + return major; + } + + gss_release_buffer(&tmpMinor, &cbToken); + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitExtensionsResp(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken) +{ OM_uint32 major; major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken); @@ -642,8 +643,8 @@ static struct gss_eap_initiator_sm { } eapGssInitiatorSm[] = { { TOK_TYPE_NONE, TOK_TYPE_EAP_RESP, eapGssSmInitIdentity }, { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitAuthenticate }, - { TOK_TYPE_NONE, TOK_TYPE_GSS_CB, eapGssSmInitGssChannelBindings }, - { TOK_TYPE_KRB_CRED,TOK_TYPE_NONE, eapGssSmInitKrbReauthCred }, + { TOK_TYPE_NONE, TOK_TYPE_EXT_REQ, eapGssSmInitExtensionsReq }, + { TOK_TYPE_EXT_RESP,TOK_TYPE_NONE, eapGssSmInitExtensionsResp }, { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmInitEstablished }, { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmInitGssReauth }, }; diff --git a/mech b/mech index 89c5512..0b0fe7f 100644 --- a/mech +++ b/mech @@ -3,8 +3,8 @@ # Any encryption type supported by Kerberos can be defined as the # last element of the OID arc. # -eap 1.3.6.1.4.1.5322.21.1 libmech_eap.dylib -eap-des3-cbc-sha1 1.3.6.1.4.1.5322.21.1.16 libmech_eap.dylib -eap-aes128 1.3.6.1.4.1.5322.21.1.17 libmech_eap.dylib -eap-aes256 1.3.6.1.4.1.5322.21.1.18 libmech_eap.dylib -eap-rc4-hmac 1.3.6.1.4.1.5322.21.1.23 libmech_eap.dylib +eap 1.3.6.1.4.1.5322.21.1 mech_eap.so +eap-des3-cbc-sha1 1.3.6.1.4.1.5322.21.1.16 mech_eap.so +eap-aes128 1.3.6.1.4.1.5322.21.1.17 mech_eap.so +eap-aes256 1.3.6.1.4.1.5322.21.1.18 mech_eap.so +eap-rc4-hmac 1.3.6.1.4.1.5322.21.1.23 mech_eap.so diff --git a/radius_ad.exports b/radius_ad.exports new file mode 100644 index 0000000..8d5d5c4 --- /dev/null +++ b/radius_ad.exports @@ -0,0 +1 @@ +authdata_client_0 diff --git a/unwrap.c b/unwrap.c index ca10b32..844c762 100644 --- a/unwrap.c +++ b/unwrap.c @@ -43,6 +43,9 @@ gss_unwrap(OM_uint32 *minor, OM_uint32 major, tmpMinor; gss_iov_buffer_desc iov[2]; + if (!CTX_IS_ESTABLISHED(ctx)) + return GSS_S_NO_CONTEXT; + iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM; iov[0].buffer = *input_message_buffer; diff --git a/unwrap_iov.c b/unwrap_iov.c index b178da8..ee2790d 100644 --- a/unwrap_iov.c +++ b/unwrap_iov.c @@ -101,21 +101,14 @@ unwrapToken(OM_uint32 *minor, flags = rfc4121Flags(ctx, TRUE); - switch (toktype) { - case TOK_TYPE_WRAP: + if (toktype == TOK_TYPE_WRAP) { keyUsage = !CTX_IS_INITIATOR(ctx) ? KEY_USAGE_INITIATOR_SEAL : KEY_USAGE_ACCEPTOR_SEAL; - break; - case TOK_TYPE_GSS_CB: - keyUsage = KEY_USAGE_CHANNEL_BINDINGS; - break; - case TOK_TYPE_MIC: - default: + } else { keyUsage = !CTX_IS_INITIATOR(ctx) ? KEY_USAGE_INITIATOR_SIGN : KEY_USAGE_ACCEPTOR_SIGN; - break; } gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen); @@ -213,7 +206,7 @@ unwrapToken(OM_uint32 *minor, } code = sequenceCheck(minor, &ctx->seqState, seqnum); - } else if (toktype == TOK_TYPE_MIC || toktype == TOK_TYPE_GSS_CB) { + } else if (toktype == TOK_TYPE_MIC) { if (load_uint16_be(ptr) != toktype) goto defective; @@ -229,8 +222,7 @@ unwrapToken(OM_uint32 *minor, *minor = code; return GSS_S_BAD_SIG; } - if (toktype != TOK_TYPE_GSS_CB) - code = sequenceCheck(minor, &ctx->seqState, seqnum); + code = sequenceCheck(minor, &ctx->seqState, seqnum); } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT) goto defective; @@ -471,9 +463,6 @@ gssEapUnwrapOrVerifyMIC(OM_uint32 *minor, { OM_uint32 major; - if (!CTX_IS_ESTABLISHED(ctx)) - return GSS_S_NO_CONTEXT; - if (ctx->encryptionType == ENCTYPE_NULL) return GSS_S_UNAVAILABLE; @@ -496,6 +485,9 @@ gss_unwrap_iov(OM_uint32 *minor, gss_iov_buffer_desc *iov, int iov_count) { + if (!CTX_IS_ESTABLISHED(ctx)) + return GSS_S_NO_CONTEXT; + return gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, iov, iov_count, TOK_TYPE_WRAP); } diff --git a/util.h b/util.h index 6b647e3..f667440 100644 --- a/util.h +++ b/util.h @@ -88,8 +88,8 @@ enum gss_eap_token_type { TOK_TYPE_DELETE_CONTEXT = 0x0405, /* RFC 2743 delete context */ TOK_TYPE_EAP_RESP = 0x0601, /* draft-howlett-eap-gss */ TOK_TYPE_EAP_REQ = 0x0602, /* draft-howlett-eap-gss */ - TOK_TYPE_GSS_CB = 0x0603, /* draft-howlett-eap-gss */ - TOK_TYPE_KRB_CRED = 0x0604, /* to be specified */ + TOK_TYPE_EXT_REQ = 0x0603, /* draft-howlett-eap-gss */ + TOK_TYPE_EXT_RESP = 0x0604, /* to be specified */ TOK_TYPE_GSS_REAUTH = 0x0605, /* to be specified */ }; diff --git a/util_adshim.c b/util_adshim.c new file mode 100644 index 0000000..c0b6837 --- /dev/null +++ b/util_adshim.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2010, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" +#include "authdata_plugin.h" + +/* + * This rubbish is necessary because MIT doesn't provide another way + * to access verified AD-KDCIssued elements. We can't verify them + * ourselves because they're signed in the ticket session key, which + * is destroyed immediately after the AP-REQ is processed. + */ + +struct radius_ad_context { + krb5_data avpdata; + krb5_boolean verified; +}; + +static krb5_data radius_ad_attr = { + KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" }; + +static krb5_error_code +radius_ad_init(krb5_context kcontext, void **plugin_context) +{ + *plugin_context = 0; + return 0; +} + +static void +radius_ad_flags(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags) +{ + *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL; +} + +static void +radius_ad_fini(krb5_context kcontext, void *plugin_context) +{ + return; +} + +static krb5_error_code +radius_ad_request_init(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void **request_context) +{ + struct radius_ad_context *ctx; + + ctx = GSSEAP_CALLOC(1, sizeof(*ctx)); + if (ctx == NULL) + return ENOMEM; + + *request_context = ctx; + + return 0; +} + +static krb5_error_code +radius_ad_export_authdata(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***out_authdata) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + krb5_authdata *data[2]; + krb5_authdata datum; + + datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP; + datum.length = radius_ad->avpdata.length; + datum.contents = (krb5_octet *)radius_ad->avpdata.data; + + data[0] = &datum; + data[1] = NULL; + + return krb5_copy_authdata(kcontext, data, out_authdata); +} + +static krb5_error_code +radius_ad_import_authdata(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + krb5_free_data_contents(kcontext, &radius_ad->avpdata); + radius_ad->verified = FALSE; + + assert(authdata[0] != NULL); + + radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length); + if (radius_ad->avpdata.data == NULL) + return ENOMEM; + + memcpy(radius_ad->avpdata.data, authdata[0]->contents, + authdata[0]->length); + radius_ad->avpdata.length = authdata[0]->length; + + radius_ad->verified = kdc_issued_flag; + + return 0; +} + +static void +radius_ad_request_fini(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + if (radius_ad != NULL) { + krb5_free_data_contents(kcontext, &radius_ad->avpdata); + GSSEAP_FREE(radius_ad); + } +} + +static krb5_error_code +radius_ad_get_attribute(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + if (attribute->length != radius_ad_attr.length || + memcmp(attribute->data, radius_ad_attr.data, + radius_ad_attr.length) != 0) + return ENOENT; + + *authenticated = radius_ad->verified; + *complete = TRUE; + *more = 0; + + value->data = GSSEAP_MALLOC(radius_ad->avpdata.length); + if (value->data == NULL) + return ENOMEM; + + memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length); + value->length = radius_ad->avpdata.length; + + return 0; +} + +static krb5_error_code +radius_ad_copy(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context) +{ + struct radius_ad_context *radius_ad_src = + (struct radius_ad_context *)request_context; + struct radius_ad_context *radius_ad_dst = + (struct radius_ad_context *)dst_request_context; + + radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length); + if (radius_ad_dst->avpdata.data == NULL) + return ENOMEM; + + memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data, + radius_ad_src->avpdata.length); + radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length; + radius_ad_dst->verified = radius_ad_src->verified; + + return 0; +} + +static krb5_authdatatype radius_ad_ad_types[] = + { KRB5_AUTHDATA_RADIUS_AVP, 0 }; + +krb5plugin_authdata_client_ftable_v0 authdata_client_0 = { + "radius_ad", + radius_ad_ad_types, + radius_ad_init, + radius_ad_fini, + radius_ad_flags, + radius_ad_request_init, + radius_ad_request_fini, + NULL, + radius_ad_get_attribute, + NULL, + NULL, + radius_ad_export_authdata, + radius_ad_import_authdata, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + radius_ad_copy +}; diff --git a/util_reauth.c b/util_reauth.c index cd73da6..63b12d9 100644 --- a/util_reauth.c +++ b/util_reauth.c @@ -66,7 +66,7 @@ getAcceptorKey(krb5_context krbContext, if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) { code = krb5_kt_get_entry(krbContext, keytab, - cred->name->krbPrincipal, 0, + cred->name->krbPrincipal, 0, ctx->encryptionType, &ktent); if (code != 0) goto cleanup; @@ -104,7 +104,7 @@ cleanup: memset(key, 0, sizeof(key)); } - return code; + return code; } OM_uint32 @@ -124,10 +124,10 @@ gssEapMakeReauthCreds(OM_uint32 *minor, krb5_data *ticketData = NULL, *credsData = NULL; krb5_creds creds = { 0 }; krb5_auth_context authContext = NULL; - + credBuf->length = 0; credBuf->value = NULL; - + GSSEAP_KRB_INIT(&krbContext); code = getAcceptorKey(krbContext, ctx, cred, @@ -170,7 +170,12 @@ gssEapMakeReauthCreds(OM_uint32 *minor, authDatum.contents = attrBuf.value; authData[0] = &authDatum; authData[1] = NULL; - enc_part.authorization_data = authData; + + code = krb5_make_authdata_kdc_issued(krbContext, &session, + ticket.server, authData, + &enc_part.authorization_data); + if (code != 0) + goto cleanup; ticket.enc_part2 = &enc_part; @@ -217,6 +222,7 @@ cleanup: gss_release_buffer(minor, &attrBuf); krb5_free_data(krbContext, ticketData); krb5_auth_con_free(krbContext, authContext); + krb5_free_authdata(krbContext, enc_part.authorization_data); if (credsData != NULL) GSSEAP_FREE(credsData); @@ -408,6 +414,16 @@ static OM_uint32 (*gssStoreCredNext)( gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored); +static OM_uint32 (*gssGetNameAttributeNext)( + OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more); + #define NEXT_SYMBOL(local, global) ((local) = dlsym(RTLD_NEXT, (global))) OM_uint32 @@ -423,6 +439,7 @@ gssEapReauthInitialize(OM_uint32 *minor) NEXT_SYMBOL(gssImportNameNext, "gss_import_name"); NEXT_SYMBOL(gssKrbExtractAuthzDataFromSecContextNext, "gsskrb5_extract_authz_data_from_sec_context"); NEXT_SYMBOL(gssStoreCredNext, "gss_store_cred"); + NEXT_SYMBOL(gssGetNameAttributeNext, "gss_get_name_attribute"); return GSS_S_COMPLETE; } @@ -574,6 +591,68 @@ gssStoreCred(OM_uint32 *minor, } OM_uint32 +gssGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + if (gssGetNameAttributeNext == NULL) + return GSS_S_UNAVAILABLE; + + return gssGetNameAttributeNext(minor, name, attr, authenticated, complete, + value, display_value, more); +} + +static gss_buffer_desc radiusAvpKrbAttr = { + sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" +}; + +/* + * Unfortunately extracting an AD-KDCIssued authorization data element + * is pretty implementation-dependent. It's not possible to verify the + * signature ourselves because the ticket session key is not exposed + * outside GSS. In an ideal world, all AD-KDCIssued elements would be + * verified by the Kerberos library and authentication would fail if + * verification failed. We're not quite there yet and as a result have + * to go through some hoops to get this to work. The alternative would + * be to sign the authorization data with our long-term key, but it + * seems a pity to compromise the design because of current implementation + * limitations. + */ +OM_uint32 +defrostAttrContext(OM_uint32 *minor, + gss_name_t glueName, + gss_name_t mechName) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc authData = GSS_C_EMPTY_BUFFER; + gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER; + int more = -1; + int authenticated, complete; + + major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr, + &authenticated, &complete, + &authData, &authDataDisplay, &more); + if (major == GSS_S_COMPLETE) { + if (authenticated == 0) + major = GSS_S_BAD_NAME; + else + major = gssEapImportAttrContext(minor, &authData, mechName); + } else if (major == GSS_S_UNAVAILABLE) { + major = GSS_S_COMPLETE; + } + + gss_release_buffer(&tmpMinor, &authData); + gss_release_buffer(&tmpMinor, &authDataDisplay); + + return major; +} + +OM_uint32 gssEapGlueToMechName(OM_uint32 *minor, gss_name_t glueName, gss_name_t *pMechName) @@ -592,7 +671,16 @@ gssEapGlueToMechName(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; + major = defrostAttrContext(minor, glueName, *pMechName); + if (GSS_ERROR(major)) + goto cleanup; + cleanup: + if (GSS_ERROR(major)) { + gssReleaseName(&tmpMinor, pMechName); + *pMechName = GSS_C_NO_NAME; + } + gss_release_buffer(&tmpMinor, &nameBuf); return major; @@ -701,3 +789,4 @@ cleanup: return major; } + diff --git a/util_reauth.h b/util_reauth.h index e37dd49..241edce 100644 --- a/util_reauth.h +++ b/util_reauth.h @@ -101,6 +101,16 @@ gssStoreCred(OM_uint32 *minor, gss_cred_usage_t *cred_usage_stored); OM_uint32 +gssGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more); + +OM_uint32 gssEapMakeReauthCreds(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred, diff --git a/wrap.c b/wrap.c index 4208e91..f6542b7 100644 --- a/wrap.c +++ b/wrap.c @@ -41,13 +41,28 @@ gss_wrap(OM_uint32 *minor, int *conf_state, gss_buffer_t output_message_buffer) { + if (!CTX_IS_ESTABLISHED(ctx)) + return GSS_S_NO_CONTEXT; + + return gssEapWrap(minor, ctx, conf_req_flag, qop_req, + input_message_buffer, + conf_state, output_message_buffer); +} + +OM_uint32 +gssEapWrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + 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 major, tmpMinor; gss_iov_buffer_desc iov[4]; unsigned char *p; int i; - if (!CTX_IS_ESTABLISHED(ctx)) - return GSS_S_NO_CONTEXT; iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; iov[0].buffer.value = NULL; diff --git a/wrap_iov.c b/wrap_iov.c index 994dded..ae43ef9 100644 --- a/wrap_iov.c +++ b/wrap_iov.c @@ -105,21 +105,14 @@ gssEapWrapOrGetMIC(OM_uint32 *minor, flags = rfc4121Flags(ctx, FALSE); - switch (toktype) { - case TOK_TYPE_WRAP: + if (toktype == TOK_TYPE_WRAP) { keyUsage = CTX_IS_INITIATOR(ctx) ? KEY_USAGE_INITIATOR_SEAL : KEY_USAGE_ACCEPTOR_SEAL; - break; - case TOK_TYPE_GSS_CB: - keyUsage = KEY_USAGE_CHANNEL_BINDINGS; - break; - case TOK_TYPE_MIC: - default: + } else { keyUsage = CTX_IS_INITIATOR(ctx) ? KEY_USAGE_INITIATOR_SIGN : KEY_USAGE_ACCEPTOR_SIGN; - break; } gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen); @@ -295,8 +288,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor, if (code != 0) goto cleanup; - if (toktype != TOK_TYPE_GSS_CB) - ctx->sendSeq++; + ctx->sendSeq++; if (toktype == TOK_TYPE_WRAP) { /* Fix up EC field */ @@ -304,7 +296,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor, /* Fix up RRC field */ store_uint16_be(rrc, outbuf + 6); } - } else if (toktype == TOK_TYPE_MIC || toktype == TOK_TYPE_GSS_CB) { + } else if (toktype == TOK_TYPE_MIC) { trailer = NULL; goto wrap_with_checksum; } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { diff --git a/wrap_iov_length.c b/wrap_iov_length.c index c451cb2..33a15ef 100644 --- a/wrap_iov_length.c +++ b/wrap_iov_length.c @@ -80,8 +80,8 @@ gssEapWrapIovLength(OM_uint32 *minor, if (qop_req != GSS_C_QOP_DEFAULT) return GSS_S_FAILURE; - if (!CTX_IS_ESTABLISHED(ctx)) - return GSS_S_NO_CONTEXT; + if (ctx->encryptionType == ENCTYPE_NULL) + return GSS_S_UNAVAILABLE; GSSEAP_KRB_INIT(&krbContext); -- 2.1.4