From 2ad2836d1c8e4e158a7f042c49320a25a06ca288 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Tue, 8 Mar 2011 17:24:09 +1100 Subject: [PATCH] get GSS-EAP working again with TLV --- accept_sec_context.c | 86 ++++++++++++++++-------- gssapiP_eap.h | 13 ++-- gsseap_err.et | 1 + init_sec_context.c | 181 ++++++++++++++++++++++++++++++++------------------- util.h | 4 +- util_sm.c | 82 +++++++++++++++++------ util_token.c | 2 + 7 files changed, 249 insertions(+), 120 deletions(-) diff --git a/accept_sec_context.c b/accept_sec_context.c index d9e232e..8b6acf0 100644 --- a/accept_sec_context.c +++ b/accept_sec_context.c @@ -49,7 +49,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState); + OM_uint32 *smFlags); #endif /* @@ -139,7 +139,7 @@ eapGssSmAcceptIdentity(OM_uint32 *minor, gss_channel_bindings_t chanBindings __attribute__((__unused__)), gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; struct wpabuf *reqData; @@ -180,7 +180,7 @@ eapGssSmAcceptIdentity(OM_uint32 *minor, wpabuf_free(reqData); *minor = 0; - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION; return GSS_S_CONTINUE_NEEDED; } @@ -430,7 +430,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major, tmpMinor; struct rs_connection *rconn; @@ -538,7 +538,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION; } major = GSS_S_CONTINUE_NEEDED; @@ -564,7 +564,7 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major, tmpMinor; gss_iov_buffer_desc iov[2]; @@ -585,6 +585,9 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) { major = GSS_S_BAD_BINDINGS; *minor = GSSEAP_BINDINGS_MISMATCH; + } else { + major = GSS_S_CONTINUE_NEEDED; + *minor = 0; } gss_release_buffer(&tmpMinor, &iov[0].buffer); @@ -592,6 +595,24 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, return major; } +static OM_uint32 +eapGssSmAcceptCompleteInitiatorExts(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target __attribute__((__unused__)), + gss_OID mech __attribute__((__unused__)), + OM_uint32 reqFlags __attribute__((__unused__)), + OM_uint32 timeReq __attribute__((__unused__)), + gss_channel_bindings_t chanBindings __attribute__((__unused__)), + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + *minor = 0; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; + return GSS_S_CONTINUE_NEEDED; +} + #ifdef GSSEAP_ENABLE_REAUTH static OM_uint32 eapGssSmAcceptReauthCreds(OM_uint32 *minor, @@ -604,7 +625,7 @@ eapGssSmAcceptReauthCreds(OM_uint32 *minor, gss_channel_bindings_t chanBindings __attribute__((__unused__)), gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; @@ -621,20 +642,20 @@ eapGssSmAcceptReauthCreds(OM_uint32 *minor, #endif static OM_uint32 -eapGssSmAcceptNegoExtFinished(OM_uint32 *minor, - gss_cred_id_t cred, - gss_ctx_id_t ctx, - gss_name_t target __attribute__((__unused__)), - gss_OID mech __attribute__((__unused__)), - OM_uint32 reqFlags __attribute__((__unused__)), - OM_uint32 timeReq __attribute__((__unused__)), - gss_channel_bindings_t chanBindings __attribute__((__unused__)), - gss_buffer_t inputToken, - gss_buffer_t outputToken, - int *transitionState) +eapGssSmAcceptCompleteAcceptorExts(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target __attribute__((__unused__)), + gss_OID mech __attribute__((__unused__)), + OM_uint32 reqFlags __attribute__((__unused__)), + OM_uint32 timeReq __attribute__((__unused__)), + gss_channel_bindings_t chanBindings __attribute__((__unused__)), + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags) { *minor = 0; - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; return GSS_S_COMPLETE; } @@ -668,16 +689,24 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { { ITOK_TYPE_GSS_CHANNEL_BINDINGS, ITOK_TYPE_NONE, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_INITIATOR_EXTS, 1, /* critical */ 1, /* required */ eapGssSmAcceptGssChannelBindings, }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + 1, /* critical */ + 1, /* required */ + eapGssSmAcceptCompleteInitiatorExts, + }, #ifdef GSSEAP_ENABLE_REAUTH { ITOK_TYPE_NONE, ITOK_TYPE_REAUTH_CREDS, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_ACCEPTOR_EXTS, 0, /* critical */ 0, /* required */ eapGssSmAcceptReauthCreds, @@ -686,10 +715,10 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { { ITOK_TYPE_NONE, ITOK_TYPE_NONE, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_ACCEPTOR_EXTS, 1, /* critical */ 1, /* required */ - eapGssSmAcceptNegoExtFinished + eapGssSmAcceptCompleteAcceptorExts }, }; @@ -827,10 +856,8 @@ acceptReadyKrb(OM_uint32 *minor, if (GSS_ERROR(major)) return major; - ctx->state = GSSEAP_STATE_NEGO_EXT; /* skip */ - *minor = 0; - return GSS_S_COMPLETE; /* advance state */ + return GSS_S_COMPLETE; } static OM_uint32 @@ -844,7 +871,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major, tmpMinor; gss_name_t krbInitiator = GSS_C_NO_NAME; @@ -873,7 +900,10 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor, if (major == GSS_S_COMPLETE) { major = acceptReadyKrb(minor, ctx, cred, krbInitiator, mech, timeRec); - *transitionState = 1; + if (major == GSS_S_COMPLETE) { + ctx->state = GSSEAP_STATE_ACCEPTOR_EXTS; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; + } } ctx->gssFlags = gssFlags; diff --git a/gssapiP_eap.h b/gssapiP_eap.h index 884ed86..290da74 100644 --- a/gssapiP_eap.h +++ b/gssapiP_eap.h @@ -143,9 +143,10 @@ struct gss_cred_id_struct enum gss_eap_state { GSSEAP_STATE_INITIAL = 0x01, /* initial state */ GSSEAP_STATE_AUTHENTICATE = 0x02, /* exchange EAP messages */ - GSSEAP_STATE_NEGO_EXT = 0x04, /* negotiate extensions */ - GSSEAP_STATE_ESTABLISHED = 0x08, /* context established */ - GSSEAP_STATE_ALL = 0x0F + GSSEAP_STATE_INITIATOR_EXTS = 0x04, /* initiator extensions */ + GSSEAP_STATE_ACCEPTOR_EXTS = 0x08, /* acceptor extensions */ + GSSEAP_STATE_ESTABLISHED = 0x10, /* context established */ + GSSEAP_STATE_ALL = 0x1F }; #define GSSEAP_STATE_NEXT(s) ((s) << 1) @@ -167,9 +168,13 @@ struct gss_eap_sm { gss_channel_bindings_t, gss_buffer_t, gss_buffer_t, - int *); + OM_uint32 *); }; +#define SM_FLAG_TRANSITION 0x00000001 +#define SM_FLAG_FORCE_SEND_TOKEN 0x00000002 +#define SM_FLAG_STOP_EVAL 0x00000004 + #define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == GSSEAP_STATE_ESTABLISHED) /* Initiator context flags */ diff --git a/gsseap_err.et b/gsseap_err.et index 0a34d12..369d2b8 100644 --- a/gsseap_err.et +++ b/gsseap_err.et @@ -95,6 +95,7 @@ error_code GSSEAP_BAD_PRF_KEY, "PRF key usage type is unknown" # error_code GSSEAP_LIBEAP_INIT_FAILURE, "Failed to initialize EAP library" error_code GSSEAP_PEER_SM_INIT_FAILURE, "Failed to create EAP state machine" +error_code GSSEAP_PEER_SM_STEP_FAILURE, "Failed to step EAP state machine" error_code GSSEAP_PEER_AUTH_FAILURE, "EAP peer authentication failure" error_code GSSEAP_PEER_BAD_MESSAGE, "Received bad EAP message" diff --git a/init_sec_context.c b/init_sec_context.c index 56bbd6c..5d3ebb7 100644 --- a/init_sec_context.c +++ b/init_sec_context.c @@ -392,7 +392,7 @@ eapGssSmInitError(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; unsigned char *p; @@ -429,7 +429,7 @@ eapGssSmInitGssReauth(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major, tmpMinor; gss_name_t mechTarget = GSS_C_NO_NAME; @@ -481,10 +481,10 @@ eapGssSmInitGssReauth(OM_uint32 *minor, major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec); if (GSS_ERROR(major)) goto cleanup; - ctx->state = GSSEAP_STATE_NEGO_EXT; /* skip */ + ctx->state = GSSEAP_STATE_ACCEPTOR_EXTS; } - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; cleanup: gssReleaseName(&tmpMinor, &mechTarget); @@ -493,6 +493,30 @@ cleanup: } #endif /* GSSEAP_ENABLE_REAUTH */ +#ifdef GSSEAP_DEBUG +static OM_uint32 +eapGssSmInitVendorInfo(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 *smFlags) +{ + OM_uint32 major; + + major = makeStringBuffer(minor, "JANET(UK)", outputToken); + if (GSS_ERROR(major)) + return major; + + return GSS_S_CONTINUE_NEEDED; +} +#endif + static OM_uint32 eapGssSmInitIdentity(OM_uint32 *minor, gss_cred_id_t cred, @@ -504,18 +528,13 @@ eapGssSmInitIdentity(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; - int initialContextToken; + struct eap_config eapConfig; assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0); - - initialContextToken = (inputToken->length == 0); - if (!initialContextToken) { - *minor = GSSEAP_WRONG_SIZE; - return GSS_S_DEFECTIVE_TOKEN; - } + assert(inputToken == GSS_C_NO_BUFFER); major = initBegin(minor, cred, ctx, target, mech, reqFlags, timeReq, chanBindings, @@ -523,17 +542,32 @@ eapGssSmInitIdentity(OM_uint32 *minor, if (GSS_ERROR(major)) return major; - outputToken->length = 0; - outputToken->value = NULL; + memset(&eapConfig, 0, sizeof(eapConfig)); + + ctx->initiatorCtx.eap = eap_peer_sm_init(ctx, + &gssEapPolicyCallbacks, + ctx, + &eapConfig); + if (ctx->initiatorCtx.eap == NULL) { + *minor = GSSEAP_PEER_SM_INIT_FAILURE; + return GSS_S_FAILURE; + } + + ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED; + + /* poke EAP state machine */ + if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) { + *minor = GSSEAP_PEER_SM_STEP_FAILURE; + return GSS_S_FAILURE; + } + /* force sending of empty token */ *minor = 0; - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_FORCE_SEND_TOKEN; - return GSS_S_COMPLETE; + return GSS_S_CONTINUE_NEEDED; } -static struct wpabuf emptyWpaBuffer; - static OM_uint32 eapGssSmInitAuthenticate(OM_uint32 *minor, gss_cred_id_t cred, @@ -545,48 +579,31 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; OM_uint32 tmpMinor; int code; struct wpabuf *resp = NULL; - int initialContextToken; *minor = 0; - initialContextToken = (inputToken == GSS_C_NO_BUFFER || - inputToken->length == 0); + assert(inputToken != GSS_C_NO_BUFFER); major = peerConfigInit(minor, cred, ctx); if (GSS_ERROR(major)) goto cleanup; - if (ctx->initiatorCtx.eap == NULL) { - struct eap_config eapConfig; - - memset(&eapConfig, 0, sizeof(eapConfig)); - - ctx->initiatorCtx.eap = eap_peer_sm_init(ctx, - &gssEapPolicyCallbacks, - ctx, - &eapConfig); - if (ctx->initiatorCtx.eap == NULL) { - major = GSS_S_FAILURE; - *minor = GSSEAP_PEER_SM_INIT_FAILURE; - goto cleanup; - } - - ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED; - } + assert(ctx->initiatorCtx.eap != NULL); + assert(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED); ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */ - major = GSS_S_CONTINUE_NEEDED; - wpabuf_set(&ctx->initiatorCtx.reqData, inputToken->value, inputToken->length); + major = GSS_S_CONTINUE_NEEDED; + code = eap_peer_sm_step(ctx->initiatorCtx.eap); if (ctx->flags & CTX_FLAG_EAP_RESP) { ctx->flags &= ~(CTX_FLAG_EAP_RESP); @@ -598,12 +615,11 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, goto cleanup; ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); - *transitionState = 1; + major = GSS_S_CONTINUE_NEEDED; + *smFlags |= SM_FLAG_TRANSITION; } else if (ctx->flags & CTX_FLAG_EAP_FAIL) { major = GSS_S_DEFECTIVE_CREDENTIAL; *minor = GSSEAP_PEER_AUTH_FAILURE; - } else if (code == 0 && initialContextToken) { - /* */ } else { major = GSS_S_DEFECTIVE_TOKEN; *minor = GSSEAP_PEER_BAD_MESSAGE; @@ -614,7 +630,7 @@ cleanup: OM_uint32 tmpMajor; gss_buffer_desc respBuf; - assert(!GSS_ERROR(major)); + assert(major == GSS_S_CONTINUE_NEEDED); respBuf.length = wpabuf_len(resp); respBuf.value = (void *)wpabuf_head(resp); @@ -643,7 +659,7 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; @@ -674,7 +690,7 @@ eapGssSmInitReauthCreds(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t inputToken, gss_buffer_t outputToken, - int *transitionState) + OM_uint32 *smFlags) { OM_uint32 major; @@ -688,28 +704,45 @@ eapGssSmInitReauthCreds(OM_uint32 *minor, #endif /* GSSEAP_ENABLE_REAUTH */ static OM_uint32 -eapGssSmInitNegoExtFinished(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, - int *transitionState) +eapGssSmInitCompleteAcceptorExts(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 *smFlags) { *minor = 0; - *transitionState = 1; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; return GSS_S_COMPLETE; } +static OM_uint32 +eapGssSmInitCompleteInitiatorExts(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 *smFlags) +{ + *minor = 0; + *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL; + return GSS_S_CONTINUE_NEEDED; +} static struct gss_eap_sm eapGssInitiatorSm[] = { { ITOK_TYPE_CONTEXT_ERR, ITOK_TYPE_NONE, - GSSEAP_STATE_ALL, + GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL), 1, /* critical */ 0, /* required */ eapGssSmInitError, @@ -724,6 +757,16 @@ static struct gss_eap_sm eapGssInitiatorSm[] = { eapGssSmInitGssReauth, }, #endif +#if 0 + { + ITOK_TYPE_NONE, + ITOK_TYPE_VENDOR_INFO, + GSSEAP_STATE_INITIAL, + 0, /* critical */ + 0, /* required */ + eapGssSmInitVendorInfo, + }, +#endif { ITOK_TYPE_NONE, ITOK_TYPE_NONE, @@ -743,16 +786,24 @@ static struct gss_eap_sm eapGssInitiatorSm[] = { { ITOK_TYPE_NONE, ITOK_TYPE_GSS_CHANNEL_BINDINGS, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_INITIATOR_EXTS, 1, /* critical */ 1, /* required */ eapGssSmInitGssChannelBindings, }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + 1, /* critical */ + 1, /* required */ + eapGssSmInitCompleteInitiatorExts + }, #ifdef GSSEAP_ENABLE_REAUTH { ITOK_TYPE_REAUTH_CREDS, ITOK_TYPE_NONE, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_ACCEPTOR_EXTS, 0, /* critical */ 0, /* required */ eapGssSmInitReauthCreds, @@ -762,10 +813,10 @@ static struct gss_eap_sm eapGssInitiatorSm[] = { { ITOK_TYPE_NONE, ITOK_TYPE_NONE, - GSSEAP_STATE_NEGO_EXT, + GSSEAP_STATE_ACCEPTOR_EXTS, 1, /* critical */ 1, /* required */ - eapGssSmInitNegoExtFinished + eapGssSmInitCompleteAcceptorExts } }; @@ -786,7 +837,6 @@ gss_init_sec_context(OM_uint32 *minor, { OM_uint32 major, tmpMinor; gss_ctx_id_t ctx = *context_handle; - int initialContextToken = 0; *minor = 0; @@ -805,7 +855,6 @@ gss_init_sec_context(OM_uint32 *minor, ctx->flags |= CTX_FLAG_INITIATOR; - initialContextToken = 1; *context_handle = ctx; } diff --git a/util.h b/util.h index 7f433e9..b081cce 100644 --- a/util.h +++ b/util.h @@ -168,11 +168,13 @@ enum gss_eap_token_type { #define ITOK_TYPE_REAUTH_CREDS 0x00000007 #define ITOK_TYPE_REAUTH_REQ 0x00000008 #define ITOK_TYPE_REAUTH_RESP 0x00000009 +#define ITOK_TYPE_VERSION_INFO 0x0000000A +#define ITOK_TYPE_VENDOR_INFO 0x0000000B #define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */ #define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */ -#define ITOK_TYPE_MASK (~(EXT_FLAG_CRITICAL | EXT_FLAG_VERIFIED)) +#define ITOK_TYPE_MASK (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED)) OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx); OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx); diff --git a/util_sm.c b/util_sm.c index 71783e2..17af663 100644 --- a/util_sm.c +++ b/util_sm.c @@ -36,6 +36,35 @@ #include "gssapiP_eap.h" +static const char * +gssEapStateToString(enum gss_eap_state state) +{ + const char *s; + + switch (state) { + case GSSEAP_STATE_INITIAL: + s = "INITIAL"; + break; + case GSSEAP_STATE_AUTHENTICATE: + s = "AUTHENTICATE"; + break; + case GSSEAP_STATE_INITIATOR_EXTS: + s = "INITIATOR_EXTS"; + break; + case GSSEAP_STATE_ACCEPTOR_EXTS: + s = "ACCEPTOR_EXTS"; + break; + case GSSEAP_STATE_ESTABLISHED: + s = "ESTABLISHED"; + break; + default: + s = "INVALID"; + break; + } + + return s; +} + static OM_uint32 makeErrorToken(OM_uint32 *minor, OM_uint32 majorStatus, @@ -90,8 +119,9 @@ gssEapSmStep(OM_uint32 *minor, gss_buffer_set_t innerInputTokens = GSS_C_NO_BUFFER_SET; gss_buffer_set_t innerOutputTokens = GSS_C_NO_BUFFER_SET; OM_uint32 *inputTokenTypes = NULL, *outputTokenTypes = NULL; + unsigned int smFlags = 0; size_t i, j; - enum gss_eap_state inputState = ctx->state; + int initialContextToken = 0; assert(smCount > 0); @@ -117,6 +147,8 @@ gssEapSmStep(OM_uint32 *minor, major = GSS_S_DEFECTIVE_TOKEN; *minor = GSSEAP_WRONG_SIZE; goto cleanup; + } else { + initialContextToken = 1; } if (ctx->state == GSSEAP_STATE_ESTABLISHED) { @@ -132,6 +164,8 @@ gssEapSmStep(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; + assert(innerInputTokens != GSS_C_NO_BUFFER_SET); + major = gss_create_empty_buffer_set(minor, &innerOutputTokens); if (GSS_ERROR(major)) goto cleanup; @@ -161,8 +195,6 @@ gssEapSmStep(OM_uint32 *minor, * is reached. */ do { - int transitionState = 0; - major = GSS_S_COMPLETE; for (i = 0; i < smCount; i++) { @@ -175,17 +207,17 @@ gssEapSmStep(OM_uint32 *minor, if ((smp->validStates & ctx->state) == 0) continue; - if (innerInputTokens == GSS_C_NO_BUFFER_SET) { - processToken = ((smp->validStates & GSSEAP_STATE_INITIAL) != 0); - } else if (inputState != ctx->state) { - processToken = (smp->inputTokenType == ITOK_TYPE_NONE); - } else { + if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) { + processToken = 1; + } else if ((smFlags & SM_FLAG_TRANSITION) == 0) { for (j = 0; j < innerInputTokens->count; j++) { - processToken = (smp->inputTokenType == inputTokenTypes[j]); - if (innerInputToken != GSS_C_NO_BUFFER && processToken) { - major = GSS_S_DEFECTIVE_TOKEN; - *minor = GSSEAP_DUPLICATE_ITOK; - break; + if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) { + processToken = 1; + if (innerInputToken != GSS_C_NO_BUFFER) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_DUPLICATE_ITOK; + break; + } } innerInputToken = &innerInputTokens->elements[j]; inputTokenType = &inputTokenTypes[j]; @@ -200,9 +232,11 @@ gssEapSmStep(OM_uint32 *minor, #endif if (processToken) { + smFlags = 0; + major = smp->processToken(minor, cred, ctx, target, mech, reqFlags, timeReq, chanBindings, innerInputToken, - &innerOutputToken, &transitionState); + &innerOutputToken, &smFlags); if (GSS_ERROR(major)) break; @@ -217,7 +251,7 @@ gssEapSmStep(OM_uint32 *minor, outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL; innerOutputTokens->count++; } - if (transitionState) + if (smFlags & SM_FLAG_STOP_EVAL) break; } else if (smp->required && smp->inputTokenType != ITOK_TYPE_NONE) { major = GSS_S_DEFECTIVE_TOKEN; @@ -226,15 +260,21 @@ gssEapSmStep(OM_uint32 *minor, } } - if (GSS_ERROR(major) || !transitionState) + if (GSS_ERROR(major) || (smFlags & SM_FLAG_TRANSITION) == 0) break; assert(ctx->state < GSSEAP_STATE_ESTABLISHED); +#ifdef GSSEAP_DEBUG + fprintf(stderr, "GSS-EAP: state transition %s->%s\n", + gssEapStateToString(ctx->state), + gssEapStateToString(GSSEAP_STATE_NEXT(ctx->state))); +#endif + ctx->state = GSSEAP_STATE_NEXT(ctx->state); - if (innerOutputTokens->count != 0) { - assert(major == GSS_S_CONTINUE_NEEDED); + if (innerOutputTokens->count != 0 || (smFlags & SM_FLAG_FORCE_SEND_TOKEN)) { + assert(major == GSS_S_CONTINUE_NEEDED || ctx->state == GSSEAP_STATE_ESTABLISHED); break; /* send any tokens if we have them */ } } while (ctx->state != GSSEAP_STATE_ESTABLISHED); @@ -242,7 +282,7 @@ gssEapSmStep(OM_uint32 *minor, assert(innerOutputTokens->count <= smCount); /* Check we understood all critical tokens */ - if (!GSS_ERROR(major) && innerInputTokens != GSS_C_NO_BUFFER_SET) { + if (!GSS_ERROR(major)) { for (j = 0; j < innerInputTokens->count; j++) { if ((inputTokenTypes[j] & ITOK_FLAG_CRITICAL) && (inputTokenTypes[j] & ITOK_FLAG_VERIFIED) == 0) { @@ -273,7 +313,7 @@ gssEapSmStep(OM_uint32 *minor, #ifdef GSSEAP_DEBUG for (i = 0; i < innerOutputTokens->count; i++) { - fprintf(stderr, "GSS-EAP: type %d length %zd value %p\n", + fprintf(stderr, "GSS-EAP: type %08x length %zd value %p\n", outputTokenTypes[i], innerOutputTokens->elements[i].length, innerOutputTokens->elements[i].value); @@ -298,7 +338,7 @@ gssEapSmStep(OM_uint32 *minor, } assert(GSS_ERROR(major) || - (major == GSS_S_CONTINUE_NEEDED && ctx->state < GSSEAP_STATE_ESTABLISHED) || + (major == GSS_S_CONTINUE_NEEDED && (ctx->state > GSSEAP_STATE_INITIAL && ctx->state < GSSEAP_STATE_ESTABLISHED)) || (major == GSS_S_COMPLETE && ctx->state == GSSEAP_STATE_ESTABLISHED)); cleanup: diff --git a/util_token.c b/util_token.c index dab1251..a929198 100644 --- a/util_token.c +++ b/util_token.c @@ -307,6 +307,8 @@ der_read_length(unsigned char **buf, ssize_t *bufsize) size_t tokenSize(const gss_OID_desc *mech, size_t body_size) { + assert(mech != GSS_C_NO_OID); + /* set body_size to sequence contents size */ body_size += 4 + (size_t) mech->length; /* NEED overflow check */ return 1 + der_length_size(body_size) + body_size; -- 2.1.4