X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=unwrap_iov.c;h=19bafc6bbd8c3a5b7c715a36e8fa8569e4ffd7c8;hb=refs%2Fheads%2Fvm-integration;hp=45c4b2508c4fd87cfe7ec49d27ff42e8b2884965;hpb=9fbf196192538e4712b5596790db276b74b7e35a;p=mech_eap.orig diff --git a/unwrap_iov.c b/unwrap_iov.c index 45c4b25..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,25 +67,35 @@ 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; - unsigned char acceptor_flag; + unsigned char flags; unsigned char *ptr = NULL; - int key_usage; + int keyUsage; size_t rrc, ec; - size_t data_length, assoc_data_length; + size_t dataLen, assocDataLen; uint64_t seqnum; int valid = 0; - krb5_cksumtype cksumtype; int conf_flag = 0; + krb5_context krbContext; +#ifdef HAVE_HEIMDAL_VERSION + int freeCrypto = (krbCrypto == NULL); +#endif + + GSSEAP_KRB_INIT(&krbContext); *minor = 0; @@ -92,39 +106,53 @@ 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); - acceptor_flag = CTX_IS_INITIATOR(ctx) ? TOK_FLAG_SENDER_IS_ACCEPTOR : 0; - key_usage = (toktype == TOK_TYPE_WRAP - ? (!CTX_IS_INITIATOR(ctx) - ? KEY_USAGE_INITIATOR_SEAL - : KEY_USAGE_ACCEPTOR_SEAL) - : (!CTX_IS_INITIATOR(ctx) - ? KEY_USAGE_INITIATOR_SIGN - : KEY_USAGE_ACCEPTOR_SIGN)); + flags = rfc4121Flags(ctx, TRUE); - gssEapIovMessageLength(iov, iov_count, &data_length, &assoc_data_length); + if (toktype == TOK_TYPE_WRAP) { + keyUsage = !CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SEAL + : KEY_USAGE_ACCEPTOR_SEAL; + } else { + keyUsage = !CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SIGN + : KEY_USAGE_ACCEPTOR_SIGN; + } + + gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen); ptr = (unsigned char *)header->buffer.value; if (header->buffer.length < 16) { - *minor = 0; - return GSS_S_DEFECTIVE_TOKEN; + code = GSSEAP_TOK_TRUNC; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; } - if ((ptr[2] & TOK_FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) { - return GSS_S_BAD_SIG; + if ((ptr[2] & flags) != flags) { + code = GSSEAP_BAD_DIRECTION; + major = GSS_S_BAD_SIG; + goto cleanup; } - if (ptr[2] & TOK_FLAG_ACCEPTOR_SUBKEY) { - 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 k5_trailerlen; + size_t krbTrailerLen; if (load_uint16_be(ptr) != TOK_TYPE_WRAP) goto defective; @@ -135,19 +163,16 @@ unwrapToken(OM_uint32 *minor, rrc = load_uint16_be(ptr + 6); seqnum = load_uint64_be(ptr + 8); - code = krb5_c_crypto_length(ctx->kerberosCtx, - KRB_KEYTYPE(ctx->encryptionKey), - conf_flag ? KRB5_CRYPTO_TYPE_TRAILER : - KRB5_CRYPTO_TYPE_CHECKSUM, - &k5_trailerlen); - 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) { - size_t desired_rrc = k5_trailerlen; + size_t desired_rrc = krbTrailerLen; if (conf_flag) { desired_rrc += 16; /* E(Header) */ @@ -167,13 +192,13 @@ unwrapToken(OM_uint32 *minor, unsigned char *althdr; /* Decrypt */ - code = gssEapDecrypt(ctx->kerberosCtx, + code = gssEapDecrypt(krbContext, ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0), - ec, rrc, ctx->encryptionKey, - key_usage, 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 */ @@ -186,30 +211,31 @@ 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 */ - if (ec != k5_trailerlen) + if (ec != krbTrailerLen) goto defective; /* Zero EC, RRC before computing checksum */ store_uint16_be(0, ptr + 4); store_uint16_be(0, ptr + 6); - code = gssEapVerify(ctx->kerberosCtx, cksumtype, rrc, - ctx->encryptionKey, key_usage, + code = gssEapVerify(krbContext, ctx->checksumType, rrc, + 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(&ctx->seqState, seqnum); + code = sequenceCheck(minor, &ctx->seqState, seqnum); } else if (toktype == TOK_TYPE_MIC) { - if (load_uint16_be(ptr) != TOK_TYPE_MIC) + if (load_uint16_be(ptr) != toktype) goto defective; verify_mic_1: @@ -217,33 +243,41 @@ unwrapToken(OM_uint32 *minor, goto defective; seqnum = load_uint64_be(ptr + 8); - code = gssEapVerify(ctx->kerberosCtx, cksumtype, 0, - ctx->encryptionKey, key_usage, + code = gssEapVerify(krbContext, ctx->checksumType, 0, + 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(&ctx->seqState, seqnum); - } else if (toktype == TOK_TYPE_DELETE) { - if (load_uint16_be(ptr) != TOK_TYPE_DELETE) + code = sequenceCheck(minor, &ctx->seqState, seqnum); + } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { + if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT) goto defective; goto verify_mic_1; } else { 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; + +cleanup: + *minor = code; +#ifdef HAVE_HEIMDAL_VERSION + if (freeCrypto && krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif - return GSS_S_DEFECTIVE_TOKEN; + return major; } int @@ -284,17 +318,22 @@ unwrapStream(OM_uint32 *minor, { unsigned char *ptr; OM_uint32 code = 0, major = GSS_S_FAILURE; - krb5_context context = ctx->kerberosCtx; + krb5_context krbContext; int conf_req_flag, toktype2; int i = 0, j; 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 || (ctx->gssFlags & GSS_C_DCE_STYLE)) { - code = EINVAL; + if (toktype != TOK_TYPE_WRAP) { + 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 k5_headerlen = 0; - unsigned int k5_trailerlen = 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,30 +420,29 @@ unwrapStream(OM_uint32 *minor, } if (conf_req_flag) { - code = krb5_c_crypto_length(context, ctx->encryptionType, - KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen); + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); if (code != 0) goto cleanup; - theader->buffer.length += k5_headerlen; /* length validated later */ + theader->buffer.length += krbHeaderLen; /* length validated later */ } /* no PADDING for CFX, EC is used instead */ - code = krb5_c_crypto_length(context, ctx->encryptionType, - conf_req_flag - ? KRB5_CRYPTO_TYPE_TRAILER - : KRB5_CRYPTO_TYPE_CHECKSUM, - &k5_trailerlen); + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_req_flag + ? KRB5_CRYPTO_TYPE_TRAILER + : KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); if (code != 0) goto cleanup; ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + - k5_trailerlen; + krbTrailerLen; ttrailer->buffer.value = (unsigned char *)stream->buffer.value + stream->buffer.length - ttrailer->buffer.length; } /* 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_IS_ESTABLISHED(ctx)) - return GSS_S_NO_CONTEXT; + 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,6 +537,30 @@ gss_unwrap_iov(OM_uint32 *minor, gss_iov_buffer_desc *iov, int iov_count) { - return gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, - iov, iov_count, TOK_TYPE_WRAP); + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + 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; }