1 /* 2 * Copyright (c) 2003, PADL Software Pty Ltd. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of PADL Software nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include "krb5/gsskrb5_locl.h" 34 35 RCSID("$Id: cfx.c 19031 2006-11-13 18:02:57Z lha $"); 36 37 /* 38 * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt 39 */ 40 41 #define CFXSentByAcceptor (1 << 0) 42 #define CFXSealed (1 << 1) 43 #define CFXAcceptorSubkey (1 << 2) 44 45 krb5_error_code 46 _gsskrb5cfx_wrap_length_cfx(krb5_context context, 47 krb5_crypto crypto, 48 int conf_req_flag, 49 size_t input_length, 50 size_t *output_length, 51 size_t *cksumsize, 52 uint16_t *padlength) 53 { 54 krb5_error_code ret; 55 krb5_cksumtype type; 56 57 /* 16-byte header is always first */ 58 *output_length = sizeof(gss_cfx_wrap_token_desc); 59 *padlength = 0; 60 61 ret = krb5_crypto_get_checksum_type(context, crypto, &type); 62 if (ret) 63 return ret; 64 65 ret = krb5_checksumsize(context, type, cksumsize); 66 if (ret) 67 return ret; 68 69 if (conf_req_flag) { 70 size_t padsize; 71 72 /* Header is concatenated with data before encryption */ 73 input_length += sizeof(gss_cfx_wrap_token_desc); 74 75 ret = krb5_crypto_getpadsize(context, crypto, &padsize); 76 if (ret) { 77 return ret; 78 } 79 if (padsize > 1) { 80 /* XXX check this */ 81 *padlength = padsize - (input_length % padsize); 82 83 /* We add the pad ourselves (noted here for completeness only) */ 84 input_length += *padlength; 85 } 86 87 *output_length += krb5_get_wrapped_length(context, 88 crypto, input_length); 89 } else { 90 /* Checksum is concatenated with data */ 91 *output_length += input_length + *cksumsize; 92 } 93 94 assert(*output_length > input_length); 95 96 return 0; 97 } 98 99 krb5_error_code 100 _gsskrb5cfx_max_wrap_length_cfx(krb5_context context, 101 krb5_crypto crypto, 102 int conf_req_flag, 103 size_t input_length, 104 OM_uint32 *output_length) 105 { 106 krb5_error_code ret; 107 108 *output_length = 0; 109 110 /* 16-byte header is always first */ 111 if (input_length < 16) 112 return 0; 113 input_length -= 16; 114 115 if (conf_req_flag) { 116 size_t wrapped_size, sz; 117 118 wrapped_size = input_length + 1; 119 do { 120 wrapped_size--; 121 sz = krb5_get_wrapped_length(context, 122 crypto, wrapped_size); 123 } while (wrapped_size && sz > input_length); 124 if (wrapped_size == 0) { 125 *output_length = 0; 126 return 0; 127 } 128 129 /* inner header */ 130 if (wrapped_size < 16) { 131 *output_length = 0; 132 return 0; 133 } 134 wrapped_size -= 16; 135 136 *output_length = wrapped_size; 137 } else { 138 krb5_cksumtype type; 139 size_t cksumsize; 140 141 ret = krb5_crypto_get_checksum_type(context, crypto, &type); 142 if (ret) 143 return ret; 144 145 ret = krb5_checksumsize(context, type, &cksumsize); 146 if (ret) 147 return ret; 148 149 if (input_length < cksumsize) 150 return 0; 151 152 /* Checksum is concatenated with data */ 153 *output_length = input_length - cksumsize; 154 } 155 156 return 0; 157 } 158 159 160 OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, 161 const gsskrb5_ctx context_handle, 162 krb5_context context, 163 int conf_req_flag, 164 gss_qop_t qop_req, 165 OM_uint32 req_output_size, 166 OM_uint32 *max_input_size, 167 krb5_keyblock *key) 168 { 169 krb5_error_code ret; 170 krb5_crypto crypto; 171 172 ret = krb5_crypto_init(context, key, 0, &crypto); 173 if (ret != 0) { 174 *minor_status = ret; 175 return GSS_S_FAILURE; 176 } 177 178 ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag, 179 req_output_size, max_input_size); 180 if (ret != 0) { 181 *minor_status = ret; 182 krb5_crypto_destroy(context, crypto); 183 return GSS_S_FAILURE; 184 } 185 186 krb5_crypto_destroy(context, crypto); 187 188 return GSS_S_COMPLETE; 189 } 190 191 /* 192 * Rotate "rrc" bytes to the front or back 193 */ 194 195 static krb5_error_code 196 rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) 197 { 198 u_char *tmp, buf[256]; 199 size_t left; 200 201 if (len == 0) 202 return 0; 203 204 rrc %= len; 205 206 if (rrc == 0) 207 return 0; 208 209 left = len - rrc; 210 211 if (rrc <= sizeof(buf)) { 212 tmp = buf; 213 } else { 214 tmp = malloc(rrc); 215 if (tmp == NULL) 216 return ENOMEM; 217 } 218 219 if (unrotate) { 220 memcpy(tmp, data, rrc); 221 memmove(data, (u_char *)data + rrc, left); 222 memcpy((u_char *)data + left, tmp, rrc); 223 } else { 224 memcpy(tmp, (u_char *)data + left, rrc); 225 memmove((u_char *)data + rrc, data, left); 226 memcpy(data, tmp, rrc); 227 } 228 229 if (rrc > sizeof(buf)) 230 free(tmp); 231 232 return 0; 233 } 234 235 OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, 236 const gsskrb5_ctx context_handle, 237 krb5_context context, 238 int conf_req_flag, 239 gss_qop_t qop_req, 240 const gss_buffer_t input_message_buffer, 241 int *conf_state, 242 gss_buffer_t output_message_buffer, 243 krb5_keyblock *key) 244 { 245 krb5_crypto crypto; 246 gss_cfx_wrap_token token; 247 krb5_error_code ret; 248 unsigned usage; 249 krb5_data cipher; 250 size_t wrapped_len, cksumsize; 251 uint16_t padlength, rrc = 0; 252 int32_t seq_number; 253 u_char *p; 254 255 ret = krb5_crypto_init(context, key, 0, &crypto); 256 if (ret != 0) { 257 *minor_status = ret; 258 return GSS_S_FAILURE; 259 } 260 261 ret = _gsskrb5cfx_wrap_length_cfx(context, 262 crypto, conf_req_flag, 263 input_message_buffer->length, 264 &wrapped_len, &cksumsize, &padlength); 265 if (ret != 0) { 266 *minor_status = ret; 267 krb5_crypto_destroy(context, crypto); 268 return GSS_S_FAILURE; 269 } 270 271 /* Always rotate encrypted token (if any) and checksum to header */ 272 rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize; 273 274 output_message_buffer->length = wrapped_len; 275 output_message_buffer->value = malloc(output_message_buffer->length); 276 if (output_message_buffer->value == NULL) { 277 *minor_status = ENOMEM; 278 krb5_crypto_destroy(context, crypto); 279 return GSS_S_FAILURE; 280 } 281 282 p = output_message_buffer->value; 283 token = (gss_cfx_wrap_token)p; 284 token->TOK_ID[0] = 0x05; 285 token->TOK_ID[1] = 0x04; 286 token->Flags = 0; 287 token->Filler = 0xFF; 288 if ((context_handle->more_flags & LOCAL) == 0) 289 token->Flags |= CFXSentByAcceptor; 290 if (context_handle->more_flags & ACCEPTOR_SUBKEY) 291 token->Flags |= CFXAcceptorSubkey; 292 if (conf_req_flag) { 293 /* 294 * In Wrap tokens with confidentiality, the EC field is 295 * used to encode the size (in bytes) of the random filler. 296 */ 297 token->Flags |= CFXSealed; 298 token->EC[0] = (padlength >> 8) & 0xFF; 299 token->EC[1] = (padlength >> 0) & 0xFF; 300 } else { 301 /* 302 * In Wrap tokens without confidentiality, the EC field is 303 * used to encode the size (in bytes) of the trailing 304 * checksum. 305 * 306 * This is not used in the checksum calcuation itself, 307 * because the checksum length could potentially vary 308 * depending on the data length. 309 */ 310 token->EC[0] = 0; 311 token->EC[1] = 0; 312 } 313 314 /* 315 * In Wrap tokens that provide for confidentiality, the RRC 316 * field in the header contains the hex value 00 00 before 317 * encryption. 318 * 319 * In Wrap tokens that do not provide for confidentiality, 320 * both the EC and RRC fields in the appended checksum 321 * contain the hex value 00 00 for the purpose of calculating 322 * the checksum. 323 */ 324 token->RRC[0] = 0; 325 token->RRC[1] = 0; 326 327 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 328 krb5_auth_con_getlocalseqnumber(context, 329 context_handle->auth_context, 330 &seq_number); 331 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 332 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 333 krb5_auth_con_setlocalseqnumber(context, 334 context_handle->auth_context, 335 ++seq_number); 336 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 337 338 /* 339 * If confidentiality is requested, the token header is 340 * appended to the plaintext before encryption; the resulting 341 * token is {"header" | encrypt(plaintext | pad | "header")}. 342 * 343 * If no confidentiality is requested, the checksum is 344 * calculated over the plaintext concatenated with the 345 * token header. 346 */ 347 if (context_handle->more_flags & LOCAL) { 348 usage = KRB5_KU_USAGE_INITIATOR_SEAL; 349 } else { 350 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 351 } 352 353 if (conf_req_flag) { 354 /* 355 * Any necessary padding is added here to ensure that the 356 * encrypted token header is always at the end of the 357 * ciphertext. 358 * 359 * The specification does not require that the padding 360 * bytes are initialized. 361 */ 362 p += sizeof(*token); 363 memcpy(p, input_message_buffer->value, input_message_buffer->length); 364 memset(p + input_message_buffer->length, 0xFF, padlength); 365 memcpy(p + input_message_buffer->length + padlength, 366 token, sizeof(*token)); 367 368 ret = krb5_encrypt(context, crypto, 369 usage, p, 370 input_message_buffer->length + padlength + 371 sizeof(*token), 372 &cipher); 373 if (ret != 0) { 374 *minor_status = ret; 375 krb5_crypto_destroy(context, crypto); 376 _gsskrb5_release_buffer(minor_status, output_message_buffer); 377 return GSS_S_FAILURE; 378 } 379 assert(sizeof(*token) + cipher.length == wrapped_len); 380 token->RRC[0] = (rrc >> 8) & 0xFF; 381 token->RRC[1] = (rrc >> 0) & 0xFF; 382 383 ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); 384 if (ret != 0) { 385 *minor_status = ret; 386 krb5_crypto_destroy(context, crypto); 387 _gsskrb5_release_buffer(minor_status, output_message_buffer); 388 return GSS_S_FAILURE; 389 } 390 memcpy(p, cipher.data, cipher.length); 391 krb5_data_free(&cipher); 392 } else { 393 char *buf; 394 Checksum cksum; 395 396 buf = malloc(input_message_buffer->length + sizeof(*token)); 397 if (buf == NULL) { 398 *minor_status = ENOMEM; 399 krb5_crypto_destroy(context, crypto); 400 _gsskrb5_release_buffer(minor_status, output_message_buffer); 401 return GSS_S_FAILURE; 402 } 403 memcpy(buf, input_message_buffer->value, input_message_buffer->length); 404 memcpy(buf + input_message_buffer->length, token, sizeof(*token)); 405 406 ret = krb5_create_checksum(context, crypto, 407 usage, 0, buf, 408 input_message_buffer->length + 409 sizeof(*token), 410 &cksum); 411 if (ret != 0) { 412 *minor_status = ret; 413 krb5_crypto_destroy(context, crypto); 414 _gsskrb5_release_buffer(minor_status, output_message_buffer); 415 free(buf); 416 return GSS_S_FAILURE; 417 } 418 419 free(buf); 420 421 assert(cksum.checksum.length == cksumsize); 422 token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; 423 token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; 424 token->RRC[0] = (rrc >> 8) & 0xFF; 425 token->RRC[1] = (rrc >> 0) & 0xFF; 426 427 p += sizeof(*token); 428 memcpy(p, input_message_buffer->value, input_message_buffer->length); 429 memcpy(p + input_message_buffer->length, 430 cksum.checksum.data, cksum.checksum.length); 431 432 ret = rrc_rotate(p, 433 input_message_buffer->length + cksum.checksum.length, rrc, FALSE); 434 if (ret != 0) { 435 *minor_status = ret; 436 krb5_crypto_destroy(context, crypto); 437 _gsskrb5_release_buffer(minor_status, output_message_buffer); 438 free_Checksum(&cksum); 439 return GSS_S_FAILURE; 440 } 441 free_Checksum(&cksum); 442 } 443 444 krb5_crypto_destroy(context, crypto); 445 446 if (conf_state != NULL) { 447 *conf_state = conf_req_flag; 448 } 449 450 *minor_status = 0; 451 return GSS_S_COMPLETE; 452 } 453 454 OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, 455 const gsskrb5_ctx context_handle, 456 krb5_context context, 457 const gss_buffer_t input_message_buffer, 458 gss_buffer_t output_message_buffer, 459 int *conf_state, 460 gss_qop_t *qop_state, 461 krb5_keyblock *key) 462 { 463 krb5_crypto crypto; 464 gss_cfx_wrap_token token; 465 u_char token_flags; 466 krb5_error_code ret; 467 unsigned usage; 468 krb5_data data; 469 uint16_t ec, rrc; 470 OM_uint32 seq_number_lo, seq_number_hi; 471 size_t len; 472 u_char *p; 473 474 *minor_status = 0; 475 476 if (input_message_buffer->length < sizeof(*token)) { 477 return GSS_S_DEFECTIVE_TOKEN; 478 } 479 480 p = input_message_buffer->value; 481 482 token = (gss_cfx_wrap_token)p; 483 484 if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) { 485 return GSS_S_DEFECTIVE_TOKEN; 486 } 487 488 /* Ignore unknown flags */ 489 token_flags = token->Flags & 490 (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); 491 492 if (token_flags & CFXSentByAcceptor) { 493 if ((context_handle->more_flags & LOCAL) == 0) 494 return GSS_S_DEFECTIVE_TOKEN; 495 } 496 497 if (context_handle->more_flags & ACCEPTOR_SUBKEY) { 498 if ((token_flags & CFXAcceptorSubkey) == 0) 499 return GSS_S_DEFECTIVE_TOKEN; 500 } else { 501 if (token_flags & CFXAcceptorSubkey) 502 return GSS_S_DEFECTIVE_TOKEN; 503 } 504 505 if (token->Filler != 0xFF) { 506 return GSS_S_DEFECTIVE_TOKEN; 507 } 508 509 if (conf_state != NULL) { 510 *conf_state = (token_flags & CFXSealed) ? 1 : 0; 511 } 512 513 ec = (token->EC[0] << 8) | token->EC[1]; 514 rrc = (token->RRC[0] << 8) | token->RRC[1]; 515 516 /* 517 * Check sequence number 518 */ 519 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 520 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 521 if (seq_number_hi) { 522 /* no support for 64-bit sequence numbers */ 523 *minor_status = ERANGE; 524 return GSS_S_UNSEQ_TOKEN; 525 } 526 527 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 528 ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); 529 if (ret != 0) { 530 *minor_status = 0; 531 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 532 _gsskrb5_release_buffer(minor_status, output_message_buffer); 533 return ret; 534 } 535 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 536 537 /* 538 * Decrypt and/or verify checksum 539 */ 540 ret = krb5_crypto_init(context, key, 0, &crypto); 541 if (ret != 0) { 542 *minor_status = ret; 543 return GSS_S_FAILURE; 544 } 545 546 if (context_handle->more_flags & LOCAL) { 547 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 548 } else { 549 usage = KRB5_KU_USAGE_INITIATOR_SEAL; 550 } 551 552 p += sizeof(*token); 553 len = input_message_buffer->length; 554 len -= (p - (u_char *)input_message_buffer->value); 555 556 /* Rotate by RRC; bogus to do this in-place XXX */ 557 *minor_status = rrc_rotate(p, len, rrc, TRUE); 558 if (*minor_status != 0) { 559 krb5_crypto_destroy(context, crypto); 560 return GSS_S_FAILURE; 561 } 562 563 if (token_flags & CFXSealed) { 564 ret = krb5_decrypt(context, crypto, usage, 565 p, len, &data); 566 if (ret != 0) { 567 *minor_status = ret; 568 krb5_crypto_destroy(context, crypto); 569 return GSS_S_BAD_MIC; 570 } 571 572 /* Check that there is room for the pad and token header */ 573 if (data.length < ec + sizeof(*token)) { 574 krb5_crypto_destroy(context, crypto); 575 krb5_data_free(&data); 576 return GSS_S_DEFECTIVE_TOKEN; 577 } 578 p = data.data; 579 p += data.length - sizeof(*token); 580 581 /* RRC is unprotected; don't modify input buffer */ 582 ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; 583 ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; 584 585 /* Check the integrity of the header */ 586 if (memcmp(p, token, sizeof(*token)) != 0) { 587 krb5_crypto_destroy(context, crypto); 588 krb5_data_free(&data); 589 return GSS_S_BAD_MIC; 590 } 591 592 output_message_buffer->value = data.data; 593 output_message_buffer->length = data.length - ec - sizeof(*token); 594 } else { 595 Checksum cksum; 596 597 /* Determine checksum type */ 598 ret = krb5_crypto_get_checksum_type(context, 599 crypto, &cksum.cksumtype); 600 if (ret != 0) { 601 *minor_status = ret; 602 krb5_crypto_destroy(context, crypto); 603 return GSS_S_FAILURE; 604 } 605 606 cksum.checksum.length = ec; 607 608 /* Check we have at least as much data as the checksum */ 609 if (len < cksum.checksum.length) { 610 *minor_status = ERANGE; 611 krb5_crypto_destroy(context, crypto); 612 return GSS_S_BAD_MIC; 613 } 614 615 /* Length now is of the plaintext only, no checksum */ 616 len -= cksum.checksum.length; 617 cksum.checksum.data = p + len; 618 619 output_message_buffer->length = len; /* for later */ 620 output_message_buffer->value = malloc(len + sizeof(*token)); 621 if (output_message_buffer->value == NULL) { 622 *minor_status = ENOMEM; 623 krb5_crypto_destroy(context, crypto); 624 return GSS_S_FAILURE; 625 } 626 627 /* Checksum is over (plaintext-data | "header") */ 628 memcpy(output_message_buffer->value, p, len); 629 memcpy((u_char *)output_message_buffer->value + len, 630 token, sizeof(*token)); 631 632 /* EC is not included in checksum calculation */ 633 token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + 634 len); 635 token->EC[0] = 0; 636 token->EC[1] = 0; 637 token->RRC[0] = 0; 638 token->RRC[1] = 0; 639 640 ret = krb5_verify_checksum(context, crypto, 641 usage, 642 output_message_buffer->value, 643 len + sizeof(*token), 644 &cksum); 645 if (ret != 0) { 646 *minor_status = ret; 647 krb5_crypto_destroy(context, crypto); 648 _gsskrb5_release_buffer(minor_status, output_message_buffer); 649 return GSS_S_BAD_MIC; 650 } 651 } 652 653 krb5_crypto_destroy(context, crypto); 654 655 if (qop_state != NULL) { 656 *qop_state = GSS_C_QOP_DEFAULT; 657 } 658 659 *minor_status = 0; 660 return GSS_S_COMPLETE; 661 } 662 663 OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, 664 const gsskrb5_ctx context_handle, 665 krb5_context context, 666 gss_qop_t qop_req, 667 const gss_buffer_t message_buffer, 668 gss_buffer_t message_token, 669 krb5_keyblock *key) 670 { 671 krb5_crypto crypto; 672 gss_cfx_mic_token token; 673 krb5_error_code ret; 674 unsigned usage; 675 Checksum cksum; 676 u_char *buf; 677 size_t len; 678 int32_t seq_number; 679 680 ret = krb5_crypto_init(context, key, 0, &crypto); 681 if (ret != 0) { 682 *minor_status = ret; 683 return GSS_S_FAILURE; 684 } 685 686 len = message_buffer->length + sizeof(*token); 687 buf = malloc(len); 688 if (buf == NULL) { 689 *minor_status = ENOMEM; 690 krb5_crypto_destroy(context, crypto); 691 return GSS_S_FAILURE; 692 } 693 694 memcpy(buf, message_buffer->value, message_buffer->length); 695 696 token = (gss_cfx_mic_token)(buf + message_buffer->length); 697 token->TOK_ID[0] = 0x04; 698 token->TOK_ID[1] = 0x04; 699 token->Flags = 0; 700 if ((context_handle->more_flags & LOCAL) == 0) 701 token->Flags |= CFXSentByAcceptor; 702 if (context_handle->more_flags & ACCEPTOR_SUBKEY) 703 token->Flags |= CFXAcceptorSubkey; 704 memset(token->Filler, 0xFF, 5); 705 706 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 707 krb5_auth_con_getlocalseqnumber(context, 708 context_handle->auth_context, 709 &seq_number); 710 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 711 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 712 krb5_auth_con_setlocalseqnumber(context, 713 context_handle->auth_context, 714 ++seq_number); 715 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 716 717 if (context_handle->more_flags & LOCAL) { 718 usage = KRB5_KU_USAGE_INITIATOR_SIGN; 719 } else { 720 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 721 } 722 723 ret = krb5_create_checksum(context, crypto, 724 usage, 0, buf, len, &cksum); 725 if (ret != 0) { 726 *minor_status = ret; 727 krb5_crypto_destroy(context, crypto); 728 free(buf); 729 return GSS_S_FAILURE; 730 } 731 krb5_crypto_destroy(context, crypto); 732 733 /* Determine MIC length */ 734 message_token->length = sizeof(*token) + cksum.checksum.length; 735 message_token->value = malloc(message_token->length); 736 if (message_token->value == NULL) { 737 *minor_status = ENOMEM; 738 free_Checksum(&cksum); 739 free(buf); 740 return GSS_S_FAILURE; 741 } 742 743 /* Token is { "header" | get_mic("header" | plaintext-data) } */ 744 memcpy(message_token->value, token, sizeof(*token)); 745 memcpy((u_char *)message_token->value + sizeof(*token), 746 cksum.checksum.data, cksum.checksum.length); 747 748 free_Checksum(&cksum); 749 free(buf); 750 751 *minor_status = 0; 752 return GSS_S_COMPLETE; 753 } 754 755 OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, 756 const gsskrb5_ctx context_handle, 757 krb5_context context, 758 const gss_buffer_t message_buffer, 759 const gss_buffer_t token_buffer, 760 gss_qop_t *qop_state, 761 krb5_keyblock *key) 762 { 763 krb5_crypto crypto; 764 gss_cfx_mic_token token; 765 u_char token_flags; 766 krb5_error_code ret; 767 unsigned usage; 768 OM_uint32 seq_number_lo, seq_number_hi; 769 u_char *buf, *p; 770 Checksum cksum; 771 772 *minor_status = 0; 773 774 if (token_buffer->length < sizeof(*token)) { 775 return GSS_S_DEFECTIVE_TOKEN; 776 } 777 778 p = token_buffer->value; 779 780 token = (gss_cfx_mic_token)p; 781 782 if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { 783 return GSS_S_DEFECTIVE_TOKEN; 784 } 785 786 /* Ignore unknown flags */ 787 token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); 788 789 if (token_flags & CFXSentByAcceptor) { 790 if ((context_handle->more_flags & LOCAL) == 0) 791 return GSS_S_DEFECTIVE_TOKEN; 792 } 793 if (context_handle->more_flags & ACCEPTOR_SUBKEY) { 794 if ((token_flags & CFXAcceptorSubkey) == 0) 795 return GSS_S_DEFECTIVE_TOKEN; 796 } else { 797 if (token_flags & CFXAcceptorSubkey) 798 return GSS_S_DEFECTIVE_TOKEN; 799 } 800 801 if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { 802 return GSS_S_DEFECTIVE_TOKEN; 803 } 804 805 /* 806 * Check sequence number 807 */ 808 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 809 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 810 if (seq_number_hi) { 811 *minor_status = ERANGE; 812 return GSS_S_UNSEQ_TOKEN; 813 } 814 815 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 816 ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); 817 if (ret != 0) { 818 *minor_status = 0; 819 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 820 return ret; 821 } 822 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 823 824 /* 825 * Verify checksum 826 */ 827 ret = krb5_crypto_init(context, key, 0, &crypto); 828 if (ret != 0) { 829 *minor_status = ret; 830 return GSS_S_FAILURE; 831 } 832 833 ret = krb5_crypto_get_checksum_type(context, crypto, 834 &cksum.cksumtype); 835 if (ret != 0) { 836 *minor_status = ret; 837 krb5_crypto_destroy(context, crypto); 838 return GSS_S_FAILURE; 839 } 840 841 cksum.checksum.data = p + sizeof(*token); 842 cksum.checksum.length = token_buffer->length - sizeof(*token); 843 844 if (context_handle->more_flags & LOCAL) { 845 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 846 } else { 847 usage = KRB5_KU_USAGE_INITIATOR_SIGN; 848 } 849 850 buf = malloc(message_buffer->length + sizeof(*token)); 851 if (buf == NULL) { 852 *minor_status = ENOMEM; 853 krb5_crypto_destroy(context, crypto); 854 return GSS_S_FAILURE; 855 } 856 memcpy(buf, message_buffer->value, message_buffer->length); 857 memcpy(buf + message_buffer->length, token, sizeof(*token)); 858 859 ret = krb5_verify_checksum(context, crypto, 860 usage, 861 buf, 862 sizeof(*token) + message_buffer->length, 863 &cksum); 864 krb5_crypto_destroy(context, crypto); 865 if (ret != 0) { 866 *minor_status = ret; 867 free(buf); 868 return GSS_S_BAD_MIC; 869 } 870 871 free(buf); 872 873 if (qop_state != NULL) { 874 *qop_state = GSS_C_QOP_DEFAULT; 875 } 876 877 return GSS_S_COMPLETE; 878 } 879