X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=blobdiff_plain;f=mech_eap%2Futil_context.c;h=b7a50c6150aba3fb6bc857db9ede37fc7fd00c97;hp=e9a930851fc584279e938b0785328042c3f5f449;hb=HEAD;hpb=fa210a112d16848a282d662f16f9b8589dd371df diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c index e9a9308..b7a50c6 100644 --- a/mech_eap/util_context.c +++ b/mech_eap/util_context.c @@ -43,7 +43,7 @@ gssEapAllocContext(OM_uint32 *minor, OM_uint32 tmpMinor; gss_ctx_id_t ctx; - assert(*pCtx == GSS_C_NO_CONTEXT); + GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT); ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx)); if (ctx == NULL) { @@ -52,12 +52,13 @@ gssEapAllocContext(OM_uint32 *minor, } if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) { - *minor = errno; + *minor = GSSEAP_GET_LAST_ERROR(); gssEapReleaseContext(&tmpMinor, &ctx); return GSS_S_FAILURE; } ctx->state = GSSEAP_STATE_INITIAL; + ctx->mechanismUsed = GSS_C_NO_OID; /* * Integrity, confidentiality, sequencing and replay detection are @@ -83,6 +84,7 @@ releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx) eap_peer_sm_deinit(ctx->eap); } +#ifdef GSSEAP_ENABLE_ACCEPTOR static void releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx) { @@ -98,6 +100,7 @@ releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx) if (ctx->vps != NULL) gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps); } +#endif /* GSSEAP_ENABLE_ACCEPTOR */ OM_uint32 gssEapReleaseContext(OM_uint32 *minor, @@ -117,19 +120,22 @@ gssEapReleaseContext(OM_uint32 *minor, if (ctx->flags & CTX_FLAG_KRB_REAUTH) { gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER); } else -#endif +#endif /* GSSEAP_ENABLE_REAUTH */ if (CTX_IS_INITIATOR(ctx)) { releaseInitiatorContext(&ctx->initiatorCtx); - } else { + } +#ifdef GSSEAP_ENABLE_ACCEPTOR + else { releaseAcceptorContext(&ctx->acceptorCtx); } +#endif /* GSSEAP_ENABLE_ACCEPTOR */ krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key); gssEapReleaseName(&tmpMinor, &ctx->initiatorName); gssEapReleaseName(&tmpMinor, &ctx->acceptorName); gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed); sequenceFree(&tmpMinor, &ctx->seqState); - gssEapReleaseCred(&tmpMinor, &ctx->defaultCred); + gssEapReleaseCred(&tmpMinor, &ctx->cred); GSSEAP_MUTEX_DESTROY(&ctx->mutex); @@ -150,6 +156,8 @@ gssEapMakeToken(OM_uint32 *minor, { unsigned char *p; + GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID); + outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length); outputToken->value = GSSEAP_MALLOC(outputToken->length); if (outputToken->value == NULL) { @@ -206,7 +214,7 @@ gssEapVerifyToken(OM_uint32 *minor, OM_uint32 gssEapContextTime(OM_uint32 *minor, - gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, OM_uint32 *time_rec) { *minor = 0; @@ -227,3 +235,223 @@ 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; + size_t i = 0, j; + enum gss_eap_token_type tokType; + OM_uint32 micTokType; + unsigned char wireTokType[2]; + unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL; + const struct gss_eap_token_buffer_set *tokens; + ssize_t checksumIndex = -1; + + krb5_keyusage usage; + krb5_error_code code = 0; + krb5_context krbContext; + krb5_crypto_iov *kiov = NULL; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; + krb5_cksumtype cksumType; +#endif + size_t kiovCount; + + GSSEAP_KRB_INIT(&krbContext); + + tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens; + + GSSEAP_ASSERT(tokens != NULL); + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; +#endif + + kiovCount = 2 + (3 * tokens->buffers.count) + 1; + + if (verifyMIC) { + assert(tokens->buffers.count != 0); + kiovCount -= 3; + } + + kiov = GSSEAP_CALLOC(kiovCount, sizeof(*kiov)); + if (kiov == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count); + if (innerTokTypes == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count); + if (innerTokLengths == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + /* Mechanism OID */ + GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID); + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = ctx->mechanismUsed->length; + kiov[i].data.data = ctx->mechanismUsed->elements; + i++; + + /* Token type */ + if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) { + tokType = TOK_TYPE_INITIATOR_CONTEXT; + micTokType = ITOK_TYPE_INITIATOR_MIC; + usage = KEY_USAGE_GSSEAP_INITOKEN_MIC; + } else { + tokType = TOK_TYPE_ACCEPTOR_CONTEXT; + micTokType = ITOK_TYPE_ACCEPTOR_MIC; + usage = KEY_USAGE_GSSEAP_ACCTOKEN_MIC; + } + store_uint16_be(tokType, wireTokType); + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = sizeof(wireTokType); + kiov[i].data.data = (char *)wireTokType; + i++; + + for (j = 0; j < tokens->buffers.count; j++) { + if (verifyMIC && + (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) { + continue; + } + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = 4; + kiov[i].data.data = (char *)&innerTokTypes[j * 4]; + store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED), + kiov[i].data.data); + i++; + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = 4; + kiov[i].data.data = (char *)&innerTokLengths[j * 4]; + store_uint32_be(tokens->buffers.elements[j].length, + kiov[i].data.data); + i++; + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + gssBufferToKrbData(&tokens->buffers.elements[j], &kiov[i].data); + i++; + } + + kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (verifyMIC) { + gssBufferToKrbData(tokenMIC, &kiov[i].data); + } else { + size_t checksumSize; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_checksumsize(krbContext, ctx->checksumType, + &checksumSize); +#else + code = krb5_c_checksum_length(krbContext, ctx->checksumType, + &checksumSize); +#endif + if (code != 0) + goto cleanup; + + kiov[i].data.data = GSSEAP_MALLOC(checksumSize); + if (kiov[i].data.data == NULL) { + code = ENOMEM; + goto cleanup; + } + kiov[i].data.length = checksumSize; + checksumIndex = i; + } + i++; + GSSEAP_ASSERT(i == kiovCount); + +#ifdef HAVE_HEIMDAL_VERSION + cksumType = ctx->checksumType; + + if (verifyMIC) { + code = krb5_verify_checksum_iov(krbContext, krbCrypto, usage, + kiov, i, &cksumType); + } else { + code = krb5_create_checksum_iov(krbContext, krbCrypto, usage, + kiov, i, &cksumType); + } +#else + if (verifyMIC) { + krb5_boolean kvalid = FALSE; + + code = krb5_c_verify_checksum_iov(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + usage, kiov, i, &kvalid); + if (code == 0 && !kvalid) { + code = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + } else { + code = krb5_c_make_checksum_iov(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + usage, kiov, i); + } +#endif /* HAVE_HEIMDAL_VERSION */ + + if (code == 0 && !verifyMIC) { + krbDataToGssBuffer(&kiov[checksumIndex].data, tokenMIC); + checksumIndex = -1; + } + +cleanup: + if (checksumIndex != -1) + GSSEAP_FREE(kiov[checksumIndex].data.data); + if (kiov != NULL) + GSSEAP_FREE(kiov); + if (innerTokTypes != NULL) + GSSEAP_FREE(innerTokTypes); + if (innerTokLengths != NULL) + GSSEAP_FREE(innerTokLengths); +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + *minor = code; + + switch (code) { + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + major = GSS_S_BAD_SIG; + break; + case 0: + major = GSS_S_COMPLETE; + break; + default: + major = GSS_S_FAILURE; + break; + } + + 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) +{ + return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE); +}