From 8511f1fd55fb0501adcd3c9719b1dd1e1a336a2b Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Thu, 19 May 2011 17:14:48 +0200 Subject: [PATCH] integrity protect extension token exchange --- mech_eap/accept_sec_context.c | 97 ++++++++++++++----------- mech_eap/gssapiP_eap.h | 2 + mech_eap/init_sec_context.c | 84 ++++++++++++---------- mech_eap/util.h | 35 +++++++-- mech_eap/util_context.c | 126 +++++++++++++++++++++++++++++++++ mech_eap/util_sm.c | 135 ++++++++++++----------------------- mech_eap/util_token.c | 160 +++++++++++++++++++++++++++++------------- 7 files changed, 418 insertions(+), 221 deletions(-) diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c index fe54b11..c2daf5a 100644 --- a/mech_eap/accept_sec_context.c +++ b/mech_eap/accept_sec_context.c @@ -662,20 +662,26 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, gss_buffer_t outputToken GSSEAP_UNUSED, OM_uint32 *smFlags GSSEAP_UNUSED) { - OM_uint32 major, tmpMinor; + OM_uint32 major; gss_iov_buffer_desc iov[2]; 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_STREAM; - iov[1].buffer = *inputToken; + iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED; + + /* XXX necessary because decrypted in place and we verify it later */ + major = duplicateBuffer(minor, inputToken, &iov[1].buffer); + if (GSS_ERROR(major)) + return major; major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, iov, 2, TOK_TYPE_WRAP); - if (GSS_ERROR(major)) + if (GSS_ERROR(major)) { + gssEapReleaseIov(iov, 2); return major; + } if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS && !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) { @@ -686,11 +692,36 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, *minor = 0; } - gss_release_buffer(&tmpMinor, &iov[0].buffer); + gssEapReleaseIov(iov, 2); return major; } +static OM_uint32 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + major = gssEapVerifyTokenMIC(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} + #ifdef GSSEAP_ENABLE_REAUTH static OM_uint32 eapGssSmAcceptReauthCreds(OM_uint32 *minor, @@ -722,42 +753,28 @@ eapGssSmAcceptReauthCreds(OM_uint32 *minor, #endif static OM_uint32 -eapGssSmAcceptCompleteInitiatorExts(OM_uint32 *minor, - gss_cred_id_t cred GSSEAP_UNUSED, - gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, - gss_OID mech GSSEAP_UNUSED, - OM_uint32 reqFlags GSSEAP_UNUSED, - OM_uint32 timeReq GSSEAP_UNUSED, - gss_channel_bindings_t chanBindings GSSEAP_UNUSED, - gss_buffer_t inputToken GSSEAP_UNUSED, - gss_buffer_t outputToken GSSEAP_UNUSED, - OM_uint32 *smFlags GSSEAP_UNUSED) +eapGssSmAcceptAcceptorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) { - GSSEAP_SM_TRANSITION_NEXT(ctx); - - *minor = 0; + OM_uint32 major; - return GSS_S_CONTINUE_NEEDED; -} + major = gssEapMakeTokenMIC(minor, ctx, outputToken); + if (GSS_ERROR(major)) + return major; -static OM_uint32 -eapGssSmAcceptCompleteAcceptorExts(OM_uint32 *minor, - gss_cred_id_t cred GSSEAP_UNUSED, - gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, - gss_OID mech GSSEAP_UNUSED, - OM_uint32 reqFlags GSSEAP_UNUSED, - OM_uint32 timeReq GSSEAP_UNUSED, - gss_channel_bindings_t chanBindings GSSEAP_UNUSED, - gss_buffer_t inputToken GSSEAP_UNUSED, - gss_buffer_t outputToken GSSEAP_UNUSED, - OM_uint32 *smFlags) -{ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); *minor = 0; - *smFlags |= SM_FLAG_FORCE_SEND_TOKEN; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; return GSS_S_COMPLETE; } @@ -817,11 +834,11 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { eapGssSmAcceptGssChannelBindings, }, { - ITOK_TYPE_NONE, + ITOK_TYPE_INITIATOR_MIC, ITOK_TYPE_NONE, GSSEAP_STATE_INITIATOR_EXTS, - 0, - eapGssSmAcceptCompleteInitiatorExts, + SM_ITOK_FLAG_REQUIRED, + eapGssSmAcceptInitiatorMIC, }, #ifdef GSSEAP_ENABLE_REAUTH { @@ -834,10 +851,10 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { #endif { ITOK_TYPE_NONE, - ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_MIC, GSSEAP_STATE_ACCEPTOR_EXTS, 0, - eapGssSmAcceptCompleteAcceptorExts + eapGssSmAcceptAcceptorMIC }, }; diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h index 8bad9a8..fc22246 100644 --- a/mech_eap/gssapiP_eap.h +++ b/mech_eap/gssapiP_eap.h @@ -207,6 +207,8 @@ struct gss_ctx_id_struct #define reauthCtx ctxU.reauth #endif } ctxU; + const struct gss_eap_token_buffer_set *inputTokens; + const struct gss_eap_token_buffer_set *outputTokens; }; #define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01 diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c index a8b7db0..1945f09 100644 --- a/mech_eap/init_sec_context.c +++ b/mech_eap/init_sec_context.c @@ -770,6 +770,33 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor, return GSS_S_CONTINUE_NEEDED; } +static OM_uint32 +eapGssSmInitInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + + major = gssEapMakeTokenMIC(minor, ctx, outputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + return GSS_S_CONTINUE_NEEDED; +} + #ifdef GSSEAP_ENABLE_REAUTH static OM_uint32 eapGssSmInitReauthCreds(OM_uint32 *minor, @@ -798,39 +825,24 @@ eapGssSmInitReauthCreds(OM_uint32 *minor, #endif /* GSSEAP_ENABLE_REAUTH */ static OM_uint32 -eapGssSmInitCompleteInitiatorExts(OM_uint32 *minor, - gss_cred_id_t cred GSSEAP_UNUSED, - gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, - gss_OID mech GSSEAP_UNUSED, - OM_uint32 reqFlags GSSEAP_UNUSED, - OM_uint32 timeReq GSSEAP_UNUSED, - gss_channel_bindings_t chanBindings GSSEAP_UNUSED, - gss_buffer_t inputToken GSSEAP_UNUSED, - gss_buffer_t outputToken GSSEAP_UNUSED, - OM_uint32 *smFlags) +eapGssSmInitAcceptorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) { - GSSEAP_SM_TRANSITION_NEXT(ctx); - - *minor = 0; - *smFlags |= SM_FLAG_FORCE_SEND_TOKEN; + OM_uint32 major; - return GSS_S_CONTINUE_NEEDED; -} + major = gssEapVerifyTokenMIC(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; -static OM_uint32 -eapGssSmInitCompleteAcceptorExts(OM_uint32 *minor, - gss_cred_id_t cred GSSEAP_UNUSED, - gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, - gss_OID mech GSSEAP_UNUSED, - OM_uint32 reqFlags GSSEAP_UNUSED, - OM_uint32 timeReq GSSEAP_UNUSED, - gss_channel_bindings_t chanBindings GSSEAP_UNUSED, - gss_buffer_t inputToken GSSEAP_UNUSED, - gss_buffer_t outputToken GSSEAP_UNUSED, - OM_uint32 *smFlags GSSEAP_UNUSED) -{ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); *minor = 0; @@ -904,10 +916,10 @@ static struct gss_eap_sm eapGssInitiatorSm[] = { }, { ITOK_TYPE_NONE, - ITOK_TYPE_NONE, + ITOK_TYPE_INITIATOR_MIC, GSSEAP_STATE_INITIATOR_EXTS, - 0, - eapGssSmInitCompleteInitiatorExts + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitInitiatorMIC }, #ifdef GSSEAP_ENABLE_REAUTH { @@ -920,11 +932,11 @@ static struct gss_eap_sm eapGssInitiatorSm[] = { #endif /* other extensions go here */ { - ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_MIC, ITOK_TYPE_NONE, GSSEAP_STATE_ACCEPTOR_EXTS, - 0, - eapGssSmInitCompleteAcceptorExts + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitAcceptorMIC } }; diff --git a/mech_eap/util.h b/mech_eap/util.h index ae2045c..1d4e47c 100644 --- a/mech_eap/util.h +++ b/mech_eap/util.h @@ -177,7 +177,9 @@ enum gss_eap_token_type { #define ITOK_TYPE_REAUTH_RESP 0x00000009 /* optional */ #define ITOK_TYPE_VERSION_INFO 0x0000000A /* optional */ #define ITOK_TYPE_VENDOR_INFO 0x0000000B /* optional */ -#define ITOK_TYPE_GSS_FLAGS 0x0000000C +#define ITOK_TYPE_GSS_FLAGS 0x0000000C /* optional */ +#define ITOK_TYPE_INITIATOR_MIC 0x0000000D /* critical, required, if not reauth */ +#define ITOK_TYPE_ACCEPTOR_MIC 0x0000000E /* TBD */ #define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */ #define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */ @@ -208,6 +210,16 @@ gssEapContextTime(OM_uint32 *minor, gss_ctx_id_t context_handle, OM_uint32 *time_rec); +OM_uint32 +gssEapMakeTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC); + +OM_uint32 +gssEapVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t tokenMIC); + /* util_cred.c */ OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred); OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred); @@ -641,16 +653,29 @@ void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state); /* util_token.c */ +struct gss_eap_token_buffer_set { + gss_buffer_set_desc buffers; /* pointers only */ + OM_uint32 *types; +}; + OM_uint32 gssEapEncodeInnerTokens(OM_uint32 *minor, - gss_buffer_set_t extensions, - OM_uint32 *types, + struct gss_eap_token_buffer_set *tokens, gss_buffer_t buffer); OM_uint32 gssEapDecodeInnerTokens(OM_uint32 *minor, const gss_buffer_t buffer, - gss_buffer_set_t *pExtensions, - OM_uint32 **pTypes); + struct gss_eap_token_buffer_set *tokens); + +OM_uint32 +gssEapReleaseInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + int freeBuffers); + +OM_uint32 +gssEapAllocInnerTokens(OM_uint32 *minor, + size_t count, + struct gss_eap_token_buffer_set *tokens); size_t tokenSize(const gss_OID_desc *mech, size_t body_size); diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c index e9a9308..5c6bbc8 100644 --- a/mech_eap/util_context.c +++ b/mech_eap/util_context.c @@ -227,3 +227,129 @@ gssEapContextTime(OM_uint32 *minor, return GSS_S_COMPLETE; } + +static OM_uint32 +gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC, + int verifyMIC) +{ + OM_uint32 major; + gss_iov_buffer_desc *iov; + size_t i = 0, j; + enum gss_eap_token_type tokType; + OM_uint32 micTokType; + unsigned char wireTokType[2]; + unsigned char *innerTokTypes; + const struct gss_eap_token_buffer_set *tokens; + + tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens; + + assert(tokens != NULL); + + iov = GSSEAP_CALLOC(2 + (2 * tokens->buffers.count) + 1, sizeof(*iov)); + if (iov == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count); + if (innerTokTypes == NULL) { + GSSEAP_FREE(iov); + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + /* Mechanism OID */ + assert(ctx->mechanismUsed != GSS_C_NO_OID); + iov[i].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[i].buffer.length = ctx->mechanismUsed->length; + iov[i].buffer.value = ctx->mechanismUsed->elements; + i++; + + /* Token type */ + if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) { + tokType = TOK_TYPE_INITIATOR_CONTEXT; + micTokType = ITOK_TYPE_INITIATOR_MIC; + } else { + tokType = TOK_TYPE_ACCEPTOR_CONTEXT; + micTokType = ITOK_TYPE_ACCEPTOR_MIC; + } + store_uint16_be(tokType, wireTokType); + + iov[i].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[i].buffer.length = sizeof(wireTokType); + iov[i].buffer.value = wireTokType; + i++; + + for (j = 0; j < tokens->buffers.count; j++) { + if (verifyMIC && + (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) + continue; /* will use this slot for trailer */ + + iov[i].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[i].buffer.length = 4; + iov[i].buffer.value = &innerTokTypes[j * 4]; + store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED), + iov[i].buffer.value); + i++; + + iov[i].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[i].buffer = tokens->buffers.elements[j]; + i++; + } + + if (verifyMIC) { + assert(tokenMIC->length >= 16); + + assert(i < 2 + (2 * tokens->buffers.count)); + + iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[i].buffer.length = 16; + iov[i].buffer.value = tokenMIC->value; + i++; + + iov[i].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[i].buffer.length = tokenMIC->length - 16; + iov[i].buffer.value = (unsigned char *)tokenMIC->value + 16; + i++; + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, + iov, i, TOK_TYPE_MIC); + } else { + iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, + iov, i, TOK_TYPE_MIC); + if (!GSS_ERROR(major)) + *tokenMIC = iov[i - 1].buffer; + } + + gssEapReleaseIov(iov, tokens->buffers.count); + GSSEAP_FREE(innerTokTypes); + + return major; +} + +OM_uint32 +gssEapMakeTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC) +{ + tokenMIC->length = 0; + tokenMIC->value = NULL; + + return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE); +} + +OM_uint32 +gssEapVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t tokenMIC) +{ + if (tokenMIC->length < 16) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_BAD_SIG; + } + + return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE); +} diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c index ca69923..8d36085 100644 --- a/mech_eap/util_sm.c +++ b/mech_eap/util_sm.c @@ -98,18 +98,14 @@ static OM_uint32 makeErrorToken(OM_uint32 *minor, OM_uint32 majorStatus, OM_uint32 minorStatus, - gss_buffer_set_t *outputToken) + struct gss_eap_token_buffer_set *token) { - OM_uint32 major; + OM_uint32 major, tmpMinor; unsigned char errorData[8]; gss_buffer_desc errorBuffer; assert(GSS_ERROR(majorStatus)); - major = gss_create_empty_buffer_set(minor, outputToken); - if (GSS_ERROR(major)) - return major; - /* * Only return error codes that the initiator could have caused, * to avoid information leakage. @@ -127,64 +123,26 @@ makeErrorToken(OM_uint32 *minor, store_uint32_be(majorStatus, &errorData[0]); store_uint32_be(minorStatus, &errorData[4]); - errorBuffer.length = sizeof(errorData); - errorBuffer.value = errorData; - - major = gss_add_buffer_set_member(minor, &errorBuffer, outputToken); - if (GSS_ERROR(major)) + major = gssEapAllocInnerTokens(&tmpMinor, 1, token); + if (GSS_ERROR(major)) { + *minor = tmpMinor; return major; - - return GSS_S_COMPLETE; -} - -static OM_uint32 -allocInnerTokens(OM_uint32 *minor, - size_t count, - gss_buffer_set_t *pTokens, - OM_uint32 **pTokenTypes) -{ - OM_uint32 major, tmpMinor; - gss_buffer_set_t tokens = GSS_C_NO_BUFFER_SET; - OM_uint32 *tokenTypes = NULL; - - major = gss_create_empty_buffer_set(minor, &tokens); - if (GSS_ERROR(major)) - goto cleanup; - - assert(tokens->count == 0); - assert(tokens->elements == NULL); - - tokens->elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc)); - if (tokens->elements == NULL) { - major = GSS_S_FAILURE; - *minor = ENOMEM; - goto cleanup; - } - - tokenTypes = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32)); - if (tokenTypes == NULL) { - major = GSS_S_FAILURE; - *minor = ENOMEM; - goto cleanup; } - major = GSS_S_COMPLETE; - *minor = 0; + errorBuffer.length = sizeof(errorData); + errorBuffer.value = errorData; -cleanup: + major = duplicateBuffer(&tmpMinor, &errorBuffer, &token->buffers.elements[0]); if (GSS_ERROR(major)) { - gss_release_buffer_set(&tmpMinor, &tokens); - tokens = GSS_C_NO_BUFFER_SET; - if (tokenTypes != NULL) { - GSSEAP_FREE(tokenTypes); - tokenTypes = NULL; - } + gssEapReleaseInnerTokens(&tmpMinor, token, 1); + *minor = tmpMinor; + return major; } - *pTokens = tokens; - *pTokenTypes = tokenTypes; + token->types[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL; - return major; + *minor = 0; + return GSS_S_COMPLETE; } OM_uint32 @@ -202,11 +160,10 @@ gssEapSmStep(OM_uint32 *minor, size_t smCount) { OM_uint32 major, tmpMajor, tmpMinor; + struct gss_eap_token_buffer_set inputTokens = { { 0, GSS_C_NO_BUFFER }, NULL }; + struct gss_eap_token_buffer_set outputTokens = { { 0, GSS_C_NO_BUFFER }, NULL }; gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER; gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER; - 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; int initialContextToken = 0; @@ -247,17 +204,17 @@ gssEapSmStep(OM_uint32 *minor, assert(ctx->state < GSSEAP_STATE_ESTABLISHED); - major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, - &innerInputTokens, &inputTokenTypes); + major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, &inputTokens); if (GSS_ERROR(major)) goto cleanup; - assert(innerInputTokens != GSS_C_NO_BUFFER_SET); - - major = allocInnerTokens(minor, smCount, &innerOutputTokens, &outputTokenTypes); + major = gssEapAllocInnerTokens(minor, smCount, &outputTokens); if (GSS_ERROR(major)) goto cleanup; + ctx->inputTokens = &inputTokens; + ctx->outputTokens = &outputTokens; + /* Process all the tokens that are valid for the current state. */ for (i = 0; i < smCount; i++) { struct gss_eap_sm *smp = &sm[i]; @@ -283,8 +240,8 @@ gssEapSmStep(OM_uint32 *minor, processToken = 1; } else if ((smFlags & SM_FLAG_TRANSITED) == 0) { /* Don't regurgitate a token which belonds to a previous state. */ - for (j = 0; j < innerInputTokens->count; j++) { - if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) { + for (j = 0; j < inputTokens.buffers.count; j++) { + if ((inputTokens.types[j] & ITOK_TYPE_MASK) == smp->inputTokenType) { if (processToken) { /* Check for duplicate inner tokens */ major = GSS_S_DEFECTIVE_TOKEN; @@ -292,8 +249,8 @@ gssEapSmStep(OM_uint32 *minor, break; } processToken = 1; - innerInputToken = &innerInputTokens->elements[j]; - inputTokenType = &inputTokenTypes[j]; + innerInputToken = &inputTokens.buffers.elements[j]; + inputTokenType = &inputTokens.types[j]; } } if (GSS_ERROR(major)) @@ -321,18 +278,18 @@ gssEapSmStep(OM_uint32 *minor, smFlags |= SM_FLAG_TRANSITED; if (innerOutputToken.value != NULL) { - innerOutputTokens->elements[innerOutputTokens->count] = innerOutputToken; + outputTokens.buffers.elements[outputTokens.buffers.count] = innerOutputToken; assert(smp->outputTokenType != ITOK_TYPE_NONE); - outputTokenTypes[innerOutputTokens->count] = smp->outputTokenType; + outputTokens.types[outputTokens.buffers.count] = smp->outputTokenType; if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL) - outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL; - innerOutputTokens->count++; + outputTokens.types[outputTokens.buffers.count] |= ITOK_FLAG_CRITICAL; + outputTokens.buffers.count++; } /* * Break out if we made a state transition and have some tokens to send. */ if ((smFlags & SM_FLAG_TRANSITED) && - ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || innerOutputTokens->count != 0)) { + ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || outputTokens.buffers.count != 0)) { SM_ASSERT_VALID(ctx, major); break; } @@ -345,13 +302,13 @@ gssEapSmStep(OM_uint32 *minor, } } - assert(innerOutputTokens->count <= smCount); + assert(outputTokens.buffers.count <= smCount); /* Check we understood all critical tokens sent by peer */ if (!GSS_ERROR(major)) { - for (j = 0; j < innerInputTokens->count; j++) { - if ((inputTokenTypes[j] & ITOK_FLAG_CRITICAL) && - (inputTokenTypes[j] & ITOK_FLAG_VERIFIED) == 0) { + for (j = 0; j < inputTokens.buffers.count; j++) { + if ((inputTokens.types[j] & ITOK_FLAG_CRITICAL) && + (inputTokens.types[j] & ITOK_FLAG_VERIFIED) == 0) { major = GSS_S_UNAVAILABLE; *minor = GSSEAP_CRIT_ITOK_UNAVAILABLE; goto cleanup; @@ -365,25 +322,21 @@ gssEapSmStep(OM_uint32 *minor, goto cleanup; /* return error directly to caller */ /* replace any emitted tokens with error token */ - gss_release_buffer_set(&tmpMinor, &innerOutputTokens); + gssEapReleaseInnerTokens(&tmpMinor, &outputTokens, 1); - tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &innerOutputTokens); + tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &outputTokens); if (GSS_ERROR(tmpMajor)) { major = tmpMajor; *minor = tmpMinor; goto cleanup; } - - if (innerOutputTokens->count != 0) - outputTokenTypes[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL; } /* Format output token from inner tokens */ - if (innerOutputTokens->count != 0 || /* inner tokens to send */ + if (outputTokens.buffers.count != 0 || /* inner tokens to send */ !CTX_IS_INITIATOR(ctx) || /* any leg acceptor */ !CTX_IS_ESTABLISHED(ctx)) { /* non-last leg initiator */ - tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, innerOutputTokens, - outputTokenTypes, &unwrappedOutputToken); + tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, &outputTokens, &unwrappedOutputToken); if (tmpMajor == GSS_S_COMPLETE) { if (CTX_IS_INITIATOR(ctx)) tokType = TOK_TYPE_INITIATOR_CONTEXT; @@ -406,13 +359,13 @@ gssEapSmStep(OM_uint32 *minor, SM_ASSERT_VALID(ctx, major); cleanup: - gss_release_buffer_set(&tmpMinor, &innerInputTokens); - gss_release_buffer_set(&tmpMinor, &innerOutputTokens); - if (inputTokenTypes != NULL) - GSSEAP_FREE(inputTokenTypes); - if (outputTokenTypes != NULL) + gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 0); + gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 1); + gss_release_buffer(&tmpMinor, &unwrappedOutputToken); - GSSEAP_FREE(outputTokenTypes); + + ctx->inputTokens = NULL; + ctx->outputTokens = NULL; return major; } diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c index a929198..eb0dd1b 100644 --- a/mech_eap/util_token.c +++ b/mech_eap/util_token.c @@ -59,8 +59,7 @@ OM_uint32 gssEapEncodeInnerTokens(OM_uint32 *minor, - gss_buffer_set_t extensions, - OM_uint32 *types, + struct gss_eap_token_buffer_set *tokens, gss_buffer_t buffer) { OM_uint32 major, tmpMinor; @@ -70,10 +69,8 @@ gssEapEncodeInnerTokens(OM_uint32 *minor, buffer->value = NULL; buffer->length = 0; - if (extensions != GSS_C_NO_BUFFER_SET) { - for (i = 0; i < extensions->count; i++) { - required += 8 + extensions->elements[i].length; - } + for (i = 0; i < tokens->buffers.count; i++) { + required += 8 + tokens->buffers.elements[i].length; } /* @@ -91,22 +88,20 @@ gssEapEncodeInnerTokens(OM_uint32 *minor, buffer->length = required; p = (unsigned char *)buffer->value; - if (extensions != GSS_C_NO_BUFFER_SET) { - for (i = 0; i < extensions->count; i++) { - gss_buffer_t extension = &extensions->elements[i]; + for (i = 0; i < tokens->buffers.count; i++) { + gss_buffer_t tokenBuffer = &tokens->buffers.elements[i]; - assert((types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */ + assert((tokens->types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */ - /* - * Extensions are encoded as type-length-value, where the upper - * bit of the type indicates criticality. - */ - store_uint32_be(types[i], &p[0]); - store_uint32_be(extension->length, &p[4]); - memcpy(&p[8], extension->value, extension->length); + /* + * Extensions are encoded as type-length-value, where the upper + * bit of the type indicates criticality. + */ + store_uint32_be(tokens->types[i], &p[0]); + store_uint32_be(tokenBuffer->length, &p[4]); + memcpy(&p[8], tokenBuffer->value, tokenBuffer->length); - p += 8 + extension->length; - } + p += 8 + tokenBuffer->length; } assert(p == (unsigned char *)buffer->value + required); @@ -126,21 +121,15 @@ cleanup: OM_uint32 gssEapDecodeInnerTokens(OM_uint32 *minor, const gss_buffer_t buffer, - gss_buffer_set_t *pExtensions, - OM_uint32 **pTypes) + struct gss_eap_token_buffer_set *tokens) { OM_uint32 major, tmpMinor; - gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET; - OM_uint32 *types = NULL; unsigned char *p; size_t remain; - *pExtensions = GSS_C_NO_BUFFER_SET; - *pTypes = NULL; - - major = gss_create_empty_buffer_set(minor, &extensions); - if (GSS_ERROR(major)) - goto cleanup; + tokens->buffers.count = 0; + tokens->buffers.elements = NULL; + tokens->types = NULL; if (buffer->length == 0) { major = GSS_S_COMPLETE; @@ -152,7 +141,7 @@ gssEapDecodeInnerTokens(OM_uint32 *minor, do { OM_uint32 *ntypes; - gss_buffer_desc extension; + gss_buffer_desc tokenBuffer, *newTokenBuffers; if (remain < 8) { major = GSS_S_DEFECTIVE_TOKEN; @@ -160,42 +149,48 @@ gssEapDecodeInnerTokens(OM_uint32 *minor, goto cleanup; } - ntypes = GSSEAP_REALLOC(types, - (extensions->count + 1) * sizeof(OM_uint32)); + ntypes = GSSEAP_REALLOC(tokens->types, + (tokens->buffers.count + 1) * sizeof(OM_uint32)); if (ntypes == NULL) { major = GSS_S_FAILURE; *minor = ENOMEM; goto cleanup; } - types = ntypes; + tokens->types = ntypes; - types[extensions->count] = load_uint32_be(&p[0]); - extension.length = load_uint32_be(&p[4]); + tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]); + tokenBuffer.length = load_uint32_be(&p[4]); - if (remain < 8 + extension.length) { + if (remain < 8 + tokenBuffer.length) { major = GSS_S_DEFECTIVE_TOKEN; *minor = GSSEAP_TOK_TRUNC; goto cleanup; } - extension.value = &p[8]; + tokenBuffer.value = &p[8]; - major = gss_add_buffer_set_member(minor, &extension, &extensions); - if (GSS_ERROR(major)) + newTokenBuffers = GSSEAP_REALLOC(tokens->buffers.elements, + (tokens->buffers.count + 1) * sizeof(gss_buffer_desc)); + if (newTokenBuffers == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; goto cleanup; + } + + tokens->buffers.elements = newTokenBuffers; + tokens->buffers.elements[tokens->buffers.count] = tokenBuffer; + tokens->buffers.count++; + + p += 8 + tokenBuffer.length; + remain -= 8 + tokenBuffer.length; - p += 8 + extension.length; - remain -= 8 + extension.length; } while (remain != 0); + major = GSS_S_COMPLETE; + *minor = 0; + cleanup: - if (GSS_ERROR(major)) { - gss_release_buffer_set(&tmpMinor, &extensions); - if (types != NULL) - GSSEAP_FREE(types); - } else { - *pExtensions = extensions; - *pTypes = types; - } + if (GSS_ERROR(major)) + gssEapReleaseInnerTokens(&tmpMinor, tokens, 0); return major; } @@ -415,3 +410,70 @@ verifyTokenHeader(OM_uint32 *minor, *minor = 0; return GSS_S_COMPLETE; } + +OM_uint32 +gssEapAllocInnerTokens(OM_uint32 *minor, + size_t count, + struct gss_eap_token_buffer_set *tokens) +{ + OM_uint32 major; + + tokens->buffers.count = 0; + tokens->buffers.elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc)); + if (tokens->buffers.elements == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + tokens->types = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32)); + if (tokens->types == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + if (tokens->buffers.elements != NULL) { + GSSEAP_FREE(tokens->buffers.elements); + tokens->buffers.elements = NULL; + } + if (tokens->types != NULL) { + GSSEAP_FREE(tokens->types); + tokens->types = NULL; + } + } + + return major; +} + +OM_uint32 +gssEapReleaseInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + int freeBuffers) +{ + OM_uint32 tmpMinor; + size_t i; + + if (tokens->buffers.elements != NULL) { + if (freeBuffers) { + for (i = 0; i < tokens->buffers.count; i++) + gss_release_buffer(&tmpMinor, &tokens->buffers.elements[i]); + } + GSSEAP_FREE(tokens->buffers.elements); + tokens->buffers.elements = NULL; + } + tokens->buffers.count = 0; + + if (tokens->types != NULL) { + GSSEAP_FREE(tokens->types); + tokens->types = NULL; + } + + *minor = 0; + return GSS_S_COMPLETE; +} -- 2.1.4