1/* 2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "gsskrb5_locl.h" 35 36/* 37 * Return initiator subkey, or if that doesn't exists, the subkey. 38 */ 39 40krb5_error_code 41_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, 42 krb5_context context, 43 krb5_keyblock **key) 44{ 45 krb5_error_code ret; 46 *key = NULL; 47 48 if (ctx->more_flags & LOCAL) { 49 ret = krb5_auth_con_getlocalsubkey(context, 50 ctx->auth_context, 51 key); 52 } else { 53 ret = krb5_auth_con_getremotesubkey(context, 54 ctx->auth_context, 55 key); 56 } 57 if (ret == 0 && *key == NULL) 58 ret = krb5_auth_con_getkey(context, 59 ctx->auth_context, 60 key); 61 if (ret == 0 && *key == NULL) { 62 krb5_set_error_message(context, 0, "No initiator subkey available"); 63 return GSS_KRB5_S_KG_NO_SUBKEY; 64 } 65 return ret; 66} 67 68krb5_error_code 69_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, 70 krb5_context context, 71 krb5_keyblock **key) 72{ 73 krb5_error_code ret; 74 *key = NULL; 75 76 if (ctx->more_flags & LOCAL) { 77 ret = krb5_auth_con_getremotesubkey(context, 78 ctx->auth_context, 79 key); 80 } else { 81 ret = krb5_auth_con_getlocalsubkey(context, 82 ctx->auth_context, 83 key); 84 } 85 if (ret == 0 && *key == NULL) { 86 krb5_set_error_message(context, 0, "No acceptor subkey available"); 87 return GSS_KRB5_S_KG_NO_SUBKEY; 88 } 89 return ret; 90} 91 92OM_uint32 93_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, 94 krb5_context context, 95 krb5_keyblock **key) 96{ 97 _gsskrb5i_get_acceptor_subkey(ctx, context, key); 98 if(*key == NULL) { 99 /* 100 * Only use the initiator subkey or ticket session key if an 101 * acceptor subkey was not required. 102 */ 103 if ((ctx->gk5c.flags & GK5C_ACCEPTOR_SUBKEY) == 0) 104 _gsskrb5i_get_initiator_subkey(ctx, context, key); 105 } 106 if (*key == NULL) { 107 krb5_set_error_message(context, 0, "No token key available"); 108 return GSS_KRB5_S_KG_NO_SUBKEY; 109 } 110 return 0; 111} 112 113#if defined(HEIM_KRB5_DES) || defined(HEIM_KRB5_DES3) 114static OM_uint32 115sub_wrap_size ( 116 OM_uint32 req_output_size, 117 OM_uint32 * max_input_size, 118 int blocksize, 119 int extrasize 120 ) 121{ 122 size_t len, total_len; 123 124 len = 8 + req_output_size + blocksize + extrasize; 125 126 _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); 127 128 total_len -= req_output_size; /* token length */ 129 if (total_len < req_output_size) { 130 *max_input_size = (OM_uint32)(req_output_size - total_len); 131 (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); 132 } else { 133 *max_input_size = 0; 134 } 135 return GSS_S_COMPLETE; 136} 137#endif 138 139OM_uint32 GSSAPI_CALLCONV 140_gsskrb5_wrap_size_limit ( 141 OM_uint32 * minor_status, 142 const gss_ctx_id_t context_handle, 143 int conf_req_flag, 144 gss_qop_t qop_req, 145 OM_uint32 req_output_size, 146 OM_uint32 * max_input_size 147 ) 148{ 149 krb5_context context; 150 krb5_keyblock *key; 151 OM_uint32 ret; 152 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; 153 154 GSSAPI_KRB5_INIT (&context); 155 156 if (ctx->more_flags & IS_CFX) 157 return _gssapi_wrap_size_cfx(minor_status, &ctx->gk5c, context, 158 conf_req_flag, qop_req, 159 req_output_size, max_input_size); 160 161 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 162 ret = _gsskrb5i_get_token_key(ctx, context, &key); 163 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 164 if (ret) { 165 *minor_status = ret; 166 return GSS_S_FAILURE; 167 } 168 169 switch (key->keytype) { 170#ifdef HEIM_KRB5_DES 171 case KRB5_ENCTYPE_DES_CBC_CRC : 172 case KRB5_ENCTYPE_DES_CBC_MD4 : 173 case KRB5_ENCTYPE_DES_CBC_MD5 : 174 ret = sub_wrap_size(req_output_size, max_input_size, 8, 22); 175 break; 176#endif 177 178#ifdef HEIM_KRB5_DES3 179 case KRB5_ENCTYPE_DES3_CBC_MD5 : 180 case KRB5_ENCTYPE_DES3_CBC_SHA1 : 181 ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); 182 break; 183#endif 184 185#ifdef HEIM_KRB5_ARCFOUR 186 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: 187 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: 188 ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context, 189 conf_req_flag, qop_req, 190 req_output_size, max_input_size, key); 191 break; 192#endif 193 default : 194 ret = GSS_S_FAILURE; 195 break; 196 } 197 krb5_free_keyblock (context, key); 198 *minor_status = 0; 199 return ret; 200} 201 202#ifdef HEIM_KRB5_DES 203 204static OM_uint32 205wrap_des 206 (OM_uint32 * minor_status, 207 const gsskrb5_ctx ctx, 208 krb5_context context, 209 int conf_req_flag, 210 gss_qop_t qop_req, 211 const gss_buffer_t input_message_buffer, 212 int * conf_state, 213 gss_buffer_t output_message_buffer, 214 krb5_keyblock *key 215 ) 216{ 217 u_char *p; 218 CCDigestRef md5; 219 u_char hash[16]; 220 DES_key_schedule schedule; 221 EVP_CIPHER_CTX des_ctx; 222 DES_cblock deskey; 223 DES_cblock zero; 224 size_t i; 225 int32_t seq_number; 226 size_t len, total_len, padlength, datalen; 227 228 if (IS_DCE_STYLE(ctx)) { 229 padlength = 0; 230 datalen = input_message_buffer->length; 231 len = 22 + 8; 232 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 233 total_len += datalen; 234 datalen += 8; 235 } else { 236 padlength = 8 - (input_message_buffer->length % 8); 237 datalen = input_message_buffer->length + padlength + 8; 238 len = datalen + 22; 239 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 240 } 241 242 output_message_buffer->length = total_len; 243 output_message_buffer->value = malloc (total_len); 244 if (output_message_buffer->value == NULL) { 245 output_message_buffer->length = 0; 246 *minor_status = ENOMEM; 247 return GSS_S_FAILURE; 248 } 249 250 p = _gsskrb5_make_header(output_message_buffer->value, 251 len, 252 "\x02\x01", /* TOK_ID */ 253 GSS_KRB5_MECHANISM); 254 255 /* SGN_ALG */ 256 memcpy (p, "\x00\x00", 2); 257 p += 2; 258 /* SEAL_ALG */ 259 if(conf_req_flag) 260 memcpy (p, "\x00\x00", 2); 261 else 262 memcpy (p, "\xff\xff", 2); 263 p += 2; 264 /* Filler */ 265 memcpy (p, "\xff\xff", 2); 266 p += 2; 267 268 /* fill in later */ 269 memset (p, 0, 16); 270 p += 16; 271 272 /* confounder + data + pad */ 273 krb5_generate_random_block(p, 8); 274 memcpy (p + 8, input_message_buffer->value, 275 input_message_buffer->length); 276 memset (p + 8 + input_message_buffer->length, (int)padlength, padlength); 277 278 /* checksum */ 279 md5 = CCDigestCreate(kCCDigestMD5); 280 CCDigestUpdate(md5, p - 24, 8); 281 CCDigestUpdate(md5, p, datalen); 282 CCDigestFinal(md5, hash); 283 CCDigestDestroy(md5); 284 285 memset (&zero, 0, sizeof(zero)); 286 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 287#ifndef __APPLE_PRIVATE__ 288 DES_set_key_unchecked (&deskey, &schedule); 289 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), 290 &schedule, &zero); 291#else 292 CCDesCBCCksum(hash, hash, sizeof(hash), deskey, sizeof(deskey), &zero); 293#endif 294 memcpy (p - 8, hash, 8); 295 296 /* sequence number */ 297 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 298 krb5_auth_con_getlocalseqnumber (context, 299 ctx->auth_context, 300 &seq_number); 301 302 p -= 16; 303 p[0] = (seq_number >> 0) & 0xFF; 304 p[1] = (seq_number >> 8) & 0xFF; 305 p[2] = (seq_number >> 16) & 0xFF; 306 p[3] = (seq_number >> 24) & 0xFF; 307 memset (p + 4, 308 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 309 4); 310 311 EVP_CIPHER_CTX_init(&des_ctx); 312 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); 313 EVP_Cipher(&des_ctx, p, p, 8); 314 EVP_CIPHER_CTX_cleanup(&des_ctx); 315 316 krb5_auth_con_setlocalseqnumber (context, 317 ctx->auth_context, 318 ++seq_number); 319 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 320 321 /* encrypt the data */ 322 p += 16; 323 324 if(conf_req_flag) { 325 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 326 327 for (i = 0; i < sizeof(deskey); ++i) 328 deskey[i] ^= 0xf0; 329 330 EVP_CIPHER_CTX_init(&des_ctx); 331 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1); 332 EVP_Cipher(&des_ctx, p, p, datalen); 333 EVP_CIPHER_CTX_cleanup(&des_ctx); 334 } 335 memset (deskey, 0, sizeof(deskey)); 336 memset (&schedule, 0, sizeof(schedule)); 337 338 if(conf_state != NULL) 339 *conf_state = conf_req_flag; 340 *minor_status = 0; 341 return GSS_S_COMPLETE; 342} 343 344#endif 345 346#ifdef HEIM_KRB5_DES3 347 348static OM_uint32 349wrap_des3 350 (OM_uint32 * minor_status, 351 const gsskrb5_ctx ctx, 352 krb5_context context, 353 int conf_req_flag, 354 gss_qop_t qop_req, 355 const gss_buffer_t input_message_buffer, 356 int * conf_state, 357 gss_buffer_t output_message_buffer, 358 krb5_keyblock *key 359 ) 360{ 361 u_char *p; 362 u_char seq[8]; 363 int32_t seq_number; 364 size_t len, total_len, padlength, datalen; 365 uint32_t ret; 366 krb5_crypto crypto; 367 Checksum cksum; 368 krb5_data encdata; 369 370 if (IS_DCE_STYLE(ctx)) { 371 padlength = 0; 372 datalen = input_message_buffer->length; 373 len = 34 + 8; 374 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 375 total_len += datalen; 376 datalen += 8; 377 } else { 378 padlength = 8 - (input_message_buffer->length % 8); 379 datalen = input_message_buffer->length + padlength + 8; 380 len = datalen + 34; 381 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 382 } 383 384 output_message_buffer->length = total_len; 385 output_message_buffer->value = malloc (total_len); 386 if (output_message_buffer->value == NULL) { 387 output_message_buffer->length = 0; 388 *minor_status = ENOMEM; 389 return GSS_S_FAILURE; 390 } 391 392 p = _gsskrb5_make_header(output_message_buffer->value, 393 len, 394 "\x02\x01", /* TOK_ID */ 395 GSS_KRB5_MECHANISM); 396 397 /* SGN_ALG */ 398 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ 399 p += 2; 400 /* SEAL_ALG */ 401 if(conf_req_flag) 402 memcpy (p, "\x02\x00", 2); /* DES3-KD */ 403 else 404 memcpy (p, "\xff\xff", 2); 405 p += 2; 406 /* Filler */ 407 memcpy (p, "\xff\xff", 2); 408 p += 2; 409 410 /* calculate checksum (the above + confounder + data + pad) */ 411 412 memcpy (p + 20, p - 8, 8); 413 krb5_generate_random_block(p + 28, 8); 414 memcpy (p + 28 + 8, input_message_buffer->value, 415 input_message_buffer->length); 416 memset (p + 28 + 8 + input_message_buffer->length, (int)padlength, padlength); 417 418 ret = krb5_crypto_init(context, key, 0, &crypto); 419 if (ret) { 420 free (output_message_buffer->value); 421 output_message_buffer->length = 0; 422 output_message_buffer->value = NULL; 423 *minor_status = ret; 424 return GSS_S_FAILURE; 425 } 426 427 ret = krb5_create_checksum (context, 428 crypto, 429 KRB5_KU_USAGE_SIGN, 430 0, 431 p + 20, 432 datalen + 8, 433 &cksum); 434 krb5_crypto_destroy (context, crypto); 435 if (ret) { 436 free (output_message_buffer->value); 437 output_message_buffer->length = 0; 438 output_message_buffer->value = NULL; 439 *minor_status = ret; 440 return GSS_S_FAILURE; 441 } 442 443 /* zero out SND_SEQ + SGN_CKSUM in case */ 444 memset (p, 0, 28); 445 446 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); 447 free_Checksum (&cksum); 448 449 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 450 /* sequence number */ 451 krb5_auth_con_getlocalseqnumber (context, 452 ctx->auth_context, 453 &seq_number); 454 455 seq[0] = (seq_number >> 0) & 0xFF; 456 seq[1] = (seq_number >> 8) & 0xFF; 457 seq[2] = (seq_number >> 16) & 0xFF; 458 seq[3] = (seq_number >> 24) & 0xFF; 459 memset (seq + 4, 460 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 461 4); 462 463 464 ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, 465 &crypto); 466 if (ret) { 467 free (output_message_buffer->value); 468 output_message_buffer->length = 0; 469 output_message_buffer->value = NULL; 470 *minor_status = ret; 471 return GSS_S_FAILURE; 472 } 473 474 { 475 unsigned char ivec[8]; 476 477 memcpy (&ivec, p + 8, 8); 478 ret = krb5_encrypt_ivec (context, 479 crypto, 480 KRB5_KU_USAGE_SEQ, 481 seq, 8, &encdata, 482 ivec); 483 } 484 krb5_crypto_destroy (context, crypto); 485 if (ret) { 486 free (output_message_buffer->value); 487 output_message_buffer->length = 0; 488 output_message_buffer->value = NULL; 489 *minor_status = ret; 490 return GSS_S_FAILURE; 491 } 492 493 assert (encdata.length == 8); 494 495 memcpy (p, encdata.data, encdata.length); 496 krb5_data_free (&encdata); 497 498 krb5_auth_con_setlocalseqnumber (context, 499 ctx->auth_context, 500 ++seq_number); 501 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 502 503 /* encrypt the data */ 504 p += 28; 505 506 if(conf_req_flag) { 507 krb5_data tmp; 508 509 ret = krb5_crypto_init(context, key, 510 ETYPE_DES3_CBC_NONE, &crypto); 511 if (ret) { 512 free (output_message_buffer->value); 513 output_message_buffer->length = 0; 514 output_message_buffer->value = NULL; 515 *minor_status = ret; 516 return GSS_S_FAILURE; 517 } 518 ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, 519 p, datalen, &tmp); 520 krb5_crypto_destroy(context, crypto); 521 if (ret) { 522 free (output_message_buffer->value); 523 output_message_buffer->length = 0; 524 output_message_buffer->value = NULL; 525 *minor_status = ret; 526 return GSS_S_FAILURE; 527 } 528 assert (tmp.length == datalen); 529 530 memcpy (p, tmp.data, datalen); 531 krb5_data_free(&tmp); 532 } 533 if(conf_state != NULL) 534 *conf_state = conf_req_flag; 535 *minor_status = 0; 536 return GSS_S_COMPLETE; 537} 538#endif 539 540OM_uint32 GSSAPI_CALLCONV 541_gsskrb5_wrap 542 (OM_uint32 * minor_status, 543 const gss_ctx_id_t context_handle, 544 int conf_req_flag, 545 gss_qop_t qop_req, 546 const gss_buffer_t input_message_buffer, 547 int * conf_state, 548 gss_buffer_t output_message_buffer 549 ) 550{ 551 krb5_context context; 552 krb5_keyblock *key; 553 OM_uint32 ret; 554 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; 555 556 output_message_buffer->value = NULL; 557 output_message_buffer->length = 0; 558 559 GSSAPI_KRB5_INIT (&context); 560 561 if (ctx->more_flags & IS_CFX) 562 return _gssapi_wrap_cfx (minor_status, &ctx->gk5c, 563 context, conf_req_flag, 564 input_message_buffer, conf_state, 565 output_message_buffer); 566 567 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 568 ret = _gsskrb5i_get_token_key(ctx, context, &key); 569 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 570 if (ret) { 571 *minor_status = ret; 572 return GSS_S_FAILURE; 573 } 574 575 switch (key->keytype) { 576#ifdef HEIM_KRB5_DES 577 case KRB5_ENCTYPE_DES_CBC_CRC : 578 case KRB5_ENCTYPE_DES_CBC_MD4 : 579 case KRB5_ENCTYPE_DES_CBC_MD5 : 580 ret = wrap_des (minor_status, ctx, context, conf_req_flag, 581 qop_req, input_message_buffer, conf_state, 582 output_message_buffer, key); 583 break; 584#endif 585 586#ifdef HEIM_KRB5_DES3 587 case KRB5_ENCTYPE_DES3_CBC_MD5 : 588 case KRB5_ENCTYPE_DES3_CBC_SHA1 : 589 ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, 590 qop_req, input_message_buffer, conf_state, 591 output_message_buffer, key); 592 break; 593#endif 594 595#ifdef HEIM_KRB5_ARCFOUR 596 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: 597 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: 598 ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, 599 qop_req, input_message_buffer, conf_state, 600 output_message_buffer, key); 601 break; 602#endif 603 default : 604 ret = GSS_S_FAILURE; 605 break; 606 } 607 krb5_free_keyblock (context, key); 608 return ret; 609} 610