Path: blob/main/crypto/heimdal/lib/gssapi/krb5/cfx.c
34923 views
/*1* Copyright (c) 2003, PADL Software Pty Ltd.2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7*8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10*11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* 3. Neither the name of PADL Software nor the names of its contributors16* may be used to endorse or promote products derived from this software17* without specific prior written permission.18*19* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*/3132#include "gsskrb5_locl.h"3334/*35* Implementation of RFC 412136*/3738#define CFXSentByAcceptor (1 << 0)39#define CFXSealed (1 << 1)40#define CFXAcceptorSubkey (1 << 2)4142krb5_error_code43_gsskrb5cfx_wrap_length_cfx(krb5_context context,44krb5_crypto crypto,45int conf_req_flag,46int dce_style,47size_t input_length,48size_t *output_length,49size_t *cksumsize,50uint16_t *padlength)51{52krb5_error_code ret;53krb5_cksumtype type;5455/* 16-byte header is always first */56*output_length = sizeof(gss_cfx_wrap_token_desc);57*padlength = 0;5859ret = krb5_crypto_get_checksum_type(context, crypto, &type);60if (ret)61return ret;6263ret = krb5_checksumsize(context, type, cksumsize);64if (ret)65return ret;6667if (conf_req_flag) {68size_t padsize;6970/* Header is concatenated with data before encryption */71input_length += sizeof(gss_cfx_wrap_token_desc);7273if (dce_style) {74ret = krb5_crypto_getblocksize(context, crypto, &padsize);75} else {76ret = krb5_crypto_getpadsize(context, crypto, &padsize);77}78if (ret) {79return ret;80}81if (padsize > 1) {82/* XXX check this */83*padlength = padsize - (input_length % padsize);8485/* We add the pad ourselves (noted here for completeness only) */86input_length += *padlength;87}8889*output_length += krb5_get_wrapped_length(context,90crypto, input_length);91} else {92/* Checksum is concatenated with data */93*output_length += input_length + *cksumsize;94}9596assert(*output_length > input_length);9798return 0;99}100101OM_uint32102_gssapi_wrap_size_cfx(OM_uint32 *minor_status,103const gsskrb5_ctx ctx,104krb5_context context,105int conf_req_flag,106gss_qop_t qop_req,107OM_uint32 req_output_size,108OM_uint32 *max_input_size)109{110krb5_error_code ret;111112*max_input_size = 0;113114/* 16-byte header is always first */115if (req_output_size < 16)116return 0;117req_output_size -= 16;118119if (conf_req_flag) {120size_t wrapped_size, sz;121122wrapped_size = req_output_size + 1;123do {124wrapped_size--;125sz = krb5_get_wrapped_length(context,126ctx->crypto, wrapped_size);127} while (wrapped_size && sz > req_output_size);128if (wrapped_size == 0)129return 0;130131/* inner header */132if (wrapped_size < 16)133return 0;134135wrapped_size -= 16;136137*max_input_size = wrapped_size;138} else {139krb5_cksumtype type;140size_t cksumsize;141142ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);143if (ret)144return ret;145146ret = krb5_checksumsize(context, type, &cksumsize);147if (ret)148return ret;149150if (req_output_size < cksumsize)151return 0;152153/* Checksum is concatenated with data */154*max_input_size = req_output_size - cksumsize;155}156157return 0;158}159160/*161* Rotate "rrc" bytes to the front or back162*/163164static krb5_error_code165rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)166{167u_char *tmp, buf[256];168size_t left;169170if (len == 0)171return 0;172173rrc %= len;174175if (rrc == 0)176return 0;177178left = len - rrc;179180if (rrc <= sizeof(buf)) {181tmp = buf;182} else {183tmp = malloc(rrc);184if (tmp == NULL)185return ENOMEM;186}187188if (unrotate) {189memcpy(tmp, data, rrc);190memmove(data, (u_char *)data + rrc, left);191memcpy((u_char *)data + left, tmp, rrc);192} else {193memcpy(tmp, (u_char *)data + left, rrc);194memmove((u_char *)data + rrc, data, left);195memcpy(data, tmp, rrc);196}197198if (rrc > sizeof(buf))199free(tmp);200201return 0;202}203204gss_iov_buffer_desc *205_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)206{207int i;208209for (i = 0; i < iov_count; i++)210if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))211return &iov[i];212return NULL;213}214215OM_uint32216_gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)217{218if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {219if (buffer->buffer.length == size)220return GSS_S_COMPLETE;221free(buffer->buffer.value);222}223224buffer->buffer.value = malloc(size);225buffer->buffer.length = size;226if (buffer->buffer.value == NULL) {227*minor_status = ENOMEM;228return GSS_S_FAILURE;229}230buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;231232return GSS_S_COMPLETE;233}234235236OM_uint32237_gk_verify_buffers(OM_uint32 *minor_status,238const gsskrb5_ctx ctx,239const gss_iov_buffer_desc *header,240const gss_iov_buffer_desc *padding,241const gss_iov_buffer_desc *trailer)242{243if (header == NULL) {244*minor_status = EINVAL;245return GSS_S_FAILURE;246}247248if (IS_DCE_STYLE(ctx)) {249/*250* In DCE style mode we reject having a padding or trailer buffer251*/252if (padding) {253*minor_status = EINVAL;254return GSS_S_FAILURE;255}256if (trailer) {257*minor_status = EINVAL;258return GSS_S_FAILURE;259}260} else {261/*262* In non-DCE style mode we require having a padding buffer263*/264if (padding == NULL) {265*minor_status = EINVAL;266return GSS_S_FAILURE;267}268}269270*minor_status = 0;271return GSS_S_COMPLETE;272}273274#if 0275OM_uint32276_gssapi_wrap_cfx_iov(OM_uint32 *minor_status,277gsskrb5_ctx ctx,278krb5_context context,279int conf_req_flag,280int *conf_state,281gss_iov_buffer_desc *iov,282int iov_count)283{284OM_uint32 major_status, junk;285gss_iov_buffer_desc *header, *trailer, *padding;286size_t gsshsize, k5hsize;287size_t gsstsize, k5tsize;288size_t rrc = 0, ec = 0;289int i;290gss_cfx_wrap_token token;291krb5_error_code ret;292int32_t seq_number;293unsigned usage;294krb5_crypto_iov *data = NULL;295296header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);297if (header == NULL) {298*minor_status = EINVAL;299return GSS_S_FAILURE;300}301302padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);303if (padding != NULL) {304padding->buffer.length = 0;305}306307trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);308309major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);310if (major_status != GSS_S_COMPLETE) {311return major_status;312}313314if (conf_req_flag) {315size_t k5psize = 0;316size_t k5pbase = 0;317size_t k5bsize = 0;318size_t size = 0;319320for (i = 0; i < iov_count; i++) {321switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {322case GSS_IOV_BUFFER_TYPE_DATA:323size += iov[i].buffer.length;324break;325default:326break;327}328}329330size += sizeof(gss_cfx_wrap_token_desc);331332*minor_status = krb5_crypto_length(context, ctx->crypto,333KRB5_CRYPTO_TYPE_HEADER,334&k5hsize);335if (*minor_status)336return GSS_S_FAILURE;337338*minor_status = krb5_crypto_length(context, ctx->crypto,339KRB5_CRYPTO_TYPE_TRAILER,340&k5tsize);341if (*minor_status)342return GSS_S_FAILURE;343344*minor_status = krb5_crypto_length(context, ctx->crypto,345KRB5_CRYPTO_TYPE_PADDING,346&k5pbase);347if (*minor_status)348return GSS_S_FAILURE;349350if (k5pbase > 1) {351k5psize = k5pbase - (size % k5pbase);352} else {353k5psize = 0;354}355356if (k5psize == 0 && IS_DCE_STYLE(ctx)) {357*minor_status = krb5_crypto_getblocksize(context, ctx->crypto,358&k5bsize);359if (*minor_status)360return GSS_S_FAILURE;361ec = k5bsize;362} else {363ec = k5psize;364}365366gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;367gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;368} else {369if (IS_DCE_STYLE(ctx)) {370*minor_status = EINVAL;371return GSS_S_FAILURE;372}373374k5hsize = 0;375*minor_status = krb5_crypto_length(context, ctx->crypto,376KRB5_CRYPTO_TYPE_CHECKSUM,377&k5tsize);378if (*minor_status)379return GSS_S_FAILURE;380381gsshsize = sizeof(gss_cfx_wrap_token_desc);382gsstsize = k5tsize;383}384385/*386*387*/388389if (trailer == NULL) {390rrc = gsstsize;391if (IS_DCE_STYLE(ctx))392rrc -= ec;393gsshsize += gsstsize;394gsstsize = 0;395} else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {396major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);397if (major_status)398goto failure;399} else if (trailer->buffer.length < gsstsize) {400*minor_status = KRB5_BAD_MSIZE;401major_status = GSS_S_FAILURE;402goto failure;403} else404trailer->buffer.length = gsstsize;405406/*407*408*/409410if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {411major_status = _gk_allocate_buffer(minor_status, header, gsshsize);412if (major_status != GSS_S_COMPLETE)413goto failure;414} else if (header->buffer.length < gsshsize) {415*minor_status = KRB5_BAD_MSIZE;416major_status = GSS_S_FAILURE;417goto failure;418} else419header->buffer.length = gsshsize;420421token = (gss_cfx_wrap_token)header->buffer.value;422423token->TOK_ID[0] = 0x05;424token->TOK_ID[1] = 0x04;425token->Flags = 0;426token->Filler = 0xFF;427428if ((ctx->more_flags & LOCAL) == 0)429token->Flags |= CFXSentByAcceptor;430431if (ctx->more_flags & ACCEPTOR_SUBKEY)432token->Flags |= CFXAcceptorSubkey;433434if (ctx->more_flags & LOCAL)435usage = KRB5_KU_USAGE_INITIATOR_SEAL;436else437usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;438439if (conf_req_flag) {440/*441* In Wrap tokens with confidentiality, the EC field is442* used to encode the size (in bytes) of the random filler.443*/444token->Flags |= CFXSealed;445token->EC[0] = (ec >> 8) & 0xFF;446token->EC[1] = (ec >> 0) & 0xFF;447448} else {449/*450* In Wrap tokens without confidentiality, the EC field is451* used to encode the size (in bytes) of the trailing452* checksum.453*454* This is not used in the checksum calcuation itself,455* because the checksum length could potentially vary456* depending on the data length.457*/458token->EC[0] = 0;459token->EC[1] = 0;460}461462/*463* In Wrap tokens that provide for confidentiality, the RRC464* field in the header contains the hex value 00 00 before465* encryption.466*467* In Wrap tokens that do not provide for confidentiality,468* both the EC and RRC fields in the appended checksum469* contain the hex value 00 00 for the purpose of calculating470* the checksum.471*/472token->RRC[0] = 0;473token->RRC[1] = 0;474475HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);476krb5_auth_con_getlocalseqnumber(context,477ctx->auth_context,478&seq_number);479_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);480_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);481krb5_auth_con_setlocalseqnumber(context,482ctx->auth_context,483++seq_number);484HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);485486data = calloc(iov_count + 3, sizeof(data[0]));487if (data == NULL) {488*minor_status = ENOMEM;489major_status = GSS_S_FAILURE;490goto failure;491}492493if (conf_req_flag) {494/*495plain packet:496497{"header" | encrypt(plaintext-data | ec-padding | E"header")}498499Expanded, this is with with RRC = 0:500501{"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }502503In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)504505{"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data }506*/507508i = 0;509data[i].flags = KRB5_CRYPTO_TYPE_HEADER;510data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;511data[i].data.length = k5hsize;512513for (i = 1; i < iov_count + 1; i++) {514switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {515case GSS_IOV_BUFFER_TYPE_DATA:516data[i].flags = KRB5_CRYPTO_TYPE_DATA;517break;518case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:519data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;520break;521default:522data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;523break;524}525data[i].data.length = iov[i - 1].buffer.length;526data[i].data.data = iov[i - 1].buffer.value;527}528529/*530* Any necessary padding is added here to ensure that the531* encrypted token header is always at the end of the532* ciphertext.533*/534535/* encrypted CFX header in trailer (or after the header if in536DCE mode). Copy in header into E"header"537*/538data[i].flags = KRB5_CRYPTO_TYPE_DATA;539if (trailer)540data[i].data.data = trailer->buffer.value;541else542data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);543544data[i].data.length = ec + sizeof(*token);545memset(data[i].data.data, 0xFF, ec);546memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));547i++;548549/* Kerberos trailer comes after the gss trailer */550data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;551data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);552data[i].data.length = k5tsize;553i++;554555ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);556if (ret != 0) {557*minor_status = ret;558major_status = GSS_S_FAILURE;559goto failure;560}561562if (rrc) {563token->RRC[0] = (rrc >> 8) & 0xFF;564token->RRC[1] = (rrc >> 0) & 0xFF;565}566567} else {568/*569plain packet:570571{data | "header" | gss-trailer (krb5 checksum)572573don't do RRC != 0574575*/576577for (i = 0; i < iov_count; i++) {578switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {579case GSS_IOV_BUFFER_TYPE_DATA:580data[i].flags = KRB5_CRYPTO_TYPE_DATA;581break;582case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:583data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;584break;585default:586data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;587break;588}589data[i].data.length = iov[i].buffer.length;590data[i].data.data = iov[i].buffer.value;591}592593data[i].flags = KRB5_CRYPTO_TYPE_DATA;594data[i].data.data = header->buffer.value;595data[i].data.length = sizeof(gss_cfx_wrap_token_desc);596i++;597598data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;599if (trailer) {600data[i].data.data = trailer->buffer.value;601} else {602data[i].data.data = (uint8_t *)header->buffer.value +603sizeof(gss_cfx_wrap_token_desc);604}605data[i].data.length = k5tsize;606i++;607608ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);609if (ret) {610*minor_status = ret;611major_status = GSS_S_FAILURE;612goto failure;613}614615if (rrc) {616token->RRC[0] = (rrc >> 8) & 0xFF;617token->RRC[1] = (rrc >> 0) & 0xFF;618}619620token->EC[0] = (k5tsize >> 8) & 0xFF;621token->EC[1] = (k5tsize >> 0) & 0xFF;622}623624if (conf_state != NULL)625*conf_state = conf_req_flag;626627free(data);628629*minor_status = 0;630return GSS_S_COMPLETE;631632failure:633if (data)634free(data);635636gss_release_iov_buffer(&junk, iov, iov_count);637638return major_status;639}640#endif641642/* This is slowpath */643static OM_uint32644unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)645{646uint8_t *p, *q;647size_t len = 0, skip;648int i;649650for (i = 0; i < iov_count; i++)651if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||652GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||653GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)654len += iov[i].buffer.length;655656p = malloc(len);657if (p == NULL) {658*minor_status = ENOMEM;659return GSS_S_FAILURE;660}661q = p;662663/* copy up */664665for (i = 0; i < iov_count; i++) {666if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||667GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||668GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)669{670memcpy(q, iov[i].buffer.value, iov[i].buffer.length);671q += iov[i].buffer.length;672}673}674assert((size_t)(q - p) == len);675676/* unrotate first part */677q = p + rrc;678skip = rrc;679for (i = 0; i < iov_count; i++) {680if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||681GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||682GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)683{684if (iov[i].buffer.length <= skip) {685skip -= iov[i].buffer.length;686} else {687memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);688q += iov[i].buffer.length - skip;689skip = 0;690}691}692}693/* copy trailer */694q = p;695skip = rrc;696for (i = 0; i < iov_count; i++) {697if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||698GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||699GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)700{701memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip));702if (iov[i].buffer.length > skip)703break;704skip -= iov[i].buffer.length;705q += iov[i].buffer.length;706}707}708return GSS_S_COMPLETE;709}710711#if 0712713OM_uint32714_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,715gsskrb5_ctx ctx,716krb5_context context,717int *conf_state,718gss_qop_t *qop_state,719gss_iov_buffer_desc *iov,720int iov_count)721{722OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;723gss_iov_buffer_desc *header, *trailer, *padding;724gss_cfx_wrap_token token, ttoken;725u_char token_flags;726krb5_error_code ret;727unsigned usage;728uint16_t ec, rrc;729krb5_crypto_iov *data = NULL;730int i, j;731732*minor_status = 0;733734header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);735if (header == NULL) {736*minor_status = EINVAL;737return GSS_S_FAILURE;738}739740if (header->buffer.length < sizeof(*token)) /* we check exact below */741return GSS_S_DEFECTIVE_TOKEN;742743padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);744if (padding != NULL && padding->buffer.length != 0) {745*minor_status = EINVAL;746return GSS_S_FAILURE;747}748749trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);750751major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);752if (major_status != GSS_S_COMPLETE) {753return major_status;754}755756token = (gss_cfx_wrap_token)header->buffer.value;757758if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)759return GSS_S_DEFECTIVE_TOKEN;760761/* Ignore unknown flags */762token_flags = token->Flags &763(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);764765if (token_flags & CFXSentByAcceptor) {766if ((ctx->more_flags & LOCAL) == 0)767return GSS_S_DEFECTIVE_TOKEN;768}769770if (ctx->more_flags & ACCEPTOR_SUBKEY) {771if ((token_flags & CFXAcceptorSubkey) == 0)772return GSS_S_DEFECTIVE_TOKEN;773} else {774if (token_flags & CFXAcceptorSubkey)775return GSS_S_DEFECTIVE_TOKEN;776}777778if (token->Filler != 0xFF)779return GSS_S_DEFECTIVE_TOKEN;780781if (conf_state != NULL)782*conf_state = (token_flags & CFXSealed) ? 1 : 0;783784ec = (token->EC[0] << 8) | token->EC[1];785rrc = (token->RRC[0] << 8) | token->RRC[1];786787/*788* Check sequence number789*/790_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);791_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);792if (seq_number_hi) {793/* no support for 64-bit sequence numbers */794*minor_status = ERANGE;795return GSS_S_UNSEQ_TOKEN;796}797798HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);799ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);800if (ret != 0) {801*minor_status = 0;802HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);803return ret;804}805HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);806807/*808* Decrypt and/or verify checksum809*/810811if (ctx->more_flags & LOCAL) {812usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;813} else {814usage = KRB5_KU_USAGE_INITIATOR_SEAL;815}816817data = calloc(iov_count + 3, sizeof(data[0]));818if (data == NULL) {819*minor_status = ENOMEM;820major_status = GSS_S_FAILURE;821goto failure;822}823824if (token_flags & CFXSealed) {825size_t k5tsize, k5hsize;826827krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);828krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);829830/* Rotate by RRC; bogus to do this in-place XXX */831/* Check RRC */832833if (trailer == NULL) {834size_t gsstsize = k5tsize + sizeof(*token);835size_t gsshsize = k5hsize + sizeof(*token);836837if (rrc != gsstsize) {838major_status = GSS_S_DEFECTIVE_TOKEN;839goto failure;840}841842if (IS_DCE_STYLE(ctx))843gsstsize += ec;844845gsshsize += gsstsize;846847if (header->buffer.length != gsshsize) {848major_status = GSS_S_DEFECTIVE_TOKEN;849goto failure;850}851} else if (trailer->buffer.length != sizeof(*token) + k5tsize) {852major_status = GSS_S_DEFECTIVE_TOKEN;853goto failure;854} else if (header->buffer.length != sizeof(*token) + k5hsize) {855major_status = GSS_S_DEFECTIVE_TOKEN;856goto failure;857} else if (rrc != 0) {858/* go though slowpath */859major_status = unrotate_iov(minor_status, rrc, iov, iov_count);860if (major_status)861goto failure;862}863864i = 0;865data[i].flags = KRB5_CRYPTO_TYPE_HEADER;866data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;867data[i].data.length = k5hsize;868i++;869870for (j = 0; j < iov_count; i++, j++) {871switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {872case GSS_IOV_BUFFER_TYPE_DATA:873data[i].flags = KRB5_CRYPTO_TYPE_DATA;874break;875case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:876data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;877break;878default:879data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;880break;881}882data[i].data.length = iov[j].buffer.length;883data[i].data.data = iov[j].buffer.value;884}885886/* encrypted CFX header in trailer (or after the header if in887DCE mode). Copy in header into E"header"888*/889data[i].flags = KRB5_CRYPTO_TYPE_DATA;890if (trailer) {891data[i].data.data = trailer->buffer.value;892} else {893data[i].data.data = ((uint8_t *)header->buffer.value) +894header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);895}896897data[i].data.length = ec + sizeof(*token);898ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);899i++;900901/* Kerberos trailer comes after the gss trailer */902data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;903data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);904data[i].data.length = k5tsize;905i++;906907ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);908if (ret != 0) {909*minor_status = ret;910major_status = GSS_S_FAILURE;911goto failure;912}913914ttoken->RRC[0] = token->RRC[0];915ttoken->RRC[1] = token->RRC[1];916917/* Check the integrity of the header */918if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {919major_status = GSS_S_BAD_MIC;920goto failure;921}922} else {923size_t gsstsize = ec;924size_t gsshsize = sizeof(*token);925926if (trailer == NULL) {927/* Check RRC */928if (rrc != gsstsize) {929*minor_status = EINVAL;930major_status = GSS_S_FAILURE;931goto failure;932}933934gsshsize += gsstsize;935gsstsize = 0;936} else if (trailer->buffer.length != gsstsize) {937major_status = GSS_S_DEFECTIVE_TOKEN;938goto failure;939} else if (rrc != 0) {940/* Check RRC */941*minor_status = EINVAL;942major_status = GSS_S_FAILURE;943goto failure;944}945946if (header->buffer.length != gsshsize) {947major_status = GSS_S_DEFECTIVE_TOKEN;948goto failure;949}950951for (i = 0; i < iov_count; i++) {952switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {953case GSS_IOV_BUFFER_TYPE_DATA:954data[i].flags = KRB5_CRYPTO_TYPE_DATA;955break;956case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:957data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;958break;959default:960data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;961break;962}963data[i].data.length = iov[i].buffer.length;964data[i].data.data = iov[i].buffer.value;965}966967data[i].flags = KRB5_CRYPTO_TYPE_DATA;968data[i].data.data = header->buffer.value;969data[i].data.length = sizeof(*token);970i++;971972data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;973if (trailer) {974data[i].data.data = trailer->buffer.value;975} else {976data[i].data.data = (uint8_t *)header->buffer.value +977sizeof(*token);978}979data[i].data.length = ec;980i++;981982token = (gss_cfx_wrap_token)header->buffer.value;983token->EC[0] = 0;984token->EC[1] = 0;985token->RRC[0] = 0;986token->RRC[1] = 0;987988ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);989if (ret) {990*minor_status = ret;991major_status = GSS_S_FAILURE;992goto failure;993}994}995996if (qop_state != NULL) {997*qop_state = GSS_C_QOP_DEFAULT;998}9991000free(data);10011002*minor_status = 0;1003return GSS_S_COMPLETE;10041005failure:1006if (data)1007free(data);10081009gss_release_iov_buffer(&junk, iov, iov_count);10101011return major_status;1012}1013#endif10141015OM_uint321016_gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,1017gsskrb5_ctx ctx,1018krb5_context context,1019int conf_req_flag,1020gss_qop_t qop_req,1021int *conf_state,1022gss_iov_buffer_desc *iov,1023int iov_count)1024{1025OM_uint32 major_status;1026size_t size;1027int i;1028gss_iov_buffer_desc *header = NULL;1029gss_iov_buffer_desc *padding = NULL;1030gss_iov_buffer_desc *trailer = NULL;1031size_t gsshsize = 0;1032size_t gsstsize = 0;1033size_t k5hsize = 0;1034size_t k5tsize = 0;10351036GSSAPI_KRB5_INIT (&context);1037*minor_status = 0;10381039for (size = 0, i = 0; i < iov_count; i++) {1040switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {1041case GSS_IOV_BUFFER_TYPE_EMPTY:1042break;1043case GSS_IOV_BUFFER_TYPE_DATA:1044size += iov[i].buffer.length;1045break;1046case GSS_IOV_BUFFER_TYPE_HEADER:1047if (header != NULL) {1048*minor_status = 0;1049return GSS_S_FAILURE;1050}1051header = &iov[i];1052break;1053case GSS_IOV_BUFFER_TYPE_TRAILER:1054if (trailer != NULL) {1055*minor_status = 0;1056return GSS_S_FAILURE;1057}1058trailer = &iov[i];1059break;1060case GSS_IOV_BUFFER_TYPE_PADDING:1061if (padding != NULL) {1062*minor_status = 0;1063return GSS_S_FAILURE;1064}1065padding = &iov[i];1066break;1067case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:1068break;1069default:1070*minor_status = EINVAL;1071return GSS_S_FAILURE;1072}1073}10741075major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);1076if (major_status != GSS_S_COMPLETE) {1077return major_status;1078}10791080if (conf_req_flag) {1081size_t k5psize = 0;1082size_t k5pbase = 0;1083size_t k5bsize = 0;1084size_t ec = 0;10851086size += sizeof(gss_cfx_wrap_token_desc);10871088*minor_status = krb5_crypto_length(context, ctx->crypto,1089KRB5_CRYPTO_TYPE_HEADER,1090&k5hsize);1091if (*minor_status)1092return GSS_S_FAILURE;10931094*minor_status = krb5_crypto_length(context, ctx->crypto,1095KRB5_CRYPTO_TYPE_TRAILER,1096&k5tsize);1097if (*minor_status)1098return GSS_S_FAILURE;10991100*minor_status = krb5_crypto_length(context, ctx->crypto,1101KRB5_CRYPTO_TYPE_PADDING,1102&k5pbase);1103if (*minor_status)1104return GSS_S_FAILURE;11051106if (k5pbase > 1) {1107k5psize = k5pbase - (size % k5pbase);1108} else {1109k5psize = 0;1110}11111112if (k5psize == 0 && IS_DCE_STYLE(ctx)) {1113*minor_status = krb5_crypto_getblocksize(context, ctx->crypto,1114&k5bsize);1115if (*minor_status)1116return GSS_S_FAILURE;11171118ec = k5bsize;1119} else {1120ec = k5psize;1121}11221123gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;1124gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;1125} else {1126*minor_status = krb5_crypto_length(context, ctx->crypto,1127KRB5_CRYPTO_TYPE_CHECKSUM,1128&k5tsize);1129if (*minor_status)1130return GSS_S_FAILURE;11311132gsshsize = sizeof(gss_cfx_wrap_token_desc);1133gsstsize = k5tsize;1134}11351136if (trailer != NULL) {1137trailer->buffer.length = gsstsize;1138} else {1139gsshsize += gsstsize;1140}11411142header->buffer.length = gsshsize;11431144if (padding) {1145/* padding is done via EC and is contained in the header or trailer */1146padding->buffer.length = 0;1147}11481149if (conf_state) {1150*conf_state = conf_req_flag;1151}11521153return GSS_S_COMPLETE;1154}11551156115711581159OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,1160const gsskrb5_ctx ctx,1161krb5_context context,1162int conf_req_flag,1163const gss_buffer_t input_message_buffer,1164int *conf_state,1165gss_buffer_t output_message_buffer)1166{1167gss_cfx_wrap_token token;1168krb5_error_code ret;1169unsigned usage;1170krb5_data cipher;1171size_t wrapped_len, cksumsize;1172uint16_t padlength, rrc = 0;1173int32_t seq_number;1174u_char *p;11751176ret = _gsskrb5cfx_wrap_length_cfx(context,1177ctx->crypto, conf_req_flag,1178IS_DCE_STYLE(ctx),1179input_message_buffer->length,1180&wrapped_len, &cksumsize, &padlength);1181if (ret != 0) {1182*minor_status = ret;1183return GSS_S_FAILURE;1184}11851186/* Always rotate encrypted token (if any) and checksum to header */1187rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;11881189output_message_buffer->length = wrapped_len;1190output_message_buffer->value = malloc(output_message_buffer->length);1191if (output_message_buffer->value == NULL) {1192*minor_status = ENOMEM;1193return GSS_S_FAILURE;1194}11951196p = output_message_buffer->value;1197token = (gss_cfx_wrap_token)p;1198token->TOK_ID[0] = 0x05;1199token->TOK_ID[1] = 0x04;1200token->Flags = 0;1201token->Filler = 0xFF;1202if ((ctx->more_flags & LOCAL) == 0)1203token->Flags |= CFXSentByAcceptor;1204if (ctx->more_flags & ACCEPTOR_SUBKEY)1205token->Flags |= CFXAcceptorSubkey;1206if (conf_req_flag) {1207/*1208* In Wrap tokens with confidentiality, the EC field is1209* used to encode the size (in bytes) of the random filler.1210*/1211token->Flags |= CFXSealed;1212token->EC[0] = (padlength >> 8) & 0xFF;1213token->EC[1] = (padlength >> 0) & 0xFF;1214} else {1215/*1216* In Wrap tokens without confidentiality, the EC field is1217* used to encode the size (in bytes) of the trailing1218* checksum.1219*1220* This is not used in the checksum calcuation itself,1221* because the checksum length could potentially vary1222* depending on the data length.1223*/1224token->EC[0] = 0;1225token->EC[1] = 0;1226}12271228/*1229* In Wrap tokens that provide for confidentiality, the RRC1230* field in the header contains the hex value 00 00 before1231* encryption.1232*1233* In Wrap tokens that do not provide for confidentiality,1234* both the EC and RRC fields in the appended checksum1235* contain the hex value 00 00 for the purpose of calculating1236* the checksum.1237*/1238token->RRC[0] = 0;1239token->RRC[1] = 0;12401241HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);1242krb5_auth_con_getlocalseqnumber(context,1243ctx->auth_context,1244&seq_number);1245_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);1246_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);1247krb5_auth_con_setlocalseqnumber(context,1248ctx->auth_context,1249++seq_number);1250HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);12511252/*1253* If confidentiality is requested, the token header is1254* appended to the plaintext before encryption; the resulting1255* token is {"header" | encrypt(plaintext | pad | "header")}.1256*1257* If no confidentiality is requested, the checksum is1258* calculated over the plaintext concatenated with the1259* token header.1260*/1261if (ctx->more_flags & LOCAL) {1262usage = KRB5_KU_USAGE_INITIATOR_SEAL;1263} else {1264usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;1265}12661267if (conf_req_flag) {1268/*1269* Any necessary padding is added here to ensure that the1270* encrypted token header is always at the end of the1271* ciphertext.1272*1273* The specification does not require that the padding1274* bytes are initialized.1275*/1276p += sizeof(*token);1277memcpy(p, input_message_buffer->value, input_message_buffer->length);1278memset(p + input_message_buffer->length, 0xFF, padlength);1279memcpy(p + input_message_buffer->length + padlength,1280token, sizeof(*token));12811282ret = krb5_encrypt(context, ctx->crypto,1283usage, p,1284input_message_buffer->length + padlength +1285sizeof(*token),1286&cipher);1287if (ret != 0) {1288*minor_status = ret;1289_gsskrb5_release_buffer(minor_status, output_message_buffer);1290return GSS_S_FAILURE;1291}1292assert(sizeof(*token) + cipher.length == wrapped_len);1293token->RRC[0] = (rrc >> 8) & 0xFF;1294token->RRC[1] = (rrc >> 0) & 0xFF;12951296/*1297* this is really ugly, but needed against windows1298* for DCERPC, as windows rotates by EC+RRC.1299*/1300if (IS_DCE_STYLE(ctx)) {1301ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);1302} else {1303ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);1304}1305if (ret != 0) {1306*minor_status = ret;1307_gsskrb5_release_buffer(minor_status, output_message_buffer);1308return GSS_S_FAILURE;1309}1310memcpy(p, cipher.data, cipher.length);1311krb5_data_free(&cipher);1312} else {1313char *buf;1314Checksum cksum;13151316buf = malloc(input_message_buffer->length + sizeof(*token));1317if (buf == NULL) {1318*minor_status = ENOMEM;1319_gsskrb5_release_buffer(minor_status, output_message_buffer);1320return GSS_S_FAILURE;1321}1322memcpy(buf, input_message_buffer->value, input_message_buffer->length);1323memcpy(buf + input_message_buffer->length, token, sizeof(*token));13241325ret = krb5_create_checksum(context, ctx->crypto,1326usage, 0, buf,1327input_message_buffer->length +1328sizeof(*token),1329&cksum);1330if (ret != 0) {1331*minor_status = ret;1332_gsskrb5_release_buffer(minor_status, output_message_buffer);1333free(buf);1334return GSS_S_FAILURE;1335}13361337free(buf);13381339assert(cksum.checksum.length == cksumsize);1340token->EC[0] = (cksum.checksum.length >> 8) & 0xFF;1341token->EC[1] = (cksum.checksum.length >> 0) & 0xFF;1342token->RRC[0] = (rrc >> 8) & 0xFF;1343token->RRC[1] = (rrc >> 0) & 0xFF;13441345p += sizeof(*token);1346memcpy(p, input_message_buffer->value, input_message_buffer->length);1347memcpy(p + input_message_buffer->length,1348cksum.checksum.data, cksum.checksum.length);13491350ret = rrc_rotate(p,1351input_message_buffer->length + cksum.checksum.length, rrc, FALSE);1352if (ret != 0) {1353*minor_status = ret;1354_gsskrb5_release_buffer(minor_status, output_message_buffer);1355free_Checksum(&cksum);1356return GSS_S_FAILURE;1357}1358free_Checksum(&cksum);1359}13601361if (conf_state != NULL) {1362*conf_state = conf_req_flag;1363}13641365*minor_status = 0;1366return GSS_S_COMPLETE;1367}13681369OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,1370const gsskrb5_ctx ctx,1371krb5_context context,1372const gss_buffer_t input_message_buffer,1373gss_buffer_t output_message_buffer,1374int *conf_state,1375gss_qop_t *qop_state)1376{1377gss_cfx_wrap_token token;1378u_char token_flags;1379krb5_error_code ret;1380unsigned usage;1381krb5_data data;1382uint16_t ec, rrc;1383OM_uint32 seq_number_lo, seq_number_hi;1384size_t len;1385u_char *p;13861387*minor_status = 0;13881389if (input_message_buffer->length < sizeof(*token)) {1390return GSS_S_DEFECTIVE_TOKEN;1391}13921393p = input_message_buffer->value;13941395token = (gss_cfx_wrap_token)p;13961397if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {1398return GSS_S_DEFECTIVE_TOKEN;1399}14001401/* Ignore unknown flags */1402token_flags = token->Flags &1403(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);14041405if (token_flags & CFXSentByAcceptor) {1406if ((ctx->more_flags & LOCAL) == 0)1407return GSS_S_DEFECTIVE_TOKEN;1408}14091410if (ctx->more_flags & ACCEPTOR_SUBKEY) {1411if ((token_flags & CFXAcceptorSubkey) == 0)1412return GSS_S_DEFECTIVE_TOKEN;1413} else {1414if (token_flags & CFXAcceptorSubkey)1415return GSS_S_DEFECTIVE_TOKEN;1416}14171418if (token->Filler != 0xFF) {1419return GSS_S_DEFECTIVE_TOKEN;1420}14211422if (conf_state != NULL) {1423*conf_state = (token_flags & CFXSealed) ? 1 : 0;1424}14251426ec = (token->EC[0] << 8) | token->EC[1];1427rrc = (token->RRC[0] << 8) | token->RRC[1];14281429/*1430* Check sequence number1431*/1432_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);1433_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);1434if (seq_number_hi) {1435/* no support for 64-bit sequence numbers */1436*minor_status = ERANGE;1437return GSS_S_UNSEQ_TOKEN;1438}14391440HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);1441ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);1442if (ret != 0) {1443*minor_status = 0;1444HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);1445_gsskrb5_release_buffer(minor_status, output_message_buffer);1446return ret;1447}1448HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);14491450/*1451* Decrypt and/or verify checksum1452*/14531454if (ctx->more_flags & LOCAL) {1455usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;1456} else {1457usage = KRB5_KU_USAGE_INITIATOR_SEAL;1458}14591460p += sizeof(*token);1461len = input_message_buffer->length;1462len -= (p - (u_char *)input_message_buffer->value);14631464if (token_flags & CFXSealed) {1465/*1466* this is really ugly, but needed against windows1467* for DCERPC, as windows rotates by EC+RRC.1468*/1469if (IS_DCE_STYLE(ctx)) {1470*minor_status = rrc_rotate(p, len, rrc+ec, TRUE);1471} else {1472*minor_status = rrc_rotate(p, len, rrc, TRUE);1473}1474if (*minor_status != 0) {1475return GSS_S_FAILURE;1476}14771478ret = krb5_decrypt(context, ctx->crypto, usage,1479p, len, &data);1480if (ret != 0) {1481*minor_status = ret;1482return GSS_S_BAD_MIC;1483}14841485/* Check that there is room for the pad and token header */1486if (data.length < ec + sizeof(*token)) {1487krb5_data_free(&data);1488return GSS_S_DEFECTIVE_TOKEN;1489}1490p = data.data;1491p += data.length - sizeof(*token);14921493/* RRC is unprotected; don't modify input buffer */1494((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];1495((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];14961497/* Check the integrity of the header */1498if (ct_memcmp(p, token, sizeof(*token)) != 0) {1499krb5_data_free(&data);1500return GSS_S_BAD_MIC;1501}15021503output_message_buffer->value = data.data;1504output_message_buffer->length = data.length - ec - sizeof(*token);1505} else {1506Checksum cksum;15071508/* Rotate by RRC; bogus to do this in-place XXX */1509*minor_status = rrc_rotate(p, len, rrc, TRUE);1510if (*minor_status != 0) {1511return GSS_S_FAILURE;1512}15131514/* Determine checksum type */1515ret = krb5_crypto_get_checksum_type(context,1516ctx->crypto,1517&cksum.cksumtype);1518if (ret != 0) {1519*minor_status = ret;1520return GSS_S_FAILURE;1521}15221523cksum.checksum.length = ec;15241525/* Check we have at least as much data as the checksum */1526if (len < cksum.checksum.length) {1527*minor_status = ERANGE;1528return GSS_S_BAD_MIC;1529}15301531/* Length now is of the plaintext only, no checksum */1532len -= cksum.checksum.length;1533cksum.checksum.data = p + len;15341535output_message_buffer->length = len; /* for later */1536output_message_buffer->value = malloc(len + sizeof(*token));1537if (output_message_buffer->value == NULL) {1538*minor_status = ENOMEM;1539return GSS_S_FAILURE;1540}15411542/* Checksum is over (plaintext-data | "header") */1543memcpy(output_message_buffer->value, p, len);1544memcpy((u_char *)output_message_buffer->value + len,1545token, sizeof(*token));15461547/* EC is not included in checksum calculation */1548token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +1549len);1550token->EC[0] = 0;1551token->EC[1] = 0;1552token->RRC[0] = 0;1553token->RRC[1] = 0;15541555ret = krb5_verify_checksum(context, ctx->crypto,1556usage,1557output_message_buffer->value,1558len + sizeof(*token),1559&cksum);1560if (ret != 0) {1561*minor_status = ret;1562_gsskrb5_release_buffer(minor_status, output_message_buffer);1563return GSS_S_BAD_MIC;1564}1565}15661567if (qop_state != NULL) {1568*qop_state = GSS_C_QOP_DEFAULT;1569}15701571*minor_status = 0;1572return GSS_S_COMPLETE;1573}15741575OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,1576const gsskrb5_ctx ctx,1577krb5_context context,1578gss_qop_t qop_req,1579const gss_buffer_t message_buffer,1580gss_buffer_t message_token)1581{1582gss_cfx_mic_token token;1583krb5_error_code ret;1584unsigned usage;1585Checksum cksum;1586u_char *buf;1587size_t len;1588int32_t seq_number;15891590len = message_buffer->length + sizeof(*token);1591buf = malloc(len);1592if (buf == NULL) {1593*minor_status = ENOMEM;1594return GSS_S_FAILURE;1595}15961597memcpy(buf, message_buffer->value, message_buffer->length);15981599token = (gss_cfx_mic_token)(buf + message_buffer->length);1600token->TOK_ID[0] = 0x04;1601token->TOK_ID[1] = 0x04;1602token->Flags = 0;1603if ((ctx->more_flags & LOCAL) == 0)1604token->Flags |= CFXSentByAcceptor;1605if (ctx->more_flags & ACCEPTOR_SUBKEY)1606token->Flags |= CFXAcceptorSubkey;1607memset(token->Filler, 0xFF, 5);16081609HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);1610krb5_auth_con_getlocalseqnumber(context,1611ctx->auth_context,1612&seq_number);1613_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);1614_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);1615krb5_auth_con_setlocalseqnumber(context,1616ctx->auth_context,1617++seq_number);1618HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);16191620if (ctx->more_flags & LOCAL) {1621usage = KRB5_KU_USAGE_INITIATOR_SIGN;1622} else {1623usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;1624}16251626ret = krb5_create_checksum(context, ctx->crypto,1627usage, 0, buf, len, &cksum);1628if (ret != 0) {1629*minor_status = ret;1630free(buf);1631return GSS_S_FAILURE;1632}16331634/* Determine MIC length */1635message_token->length = sizeof(*token) + cksum.checksum.length;1636message_token->value = malloc(message_token->length);1637if (message_token->value == NULL) {1638*minor_status = ENOMEM;1639free_Checksum(&cksum);1640free(buf);1641return GSS_S_FAILURE;1642}16431644/* Token is { "header" | get_mic("header" | plaintext-data) } */1645memcpy(message_token->value, token, sizeof(*token));1646memcpy((u_char *)message_token->value + sizeof(*token),1647cksum.checksum.data, cksum.checksum.length);16481649free_Checksum(&cksum);1650free(buf);16511652*minor_status = 0;1653return GSS_S_COMPLETE;1654}16551656OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,1657const gsskrb5_ctx ctx,1658krb5_context context,1659const gss_buffer_t message_buffer,1660const gss_buffer_t token_buffer,1661gss_qop_t *qop_state)1662{1663gss_cfx_mic_token token;1664u_char token_flags;1665krb5_error_code ret;1666unsigned usage;1667OM_uint32 seq_number_lo, seq_number_hi;1668u_char *buf, *p;1669Checksum cksum;16701671*minor_status = 0;16721673if (token_buffer->length < sizeof(*token)) {1674return GSS_S_DEFECTIVE_TOKEN;1675}16761677p = token_buffer->value;16781679token = (gss_cfx_mic_token)p;16801681if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {1682return GSS_S_DEFECTIVE_TOKEN;1683}16841685/* Ignore unknown flags */1686token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);16871688if (token_flags & CFXSentByAcceptor) {1689if ((ctx->more_flags & LOCAL) == 0)1690return GSS_S_DEFECTIVE_TOKEN;1691}1692if (ctx->more_flags & ACCEPTOR_SUBKEY) {1693if ((token_flags & CFXAcceptorSubkey) == 0)1694return GSS_S_DEFECTIVE_TOKEN;1695} else {1696if (token_flags & CFXAcceptorSubkey)1697return GSS_S_DEFECTIVE_TOKEN;1698}16991700if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {1701return GSS_S_DEFECTIVE_TOKEN;1702}17031704/*1705* Check sequence number1706*/1707_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);1708_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);1709if (seq_number_hi) {1710*minor_status = ERANGE;1711return GSS_S_UNSEQ_TOKEN;1712}17131714HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);1715ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);1716if (ret != 0) {1717*minor_status = 0;1718HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);1719return ret;1720}1721HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);17221723/*1724* Verify checksum1725*/1726ret = krb5_crypto_get_checksum_type(context, ctx->crypto,1727&cksum.cksumtype);1728if (ret != 0) {1729*minor_status = ret;1730return GSS_S_FAILURE;1731}17321733cksum.checksum.data = p + sizeof(*token);1734cksum.checksum.length = token_buffer->length - sizeof(*token);17351736if (ctx->more_flags & LOCAL) {1737usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;1738} else {1739usage = KRB5_KU_USAGE_INITIATOR_SIGN;1740}17411742buf = malloc(message_buffer->length + sizeof(*token));1743if (buf == NULL) {1744*minor_status = ENOMEM;1745return GSS_S_FAILURE;1746}1747memcpy(buf, message_buffer->value, message_buffer->length);1748memcpy(buf + message_buffer->length, token, sizeof(*token));17491750ret = krb5_verify_checksum(context, ctx->crypto,1751usage,1752buf,1753sizeof(*token) + message_buffer->length,1754&cksum);1755if (ret != 0) {1756*minor_status = ret;1757free(buf);1758return GSS_S_BAD_MIC;1759}17601761free(buf);17621763if (qop_state != NULL) {1764*qop_state = GSS_C_QOP_DEFAULT;1765}17661767return GSS_S_COMPLETE;1768}176917701771