1178825Sdfr/* 2178825Sdfr * Copyright (c) 2003, PADL Software Pty Ltd. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5178825Sdfr * Redistribution and use in source and binary forms, with or without 6178825Sdfr * modification, are permitted provided that the following conditions 7178825Sdfr * are met: 8178825Sdfr * 9178825Sdfr * 1. Redistributions of source code must retain the above copyright 10178825Sdfr * notice, this list of conditions and the following disclaimer. 11178825Sdfr * 12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13178825Sdfr * notice, this list of conditions and the following disclaimer in the 14178825Sdfr * documentation and/or other materials provided with the distribution. 15178825Sdfr * 16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors 17178825Sdfr * may be used to endorse or promote products derived from this software 18178825Sdfr * without specific prior written permission. 19178825Sdfr * 20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30178825Sdfr * SUCH DAMAGE. 31178825Sdfr */ 32178825Sdfr 33233294Sstas#include "gsskrb5_locl.h" 34178825Sdfr 35178825Sdfr/* 36233294Sstas * Implementation of RFC 4121 37178825Sdfr */ 38178825Sdfr 39178825Sdfr#define CFXSentByAcceptor (1 << 0) 40178825Sdfr#define CFXSealed (1 << 1) 41178825Sdfr#define CFXAcceptorSubkey (1 << 2) 42178825Sdfr 43178825Sdfrkrb5_error_code 44178825Sdfr_gsskrb5cfx_wrap_length_cfx(krb5_context context, 45178825Sdfr krb5_crypto crypto, 46178825Sdfr int conf_req_flag, 47233294Sstas int dce_style, 48178825Sdfr size_t input_length, 49178825Sdfr size_t *output_length, 50178825Sdfr size_t *cksumsize, 51178825Sdfr uint16_t *padlength) 52178825Sdfr{ 53178825Sdfr krb5_error_code ret; 54178825Sdfr krb5_cksumtype type; 55178825Sdfr 56178825Sdfr /* 16-byte header is always first */ 57178825Sdfr *output_length = sizeof(gss_cfx_wrap_token_desc); 58178825Sdfr *padlength = 0; 59178825Sdfr 60178825Sdfr ret = krb5_crypto_get_checksum_type(context, crypto, &type); 61178825Sdfr if (ret) 62178825Sdfr return ret; 63178825Sdfr 64178825Sdfr ret = krb5_checksumsize(context, type, cksumsize); 65178825Sdfr if (ret) 66178825Sdfr return ret; 67178825Sdfr 68178825Sdfr if (conf_req_flag) { 69178825Sdfr size_t padsize; 70178825Sdfr 71178825Sdfr /* Header is concatenated with data before encryption */ 72178825Sdfr input_length += sizeof(gss_cfx_wrap_token_desc); 73178825Sdfr 74233294Sstas if (dce_style) { 75233294Sstas ret = krb5_crypto_getblocksize(context, crypto, &padsize); 76233294Sstas } else { 77233294Sstas ret = krb5_crypto_getpadsize(context, crypto, &padsize); 78233294Sstas } 79178825Sdfr if (ret) { 80178825Sdfr return ret; 81178825Sdfr } 82178825Sdfr if (padsize > 1) { 83178825Sdfr /* XXX check this */ 84178825Sdfr *padlength = padsize - (input_length % padsize); 85178825Sdfr 86178825Sdfr /* We add the pad ourselves (noted here for completeness only) */ 87178825Sdfr input_length += *padlength; 88178825Sdfr } 89178825Sdfr 90178825Sdfr *output_length += krb5_get_wrapped_length(context, 91178825Sdfr crypto, input_length); 92178825Sdfr } else { 93178825Sdfr /* Checksum is concatenated with data */ 94178825Sdfr *output_length += input_length + *cksumsize; 95178825Sdfr } 96178825Sdfr 97178825Sdfr assert(*output_length > input_length); 98178825Sdfr 99178825Sdfr return 0; 100178825Sdfr} 101178825Sdfr 102233294SstasOM_uint32 103233294Sstas_gssapi_wrap_size_cfx(OM_uint32 *minor_status, 104233294Sstas const gsskrb5_ctx ctx, 105233294Sstas krb5_context context, 106233294Sstas int conf_req_flag, 107233294Sstas gss_qop_t qop_req, 108233294Sstas OM_uint32 req_output_size, 109233294Sstas OM_uint32 *max_input_size) 110178825Sdfr{ 111178825Sdfr krb5_error_code ret; 112178825Sdfr 113233294Sstas *max_input_size = 0; 114178825Sdfr 115178825Sdfr /* 16-byte header is always first */ 116233294Sstas if (req_output_size < 16) 117178825Sdfr return 0; 118233294Sstas req_output_size -= 16; 119178825Sdfr 120178825Sdfr if (conf_req_flag) { 121178825Sdfr size_t wrapped_size, sz; 122178825Sdfr 123233294Sstas wrapped_size = req_output_size + 1; 124178825Sdfr do { 125178825Sdfr wrapped_size--; 126233294Sstas sz = krb5_get_wrapped_length(context, 127233294Sstas ctx->crypto, wrapped_size); 128233294Sstas } while (wrapped_size && sz > req_output_size); 129233294Sstas if (wrapped_size == 0) 130178825Sdfr return 0; 131178825Sdfr 132178825Sdfr /* inner header */ 133233294Sstas if (wrapped_size < 16) 134178825Sdfr return 0; 135233294Sstas 136178825Sdfr wrapped_size -= 16; 137178825Sdfr 138233294Sstas *max_input_size = wrapped_size; 139178825Sdfr } else { 140178825Sdfr krb5_cksumtype type; 141178825Sdfr size_t cksumsize; 142178825Sdfr 143233294Sstas ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type); 144178825Sdfr if (ret) 145178825Sdfr return ret; 146178825Sdfr 147178825Sdfr ret = krb5_checksumsize(context, type, &cksumsize); 148178825Sdfr if (ret) 149178825Sdfr return ret; 150178825Sdfr 151233294Sstas if (req_output_size < cksumsize) 152178825Sdfr return 0; 153178825Sdfr 154178825Sdfr /* Checksum is concatenated with data */ 155233294Sstas *max_input_size = req_output_size - cksumsize; 156178825Sdfr } 157178825Sdfr 158178825Sdfr return 0; 159178825Sdfr} 160178825Sdfr 161178825Sdfr/* 162178825Sdfr * Rotate "rrc" bytes to the front or back 163178825Sdfr */ 164178825Sdfr 165178825Sdfrstatic krb5_error_code 166178825Sdfrrrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) 167178825Sdfr{ 168178825Sdfr u_char *tmp, buf[256]; 169178825Sdfr size_t left; 170178825Sdfr 171178825Sdfr if (len == 0) 172178825Sdfr return 0; 173178825Sdfr 174178825Sdfr rrc %= len; 175178825Sdfr 176178825Sdfr if (rrc == 0) 177178825Sdfr return 0; 178178825Sdfr 179178825Sdfr left = len - rrc; 180178825Sdfr 181178825Sdfr if (rrc <= sizeof(buf)) { 182178825Sdfr tmp = buf; 183178825Sdfr } else { 184178825Sdfr tmp = malloc(rrc); 185233294Sstas if (tmp == NULL) 186178825Sdfr return ENOMEM; 187178825Sdfr } 188233294Sstas 189178825Sdfr if (unrotate) { 190178825Sdfr memcpy(tmp, data, rrc); 191178825Sdfr memmove(data, (u_char *)data + rrc, left); 192178825Sdfr memcpy((u_char *)data + left, tmp, rrc); 193178825Sdfr } else { 194178825Sdfr memcpy(tmp, (u_char *)data + left, rrc); 195178825Sdfr memmove((u_char *)data + rrc, data, left); 196178825Sdfr memcpy(data, tmp, rrc); 197178825Sdfr } 198178825Sdfr 199233294Sstas if (rrc > sizeof(buf)) 200178825Sdfr free(tmp); 201178825Sdfr 202178825Sdfr return 0; 203178825Sdfr} 204178825Sdfr 205233294Sstasgss_iov_buffer_desc * 206233294Sstas_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type) 207233294Sstas{ 208233294Sstas int i; 209233294Sstas 210233294Sstas for (i = 0; i < iov_count; i++) 211233294Sstas if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) 212233294Sstas return &iov[i]; 213233294Sstas return NULL; 214233294Sstas} 215233294Sstas 216233294SstasOM_uint32 217233294Sstas_gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size) 218233294Sstas{ 219233294Sstas if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { 220233294Sstas if (buffer->buffer.length == size) 221233294Sstas return GSS_S_COMPLETE; 222233294Sstas free(buffer->buffer.value); 223233294Sstas } 224233294Sstas 225233294Sstas buffer->buffer.value = malloc(size); 226233294Sstas buffer->buffer.length = size; 227233294Sstas if (buffer->buffer.value == NULL) { 228233294Sstas *minor_status = ENOMEM; 229233294Sstas return GSS_S_FAILURE; 230233294Sstas } 231233294Sstas buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED; 232233294Sstas 233233294Sstas return GSS_S_COMPLETE; 234233294Sstas} 235233294Sstas 236233294Sstas 237233294SstasOM_uint32 238233294Sstas_gk_verify_buffers(OM_uint32 *minor_status, 239233294Sstas const gsskrb5_ctx ctx, 240233294Sstas const gss_iov_buffer_desc *header, 241233294Sstas const gss_iov_buffer_desc *padding, 242233294Sstas const gss_iov_buffer_desc *trailer) 243233294Sstas{ 244233294Sstas if (header == NULL) { 245233294Sstas *minor_status = EINVAL; 246233294Sstas return GSS_S_FAILURE; 247233294Sstas } 248233294Sstas 249233294Sstas if (IS_DCE_STYLE(ctx)) { 250233294Sstas /* 251233294Sstas * In DCE style mode we reject having a padding or trailer buffer 252233294Sstas */ 253233294Sstas if (padding) { 254233294Sstas *minor_status = EINVAL; 255233294Sstas return GSS_S_FAILURE; 256233294Sstas } 257233294Sstas if (trailer) { 258233294Sstas *minor_status = EINVAL; 259233294Sstas return GSS_S_FAILURE; 260233294Sstas } 261233294Sstas } else { 262233294Sstas /* 263233294Sstas * In non-DCE style mode we require having a padding buffer 264233294Sstas */ 265233294Sstas if (padding == NULL) { 266233294Sstas *minor_status = EINVAL; 267233294Sstas return GSS_S_FAILURE; 268233294Sstas } 269233294Sstas } 270233294Sstas 271233294Sstas *minor_status = 0; 272233294Sstas return GSS_S_COMPLETE; 273233294Sstas} 274233294Sstas 275233294Sstas#if 0 276233294SstasOM_uint32 277233294Sstas_gssapi_wrap_cfx_iov(OM_uint32 *minor_status, 278233294Sstas gsskrb5_ctx ctx, 279233294Sstas krb5_context context, 280233294Sstas int conf_req_flag, 281233294Sstas int *conf_state, 282233294Sstas gss_iov_buffer_desc *iov, 283233294Sstas int iov_count) 284233294Sstas{ 285233294Sstas OM_uint32 major_status, junk; 286233294Sstas gss_iov_buffer_desc *header, *trailer, *padding; 287233294Sstas size_t gsshsize, k5hsize; 288233294Sstas size_t gsstsize, k5tsize; 289233294Sstas size_t rrc = 0, ec = 0; 290233294Sstas int i; 291233294Sstas gss_cfx_wrap_token token; 292233294Sstas krb5_error_code ret; 293233294Sstas int32_t seq_number; 294233294Sstas unsigned usage; 295233294Sstas krb5_crypto_iov *data = NULL; 296233294Sstas 297233294Sstas header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); 298233294Sstas if (header == NULL) { 299233294Sstas *minor_status = EINVAL; 300233294Sstas return GSS_S_FAILURE; 301233294Sstas } 302233294Sstas 303233294Sstas padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); 304233294Sstas if (padding != NULL) { 305233294Sstas padding->buffer.length = 0; 306233294Sstas } 307233294Sstas 308233294Sstas trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); 309233294Sstas 310233294Sstas major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); 311233294Sstas if (major_status != GSS_S_COMPLETE) { 312233294Sstas return major_status; 313233294Sstas } 314233294Sstas 315233294Sstas if (conf_req_flag) { 316233294Sstas size_t k5psize = 0; 317233294Sstas size_t k5pbase = 0; 318233294Sstas size_t k5bsize = 0; 319233294Sstas size_t size = 0; 320233294Sstas 321233294Sstas for (i = 0; i < iov_count; i++) { 322233294Sstas switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { 323233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 324233294Sstas size += iov[i].buffer.length; 325233294Sstas break; 326233294Sstas default: 327233294Sstas break; 328233294Sstas } 329233294Sstas } 330233294Sstas 331233294Sstas size += sizeof(gss_cfx_wrap_token_desc); 332233294Sstas 333233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 334233294Sstas KRB5_CRYPTO_TYPE_HEADER, 335233294Sstas &k5hsize); 336233294Sstas if (*minor_status) 337233294Sstas return GSS_S_FAILURE; 338233294Sstas 339233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 340233294Sstas KRB5_CRYPTO_TYPE_TRAILER, 341233294Sstas &k5tsize); 342233294Sstas if (*minor_status) 343233294Sstas return GSS_S_FAILURE; 344233294Sstas 345233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 346233294Sstas KRB5_CRYPTO_TYPE_PADDING, 347233294Sstas &k5pbase); 348233294Sstas if (*minor_status) 349233294Sstas return GSS_S_FAILURE; 350233294Sstas 351233294Sstas if (k5pbase > 1) { 352233294Sstas k5psize = k5pbase - (size % k5pbase); 353233294Sstas } else { 354233294Sstas k5psize = 0; 355233294Sstas } 356233294Sstas 357233294Sstas if (k5psize == 0 && IS_DCE_STYLE(ctx)) { 358233294Sstas *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, 359233294Sstas &k5bsize); 360233294Sstas if (*minor_status) 361233294Sstas return GSS_S_FAILURE; 362233294Sstas ec = k5bsize; 363233294Sstas } else { 364233294Sstas ec = k5psize; 365233294Sstas } 366233294Sstas 367233294Sstas gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; 368233294Sstas gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; 369233294Sstas } else { 370233294Sstas if (IS_DCE_STYLE(ctx)) { 371233294Sstas *minor_status = EINVAL; 372233294Sstas return GSS_S_FAILURE; 373233294Sstas } 374233294Sstas 375233294Sstas k5hsize = 0; 376233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 377233294Sstas KRB5_CRYPTO_TYPE_CHECKSUM, 378233294Sstas &k5tsize); 379233294Sstas if (*minor_status) 380233294Sstas return GSS_S_FAILURE; 381233294Sstas 382233294Sstas gsshsize = sizeof(gss_cfx_wrap_token_desc); 383233294Sstas gsstsize = k5tsize; 384233294Sstas } 385233294Sstas 386233294Sstas /* 387233294Sstas * 388233294Sstas */ 389233294Sstas 390233294Sstas if (trailer == NULL) { 391233294Sstas rrc = gsstsize; 392233294Sstas if (IS_DCE_STYLE(ctx)) 393233294Sstas rrc -= ec; 394233294Sstas gsshsize += gsstsize; 395233294Sstas gsstsize = 0; 396233294Sstas } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { 397233294Sstas major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize); 398233294Sstas if (major_status) 399233294Sstas goto failure; 400233294Sstas } else if (trailer->buffer.length < gsstsize) { 401233294Sstas *minor_status = KRB5_BAD_MSIZE; 402233294Sstas major_status = GSS_S_FAILURE; 403233294Sstas goto failure; 404233294Sstas } else 405233294Sstas trailer->buffer.length = gsstsize; 406233294Sstas 407233294Sstas /* 408233294Sstas * 409233294Sstas */ 410233294Sstas 411233294Sstas if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { 412233294Sstas major_status = _gk_allocate_buffer(minor_status, header, gsshsize); 413233294Sstas if (major_status != GSS_S_COMPLETE) 414233294Sstas goto failure; 415233294Sstas } else if (header->buffer.length < gsshsize) { 416233294Sstas *minor_status = KRB5_BAD_MSIZE; 417233294Sstas major_status = GSS_S_FAILURE; 418233294Sstas goto failure; 419233294Sstas } else 420233294Sstas header->buffer.length = gsshsize; 421233294Sstas 422233294Sstas token = (gss_cfx_wrap_token)header->buffer.value; 423233294Sstas 424233294Sstas token->TOK_ID[0] = 0x05; 425233294Sstas token->TOK_ID[1] = 0x04; 426233294Sstas token->Flags = 0; 427233294Sstas token->Filler = 0xFF; 428233294Sstas 429233294Sstas if ((ctx->more_flags & LOCAL) == 0) 430233294Sstas token->Flags |= CFXSentByAcceptor; 431233294Sstas 432233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) 433233294Sstas token->Flags |= CFXAcceptorSubkey; 434233294Sstas 435233294Sstas if (ctx->more_flags & LOCAL) 436233294Sstas usage = KRB5_KU_USAGE_INITIATOR_SEAL; 437233294Sstas else 438233294Sstas usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 439233294Sstas 440233294Sstas if (conf_req_flag) { 441233294Sstas /* 442233294Sstas * In Wrap tokens with confidentiality, the EC field is 443233294Sstas * used to encode the size (in bytes) of the random filler. 444233294Sstas */ 445233294Sstas token->Flags |= CFXSealed; 446233294Sstas token->EC[0] = (ec >> 8) & 0xFF; 447233294Sstas token->EC[1] = (ec >> 0) & 0xFF; 448233294Sstas 449233294Sstas } else { 450233294Sstas /* 451233294Sstas * In Wrap tokens without confidentiality, the EC field is 452233294Sstas * used to encode the size (in bytes) of the trailing 453233294Sstas * checksum. 454233294Sstas * 455233294Sstas * This is not used in the checksum calcuation itself, 456233294Sstas * because the checksum length could potentially vary 457233294Sstas * depending on the data length. 458233294Sstas */ 459233294Sstas token->EC[0] = 0; 460233294Sstas token->EC[1] = 0; 461233294Sstas } 462233294Sstas 463233294Sstas /* 464233294Sstas * In Wrap tokens that provide for confidentiality, the RRC 465233294Sstas * field in the header contains the hex value 00 00 before 466233294Sstas * encryption. 467233294Sstas * 468233294Sstas * In Wrap tokens that do not provide for confidentiality, 469233294Sstas * both the EC and RRC fields in the appended checksum 470233294Sstas * contain the hex value 00 00 for the purpose of calculating 471233294Sstas * the checksum. 472233294Sstas */ 473233294Sstas token->RRC[0] = 0; 474233294Sstas token->RRC[1] = 0; 475233294Sstas 476233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 477233294Sstas krb5_auth_con_getlocalseqnumber(context, 478233294Sstas ctx->auth_context, 479233294Sstas &seq_number); 480233294Sstas _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 481233294Sstas _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 482233294Sstas krb5_auth_con_setlocalseqnumber(context, 483233294Sstas ctx->auth_context, 484233294Sstas ++seq_number); 485233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 486233294Sstas 487233294Sstas data = calloc(iov_count + 3, sizeof(data[0])); 488233294Sstas if (data == NULL) { 489233294Sstas *minor_status = ENOMEM; 490233294Sstas major_status = GSS_S_FAILURE; 491233294Sstas goto failure; 492233294Sstas } 493233294Sstas 494233294Sstas if (conf_req_flag) { 495233294Sstas /* 496233294Sstas plain packet: 497233294Sstas 498233294Sstas {"header" | encrypt(plaintext-data | ec-padding | E"header")} 499233294Sstas 500233294Sstas Expanded, this is with with RRC = 0: 501233294Sstas 502233294Sstas {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer } 503233294Sstas 504233294Sstas In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer) 505233294Sstas 506233294Sstas {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data } 507233294Sstas */ 508233294Sstas 509233294Sstas i = 0; 510233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_HEADER; 511233294Sstas data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; 512233294Sstas data[i].data.length = k5hsize; 513233294Sstas 514233294Sstas for (i = 1; i < iov_count + 1; i++) { 515233294Sstas switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) { 516233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 517233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 518233294Sstas break; 519233294Sstas case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: 520233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 521233294Sstas break; 522233294Sstas default: 523233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; 524233294Sstas break; 525233294Sstas } 526233294Sstas data[i].data.length = iov[i - 1].buffer.length; 527233294Sstas data[i].data.data = iov[i - 1].buffer.value; 528233294Sstas } 529233294Sstas 530233294Sstas /* 531233294Sstas * Any necessary padding is added here to ensure that the 532233294Sstas * encrypted token header is always at the end of the 533233294Sstas * ciphertext. 534233294Sstas */ 535233294Sstas 536233294Sstas /* encrypted CFX header in trailer (or after the header if in 537233294Sstas DCE mode). Copy in header into E"header" 538233294Sstas */ 539233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 540233294Sstas if (trailer) 541233294Sstas data[i].data.data = trailer->buffer.value; 542233294Sstas else 543233294Sstas data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token); 544233294Sstas 545233294Sstas data[i].data.length = ec + sizeof(*token); 546233294Sstas memset(data[i].data.data, 0xFF, ec); 547233294Sstas memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token)); 548233294Sstas i++; 549233294Sstas 550233294Sstas /* Kerberos trailer comes after the gss trailer */ 551233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; 552233294Sstas data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); 553233294Sstas data[i].data.length = k5tsize; 554233294Sstas i++; 555233294Sstas 556233294Sstas ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); 557233294Sstas if (ret != 0) { 558233294Sstas *minor_status = ret; 559233294Sstas major_status = GSS_S_FAILURE; 560233294Sstas goto failure; 561233294Sstas } 562233294Sstas 563233294Sstas if (rrc) { 564233294Sstas token->RRC[0] = (rrc >> 8) & 0xFF; 565233294Sstas token->RRC[1] = (rrc >> 0) & 0xFF; 566233294Sstas } 567233294Sstas 568233294Sstas } else { 569233294Sstas /* 570233294Sstas plain packet: 571233294Sstas 572233294Sstas {data | "header" | gss-trailer (krb5 checksum) 573233294Sstas 574233294Sstas don't do RRC != 0 575233294Sstas 576233294Sstas */ 577233294Sstas 578233294Sstas for (i = 0; i < iov_count; i++) { 579233294Sstas switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { 580233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 581233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 582233294Sstas break; 583233294Sstas case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: 584233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 585233294Sstas break; 586233294Sstas default: 587233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; 588233294Sstas break; 589233294Sstas } 590233294Sstas data[i].data.length = iov[i].buffer.length; 591233294Sstas data[i].data.data = iov[i].buffer.value; 592233294Sstas } 593233294Sstas 594233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 595233294Sstas data[i].data.data = header->buffer.value; 596233294Sstas data[i].data.length = sizeof(gss_cfx_wrap_token_desc); 597233294Sstas i++; 598233294Sstas 599233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 600233294Sstas if (trailer) { 601233294Sstas data[i].data.data = trailer->buffer.value; 602233294Sstas } else { 603233294Sstas data[i].data.data = (uint8_t *)header->buffer.value + 604233294Sstas sizeof(gss_cfx_wrap_token_desc); 605233294Sstas } 606233294Sstas data[i].data.length = k5tsize; 607233294Sstas i++; 608233294Sstas 609233294Sstas ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL); 610233294Sstas if (ret) { 611233294Sstas *minor_status = ret; 612233294Sstas major_status = GSS_S_FAILURE; 613233294Sstas goto failure; 614233294Sstas } 615233294Sstas 616233294Sstas if (rrc) { 617233294Sstas token->RRC[0] = (rrc >> 8) & 0xFF; 618233294Sstas token->RRC[1] = (rrc >> 0) & 0xFF; 619233294Sstas } 620233294Sstas 621233294Sstas token->EC[0] = (k5tsize >> 8) & 0xFF; 622233294Sstas token->EC[1] = (k5tsize >> 0) & 0xFF; 623233294Sstas } 624233294Sstas 625233294Sstas if (conf_state != NULL) 626233294Sstas *conf_state = conf_req_flag; 627233294Sstas 628233294Sstas free(data); 629233294Sstas 630233294Sstas *minor_status = 0; 631233294Sstas return GSS_S_COMPLETE; 632233294Sstas 633233294Sstas failure: 634233294Sstas if (data) 635233294Sstas free(data); 636233294Sstas 637233294Sstas gss_release_iov_buffer(&junk, iov, iov_count); 638233294Sstas 639233294Sstas return major_status; 640233294Sstas} 641233294Sstas#endif 642233294Sstas 643233294Sstas/* This is slowpath */ 644233294Sstasstatic OM_uint32 645233294Sstasunrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count) 646233294Sstas{ 647233294Sstas uint8_t *p, *q; 648233294Sstas size_t len = 0, skip; 649233294Sstas int i; 650233294Sstas 651233294Sstas for (i = 0; i < iov_count; i++) 652233294Sstas if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || 653233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || 654233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) 655233294Sstas len += iov[i].buffer.length; 656233294Sstas 657233294Sstas p = malloc(len); 658233294Sstas if (p == NULL) { 659233294Sstas *minor_status = ENOMEM; 660233294Sstas return GSS_S_FAILURE; 661233294Sstas } 662233294Sstas q = p; 663233294Sstas 664233294Sstas /* copy up */ 665233294Sstas 666233294Sstas for (i = 0; i < iov_count; i++) { 667233294Sstas if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || 668233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || 669233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) 670233294Sstas { 671233294Sstas memcpy(q, iov[i].buffer.value, iov[i].buffer.length); 672233294Sstas q += iov[i].buffer.length; 673233294Sstas } 674233294Sstas } 675233294Sstas assert((size_t)(q - p) == len); 676233294Sstas 677233294Sstas /* unrotate first part */ 678233294Sstas q = p + rrc; 679233294Sstas skip = rrc; 680233294Sstas for (i = 0; i < iov_count; i++) { 681233294Sstas if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || 682233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || 683233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) 684233294Sstas { 685233294Sstas if (iov[i].buffer.length <= skip) { 686233294Sstas skip -= iov[i].buffer.length; 687233294Sstas } else { 688233294Sstas memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip); 689233294Sstas q += iov[i].buffer.length - skip; 690233294Sstas skip = 0; 691233294Sstas } 692233294Sstas } 693233294Sstas } 694233294Sstas /* copy trailer */ 695233294Sstas q = p; 696233294Sstas skip = rrc; 697233294Sstas for (i = 0; i < iov_count; i++) { 698233294Sstas if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || 699233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || 700233294Sstas GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) 701233294Sstas { 702233294Sstas memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip)); 703233294Sstas if (iov[i].buffer.length > skip) 704233294Sstas break; 705233294Sstas skip -= iov[i].buffer.length; 706233294Sstas q += iov[i].buffer.length; 707233294Sstas } 708233294Sstas } 709233294Sstas return GSS_S_COMPLETE; 710233294Sstas} 711233294Sstas 712233294Sstas#if 0 713233294Sstas 714233294SstasOM_uint32 715233294Sstas_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status, 716233294Sstas gsskrb5_ctx ctx, 717233294Sstas krb5_context context, 718233294Sstas int *conf_state, 719233294Sstas gss_qop_t *qop_state, 720233294Sstas gss_iov_buffer_desc *iov, 721233294Sstas int iov_count) 722233294Sstas{ 723233294Sstas OM_uint32 seq_number_lo, seq_number_hi, major_status, junk; 724233294Sstas gss_iov_buffer_desc *header, *trailer, *padding; 725233294Sstas gss_cfx_wrap_token token, ttoken; 726233294Sstas u_char token_flags; 727233294Sstas krb5_error_code ret; 728233294Sstas unsigned usage; 729233294Sstas uint16_t ec, rrc; 730233294Sstas krb5_crypto_iov *data = NULL; 731233294Sstas int i, j; 732233294Sstas 733233294Sstas *minor_status = 0; 734233294Sstas 735233294Sstas header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); 736233294Sstas if (header == NULL) { 737233294Sstas *minor_status = EINVAL; 738233294Sstas return GSS_S_FAILURE; 739233294Sstas } 740233294Sstas 741233294Sstas if (header->buffer.length < sizeof(*token)) /* we check exact below */ 742233294Sstas return GSS_S_DEFECTIVE_TOKEN; 743233294Sstas 744233294Sstas padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); 745233294Sstas if (padding != NULL && padding->buffer.length != 0) { 746233294Sstas *minor_status = EINVAL; 747233294Sstas return GSS_S_FAILURE; 748233294Sstas } 749233294Sstas 750233294Sstas trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); 751233294Sstas 752233294Sstas major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); 753233294Sstas if (major_status != GSS_S_COMPLETE) { 754233294Sstas return major_status; 755233294Sstas } 756233294Sstas 757233294Sstas token = (gss_cfx_wrap_token)header->buffer.value; 758233294Sstas 759233294Sstas if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) 760233294Sstas return GSS_S_DEFECTIVE_TOKEN; 761233294Sstas 762233294Sstas /* Ignore unknown flags */ 763233294Sstas token_flags = token->Flags & 764233294Sstas (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); 765233294Sstas 766233294Sstas if (token_flags & CFXSentByAcceptor) { 767233294Sstas if ((ctx->more_flags & LOCAL) == 0) 768233294Sstas return GSS_S_DEFECTIVE_TOKEN; 769233294Sstas } 770233294Sstas 771233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) { 772233294Sstas if ((token_flags & CFXAcceptorSubkey) == 0) 773233294Sstas return GSS_S_DEFECTIVE_TOKEN; 774233294Sstas } else { 775233294Sstas if (token_flags & CFXAcceptorSubkey) 776233294Sstas return GSS_S_DEFECTIVE_TOKEN; 777233294Sstas } 778233294Sstas 779233294Sstas if (token->Filler != 0xFF) 780233294Sstas return GSS_S_DEFECTIVE_TOKEN; 781233294Sstas 782233294Sstas if (conf_state != NULL) 783233294Sstas *conf_state = (token_flags & CFXSealed) ? 1 : 0; 784233294Sstas 785233294Sstas ec = (token->EC[0] << 8) | token->EC[1]; 786233294Sstas rrc = (token->RRC[0] << 8) | token->RRC[1]; 787233294Sstas 788233294Sstas /* 789233294Sstas * Check sequence number 790233294Sstas */ 791233294Sstas _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 792233294Sstas _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 793233294Sstas if (seq_number_hi) { 794233294Sstas /* no support for 64-bit sequence numbers */ 795233294Sstas *minor_status = ERANGE; 796233294Sstas return GSS_S_UNSEQ_TOKEN; 797233294Sstas } 798233294Sstas 799233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 800233294Sstas ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); 801233294Sstas if (ret != 0) { 802233294Sstas *minor_status = 0; 803233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 804233294Sstas return ret; 805233294Sstas } 806233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 807233294Sstas 808233294Sstas /* 809233294Sstas * Decrypt and/or verify checksum 810233294Sstas */ 811233294Sstas 812233294Sstas if (ctx->more_flags & LOCAL) { 813233294Sstas usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 814233294Sstas } else { 815233294Sstas usage = KRB5_KU_USAGE_INITIATOR_SEAL; 816233294Sstas } 817233294Sstas 818233294Sstas data = calloc(iov_count + 3, sizeof(data[0])); 819233294Sstas if (data == NULL) { 820233294Sstas *minor_status = ENOMEM; 821233294Sstas major_status = GSS_S_FAILURE; 822233294Sstas goto failure; 823233294Sstas } 824233294Sstas 825233294Sstas if (token_flags & CFXSealed) { 826233294Sstas size_t k5tsize, k5hsize; 827233294Sstas 828233294Sstas krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize); 829233294Sstas krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize); 830233294Sstas 831233294Sstas /* Rotate by RRC; bogus to do this in-place XXX */ 832233294Sstas /* Check RRC */ 833233294Sstas 834233294Sstas if (trailer == NULL) { 835233294Sstas size_t gsstsize = k5tsize + sizeof(*token); 836233294Sstas size_t gsshsize = k5hsize + sizeof(*token); 837233294Sstas 838233294Sstas if (rrc != gsstsize) { 839233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 840233294Sstas goto failure; 841233294Sstas } 842233294Sstas 843233294Sstas if (IS_DCE_STYLE(ctx)) 844233294Sstas gsstsize += ec; 845233294Sstas 846233294Sstas gsshsize += gsstsize; 847233294Sstas 848233294Sstas if (header->buffer.length != gsshsize) { 849233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 850233294Sstas goto failure; 851233294Sstas } 852233294Sstas } else if (trailer->buffer.length != sizeof(*token) + k5tsize) { 853233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 854233294Sstas goto failure; 855233294Sstas } else if (header->buffer.length != sizeof(*token) + k5hsize) { 856233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 857233294Sstas goto failure; 858233294Sstas } else if (rrc != 0) { 859233294Sstas /* go though slowpath */ 860233294Sstas major_status = unrotate_iov(minor_status, rrc, iov, iov_count); 861233294Sstas if (major_status) 862233294Sstas goto failure; 863233294Sstas } 864233294Sstas 865233294Sstas i = 0; 866233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_HEADER; 867233294Sstas data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; 868233294Sstas data[i].data.length = k5hsize; 869233294Sstas i++; 870233294Sstas 871233294Sstas for (j = 0; j < iov_count; i++, j++) { 872233294Sstas switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) { 873233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 874233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 875233294Sstas break; 876233294Sstas case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: 877233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 878233294Sstas break; 879233294Sstas default: 880233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; 881233294Sstas break; 882233294Sstas } 883233294Sstas data[i].data.length = iov[j].buffer.length; 884233294Sstas data[i].data.data = iov[j].buffer.value; 885233294Sstas } 886233294Sstas 887233294Sstas /* encrypted CFX header in trailer (or after the header if in 888233294Sstas DCE mode). Copy in header into E"header" 889233294Sstas */ 890233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 891233294Sstas if (trailer) { 892233294Sstas data[i].data.data = trailer->buffer.value; 893233294Sstas } else { 894233294Sstas data[i].data.data = ((uint8_t *)header->buffer.value) + 895233294Sstas header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token); 896233294Sstas } 897233294Sstas 898233294Sstas data[i].data.length = ec + sizeof(*token); 899233294Sstas ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec); 900233294Sstas i++; 901233294Sstas 902233294Sstas /* Kerberos trailer comes after the gss trailer */ 903233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; 904233294Sstas data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); 905233294Sstas data[i].data.length = k5tsize; 906233294Sstas i++; 907233294Sstas 908233294Sstas ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); 909233294Sstas if (ret != 0) { 910233294Sstas *minor_status = ret; 911233294Sstas major_status = GSS_S_FAILURE; 912233294Sstas goto failure; 913233294Sstas } 914233294Sstas 915233294Sstas ttoken->RRC[0] = token->RRC[0]; 916233294Sstas ttoken->RRC[1] = token->RRC[1]; 917233294Sstas 918233294Sstas /* Check the integrity of the header */ 919233294Sstas if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) { 920233294Sstas major_status = GSS_S_BAD_MIC; 921233294Sstas goto failure; 922233294Sstas } 923233294Sstas } else { 924233294Sstas size_t gsstsize = ec; 925233294Sstas size_t gsshsize = sizeof(*token); 926233294Sstas 927233294Sstas if (trailer == NULL) { 928233294Sstas /* Check RRC */ 929233294Sstas if (rrc != gsstsize) { 930233294Sstas *minor_status = EINVAL; 931233294Sstas major_status = GSS_S_FAILURE; 932233294Sstas goto failure; 933233294Sstas } 934233294Sstas 935233294Sstas gsshsize += gsstsize; 936233294Sstas gsstsize = 0; 937233294Sstas } else if (trailer->buffer.length != gsstsize) { 938233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 939233294Sstas goto failure; 940233294Sstas } else if (rrc != 0) { 941233294Sstas /* Check RRC */ 942233294Sstas *minor_status = EINVAL; 943233294Sstas major_status = GSS_S_FAILURE; 944233294Sstas goto failure; 945233294Sstas } 946233294Sstas 947233294Sstas if (header->buffer.length != gsshsize) { 948233294Sstas major_status = GSS_S_DEFECTIVE_TOKEN; 949233294Sstas goto failure; 950233294Sstas } 951233294Sstas 952233294Sstas for (i = 0; i < iov_count; i++) { 953233294Sstas switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { 954233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 955233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 956233294Sstas break; 957233294Sstas case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: 958233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 959233294Sstas break; 960233294Sstas default: 961233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; 962233294Sstas break; 963233294Sstas } 964233294Sstas data[i].data.length = iov[i].buffer.length; 965233294Sstas data[i].data.data = iov[i].buffer.value; 966233294Sstas } 967233294Sstas 968233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_DATA; 969233294Sstas data[i].data.data = header->buffer.value; 970233294Sstas data[i].data.length = sizeof(*token); 971233294Sstas i++; 972233294Sstas 973233294Sstas data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 974233294Sstas if (trailer) { 975233294Sstas data[i].data.data = trailer->buffer.value; 976233294Sstas } else { 977233294Sstas data[i].data.data = (uint8_t *)header->buffer.value + 978233294Sstas sizeof(*token); 979233294Sstas } 980233294Sstas data[i].data.length = ec; 981233294Sstas i++; 982233294Sstas 983233294Sstas token = (gss_cfx_wrap_token)header->buffer.value; 984233294Sstas token->EC[0] = 0; 985233294Sstas token->EC[1] = 0; 986233294Sstas token->RRC[0] = 0; 987233294Sstas token->RRC[1] = 0; 988233294Sstas 989233294Sstas ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL); 990233294Sstas if (ret) { 991233294Sstas *minor_status = ret; 992233294Sstas major_status = GSS_S_FAILURE; 993233294Sstas goto failure; 994233294Sstas } 995233294Sstas } 996233294Sstas 997233294Sstas if (qop_state != NULL) { 998233294Sstas *qop_state = GSS_C_QOP_DEFAULT; 999233294Sstas } 1000233294Sstas 1001233294Sstas free(data); 1002233294Sstas 1003233294Sstas *minor_status = 0; 1004233294Sstas return GSS_S_COMPLETE; 1005233294Sstas 1006233294Sstas failure: 1007233294Sstas if (data) 1008233294Sstas free(data); 1009233294Sstas 1010233294Sstas gss_release_iov_buffer(&junk, iov, iov_count); 1011233294Sstas 1012233294Sstas return major_status; 1013233294Sstas} 1014233294Sstas#endif 1015233294Sstas 1016233294SstasOM_uint32 1017233294Sstas_gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status, 1018233294Sstas gsskrb5_ctx ctx, 1019233294Sstas krb5_context context, 1020233294Sstas int conf_req_flag, 1021233294Sstas gss_qop_t qop_req, 1022233294Sstas int *conf_state, 1023233294Sstas gss_iov_buffer_desc *iov, 1024233294Sstas int iov_count) 1025233294Sstas{ 1026233294Sstas OM_uint32 major_status; 1027233294Sstas size_t size; 1028233294Sstas int i; 1029233294Sstas gss_iov_buffer_desc *header = NULL; 1030233294Sstas gss_iov_buffer_desc *padding = NULL; 1031233294Sstas gss_iov_buffer_desc *trailer = NULL; 1032233294Sstas size_t gsshsize = 0; 1033233294Sstas size_t gsstsize = 0; 1034233294Sstas size_t k5hsize = 0; 1035233294Sstas size_t k5tsize = 0; 1036233294Sstas 1037233294Sstas GSSAPI_KRB5_INIT (&context); 1038233294Sstas *minor_status = 0; 1039233294Sstas 1040233294Sstas for (size = 0, i = 0; i < iov_count; i++) { 1041233294Sstas switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { 1042233294Sstas case GSS_IOV_BUFFER_TYPE_EMPTY: 1043233294Sstas break; 1044233294Sstas case GSS_IOV_BUFFER_TYPE_DATA: 1045233294Sstas size += iov[i].buffer.length; 1046233294Sstas break; 1047233294Sstas case GSS_IOV_BUFFER_TYPE_HEADER: 1048233294Sstas if (header != NULL) { 1049233294Sstas *minor_status = 0; 1050233294Sstas return GSS_S_FAILURE; 1051233294Sstas } 1052233294Sstas header = &iov[i]; 1053233294Sstas break; 1054233294Sstas case GSS_IOV_BUFFER_TYPE_TRAILER: 1055233294Sstas if (trailer != NULL) { 1056233294Sstas *minor_status = 0; 1057233294Sstas return GSS_S_FAILURE; 1058233294Sstas } 1059233294Sstas trailer = &iov[i]; 1060233294Sstas break; 1061233294Sstas case GSS_IOV_BUFFER_TYPE_PADDING: 1062233294Sstas if (padding != NULL) { 1063233294Sstas *minor_status = 0; 1064233294Sstas return GSS_S_FAILURE; 1065233294Sstas } 1066233294Sstas padding = &iov[i]; 1067233294Sstas break; 1068233294Sstas case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: 1069233294Sstas break; 1070233294Sstas default: 1071233294Sstas *minor_status = EINVAL; 1072233294Sstas return GSS_S_FAILURE; 1073233294Sstas } 1074233294Sstas } 1075233294Sstas 1076233294Sstas major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); 1077233294Sstas if (major_status != GSS_S_COMPLETE) { 1078233294Sstas return major_status; 1079233294Sstas } 1080233294Sstas 1081233294Sstas if (conf_req_flag) { 1082233294Sstas size_t k5psize = 0; 1083233294Sstas size_t k5pbase = 0; 1084233294Sstas size_t k5bsize = 0; 1085233294Sstas size_t ec = 0; 1086233294Sstas 1087233294Sstas size += sizeof(gss_cfx_wrap_token_desc); 1088233294Sstas 1089233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 1090233294Sstas KRB5_CRYPTO_TYPE_HEADER, 1091233294Sstas &k5hsize); 1092233294Sstas if (*minor_status) 1093233294Sstas return GSS_S_FAILURE; 1094233294Sstas 1095233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 1096233294Sstas KRB5_CRYPTO_TYPE_TRAILER, 1097233294Sstas &k5tsize); 1098233294Sstas if (*minor_status) 1099233294Sstas return GSS_S_FAILURE; 1100233294Sstas 1101233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 1102233294Sstas KRB5_CRYPTO_TYPE_PADDING, 1103233294Sstas &k5pbase); 1104233294Sstas if (*minor_status) 1105233294Sstas return GSS_S_FAILURE; 1106233294Sstas 1107233294Sstas if (k5pbase > 1) { 1108233294Sstas k5psize = k5pbase - (size % k5pbase); 1109233294Sstas } else { 1110233294Sstas k5psize = 0; 1111233294Sstas } 1112233294Sstas 1113233294Sstas if (k5psize == 0 && IS_DCE_STYLE(ctx)) { 1114233294Sstas *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, 1115233294Sstas &k5bsize); 1116233294Sstas if (*minor_status) 1117233294Sstas return GSS_S_FAILURE; 1118233294Sstas 1119233294Sstas ec = k5bsize; 1120233294Sstas } else { 1121233294Sstas ec = k5psize; 1122233294Sstas } 1123233294Sstas 1124233294Sstas gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; 1125233294Sstas gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; 1126233294Sstas } else { 1127233294Sstas *minor_status = krb5_crypto_length(context, ctx->crypto, 1128233294Sstas KRB5_CRYPTO_TYPE_CHECKSUM, 1129233294Sstas &k5tsize); 1130233294Sstas if (*minor_status) 1131233294Sstas return GSS_S_FAILURE; 1132233294Sstas 1133233294Sstas gsshsize = sizeof(gss_cfx_wrap_token_desc); 1134233294Sstas gsstsize = k5tsize; 1135233294Sstas } 1136233294Sstas 1137233294Sstas if (trailer != NULL) { 1138233294Sstas trailer->buffer.length = gsstsize; 1139233294Sstas } else { 1140233294Sstas gsshsize += gsstsize; 1141233294Sstas } 1142233294Sstas 1143233294Sstas header->buffer.length = gsshsize; 1144233294Sstas 1145233294Sstas if (padding) { 1146233294Sstas /* padding is done via EC and is contained in the header or trailer */ 1147233294Sstas padding->buffer.length = 0; 1148233294Sstas } 1149233294Sstas 1150233294Sstas if (conf_state) { 1151233294Sstas *conf_state = conf_req_flag; 1152233294Sstas } 1153233294Sstas 1154233294Sstas return GSS_S_COMPLETE; 1155233294Sstas} 1156233294Sstas 1157233294Sstas 1158233294Sstas 1159233294Sstas 1160178825SdfrOM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, 1161233294Sstas const gsskrb5_ctx ctx, 1162178825Sdfr krb5_context context, 1163178825Sdfr int conf_req_flag, 1164178825Sdfr const gss_buffer_t input_message_buffer, 1165178825Sdfr int *conf_state, 1166233294Sstas gss_buffer_t output_message_buffer) 1167178825Sdfr{ 1168178825Sdfr gss_cfx_wrap_token token; 1169178825Sdfr krb5_error_code ret; 1170178825Sdfr unsigned usage; 1171178825Sdfr krb5_data cipher; 1172178825Sdfr size_t wrapped_len, cksumsize; 1173178825Sdfr uint16_t padlength, rrc = 0; 1174178825Sdfr int32_t seq_number; 1175178825Sdfr u_char *p; 1176178825Sdfr 1177178825Sdfr ret = _gsskrb5cfx_wrap_length_cfx(context, 1178233294Sstas ctx->crypto, conf_req_flag, 1179233294Sstas IS_DCE_STYLE(ctx), 1180178825Sdfr input_message_buffer->length, 1181178825Sdfr &wrapped_len, &cksumsize, &padlength); 1182178825Sdfr if (ret != 0) { 1183178825Sdfr *minor_status = ret; 1184178825Sdfr return GSS_S_FAILURE; 1185178825Sdfr } 1186178825Sdfr 1187178825Sdfr /* Always rotate encrypted token (if any) and checksum to header */ 1188178825Sdfr rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize; 1189178825Sdfr 1190178825Sdfr output_message_buffer->length = wrapped_len; 1191178825Sdfr output_message_buffer->value = malloc(output_message_buffer->length); 1192178825Sdfr if (output_message_buffer->value == NULL) { 1193178825Sdfr *minor_status = ENOMEM; 1194178825Sdfr return GSS_S_FAILURE; 1195178825Sdfr } 1196178825Sdfr 1197178825Sdfr p = output_message_buffer->value; 1198178825Sdfr token = (gss_cfx_wrap_token)p; 1199178825Sdfr token->TOK_ID[0] = 0x05; 1200178825Sdfr token->TOK_ID[1] = 0x04; 1201178825Sdfr token->Flags = 0; 1202178825Sdfr token->Filler = 0xFF; 1203233294Sstas if ((ctx->more_flags & LOCAL) == 0) 1204178825Sdfr token->Flags |= CFXSentByAcceptor; 1205233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) 1206178825Sdfr token->Flags |= CFXAcceptorSubkey; 1207178825Sdfr if (conf_req_flag) { 1208178825Sdfr /* 1209178825Sdfr * In Wrap tokens with confidentiality, the EC field is 1210178825Sdfr * used to encode the size (in bytes) of the random filler. 1211178825Sdfr */ 1212178825Sdfr token->Flags |= CFXSealed; 1213178825Sdfr token->EC[0] = (padlength >> 8) & 0xFF; 1214178825Sdfr token->EC[1] = (padlength >> 0) & 0xFF; 1215178825Sdfr } else { 1216178825Sdfr /* 1217178825Sdfr * In Wrap tokens without confidentiality, the EC field is 1218178825Sdfr * used to encode the size (in bytes) of the trailing 1219178825Sdfr * checksum. 1220178825Sdfr * 1221178825Sdfr * This is not used in the checksum calcuation itself, 1222178825Sdfr * because the checksum length could potentially vary 1223178825Sdfr * depending on the data length. 1224178825Sdfr */ 1225178825Sdfr token->EC[0] = 0; 1226178825Sdfr token->EC[1] = 0; 1227178825Sdfr } 1228178825Sdfr 1229178825Sdfr /* 1230178825Sdfr * In Wrap tokens that provide for confidentiality, the RRC 1231178825Sdfr * field in the header contains the hex value 00 00 before 1232178825Sdfr * encryption. 1233178825Sdfr * 1234178825Sdfr * In Wrap tokens that do not provide for confidentiality, 1235178825Sdfr * both the EC and RRC fields in the appended checksum 1236178825Sdfr * contain the hex value 00 00 for the purpose of calculating 1237178825Sdfr * the checksum. 1238178825Sdfr */ 1239178825Sdfr token->RRC[0] = 0; 1240178825Sdfr token->RRC[1] = 0; 1241178825Sdfr 1242233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1243178825Sdfr krb5_auth_con_getlocalseqnumber(context, 1244233294Sstas ctx->auth_context, 1245178825Sdfr &seq_number); 1246178825Sdfr _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 1247178825Sdfr _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 1248178825Sdfr krb5_auth_con_setlocalseqnumber(context, 1249233294Sstas ctx->auth_context, 1250178825Sdfr ++seq_number); 1251233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1252178825Sdfr 1253178825Sdfr /* 1254178825Sdfr * If confidentiality is requested, the token header is 1255178825Sdfr * appended to the plaintext before encryption; the resulting 1256178825Sdfr * token is {"header" | encrypt(plaintext | pad | "header")}. 1257178825Sdfr * 1258178825Sdfr * If no confidentiality is requested, the checksum is 1259178825Sdfr * calculated over the plaintext concatenated with the 1260178825Sdfr * token header. 1261178825Sdfr */ 1262233294Sstas if (ctx->more_flags & LOCAL) { 1263178825Sdfr usage = KRB5_KU_USAGE_INITIATOR_SEAL; 1264178825Sdfr } else { 1265178825Sdfr usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 1266178825Sdfr } 1267178825Sdfr 1268178825Sdfr if (conf_req_flag) { 1269178825Sdfr /* 1270178825Sdfr * Any necessary padding is added here to ensure that the 1271178825Sdfr * encrypted token header is always at the end of the 1272178825Sdfr * ciphertext. 1273178825Sdfr * 1274178825Sdfr * The specification does not require that the padding 1275178825Sdfr * bytes are initialized. 1276178825Sdfr */ 1277178825Sdfr p += sizeof(*token); 1278178825Sdfr memcpy(p, input_message_buffer->value, input_message_buffer->length); 1279178825Sdfr memset(p + input_message_buffer->length, 0xFF, padlength); 1280178825Sdfr memcpy(p + input_message_buffer->length + padlength, 1281178825Sdfr token, sizeof(*token)); 1282178825Sdfr 1283233294Sstas ret = krb5_encrypt(context, ctx->crypto, 1284178825Sdfr usage, p, 1285178825Sdfr input_message_buffer->length + padlength + 1286178825Sdfr sizeof(*token), 1287178825Sdfr &cipher); 1288178825Sdfr if (ret != 0) { 1289178825Sdfr *minor_status = ret; 1290178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1291178825Sdfr return GSS_S_FAILURE; 1292178825Sdfr } 1293178825Sdfr assert(sizeof(*token) + cipher.length == wrapped_len); 1294233294Sstas token->RRC[0] = (rrc >> 8) & 0xFF; 1295178825Sdfr token->RRC[1] = (rrc >> 0) & 0xFF; 1296178825Sdfr 1297233294Sstas /* 1298233294Sstas * this is really ugly, but needed against windows 1299233294Sstas * for DCERPC, as windows rotates by EC+RRC. 1300233294Sstas */ 1301233294Sstas if (IS_DCE_STYLE(ctx)) { 1302233294Sstas ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE); 1303233294Sstas } else { 1304233294Sstas ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); 1305233294Sstas } 1306178825Sdfr if (ret != 0) { 1307178825Sdfr *minor_status = ret; 1308178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1309178825Sdfr return GSS_S_FAILURE; 1310178825Sdfr } 1311178825Sdfr memcpy(p, cipher.data, cipher.length); 1312178825Sdfr krb5_data_free(&cipher); 1313178825Sdfr } else { 1314178825Sdfr char *buf; 1315178825Sdfr Checksum cksum; 1316178825Sdfr 1317178825Sdfr buf = malloc(input_message_buffer->length + sizeof(*token)); 1318178825Sdfr if (buf == NULL) { 1319178825Sdfr *minor_status = ENOMEM; 1320178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1321178825Sdfr return GSS_S_FAILURE; 1322178825Sdfr } 1323178825Sdfr memcpy(buf, input_message_buffer->value, input_message_buffer->length); 1324178825Sdfr memcpy(buf + input_message_buffer->length, token, sizeof(*token)); 1325178825Sdfr 1326233294Sstas ret = krb5_create_checksum(context, ctx->crypto, 1327233294Sstas usage, 0, buf, 1328178825Sdfr input_message_buffer->length + 1329233294Sstas sizeof(*token), 1330178825Sdfr &cksum); 1331178825Sdfr if (ret != 0) { 1332178825Sdfr *minor_status = ret; 1333178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1334178825Sdfr free(buf); 1335178825Sdfr return GSS_S_FAILURE; 1336178825Sdfr } 1337178825Sdfr 1338178825Sdfr free(buf); 1339178825Sdfr 1340178825Sdfr assert(cksum.checksum.length == cksumsize); 1341178825Sdfr token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; 1342178825Sdfr token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; 1343233294Sstas token->RRC[0] = (rrc >> 8) & 0xFF; 1344178825Sdfr token->RRC[1] = (rrc >> 0) & 0xFF; 1345178825Sdfr 1346178825Sdfr p += sizeof(*token); 1347178825Sdfr memcpy(p, input_message_buffer->value, input_message_buffer->length); 1348178825Sdfr memcpy(p + input_message_buffer->length, 1349178825Sdfr cksum.checksum.data, cksum.checksum.length); 1350178825Sdfr 1351178825Sdfr ret = rrc_rotate(p, 1352178825Sdfr input_message_buffer->length + cksum.checksum.length, rrc, FALSE); 1353178825Sdfr if (ret != 0) { 1354178825Sdfr *minor_status = ret; 1355178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1356178825Sdfr free_Checksum(&cksum); 1357178825Sdfr return GSS_S_FAILURE; 1358178825Sdfr } 1359178825Sdfr free_Checksum(&cksum); 1360178825Sdfr } 1361178825Sdfr 1362178825Sdfr if (conf_state != NULL) { 1363178825Sdfr *conf_state = conf_req_flag; 1364178825Sdfr } 1365178825Sdfr 1366178825Sdfr *minor_status = 0; 1367178825Sdfr return GSS_S_COMPLETE; 1368178825Sdfr} 1369178825Sdfr 1370178825SdfrOM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, 1371233294Sstas const gsskrb5_ctx ctx, 1372178825Sdfr krb5_context context, 1373178825Sdfr const gss_buffer_t input_message_buffer, 1374178825Sdfr gss_buffer_t output_message_buffer, 1375178825Sdfr int *conf_state, 1376233294Sstas gss_qop_t *qop_state) 1377178825Sdfr{ 1378178825Sdfr gss_cfx_wrap_token token; 1379178825Sdfr u_char token_flags; 1380178825Sdfr krb5_error_code ret; 1381178825Sdfr unsigned usage; 1382178825Sdfr krb5_data data; 1383178825Sdfr uint16_t ec, rrc; 1384178825Sdfr OM_uint32 seq_number_lo, seq_number_hi; 1385178825Sdfr size_t len; 1386178825Sdfr u_char *p; 1387178825Sdfr 1388178825Sdfr *minor_status = 0; 1389178825Sdfr 1390178825Sdfr if (input_message_buffer->length < sizeof(*token)) { 1391178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1392178825Sdfr } 1393178825Sdfr 1394178825Sdfr p = input_message_buffer->value; 1395178825Sdfr 1396178825Sdfr token = (gss_cfx_wrap_token)p; 1397178825Sdfr 1398178825Sdfr if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) { 1399178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1400178825Sdfr } 1401178825Sdfr 1402178825Sdfr /* Ignore unknown flags */ 1403178825Sdfr token_flags = token->Flags & 1404178825Sdfr (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); 1405178825Sdfr 1406178825Sdfr if (token_flags & CFXSentByAcceptor) { 1407233294Sstas if ((ctx->more_flags & LOCAL) == 0) 1408178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1409178825Sdfr } 1410178825Sdfr 1411233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) { 1412178825Sdfr if ((token_flags & CFXAcceptorSubkey) == 0) 1413178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1414178825Sdfr } else { 1415178825Sdfr if (token_flags & CFXAcceptorSubkey) 1416178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1417178825Sdfr } 1418178825Sdfr 1419178825Sdfr if (token->Filler != 0xFF) { 1420178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1421178825Sdfr } 1422178825Sdfr 1423178825Sdfr if (conf_state != NULL) { 1424178825Sdfr *conf_state = (token_flags & CFXSealed) ? 1 : 0; 1425178825Sdfr } 1426178825Sdfr 1427178825Sdfr ec = (token->EC[0] << 8) | token->EC[1]; 1428178825Sdfr rrc = (token->RRC[0] << 8) | token->RRC[1]; 1429178825Sdfr 1430178825Sdfr /* 1431178825Sdfr * Check sequence number 1432178825Sdfr */ 1433178825Sdfr _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 1434178825Sdfr _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 1435178825Sdfr if (seq_number_hi) { 1436178825Sdfr /* no support for 64-bit sequence numbers */ 1437178825Sdfr *minor_status = ERANGE; 1438178825Sdfr return GSS_S_UNSEQ_TOKEN; 1439178825Sdfr } 1440178825Sdfr 1441233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1442233294Sstas ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); 1443178825Sdfr if (ret != 0) { 1444178825Sdfr *minor_status = 0; 1445233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1446178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1447178825Sdfr return ret; 1448178825Sdfr } 1449233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1450178825Sdfr 1451178825Sdfr /* 1452178825Sdfr * Decrypt and/or verify checksum 1453178825Sdfr */ 1454178825Sdfr 1455233294Sstas if (ctx->more_flags & LOCAL) { 1456178825Sdfr usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 1457178825Sdfr } else { 1458178825Sdfr usage = KRB5_KU_USAGE_INITIATOR_SEAL; 1459178825Sdfr } 1460178825Sdfr 1461178825Sdfr p += sizeof(*token); 1462178825Sdfr len = input_message_buffer->length; 1463178825Sdfr len -= (p - (u_char *)input_message_buffer->value); 1464178825Sdfr 1465233294Sstas if (token_flags & CFXSealed) { 1466233294Sstas /* 1467233294Sstas * this is really ugly, but needed against windows 1468233294Sstas * for DCERPC, as windows rotates by EC+RRC. 1469233294Sstas */ 1470233294Sstas if (IS_DCE_STYLE(ctx)) { 1471233294Sstas *minor_status = rrc_rotate(p, len, rrc+ec, TRUE); 1472233294Sstas } else { 1473233294Sstas *minor_status = rrc_rotate(p, len, rrc, TRUE); 1474233294Sstas } 1475233294Sstas if (*minor_status != 0) { 1476233294Sstas return GSS_S_FAILURE; 1477233294Sstas } 1478178825Sdfr 1479233294Sstas ret = krb5_decrypt(context, ctx->crypto, usage, 1480178825Sdfr p, len, &data); 1481178825Sdfr if (ret != 0) { 1482178825Sdfr *minor_status = ret; 1483178825Sdfr return GSS_S_BAD_MIC; 1484178825Sdfr } 1485178825Sdfr 1486178825Sdfr /* Check that there is room for the pad and token header */ 1487178825Sdfr if (data.length < ec + sizeof(*token)) { 1488178825Sdfr krb5_data_free(&data); 1489178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1490178825Sdfr } 1491178825Sdfr p = data.data; 1492178825Sdfr p += data.length - sizeof(*token); 1493178825Sdfr 1494178825Sdfr /* RRC is unprotected; don't modify input buffer */ 1495178825Sdfr ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; 1496178825Sdfr ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; 1497178825Sdfr 1498178825Sdfr /* Check the integrity of the header */ 1499233294Sstas if (ct_memcmp(p, token, sizeof(*token)) != 0) { 1500178825Sdfr krb5_data_free(&data); 1501178825Sdfr return GSS_S_BAD_MIC; 1502178825Sdfr } 1503178825Sdfr 1504178825Sdfr output_message_buffer->value = data.data; 1505178825Sdfr output_message_buffer->length = data.length - ec - sizeof(*token); 1506178825Sdfr } else { 1507178825Sdfr Checksum cksum; 1508178825Sdfr 1509233294Sstas /* Rotate by RRC; bogus to do this in-place XXX */ 1510233294Sstas *minor_status = rrc_rotate(p, len, rrc, TRUE); 1511233294Sstas if (*minor_status != 0) { 1512233294Sstas return GSS_S_FAILURE; 1513233294Sstas } 1514233294Sstas 1515178825Sdfr /* Determine checksum type */ 1516178825Sdfr ret = krb5_crypto_get_checksum_type(context, 1517233294Sstas ctx->crypto, 1518233294Sstas &cksum.cksumtype); 1519178825Sdfr if (ret != 0) { 1520178825Sdfr *minor_status = ret; 1521178825Sdfr return GSS_S_FAILURE; 1522178825Sdfr } 1523178825Sdfr 1524178825Sdfr cksum.checksum.length = ec; 1525178825Sdfr 1526178825Sdfr /* Check we have at least as much data as the checksum */ 1527178825Sdfr if (len < cksum.checksum.length) { 1528178825Sdfr *minor_status = ERANGE; 1529178825Sdfr return GSS_S_BAD_MIC; 1530178825Sdfr } 1531178825Sdfr 1532178825Sdfr /* Length now is of the plaintext only, no checksum */ 1533178825Sdfr len -= cksum.checksum.length; 1534178825Sdfr cksum.checksum.data = p + len; 1535178825Sdfr 1536178825Sdfr output_message_buffer->length = len; /* for later */ 1537178825Sdfr output_message_buffer->value = malloc(len + sizeof(*token)); 1538178825Sdfr if (output_message_buffer->value == NULL) { 1539178825Sdfr *minor_status = ENOMEM; 1540178825Sdfr return GSS_S_FAILURE; 1541178825Sdfr } 1542178825Sdfr 1543178825Sdfr /* Checksum is over (plaintext-data | "header") */ 1544178825Sdfr memcpy(output_message_buffer->value, p, len); 1545233294Sstas memcpy((u_char *)output_message_buffer->value + len, 1546178825Sdfr token, sizeof(*token)); 1547178825Sdfr 1548178825Sdfr /* EC is not included in checksum calculation */ 1549178825Sdfr token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + 1550178825Sdfr len); 1551178825Sdfr token->EC[0] = 0; 1552178825Sdfr token->EC[1] = 0; 1553178825Sdfr token->RRC[0] = 0; 1554178825Sdfr token->RRC[1] = 0; 1555178825Sdfr 1556233294Sstas ret = krb5_verify_checksum(context, ctx->crypto, 1557178825Sdfr usage, 1558178825Sdfr output_message_buffer->value, 1559178825Sdfr len + sizeof(*token), 1560178825Sdfr &cksum); 1561178825Sdfr if (ret != 0) { 1562178825Sdfr *minor_status = ret; 1563178825Sdfr _gsskrb5_release_buffer(minor_status, output_message_buffer); 1564178825Sdfr return GSS_S_BAD_MIC; 1565178825Sdfr } 1566178825Sdfr } 1567178825Sdfr 1568178825Sdfr if (qop_state != NULL) { 1569178825Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1570178825Sdfr } 1571178825Sdfr 1572178825Sdfr *minor_status = 0; 1573178825Sdfr return GSS_S_COMPLETE; 1574178825Sdfr} 1575178825Sdfr 1576178825SdfrOM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, 1577233294Sstas const gsskrb5_ctx ctx, 1578178825Sdfr krb5_context context, 1579178825Sdfr gss_qop_t qop_req, 1580178825Sdfr const gss_buffer_t message_buffer, 1581233294Sstas gss_buffer_t message_token) 1582178825Sdfr{ 1583178825Sdfr gss_cfx_mic_token token; 1584178825Sdfr krb5_error_code ret; 1585178825Sdfr unsigned usage; 1586178825Sdfr Checksum cksum; 1587178825Sdfr u_char *buf; 1588178825Sdfr size_t len; 1589178825Sdfr int32_t seq_number; 1590178825Sdfr 1591178825Sdfr len = message_buffer->length + sizeof(*token); 1592178825Sdfr buf = malloc(len); 1593178825Sdfr if (buf == NULL) { 1594178825Sdfr *minor_status = ENOMEM; 1595178825Sdfr return GSS_S_FAILURE; 1596178825Sdfr } 1597178825Sdfr 1598178825Sdfr memcpy(buf, message_buffer->value, message_buffer->length); 1599178825Sdfr 1600178825Sdfr token = (gss_cfx_mic_token)(buf + message_buffer->length); 1601178825Sdfr token->TOK_ID[0] = 0x04; 1602178825Sdfr token->TOK_ID[1] = 0x04; 1603178825Sdfr token->Flags = 0; 1604233294Sstas if ((ctx->more_flags & LOCAL) == 0) 1605178825Sdfr token->Flags |= CFXSentByAcceptor; 1606233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) 1607178825Sdfr token->Flags |= CFXAcceptorSubkey; 1608178825Sdfr memset(token->Filler, 0xFF, 5); 1609178825Sdfr 1610233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1611178825Sdfr krb5_auth_con_getlocalseqnumber(context, 1612233294Sstas ctx->auth_context, 1613178825Sdfr &seq_number); 1614178825Sdfr _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 1615178825Sdfr _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 1616178825Sdfr krb5_auth_con_setlocalseqnumber(context, 1617233294Sstas ctx->auth_context, 1618178825Sdfr ++seq_number); 1619233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1620178825Sdfr 1621233294Sstas if (ctx->more_flags & LOCAL) { 1622178825Sdfr usage = KRB5_KU_USAGE_INITIATOR_SIGN; 1623178825Sdfr } else { 1624178825Sdfr usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 1625178825Sdfr } 1626178825Sdfr 1627233294Sstas ret = krb5_create_checksum(context, ctx->crypto, 1628178825Sdfr usage, 0, buf, len, &cksum); 1629178825Sdfr if (ret != 0) { 1630178825Sdfr *minor_status = ret; 1631178825Sdfr free(buf); 1632178825Sdfr return GSS_S_FAILURE; 1633178825Sdfr } 1634178825Sdfr 1635178825Sdfr /* Determine MIC length */ 1636178825Sdfr message_token->length = sizeof(*token) + cksum.checksum.length; 1637178825Sdfr message_token->value = malloc(message_token->length); 1638178825Sdfr if (message_token->value == NULL) { 1639178825Sdfr *minor_status = ENOMEM; 1640178825Sdfr free_Checksum(&cksum); 1641178825Sdfr free(buf); 1642178825Sdfr return GSS_S_FAILURE; 1643178825Sdfr } 1644178825Sdfr 1645178825Sdfr /* Token is { "header" | get_mic("header" | plaintext-data) } */ 1646178825Sdfr memcpy(message_token->value, token, sizeof(*token)); 1647178825Sdfr memcpy((u_char *)message_token->value + sizeof(*token), 1648178825Sdfr cksum.checksum.data, cksum.checksum.length); 1649178825Sdfr 1650178825Sdfr free_Checksum(&cksum); 1651178825Sdfr free(buf); 1652178825Sdfr 1653178825Sdfr *minor_status = 0; 1654178825Sdfr return GSS_S_COMPLETE; 1655178825Sdfr} 1656178825Sdfr 1657178825SdfrOM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, 1658233294Sstas const gsskrb5_ctx ctx, 1659178825Sdfr krb5_context context, 1660178825Sdfr const gss_buffer_t message_buffer, 1661178825Sdfr const gss_buffer_t token_buffer, 1662233294Sstas gss_qop_t *qop_state) 1663178825Sdfr{ 1664178825Sdfr gss_cfx_mic_token token; 1665178825Sdfr u_char token_flags; 1666178825Sdfr krb5_error_code ret; 1667178825Sdfr unsigned usage; 1668178825Sdfr OM_uint32 seq_number_lo, seq_number_hi; 1669178825Sdfr u_char *buf, *p; 1670178825Sdfr Checksum cksum; 1671178825Sdfr 1672178825Sdfr *minor_status = 0; 1673178825Sdfr 1674178825Sdfr if (token_buffer->length < sizeof(*token)) { 1675178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1676178825Sdfr } 1677178825Sdfr 1678178825Sdfr p = token_buffer->value; 1679178825Sdfr 1680178825Sdfr token = (gss_cfx_mic_token)p; 1681178825Sdfr 1682178825Sdfr if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { 1683178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1684178825Sdfr } 1685178825Sdfr 1686178825Sdfr /* Ignore unknown flags */ 1687178825Sdfr token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); 1688178825Sdfr 1689178825Sdfr if (token_flags & CFXSentByAcceptor) { 1690233294Sstas if ((ctx->more_flags & LOCAL) == 0) 1691178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1692178825Sdfr } 1693233294Sstas if (ctx->more_flags & ACCEPTOR_SUBKEY) { 1694178825Sdfr if ((token_flags & CFXAcceptorSubkey) == 0) 1695178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1696178825Sdfr } else { 1697178825Sdfr if (token_flags & CFXAcceptorSubkey) 1698178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1699178825Sdfr } 1700178825Sdfr 1701233294Sstas if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { 1702178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 1703178825Sdfr } 1704178825Sdfr 1705178825Sdfr /* 1706178825Sdfr * Check sequence number 1707178825Sdfr */ 1708178825Sdfr _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 1709178825Sdfr _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 1710178825Sdfr if (seq_number_hi) { 1711178825Sdfr *minor_status = ERANGE; 1712178825Sdfr return GSS_S_UNSEQ_TOKEN; 1713178825Sdfr } 1714178825Sdfr 1715233294Sstas HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1716233294Sstas ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); 1717178825Sdfr if (ret != 0) { 1718178825Sdfr *minor_status = 0; 1719233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1720178825Sdfr return ret; 1721178825Sdfr } 1722233294Sstas HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1723178825Sdfr 1724178825Sdfr /* 1725178825Sdfr * Verify checksum 1726178825Sdfr */ 1727233294Sstas ret = krb5_crypto_get_checksum_type(context, ctx->crypto, 1728178825Sdfr &cksum.cksumtype); 1729178825Sdfr if (ret != 0) { 1730178825Sdfr *minor_status = ret; 1731178825Sdfr return GSS_S_FAILURE; 1732178825Sdfr } 1733178825Sdfr 1734178825Sdfr cksum.checksum.data = p + sizeof(*token); 1735178825Sdfr cksum.checksum.length = token_buffer->length - sizeof(*token); 1736178825Sdfr 1737233294Sstas if (ctx->more_flags & LOCAL) { 1738178825Sdfr usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 1739178825Sdfr } else { 1740178825Sdfr usage = KRB5_KU_USAGE_INITIATOR_SIGN; 1741178825Sdfr } 1742178825Sdfr 1743178825Sdfr buf = malloc(message_buffer->length + sizeof(*token)); 1744178825Sdfr if (buf == NULL) { 1745178825Sdfr *minor_status = ENOMEM; 1746178825Sdfr return GSS_S_FAILURE; 1747178825Sdfr } 1748178825Sdfr memcpy(buf, message_buffer->value, message_buffer->length); 1749178825Sdfr memcpy(buf + message_buffer->length, token, sizeof(*token)); 1750178825Sdfr 1751233294Sstas ret = krb5_verify_checksum(context, ctx->crypto, 1752178825Sdfr usage, 1753178825Sdfr buf, 1754178825Sdfr sizeof(*token) + message_buffer->length, 1755178825Sdfr &cksum); 1756178825Sdfr if (ret != 0) { 1757178825Sdfr *minor_status = ret; 1758178825Sdfr free(buf); 1759178825Sdfr return GSS_S_BAD_MIC; 1760178825Sdfr } 1761178825Sdfr 1762178825Sdfr free(buf); 1763178825Sdfr 1764178825Sdfr if (qop_state != NULL) { 1765178825Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1766178825Sdfr } 1767178825Sdfr 1768178825Sdfr return GSS_S_COMPLETE; 1769178825Sdfr} 1770