X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wrap_iov.c;h=ae43ef9b8ebcc051cb16989187be28ff5f668307;hb=31355119edb3a282ab302c05e33e23430af67603;hp=ccc9b161c1cfd9b62a6747e2e9d3ab07664e1f35;hpb=2726871e0ab92938b385d2a1e6deef44ecb208b8;p=mech_eap.orig diff --git a/wrap_iov.c b/wrap_iov.c index ccc9b16..ae43ef9 100644 --- a/wrap_iov.c +++ b/wrap_iov.c @@ -29,9 +29,294 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +/* + * Copyright 2008 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ #include "gssapiP_eap.h" +unsigned char +rfc4121Flags(gss_ctx_id_t ctx, int receiving) +{ + unsigned char flags; + int isAcceptor; + + isAcceptor = !CTX_IS_INITIATOR(ctx); + if (receiving) + isAcceptor = !isAcceptor; + + flags = 0; + if (isAcceptor) + flags |= TOK_FLAG_SENDER_IS_ACCEPTOR; + + if ((ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) && + (ctx->gssFlags & GSS_C_MUTUAL_FLAG)) + flags |= TOK_FLAG_ACCEPTOR_SUBKEY; + + return flags; +} + +OM_uint32 +gssEapWrapOrGetMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype) +{ + krb5_error_code code = 0; + gss_iov_buffer_t header; + gss_iov_buffer_t padding; + gss_iov_buffer_t trailer; + unsigned char flags; + unsigned char *outbuf = NULL; + unsigned char *tbuf = NULL; + int keyUsage; + size_t rrc = 0; + unsigned int gssHeaderLen, gssTrailerLen; + size_t dataLen, assocDataLen; + krb5_context krbContext; + + if (ctx->encryptionType == ENCTYPE_NULL) + return GSS_S_UNAVAILABLE; + + GSSEAP_KRB_INIT(&krbContext); + + flags = rfc4121Flags(ctx, FALSE); + + 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); + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor = EINVAL; + return GSS_S_FAILURE; + } + + padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL) + padding->buffer.length = 0; + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + if (toktype == TOK_TYPE_WRAP && conf_req_flag) { + unsigned int krbHeaderLen, krbTrailerLen, krbPadLen; + size_t ec = 0; + size_t confDataLen = dataLen - assocDataLen; + + code = krb5_c_crypto_length(krbContext, ctx->encryptionType, + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); + if (code != 0) + goto cleanup; + + code = krb5_c_padding_length(krbContext, ctx->encryptionType, + confDataLen + 16 /* E(Header) */, + &krbPadLen); + if (code != 0) + goto cleanup; + + if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) { + /* Windows rejects AEAD tokens with non-zero EC */ + code = krb5_c_block_size(krbContext, ctx->encryptionType, &ec); + if (code != 0) + goto cleanup; + } else + ec = krbPadLen; + + code = krb5_c_crypto_length(krbContext, ctx->encryptionType, + KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen); + if (code != 0) + goto cleanup; + + gssHeaderLen = 16 /* Header */ + krbHeaderLen; + gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen; + + if (trailer == NULL) { + rrc = gssTrailerLen; + /* Workaround for Windows bug where it rotates by EC + RRC */ + if (ctx->gssFlags & GSS_C_DCE_STYLE) + rrc -= ec; + gssHeaderLen += gssTrailerLen; + } + + if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + code = gssEapAllocIov(header, (size_t)gssHeaderLen); + } else if (header->buffer.length < gssHeaderLen) + code = KRB5_BAD_MSIZE; + if (code != 0) + goto cleanup; + outbuf = (unsigned char *)header->buffer.value; + header->buffer.length = (size_t)gssHeaderLen; + + if (trailer != NULL) { + if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(trailer, (size_t)gssTrailerLen); + else if (trailer->buffer.length < gssTrailerLen) + code = KRB5_BAD_MSIZE; + if (code != 0) + goto cleanup; + trailer->buffer.length = (size_t)gssTrailerLen; + } + + /* TOK_ID */ + store_uint16_be((uint16_t)toktype, outbuf); + /* flags */ + outbuf[2] = flags + | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0); + /* filler */ + outbuf[3] = 0xFF; + /* EC */ + store_uint16_be(ec, outbuf + 4); + /* RRC */ + store_uint16_be(0, outbuf + 6); + store_uint64_be(ctx->sendSeq, outbuf + 8); + + /* + * EC | copy of header to be encrypted, located in + * (possibly rotated) trailer + */ + if (trailer == NULL) + tbuf = (unsigned char *)header->buffer.value + 16; /* Header */ + else + tbuf = (unsigned char *)trailer->buffer.value; + + memset(tbuf, 0xFF, ec); + memcpy(tbuf + ec, header->buffer.value, 16); + + code = gssEapEncrypt(krbContext, + ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0), + ec, rrc, &ctx->rfc3961Key, + keyUsage, 0, iov, iov_count); + if (code != 0) + goto cleanup; + + /* RRC */ + store_uint16_be(rrc, outbuf + 6); + + ctx->sendSeq++; + } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) { + wrap_with_checksum: + + gssHeaderLen = 16; + + code = krb5_c_crypto_length(krbContext, ctx->encryptionType, + KRB5_CRYPTO_TYPE_CHECKSUM, + &gssTrailerLen); + if (code != 0) + goto cleanup; + + assert(gssTrailerLen <= 0xFFFF); + + if (trailer == NULL) { + rrc = gssTrailerLen; + gssHeaderLen += gssTrailerLen; + } + + if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(header, (size_t)gssHeaderLen); + else if (header->buffer.length < gssHeaderLen) + code = KRB5_BAD_MSIZE; + if (code != 0) + goto cleanup; + outbuf = (unsigned char *)header->buffer.value; + header->buffer.length = (size_t)gssHeaderLen; + + if (trailer != NULL) { + if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(trailer, (size_t)gssTrailerLen); + else if (trailer->buffer.length < gssTrailerLen) + code = KRB5_BAD_MSIZE; + if (code != 0) + goto cleanup; + trailer->buffer.length = (size_t)gssTrailerLen; + } + + /* TOK_ID */ + store_uint16_be((uint16_t)toktype, outbuf); + /* flags */ + outbuf[2] = flags; + /* filler */ + outbuf[3] = 0xFF; + if (toktype == TOK_TYPE_WRAP) { + /* Use 0 for checksum calculation, substitute + * checksum length later. + */ + /* EC */ + store_uint16_be(0, outbuf + 4); + /* RRC */ + store_uint16_be(0, outbuf + 6); + } else { + /* MIC and DEL store 0xFF in EC and RRC */ + store_uint16_be(0xFFFF, outbuf + 4); + store_uint16_be(0xFFFF, outbuf + 6); + } + store_uint64_be(ctx->sendSeq, outbuf + 8); + + code = gssEapSign(krbContext, ctx->checksumType, + rrc, &ctx->rfc3961Key, keyUsage, + iov, iov_count); + if (code != 0) + goto cleanup; + + ctx->sendSeq++; + + if (toktype == TOK_TYPE_WRAP) { + /* Fix up EC field */ + store_uint16_be(gssTrailerLen, outbuf + 4); + /* Fix up RRC field */ + store_uint16_be(rrc, outbuf + 6); + } + } else if (toktype == TOK_TYPE_MIC) { + trailer = NULL; + goto wrap_with_checksum; + } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { + trailer = NULL; + goto wrap_with_checksum; + } else { + abort(); + } + + code = 0; + +cleanup: + if (code != 0) + gssEapReleaseIov(iov, iov_count); + + *minor = code; + + return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + OM_uint32 gss_wrap_iov(OM_uint32 *minor, gss_ctx_id_t ctx, @@ -41,5 +326,9 @@ gss_wrap_iov(OM_uint32 *minor, gss_iov_buffer_desc *iov, int iov_count) { - GSSEAP_NOT_IMPLEMENTED; + if (!CTX_IS_ESTABLISHED(ctx)) + return GSS_S_NO_CONTEXT; + + return gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state, + iov, iov_count, TOK_TYPE_WRAP); }