X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=mech_eap%2Faccept_sec_context.c;h=b594af0abd9d857a26dd2ce29e08e19ec0b86d5b;hb=3f993b33bfbccc6ac801d665a3d77a6f911ff74a;hp=cc8702dbcfbe78554a639409295a0d4404660b86;hpb=ccf542544c4add8d720da2e5c9e048bab695732d;p=mech_eap.git diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c index cc8702d..b594af0 100644 --- a/mech_eap/accept_sec_context.c +++ b/mech_eap/accept_sec_context.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, JANET(UK) + * Copyright (c) 2011, 2013, 2015, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,7 +42,7 @@ static OM_uint32 eapGssSmAcceptGssReauth(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, - gss_name_t target, + gss_const_name_t target, gss_OID mech, OM_uint32 reqFlags, OM_uint32 timeReq, @@ -59,7 +59,7 @@ static OM_uint32 acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) { OM_uint32 major, tmpMinor; - VALUE_PAIR *vp; + rs_const_avp *vp; gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; /* Cache encryption type derived from selected mechanism OID */ @@ -72,9 +72,10 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps, PW_USER_NAME, 0, &vp); - if (major == GSS_S_COMPLETE && vp->length) { - nameBuf.length = vp->length; - nameBuf.value = vp->vp_strvalue; + if (major == GSS_S_COMPLETE && rs_avp_length(vp) != 0) { + rs_avp_octets_value_byref((rs_avp *)vp, + (unsigned char **)&nameBuf.value, + &nameBuf.length); } else { ctx->gssFlags |= GSS_C_ANON_FLAG; } @@ -88,15 +89,15 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) return major; major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps, - PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp); + PW_MS_MPPE_SEND_KEY, VENDORPEC_MICROSOFT, &vp); if (GSS_ERROR(major)) { *minor = GSSEAP_KEY_UNAVAILABLE; return GSS_S_UNAVAILABLE; } major = gssEapDeriveRfc3961Key(minor, - vp->vp_octets, - vp->length, + rs_avp_octets_value_const_ptr(vp), + rs_avp_length(vp), ctx->encryptionType, &ctx->rfc3961Key); if (GSS_ERROR(major)) @@ -134,7 +135,7 @@ static OM_uint32 eapGssSmAcceptAcceptorName(OM_uint32 *minor, gss_cred_id_t cred GSSEAP_UNUSED, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -163,7 +164,7 @@ static OM_uint32 eapGssSmAcceptVendorInfo(OM_uint32 *minor, gss_cred_id_t cred GSSEAP_UNUSED, gss_ctx_id_t ctx GSSEAP_UNUSED, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -189,7 +190,7 @@ static OM_uint32 eapGssSmAcceptIdentity(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -287,7 +288,7 @@ importInitiatorIdentity(OM_uint32 *minor, static OM_uint32 setInitiatorIdentity(OM_uint32 *minor, gss_ctx_id_t ctx, - VALUE_PAIR **vps) + struct rs_packet *req) { OM_uint32 major, tmpMinor; gss_buffer_desc nameBuf; @@ -303,7 +304,7 @@ setInitiatorIdentity(OM_uint32 *minor, if (GSS_ERROR(major)) return major; - major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf); + major = gssEapRadiusAddAvp(minor, req, PW_USER_NAME, 0, &nameBuf); if (GSS_ERROR(major)) return major; @@ -320,7 +321,7 @@ setInitiatorIdentity(OM_uint32 *minor, static OM_uint32 setAcceptorIdentity(OM_uint32 *minor, gss_ctx_id_t ctx, - VALUE_PAIR **vps) + struct rs_packet *req) { OM_uint32 major; gss_buffer_desc nameBuf; @@ -328,7 +329,7 @@ setAcceptorIdentity(OM_uint32 *minor, krb5_principal krbPrinc; struct rs_context *rc = ctx->acceptorCtx.radContext; - assert(rc != NULL); + GSSEAP_ASSERT(rc != NULL); if (ctx->acceptorName == GSS_C_NO_NAME) { *minor = 0; @@ -343,63 +344,52 @@ setAcceptorIdentity(OM_uint32 *minor, GSSEAP_KRB_INIT(&krbContext); krbPrinc = ctx->acceptorName->krbPrincipal; - assert(krbPrinc != NULL); - assert(KRB_PRINC_LENGTH(krbPrinc) >= 2); + GSSEAP_ASSERT(krbPrinc != NULL); + GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 1); /* Acceptor-Service-Name */ krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf); - major = gssEapRadiusAddAvp(minor, vps, + major = gssEapRadiusAddAvp(minor, req, PW_GSS_ACCEPTOR_SERVICE_NAME, - VENDORPEC_UKERNA, + 0, &nameBuf); if (GSS_ERROR(major)) return major; /* Acceptor-Host-Name */ - krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf); - - major = gssEapRadiusAddAvp(minor, vps, - PW_GSS_ACCEPTOR_HOST_NAME, - VENDORPEC_UKERNA, - &nameBuf); - if (GSS_ERROR(major)) - return major; - + if (KRB_PRINC_LENGTH(krbPrinc) >= 2) { + krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf); + + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_HOST_NAME, + 0, + &nameBuf); + if (GSS_ERROR(major)) + return major; + } if (KRB_PRINC_LENGTH(krbPrinc) > 2) { /* Acceptor-Service-Specific */ - krb5_principal_data ssiPrinc = *krbPrinc; - char *ssi; - - KRB_PRINC_LENGTH(&ssiPrinc) -= 2; - KRB_PRINC_NAME(&ssiPrinc) += 2; - - *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc, - KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi); + *minor = krbPrincUnparseServiceSpecifics(krbContext, + krbPrinc, &nameBuf); if (*minor != 0) return GSS_S_FAILURE; - nameBuf.value = ssi; - nameBuf.length = strlen(ssi); - - major = gssEapRadiusAddAvp(minor, vps, - PW_GSS_ACCEPTOR_SERVICE_SPECIFIC, - VENDORPEC_UKERNA, + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_SERVICE_SPECIFICS, + 0, &nameBuf); - - if (GSS_ERROR(major)) { - krb5_free_unparsed_name(krbContext, ssi); + krbFreeUnparsedName(krbContext, &nameBuf); + if (GSS_ERROR(major)) return major; - } - krb5_free_unparsed_name(krbContext, ssi); } krbPrincRealmToGssBuffer(krbPrinc, &nameBuf); if (nameBuf.length != 0) { /* Acceptor-Realm-Name */ - major = gssEapRadiusAddAvp(minor, vps, + major = gssEapRadiusAddAvp(minor, req, PW_GSS_ACCEPTOR_REALM_NAME, - VENDORPEC_UKERNA, + 0, &nameBuf); if (GSS_ERROR(major)) return major; @@ -418,58 +408,84 @@ createRadiusHandle(OM_uint32 *minor, gss_ctx_id_t ctx) { struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx; - const char *configFile = RS_CONFIG_FILE; - const char *configStanza = "gss-eap"; - struct rs_alloc_scheme ralloc; struct rs_error *err; + const char *configStanza = "gss-eap"; + OM_uint32 major; - assert(actx->radContext == NULL); - assert(actx->radConn == NULL); - - if (rs_context_create(&actx->radContext) != 0) { - *minor = GSSEAP_RADSEC_CONTEXT_FAILURE; - return GSS_S_FAILURE; - } - - if (cred->radiusConfigFile != NULL) - configFile = cred->radiusConfigFile; - if (cred->radiusConfigStanza != NULL) - configStanza = cred->radiusConfigStanza; - - ralloc.calloc = GSSEAP_CALLOC; - ralloc.malloc = GSSEAP_MALLOC; - ralloc.free = GSSEAP_FREE; - ralloc.realloc = GSSEAP_REALLOC; - - rs_context_set_alloc_scheme(actx->radContext, &ralloc); + GSSEAP_ASSERT(actx->radContext == NULL); + GSSEAP_ASSERT(actx->radConn == NULL); + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); - if (rs_context_read_config(actx->radContext, configFile) != 0) { - err = rs_err_ctx_pop(actx->radContext); - goto fail; - } + major = gssEapCreateRadiusContext(minor, cred, &actx->radContext); + if (GSS_ERROR(major)) + return major; - if (rs_context_init_freeradius_dict(actx->radContext, NULL) != 0) { - err = rs_err_ctx_pop(actx->radContext); - goto fail; - } + if (cred->radiusConfigStanza.value != NULL) + configStanza = (const char *)cred->radiusConfigStanza.value; if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) { err = rs_err_conn_pop(actx->radConn); - goto fail; + return gssEapRadiusMapError(minor, err); } if (actx->radServer != NULL) { if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) { err = rs_err_conn_pop(actx->radConn); - goto fail; + return gssEapRadiusMapError(minor, err); } } *minor = 0; return GSS_S_COMPLETE; +} + +/** + * Choose the correct error for an access reject packet. + */ +static OM_uint32 +eapGssAcceptHandleReject(OM_uint32 *minor, + struct rs_packet *response) +{ + rs_avp **vps; + rs_const_avp *vp = NULL; + OM_uint32 major; + const char *reply_message = NULL; + size_t reply_length = 0; + + rs_packet_avps(response, &vps); + major = gssEapRadiusGetRawAvp(minor, *vps, + PW_REPLY_MESSAGE, 0, &vp); + if (!GSS_ERROR(major)) { + reply_message = rs_avp_string_value(vp); + reply_length = rs_avp_length(vp); + } + + major = gssEapRadiusGetRawAvp(minor, *vps, + PW_ERROR_CAUSE, 0, &vp); + if (!GSS_ERROR(major)) { + switch (rs_avp_integer_value(vp)) { + /* Values from http://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-18 */ + case 502: /* request not routable (proxy) */ + *minor = GSSEAP_RADIUS_UNROUTABLE; + break; + case 501: /* administratively prohibited */ + *minor = GSSEAP_RADIUS_ADMIN_PROHIBIT; + break; + + default: + *minor = GSSEAP_RADIUS_AUTH_FAILURE; + break; + } + } else + *minor = GSSEAP_RADIUS_AUTH_FAILURE; + + if (reply_message != NULL) + gssEapSaveStatusInfo(*minor, "%s: %.*s", error_message(*minor), + reply_length, reply_message); + else + gssEapSaveStatusInfo(*minor, "%s", error_message(*minor)); -fail: - return gssEapRadiusMapError(minor, err); + return GSS_S_DEFECTIVE_CREDENTIAL; } /* @@ -479,7 +495,7 @@ static OM_uint32 eapGssSmAcceptAuthenticate(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -492,7 +508,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, struct rs_connection *rconn; struct rs_request *request = NULL; struct rs_packet *req = NULL, *resp = NULL; - struct radius_packet *frreq, *frresp; + int isAccessChallenge; if (ctx->acceptorCtx.radContext == NULL) { /* May be NULL from an imported partial context */ @@ -513,23 +529,22 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); goto cleanup; } - frreq = rs_packet_frpkt(req); - major = setInitiatorIdentity(minor, ctx, &frreq->vps); + major = setInitiatorIdentity(minor, ctx, req); if (GSS_ERROR(major)) goto cleanup; - major = setAcceptorIdentity(minor, ctx, &frreq->vps); + major = setAcceptorIdentity(minor, ctx, req); if (GSS_ERROR(major)) goto cleanup; - major = gssEapRadiusAddAvp(minor, &frreq->vps, + major = gssEapRadiusAddAvp(minor, req, PW_EAP_MESSAGE, 0, inputToken); if (GSS_ERROR(major)) goto cleanup; if (ctx->acceptorCtx.state.length != 0) { - major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0, + major = gssEapRadiusAddAvp(minor, req, PW_STATE, 0, &ctx->acceptorCtx.state); if (GSS_ERROR(major)) goto cleanup; @@ -550,16 +565,18 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, goto cleanup; } - assert(resp != NULL); + GSSEAP_ASSERT(resp != NULL); - frresp = rs_packet_frpkt(resp); - switch (frresp->code) { + isAccessChallenge = 0; + + switch (rs_packet_code(resp)) { case PW_ACCESS_CHALLENGE: - case PW_AUTHENTICATION_ACK: + isAccessChallenge = 1; break; - case PW_AUTHENTICATION_REJECT: - *minor = GSSEAP_RADIUS_AUTH_FAILURE; - major = GSS_S_DEFECTIVE_CREDENTIAL; + case PW_ACCESS_ACCEPT: + break; + case PW_ACCESS_REJECT: + major = eapGssAcceptHandleReject( minor, resp); goto cleanup; break; default: @@ -569,23 +586,27 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, break; } - major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0, + major = gssEapRadiusGetAvp(minor, resp, PW_EAP_MESSAGE, 0, outputToken, TRUE); - if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) { + if (major == GSS_S_UNAVAILABLE && isAccessChallenge) { *minor = GSSEAP_MISSING_EAP_REQUEST; major = GSS_S_DEFECTIVE_TOKEN; goto cleanup; } else if (GSS_ERROR(major)) goto cleanup; - if (frresp->code == PW_ACCESS_CHALLENGE) { - major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0, + if (isAccessChallenge) { + major = gssEapRadiusGetAvp(minor, resp, PW_STATE, 0, &ctx->acceptorCtx.state, TRUE); if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR) goto cleanup; } else { - ctx->acceptorCtx.vps = frresp->vps; - frresp->vps = NULL; + rs_avp **vps; + + rs_packet_avps(resp, &vps); + + ctx->acceptorCtx.vps = *vps; + *vps = NULL; major = acceptReadyEap(minor, ctx, cred); if (GSS_ERROR(major)) @@ -606,7 +627,7 @@ cleanup: if (resp != NULL) rs_packet_destroy(resp); if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) { - assert(major == GSS_S_CONTINUE_NEEDED); + GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED); rs_conn_destroy(ctx->acceptorCtx.radConn); ctx->acceptorCtx.radConn = NULL; @@ -616,10 +637,44 @@ cleanup: } static OM_uint32 +eapGssSmAcceptGssFlags(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_const_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) +{ + unsigned char *p; + OM_uint32 initiatorGssFlags; + + GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0); + + if (inputToken->length < 4) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* allow flags to grow for future expansion */ + p = (unsigned char *)inputToken->value + inputToken->length - 4; + + initiatorGssFlags = load_uint32_be(p); + initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK; + + ctx->gssFlags |= initiatorGssFlags; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, gss_cred_id_t cred GSSEAP_UNUSED, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -628,33 +683,103 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, gss_buffer_t outputToken GSSEAP_UNUSED, OM_uint32 *smFlags GSSEAP_UNUSED) { - OM_uint32 major, tmpMinor; - gss_iov_buffer_desc iov[2]; + krb5_error_code code; + krb5_context krbContext; + krb5_data data; + krb5_checksum cksum; + krb5_boolean valid = FALSE; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto; +#endif + + if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS || + chanBindings->application_data.length == 0) + return GSS_S_CONTINUE_NEEDED; - iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE; - iov[0].buffer.length = 0; - iov[0].buffer.value = NULL; + GSSEAP_KRB_INIT(&krbContext); - iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM; - iov[1].buffer = *inputToken; + KRB_DATA_INIT(&data); - major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, - iov, 2, TOK_TYPE_WRAP); - if (GSS_ERROR(major)) - return major; + gssBufferToKrbData(&chanBindings->application_data, &data); + + KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken); + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, 0, &krbCrypto); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } - if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS && - !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) { - major = GSS_S_BAD_BINDINGS; + code = krb5_verify_checksum(krbContext, krbCrypto, + KEY_USAGE_GSSEAP_CHBIND_MIC, + data.data, data.length, &cksum); + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + code = 0; + valid = FALSE; + } else if (code == 0) { + valid = TRUE; + } + + krb5_crypto_destroy(krbContext, krbCrypto); +#else + code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key, + KEY_USAGE_GSSEAP_CHBIND_MIC, + &data, &cksum, &valid); +#endif /* HAVE_HEIMDAL_VERSION */ + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + if (valid == FALSE) { *minor = GSSEAP_BINDINGS_MISMATCH; - } else { - major = GSS_S_CONTINUE_NEEDED; - *minor = 0; + return GSS_S_BAD_BINDINGS; } - gss_release_buffer(&tmpMinor, &iov[0].buffer); + ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED; - return major; + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_const_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, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + /* + * The channel binding token is optional, however if the caller indicated + * bindings we must raise an error if it was absent. + * + * In the future, we might use a context option to allow the caller to + * indicate that missing bindings are acceptable. + */ + if (chanBindings != NULL && + chanBindings->application_data.length != 0 && + (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) { + *minor = GSSEAP_MISSING_BINDINGS; + return GSS_S_BAD_BINDINGS; + } + + 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 @@ -662,7 +787,7 @@ static OM_uint32 eapGssSmAcceptReauthCreds(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -688,42 +813,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_const_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; } @@ -769,18 +880,25 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { eapGssSmAcceptAuthenticate }, { + ITOK_TYPE_GSS_FLAGS, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmAcceptGssFlags + }, + { ITOK_TYPE_GSS_CHANNEL_BINDINGS, ITOK_TYPE_NONE, GSSEAP_STATE_INITIATOR_EXTS, - SM_ITOK_FLAG_REQUIRED, + 0, 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 { @@ -793,16 +911,23 @@ static struct gss_eap_sm eapGssAcceptorSm[] = { #endif { ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_NAME_RESP, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmAcceptAcceptorName + }, + { ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_MIC, GSSEAP_STATE_ACCEPTOR_EXTS, 0, - eapGssSmAcceptCompleteAcceptorExts + eapGssSmAcceptAcceptorMIC }, }; OM_uint32 -gss_accept_sec_context(OM_uint32 *minor, - gss_ctx_id_t *context_handle, +gssEapAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, gss_cred_id_t cred, gss_buffer_t input_token, gss_channel_bindings_t input_chan_bindings, @@ -814,50 +939,29 @@ gss_accept_sec_context(OM_uint32 *minor, gss_cred_id_t *delegated_cred_handle) { OM_uint32 major, tmpMinor; - gss_ctx_id_t ctx = *context_handle; - - *minor = 0; - - output_token->length = 0; - output_token->value = NULL; - - if (src_name != NULL) - *src_name = GSS_C_NO_NAME; - - if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { - *minor = GSSEAP_TOK_TRUNC; - return GSS_S_DEFECTIVE_TOKEN; - } - - if (ctx == GSS_C_NO_CONTEXT) { - major = gssEapAllocContext(minor, &ctx); - if (GSS_ERROR(major)) - return major; - - *context_handle = ctx; - } - - GSSEAP_MUTEX_LOCK(&ctx->mutex); if (cred == GSS_C_NO_CREDENTIAL) { - if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) { + if (ctx->cred == GSS_C_NO_CREDENTIAL) { major = gssEapAcquireCred(minor, GSS_C_NO_NAME, - GSS_C_NO_BUFFER, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, - &ctx->defaultCred, + &ctx->cred, NULL, NULL); if (GSS_ERROR(major)) goto cleanup; } - cred = ctx->defaultCred; + cred = ctx->cred; } - GSSEAP_MUTEX_LOCK(&cred->mutex); + /* + * Previously we acquired the credential mutex here, but it should not be + * necessary as the acceptor does not access any mutable elements of the + * credential handle. + */ if (cred->name != GSS_C_NO_NAME) { major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName); @@ -908,16 +1012,9 @@ gss_accept_sec_context(OM_uint32 *minor, } } - assert(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED); + GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED); cleanup: - if (cred != GSS_C_NO_CREDENTIAL) - GSSEAP_MUTEX_UNLOCK(&cred->mutex); - GSSEAP_MUTEX_UNLOCK(&ctx->mutex); - - if (GSS_ERROR(major)) - gssEapReleaseContext(&tmpMinor, context_handle); - return major; } @@ -948,7 +1045,7 @@ static OM_uint32 eapGssSmAcceptGssReauth(OM_uint32 *minor, gss_cred_id_t cred, gss_ctx_id_t ctx, - gss_name_t target GSSEAP_UNUSED, + gss_const_name_t target GSSEAP_UNUSED, gss_OID mech, OM_uint32 reqFlags GSSEAP_UNUSED, OM_uint32 timeReq GSSEAP_UNUSED, @@ -1002,3 +1099,68 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor, return major; } #endif /* GSSEAP_ENABLE_REAUTH */ + +OM_uint32 GSSAPI_CALLCONV +gss_accept_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, +#ifdef HAVE_HEIMDAL_VERSION + gss_const_cred_id_t cred, +#else + gss_cred_id_t cred, +#endif + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = *context_handle; + + *minor = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = GSS_C_NO_NAME; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx == GSS_C_NO_CONTEXT) { + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + *context_handle = ctx; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapAcceptSecContext(minor, + ctx, + (gss_cred_id_t)cred, + input_token, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + if (GSS_ERROR(major)) + gssEapReleaseContext(&tmpMinor, context_handle); + + gssEapTraceStatus("gss_accept_sec_context", major, *minor); + + return major; +}