X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=blobdiff_plain;f=unwrap_iov.c;h=19bafc6bbd8c3a5b7c715a36e8fa8569e4ffd7c8;hp=dcb1ff1102517a6eabc95e38a172030b1e903fb2;hb=ae79fdae047f980d01b2b4e84ccea52e24d8c7a0;hpb=d5a9b52e3911edd09988005462028ed7dbdf5899 diff --git a/unwrap_iov.c b/unwrap_iov.c index dcb1ff1..19bafc6 100644 --- a/unwrap_iov.c +++ b/unwrap_iov.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, JANET(UK) + * Copyright (c) 2011, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,10 @@ * or implied warranty. */ +/* + * Message protection services: unwrap with scatter-gather API. + */ + #include "gssapiP_eap.h" /* @@ -63,13 +67,18 @@ OM_uint32 unwrapToken(OM_uint32 *minor, gss_ctx_id_t ctx, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *unused GSSEAP_UNUSED, +#endif int *conf_state, gss_qop_t *qop_state, gss_iov_buffer_desc *iov, int iov_count, enum gss_eap_token_type toktype) { - OM_uint32 code; + OM_uint32 major = GSS_S_FAILURE, code; gss_iov_buffer_t header; gss_iov_buffer_t padding; gss_iov_buffer_t trailer; @@ -82,6 +91,9 @@ unwrapToken(OM_uint32 *minor, int valid = 0; int conf_flag = 0; krb5_context krbContext; +#ifdef HAVE_HEIMDAL_VERSION + int freeCrypto = (krbCrypto == NULL); +#endif GSSEAP_KRB_INIT(&krbContext); @@ -94,8 +106,11 @@ unwrapToken(OM_uint32 *minor, assert(header != NULL); padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); - if (padding != NULL && padding->buffer.length != 0) - return GSS_S_DEFECTIVE_TOKEN; + if (padding != NULL && padding->buffer.length != 0) { + code = GSSEAP_BAD_PADDING_IOV; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); @@ -115,14 +130,29 @@ unwrapToken(OM_uint32 *minor, ptr = (unsigned char *)header->buffer.value; - if (header->buffer.length < 16) - return GSS_S_DEFECTIVE_TOKEN; + if (header->buffer.length < 16) { + code = GSSEAP_TOK_TRUNC; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } + + if ((ptr[2] & flags) != flags) { + code = GSSEAP_BAD_DIRECTION; + major = GSS_S_BAD_SIG; + goto cleanup; + } - if ((ptr[2] & flags) != flags) - return GSS_S_BAD_SIG; +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto == NULL) { + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, + ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; + } +#endif if (toktype == TOK_TYPE_WRAP) { - unsigned int krbTrailerLen; + size_t krbTrailerLen; if (load_uint16_be(ptr) != TOK_TYPE_WRAP) goto defective; @@ -133,15 +163,12 @@ unwrapToken(OM_uint32 *minor, rrc = load_uint16_be(ptr + 6); seqnum = load_uint64_be(ptr + 8); - code = krb5_c_crypto_length(krbContext, - ctx->encryptionType, - conf_flag ? KRB5_CRYPTO_TYPE_TRAILER : - KRB5_CRYPTO_TYPE_CHECKSUM, - &krbTrailerLen); - if (code != 0) { - *minor = code; - return GSS_S_FAILURE; - } + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_flag ? KRB5_CRYPTO_TYPE_TRAILER : + KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); + if (code != 0) + goto cleanup; /* Deal with RRC */ if (trailer == NULL) { @@ -167,11 +194,11 @@ unwrapToken(OM_uint32 *minor, /* Decrypt */ code = gssEapDecrypt(krbContext, ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0), - ec, rrc, &ctx->rfc3961Key, - keyUsage, 0, iov, iov_count); + ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage, + iov, iov_count); if (code != 0) { - *minor = code; - return GSS_S_BAD_SIG; + major = GSS_S_BAD_SIG; + goto cleanup; } /* Validate header integrity */ @@ -184,8 +211,9 @@ unwrapToken(OM_uint32 *minor, || althdr[2] != ptr[2] || althdr[3] != ptr[3] || memcmp(althdr + 8, ptr + 8, 8) != 0) { - *minor = 0; - return GSS_S_BAD_SIG; + code = GSSEAP_BAD_WRAP_TOKEN; + major = GSS_S_BAD_SIG; + goto cleanup; } } else { /* Verify checksum: note EC is checksum size here, not padding */ @@ -197,11 +225,11 @@ unwrapToken(OM_uint32 *minor, store_uint16_be(0, ptr + 6); code = gssEapVerify(krbContext, ctx->checksumType, rrc, - &ctx->rfc3961Key, keyUsage, + KRB_CRYPTO_CONTEXT(ctx), keyUsage, iov, iov_count, &valid); if (code != 0 || valid == FALSE) { - *minor = code; - return GSS_S_BAD_SIG; + major = GSS_S_BAD_SIG; + goto cleanup; } } @@ -216,11 +244,11 @@ unwrapToken(OM_uint32 *minor, seqnum = load_uint64_be(ptr + 8); code = gssEapVerify(krbContext, ctx->checksumType, 0, - &ctx->rfc3961Key, keyUsage, + KRB_CRYPTO_CONTEXT(ctx), keyUsage, iov, iov_count, &valid); if (code != 0 || valid == FALSE) { - *minor = code; - return GSS_S_BAD_SIG; + major = GSS_S_BAD_SIG; + goto cleanup; } code = sequenceCheck(minor, &ctx->seqState, seqnum); } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { @@ -231,17 +259,25 @@ unwrapToken(OM_uint32 *minor, goto defective; } - *minor = 0; - if (conf_state != NULL) *conf_state = conf_flag; - return code; + code = 0; + major = GSS_S_COMPLETE; + goto cleanup; defective: - *minor = 0; + code = GSSEAP_BAD_WRAP_TOKEN; + major = GSS_S_DEFECTIVE_TOKEN; - return GSS_S_DEFECTIVE_TOKEN; +cleanup: + *minor = code; +#ifdef HAVE_HEIMDAL_VERSION + if (freeCrypto && krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + return major; } int @@ -288,13 +324,16 @@ unwrapStream(OM_uint32 *minor, gss_iov_buffer_desc *tiov = NULL; gss_iov_buffer_t stream, data = NULL; gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; +#endif GSSEAP_KRB_INIT(&krbContext); assert(toktype == TOK_TYPE_WRAP); if (toktype != TOK_TYPE_WRAP) { - code = EINVAL; + code = GSSEAP_WRONG_TOK_ID; goto cleanup; } @@ -330,7 +369,7 @@ unwrapStream(OM_uint32 *minor, if (type == GSS_IOV_BUFFER_TYPE_DATA) { if (data != NULL) { /* only a single DATA buffer can appear */ - code = EINVAL; + code = GSSEAP_BAD_STREAM_IOV; goto cleanup; } @@ -344,7 +383,7 @@ unwrapStream(OM_uint32 *minor, if (data == NULL) { /* a single DATA buffer must be present */ - code = EINVAL; + code = GSSEAP_BAD_STREAM_IOV; goto cleanup; } @@ -357,10 +396,16 @@ unwrapStream(OM_uint32 *minor, ttrailer = &tiov[i++]; ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER; +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; +#endif + { size_t ec, rrc; - unsigned int krbHeaderLen = 0; - unsigned int krbTrailerLen = 0; + size_t krbHeaderLen = 0; + size_t krbTrailerLen = 0; conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0); ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0; @@ -375,19 +420,19 @@ unwrapStream(OM_uint32 *minor, } if (conf_req_flag) { - code = krb5_c_crypto_length(krbContext, ctx->encryptionType, - KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); if (code != 0) goto cleanup; theader->buffer.length += krbHeaderLen; /* length validated later */ } /* no PADDING for CFX, EC is used instead */ - code = krb5_c_crypto_length(krbContext, ctx->encryptionType, - conf_req_flag - ? KRB5_CRYPTO_TYPE_TRAILER - : KRB5_CRYPTO_TYPE_CHECKSUM, - &krbTrailerLen); + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_req_flag + ? KRB5_CRYPTO_TYPE_TRAILER + : KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); if (code != 0) goto cleanup; @@ -398,7 +443,6 @@ unwrapStream(OM_uint32 *minor, } /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/ - /* Old: GSS-Header | Conf | Data | Pad | */ /* CFX: GSS-Header | Kerb-Header | Data | | EC | E(Header) | Kerb-Trailer */ /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/ @@ -406,8 +450,8 @@ unwrapStream(OM_uint32 *minor, if (stream->buffer.length < theader->buffer.length + tpadding->buffer.length + ttrailer->buffer.length) { - code = KRB5_BAD_MSIZE; major = GSS_S_DEFECTIVE_TOKEN; + code = GSSEAP_TOK_TRUNC; goto cleanup; } @@ -432,8 +476,8 @@ unwrapStream(OM_uint32 *minor, assert(i <= iov_count + 2); - major = unwrapToken(&code, ctx, conf_state, qop_state, - tiov, i, toktype); + major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx), + conf_state, qop_state, tiov, i, toktype); if (major == GSS_S_COMPLETE) { *data = *tdata; } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { @@ -446,6 +490,10 @@ unwrapStream(OM_uint32 *minor, cleanup: if (tiov != NULL) GSSEAP_FREE(tiov); +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif *minor = code; @@ -463,14 +511,18 @@ gssEapUnwrapOrVerifyMIC(OM_uint32 *minor, { OM_uint32 major; - if (ctx->encryptionType == ENCTYPE_NULL) + if (ctx->encryptionType == ENCTYPE_NULL) { + *minor = GSSEAP_KEY_UNAVAILABLE; return GSS_S_UNAVAILABLE; + } if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) { major = unwrapStream(minor, ctx, conf_state, qop_state, iov, iov_count, toktype); } else { - major = unwrapToken(minor, ctx, conf_state, qop_state, + major = unwrapToken(minor, ctx, + NULL, /* krbCrypto */ + conf_state, qop_state, iov, iov_count, toktype); } @@ -485,20 +537,29 @@ gss_unwrap_iov(OM_uint32 *minor, gss_iov_buffer_desc *iov, int iov_count) { - OM_uint32 major = GSS_C_NO_CONTEXT; + OM_uint32 major; - *minor = 0; + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } - if (ctx == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + *minor = 0; GSSEAP_MUTEX_LOCK(&ctx->mutex); - if (CTX_IS_ESTABLISHED(ctx)) { - major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, - iov, iov_count, TOK_TYPE_WRAP); + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; } + major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, + iov, iov_count, TOK_TYPE_WRAP); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: GSSEAP_MUTEX_UNLOCK(&ctx->mutex); return major;