From: Luke Howard Date: Thu, 9 Sep 2010 15:55:20 +0000 (+0200) Subject: Get simple EAP case working X-Git-Tag: vm/20110310~353 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.orig;a=commitdiff_plain;h=8d5242de8807f650fd9634fad250bf3d0d8dbbb2 Get simple EAP case working --- diff --git a/accept_sec_context.c b/accept_sec_context.c index e254ade..332a6c8 100644 --- a/accept_sec_context.c +++ b/accept_sec_context.c @@ -214,8 +214,7 @@ serverGetEapReqIdText(void *ctx, #endif static OM_uint32 -serverDeriveKey(OM_uint32 *minor, - gss_ctx_id_t ctx) +completeAccept(OM_uint32 *minor, gss_ctx_id_t ctx) { OM_uint32 major; krb5_context krbContext; @@ -245,6 +244,11 @@ serverDeriveKey(OM_uint32 *minor, ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); } + sequenceInit(&ctx->seqState, ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + return GSS_S_COMPLETE; } @@ -256,26 +260,24 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, gss_channel_bindings_t chanBindings, gss_buffer_t outputToken) { - OM_uint32 major, tmpMinor, tmpMajor; + OM_uint32 major; + OM_uint32 tmpMinor, tmpMajor; int code; struct wpabuf respData; - struct eap_config *config = (struct eap_config *)&ctx->acceptorCtx.eapConfig; static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText }; - wpabuf_set(&respData, inputToken->value, inputToken->length); - ctx->acceptorCtx.eapPolInterface->eapRespData = &respData; - ctx->acceptorCtx.eapPolInterface->eapResp = TRUE; - if (ctx->acceptorCtx.eap == NULL) { - /* initial context token */ - config->eap_server = 1; - config->ssl_ctx = ctx->acceptorCtx.tlsContext; + struct eap_config eapConfig; major = initTls(minor, ctx); if (GSS_ERROR(major)) goto cleanup; - ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, config); + memset(&eapConfig, 0, sizeof(eapConfig)); + eapConfig.eap_server = 1; + eapConfig.ssl_ctx = ctx->acceptorCtx.tlsContext; + + ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, &eapConfig); if (ctx->acceptorCtx.eap == NULL) { major = GSS_S_FAILURE; goto cleanup; @@ -286,12 +288,18 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, ctx->acceptorCtx.eapPolInterface->eapRestart = TRUE; } - if (ctx->acceptorName == GSS_C_NO_NAME && cred->name != GSS_C_NO_NAME) { + if (ctx->acceptorName == GSS_C_NO_NAME && + cred != GSS_C_NO_CREDENTIAL && + cred->name != GSS_C_NO_NAME) { major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName); if (GSS_ERROR(major)) goto cleanup; } + wpabuf_set(&respData, inputToken->value, inputToken->length); + ctx->acceptorCtx.eapPolInterface->eapRespData = &respData; + ctx->acceptorCtx.eapPolInterface->eapResp = TRUE; + code = eap_server_sm_step(ctx->acceptorCtx.eap); if (ctx->acceptorCtx.eapPolInterface->eapReq) { @@ -300,13 +308,9 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, } if (ctx->acceptorCtx.eapPolInterface->eapSuccess) { - major = serverDeriveKey(minor, ctx); - if (GSS_ERROR(major)) - goto cleanup; - ctx->acceptorCtx.eapPolInterface->eapSuccess = 0; ctx->state = EAP_STATE_ESTABLISHED; - major = GSS_S_COMPLETE; + major = completeAccept(minor, ctx); } else if (ctx->acceptorCtx.eapPolInterface->eapFail) { ctx->acceptorCtx.eapPolInterface->eapFail = 0; major = GSS_S_FAILURE; @@ -323,11 +327,14 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken); if (GSS_ERROR(tmpMajor)) { major = tmpMajor; + *minor = tmpMinor; goto cleanup; } } cleanup: + ctx->acceptorCtx.eapPolInterface->eapRespData = NULL; + return major; } @@ -374,7 +381,8 @@ gss_accept_sec_context(OM_uint32 *minor, OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle) { - OM_uint32 major, tmpMinor; + OM_uint32 major; + OM_uint32 tmpMajor, tmpMinor; gss_ctx_id_t ctx = *context_handle; struct eap_gss_acceptor_sm *sm = NULL; gss_buffer_desc innerInputToken, innerOutputToken; @@ -423,28 +431,34 @@ gss_accept_sec_context(OM_uint32 *minor, goto cleanup; } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0); - if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) { - major = gss_duplicate_name(minor, ctx->initiatorName, src_name); - if (GSS_ERROR(major)) - goto cleanup; - } if (mech_type != NULL) { if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type)) duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type); } if (innerOutputToken.length != 0) { - major = gssEapMakeToken(minor, ctx, &innerOutputToken, - sm->outputTokenType, output_token); - if (GSS_ERROR(major)) + tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken, + sm->outputTokenType, output_token); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; goto cleanup; + } } if (ret_flags != NULL) *ret_flags = ctx->gssFlags; - if (time_rec != NULL) - gss_context_time(&tmpMinor, ctx, time_rec); if (delegated_cred_handle != NULL) *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + if (major == GSS_S_COMPLETE) { + if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) { + major = gss_duplicate_name(&tmpMinor, ctx->initiatorName, src_name); + if (GSS_ERROR(major)) + goto cleanup; + } + if (time_rec != NULL) + gss_context_time(&tmpMinor, ctx, time_rec); + } + assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED); cleanup: diff --git a/display_name.c b/display_name.c index 96e1613..9ef4314 100644 --- a/display_name.c +++ b/display_name.c @@ -65,7 +65,8 @@ gss_display_name(OM_uint32 *minor, krb5_free_unparsed_name(krbContext, krbName); - *output_name_type = GSS_EAP_NT_PRINCIPAL_NAME; + if (output_name_type != NULL) + *output_name_type = GSS_EAP_NT_PRINCIPAL_NAME; return GSS_S_COMPLETE; } diff --git a/gssapiP_eap.h b/gssapiP_eap.h index 2369f47..0c19b91 100644 --- a/gssapiP_eap.h +++ b/gssapiP_eap.h @@ -49,6 +49,7 @@ /* EAP includes */ #include #include +#include #include #include /* XXX testing implementation only */ #include @@ -117,7 +118,6 @@ enum eap_gss_state { struct eap_gss_initiator_ctx { unsigned int idleWhile; struct eap_peer_config eapPeerConfig; - struct eap_config eapConfig; struct eap_sm *eap; struct wpabuf reqData; }; @@ -126,7 +126,6 @@ struct eap_gss_acceptor_ctx { struct eap_eapol_interface *eapPolInterface; void *tlsContext; struct eap_sm *eap; - struct eap_config eapConfig; /* XXX */ }; struct gss_ctx_id_struct { diff --git a/init_sec_context.c b/init_sec_context.c index 119eb4f..48784dd 100644 --- a/init_sec_context.c +++ b/init_sec_context.c @@ -68,6 +68,7 @@ policyVariableToFlag(enum eapol_bool_var variable) } return flag; + } static struct eap_peer_config * @@ -183,6 +184,8 @@ static struct eapol_callbacks gssEapPolicyCallbacks = { peerNotifyPending, }; +extern int wpa_debug_level; + static OM_uint32 peerConfigInit(OM_uint32 *minor, gss_cred_id_t cred, @@ -197,6 +200,8 @@ peerConfigInit(OM_uint32 *minor, GSSEAP_KRB_INIT(&krbContext); if (loadConfig) { + eapPeerConfig->fragment_size = 1024; + wpa_debug_level = 0; } code = krb5_unparse_name(krbContext, cred->name->krbPrincipal, &identity); @@ -228,8 +233,8 @@ peerConfigFree(OM_uint32 *minor, } static OM_uint32 -peerDeriveKey(OM_uint32 *minor, - gss_ctx_id_t ctx) +completeInit(OM_uint32 *minor, + gss_ctx_id_t ctx) { OM_uint32 major; const unsigned char *key; @@ -260,6 +265,11 @@ peerDeriveKey(OM_uint32 *minor, ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); } + sequenceInit(&ctx->seqState, ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + return GSS_S_COMPLETE; } @@ -275,9 +285,11 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, gss_buffer_t inputToken, gss_buffer_t outputToken) { - OM_uint32 major, tmpMinor; + OM_uint32 major; + OM_uint32 tmpMajor, tmpMinor; time_t now; int initialContextToken = 0, code; + struct wpabuf *resp = NULL; initialContextToken = (inputToken == GSS_C_NO_BUFFER || inputToken->length == 0); @@ -287,12 +299,15 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, goto cleanup; if (initialContextToken) { + struct eap_config eapConfig; + + memset(&eapConfig, 0, sizeof(eapConfig)); ctx->flags |= CTX_FLAG_EAP_PORT_ENABLED; ctx->initiatorCtx.eap = eap_peer_sm_init(ctx, &gssEapPolicyCallbacks, ctx, - &ctx->initiatorCtx.eapConfig); + &eapConfig); time(&now); if (timeReq == 0 || timeReq == GSS_C_INDEFINITE) @@ -318,46 +333,49 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, } if (GSS_ERROR(major)) goto cleanup; + + resp = eap_sm_buildIdentity(ctx->initiatorCtx.eap, 0, 0); + major = GSS_S_CONTINUE_NEEDED; + goto cleanup; + } else { + ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */ } wpabuf_set(&ctx->initiatorCtx.reqData, inputToken->value, inputToken->length); - code = eap_peer_sm_step(ctx->initiatorCtx.eap); + major = GSS_S_CONTINUE_NEEDED; + code = eap_peer_sm_step(ctx->initiatorCtx.eap); if (ctx->flags & CTX_FLAG_EAP_RESP) { - struct wpabuf *resp; - gss_buffer_desc buf; - ctx->flags &= ~(CTX_FLAG_EAP_RESP); resp = eap_get_eapRespData(ctx->initiatorCtx.eap); - - if (resp != NULL) { - buf.length = wpabuf_len(resp); - buf.value = (void *)wpabuf_head(resp); - - major = duplicateBuffer(minor, &buf, outputToken); - if (GSS_ERROR(major)) - goto cleanup; - - major = GSS_S_CONTINUE_NEEDED; - } - } - - if (ctx->flags & CTX_FLAG_EAP_SUCCESS) { - major = peerDeriveKey(minor, ctx); - if (GSS_ERROR(major)) - goto cleanup; - + } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) { + major = completeInit(minor, ctx); ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); ctx->state = EAP_STATE_ESTABLISHED; - major = GSS_S_COMPLETE; } else if ((ctx->flags & CTX_FLAG_EAP_FAIL) || code == 0) { major = GSS_S_FAILURE; } cleanup: + if (resp != NULL) { + OM_uint32 tmpMajor; + gss_buffer_desc buf; + + assert(major == GSS_S_CONTINUE_NEEDED); + + buf.length = wpabuf_len(resp); + buf.value = (void *)wpabuf_head(resp); + + tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + } + } + wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0); peerConfigFree(&tmpMinor, ctx); @@ -462,7 +480,8 @@ gss_init_sec_context(OM_uint32 *minor, OM_uint32 *ret_flags, OM_uint32 *time_rec) { - OM_uint32 major, tmpMinor; + OM_uint32 major; + OM_uint32 tmpMajor, tmpMinor; gss_ctx_id_t ctx = *context_handle; struct eap_gss_initiator_sm *sm = NULL; gss_buffer_desc innerInputToken, innerOutputToken; @@ -531,10 +550,13 @@ gss_init_sec_context(OM_uint32 *minor, duplicateOid(&tmpMinor, ctx->mechanismUsed, actual_mech_type); } if (innerOutputToken.length != 0) { - major = gssEapMakeToken(minor, ctx, &innerOutputToken, - sm->outputTokenType, output_token); - if (GSS_ERROR(major)) + tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken, + sm->outputTokenType, output_token); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; goto cleanup; + } } if (ret_flags != NULL) *ret_flags = ctx->gssFlags; diff --git a/mech_eap.exports b/mech_eap.exports index f097029..ad4dc24 100644 --- a/mech_eap.exports +++ b/mech_eap.exports @@ -8,8 +8,10 @@ gss_context_time gss_delete_sec_context gss_display_name gss_display_name_ext +gss_display_status gss_duplicate_name gss_export_name +gss_export_name_composite gss_export_sec_context gss_get_mic gss_get_name_attribute @@ -19,17 +21,20 @@ gss_indicate_mechs gss_init_sec_context gss_inquire_context gss_inquire_cred -gss_inquire_name +gss_inquire_cred_by_oid gss_inquire_mechs_for_name +gss_inquire_name gss_inquire_names_for_mech +gss_inquire_sec_context_by_oid gss_map_name_to_any gss_process_context_token gss_pseudo_random gss_release_any_name_mapping gss_release_cred -gss_internal_release_oid gss_release_name +gss_internal_release_oid gss_set_name_attribute +gss_set_sec_context_option gss_store_cred gss_unwrap gss_unwrap_iov diff --git a/unwrap_iov.c b/unwrap_iov.c index 6ed4caf..d10f71c 100644 --- a/unwrap_iov.c +++ b/unwrap_iov.c @@ -80,7 +80,6 @@ unwrapToken(OM_uint32 *minor, size_t dataLen, assocDataLen; uint64_t seqnum; int valid = 0; - krb5_cksumtype cksumtype; int conf_flag = 0; krb5_context krbContext; @@ -201,7 +200,7 @@ unwrapToken(OM_uint32 *minor, store_uint16_be(0, ptr + 4); store_uint16_be(0, ptr + 6); - code = gssEapVerify(krbContext, cksumtype, rrc, + code = gssEapVerify(krbContext, 0, rrc, &ctx->rfc3961Key, keyUsage, iov, iov_count, &valid); if (code != 0 || valid == FALSE) { @@ -220,7 +219,7 @@ unwrapToken(OM_uint32 *minor, goto defective; seqnum = load_uint64_be(ptr + 8); - code = gssEapVerify(krbContext, cksumtype, 0, + code = gssEapVerify(krbContext, 0, 0, &ctx->rfc3961Key, keyUsage, iov, iov_count, &valid); if (code != 0 || valid == FALSE) { diff --git a/util_context.c b/util_context.c index 6352319..eff975c 100644 --- a/util_context.c +++ b/util_context.c @@ -110,7 +110,7 @@ gssEapReleaseContext(OM_uint32 *minor, gssEapReleaseName(&tmpMinor, &ctx->initiatorName); gssEapReleaseName(&tmpMinor, &ctx->acceptorName); gss_release_oid(&tmpMinor, &ctx->mechanismUsed); - sequenceFree(ctx->seqState); + sequenceFree(&ctx->seqState); GSSEAP_MUTEX_DESTROY(&ctx->mutex); @@ -171,7 +171,7 @@ gssEapVerifyToken(OM_uint32 *minor, if (GSS_ERROR(major)) return major; - if (ctx->mechanismUsed != GSS_C_NO_OID) { + if (ctx->mechanismUsed == GSS_C_NO_OID) { if (!gssEapIsConcreteMechanismOid(oid)) return GSS_S_BAD_MECH; diff --git a/util_krb.c b/util_krb.c index 35e2395..dd52890 100644 --- a/util_krb.c +++ b/util_krb.c @@ -108,7 +108,12 @@ gssEapDeriveRFC3961Key(OM_uint32 *minor, if (code != 0) goto cleanup; - data.length = keyLength; + if (keyLength < keybytes) { + code = KRB5_BAD_MSIZE; + goto cleanup; + } + + data.length = keybytes; data.data = (char *)key; kd.contents = GSSEAP_MALLOC(keylength); @@ -131,7 +136,11 @@ gssEapDeriveRFC3961Key(OM_uint32 *minor, if (code != 0) goto cleanup; - prf.length = prflength; + if (prflength < keybytes) { + code = KRB5_CRYPTO_INTERNAL; + goto cleanup; + } + prf.length = keybytes; prf.data = GSSEAP_MALLOC(prflength); if (data.data == NULL) { code = ENOMEM; diff --git a/util_token.c b/util_token.c index e089690..c331945 100644 --- a/util_token.c +++ b/util_token.c @@ -208,7 +208,7 @@ verifyTokenHeader(gss_OID mech, gss_OID_desc toid; ssize_t toksize = (ssize_t)toksize_in; - if (toksize -= 1 < 0) + if ((toksize -= 1) < 0) return ERANGE; if (*buf++ != 0x60) @@ -221,18 +221,18 @@ verifyTokenHeader(gss_OID mech, if (seqsize != toksize) return ERANGE; - if (toksize -= 1 < 0) + if ((toksize -= 1) < 0) return ERANGE; if (*buf++ != 0x06) return EINVAL; - if (toksize -= 1 < 0) + if ((toksize -= 1) < 0) return ERANGE; toid.length = *buf++; - if (toksize -= toid.length < 0) + if ((toksize -= toid.length) < 0) return ERANGE; toid.elements = buf; @@ -247,7 +247,7 @@ verifyTokenHeader(gss_OID mech, } if (tok_type != TOK_TYPE_NONE) { - if (toksize -= 2 < 0) + if ((toksize -= 2) < 0) return EINVAL; if ((*buf++ != ((tok_type >> 8) & 0xff)) || diff --git a/verify_mic.c b/verify_mic.c index ee19b01..2d72307 100644 --- a/verify_mic.c +++ b/verify_mic.c @@ -39,15 +39,25 @@ gss_verify_mic(OM_uint32 *minor, gss_buffer_t message_token, gss_qop_t *qop_state) { - gss_iov_buffer_desc iov[2]; + gss_iov_buffer_desc iov[3]; int conf_state; + if (message_token->length < 16) { + *minor = KRB5_BAD_MSIZE; + return GSS_S_BAD_SIG; + } + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; iov[0].buffer = *message_buffer; iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER; - iov[1].buffer = *message_token; + iov[1].buffer.length = 16; + iov[1].buffer.value = message_token->value; + + iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[2].buffer.length = message_token->length - 16; + iov[2].buffer.value = (unsigned char *)message_token->value + 16; return gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state, - iov, 2, TOK_TYPE_MIC); + iov, 3, TOK_TYPE_MIC); } diff --git a/wrap_iov.c b/wrap_iov.c index f9681fa..6f53365 100644 --- a/wrap_iov.c +++ b/wrap_iov.c @@ -295,10 +295,7 @@ cleanup: *minor = code; - if (code == 0) - return GSS_S_FAILURE; - else - return GSS_S_COMPLETE; + return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; } OM_uint32