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 40 krb5_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 68 krb5_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 92 OM_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->more_flags & 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 static OM_uint32 114 sub_wrap_size ( 115 OM_uint32 req_output_size, 116 OM_uint32 * max_input_size, 117 int blocksize, 118 int extrasize 119 ) 120 { 121 size_t len, total_len; 122 123 len = 8 + req_output_size + blocksize + extrasize; 124 125 _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); 126 127 total_len -= req_output_size; /* token length */ 128 if (total_len < req_output_size) { 129 *max_input_size = (req_output_size - total_len); 130 (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); 131 } else { 132 *max_input_size = 0; 133 } 134 return GSS_S_COMPLETE; 135 } 136 137 OM_uint32 GSSAPI_CALLCONV 138 _gsskrb5_wrap_size_limit ( 139 OM_uint32 * minor_status, 140 const gss_ctx_id_t context_handle, 141 int conf_req_flag, 142 gss_qop_t qop_req, 143 OM_uint32 req_output_size, 144 OM_uint32 * max_input_size 145 ) 146 { 147 krb5_context context; 148 krb5_keyblock *key; 149 OM_uint32 ret; 150 krb5_keytype keytype; 151 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; 152 153 GSSAPI_KRB5_INIT (&context); 154 155 if (ctx->more_flags & IS_CFX) 156 return _gssapi_wrap_size_cfx(minor_status, ctx, context, 157 conf_req_flag, qop_req, 158 req_output_size, max_input_size); 159 160 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 161 ret = _gsskrb5i_get_token_key(ctx, context, &key); 162 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 163 if (ret) { 164 *minor_status = ret; 165 return GSS_S_FAILURE; 166 } 167 krb5_enctype_to_keytype (context, key->keytype, &keytype); 168 169 switch (keytype) { 170 case KEYTYPE_DES : 171 #ifdef HEIM_WEAK_CRYPTO 172 ret = sub_wrap_size(req_output_size, max_input_size, 8, 22); 173 #else 174 ret = GSS_S_FAILURE; 175 #endif 176 break; 177 case ENCTYPE_ARCFOUR_HMAC_MD5: 178 case ENCTYPE_ARCFOUR_HMAC_MD5_56: 179 ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context, 180 conf_req_flag, qop_req, 181 req_output_size, max_input_size, key); 182 break; 183 case KEYTYPE_DES3 : 184 ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); 185 break; 186 default : 187 abort(); 188 break; 189 } 190 krb5_free_keyblock (context, key); 191 *minor_status = 0; 192 return ret; 193 } 194 195 #ifdef HEIM_WEAK_CRYPTO 196 197 static OM_uint32 198 wrap_des 199 (OM_uint32 * minor_status, 200 const gsskrb5_ctx ctx, 201 krb5_context context, 202 int conf_req_flag, 203 gss_qop_t qop_req, 204 const gss_buffer_t input_message_buffer, 205 int * conf_state, 206 gss_buffer_t output_message_buffer, 207 krb5_keyblock *key 208 ) 209 { 210 u_char *p; 211 EVP_MD_CTX *md5; 212 u_char hash[16]; 213 DES_key_schedule schedule; 214 EVP_CIPHER_CTX *des_ctx; 215 DES_cblock deskey; 216 DES_cblock zero; 217 size_t i; 218 int32_t seq_number; 219 size_t len, total_len, padlength, datalen; 220 221 if (IS_DCE_STYLE(ctx)) { 222 padlength = 0; 223 datalen = input_message_buffer->length; 224 len = 22 + 8; 225 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 226 total_len += datalen; 227 datalen += 8; 228 } else { 229 padlength = 8 - (input_message_buffer->length % 8); 230 datalen = input_message_buffer->length + padlength + 8; 231 len = datalen + 22; 232 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 233 } 234 235 output_message_buffer->length = total_len; 236 output_message_buffer->value = malloc (total_len); 237 if (output_message_buffer->value == NULL) { 238 output_message_buffer->length = 0; 239 *minor_status = ENOMEM; 240 return GSS_S_FAILURE; 241 } 242 243 p = _gsskrb5_make_header(output_message_buffer->value, 244 len, 245 "\x02\x01", /* TOK_ID */ 246 GSS_KRB5_MECHANISM); 247 248 /* SGN_ALG */ 249 memcpy (p, "\x00\x00", 2); 250 p += 2; 251 /* SEAL_ALG */ 252 if(conf_req_flag) 253 memcpy (p, "\x00\x00", 2); 254 else 255 memcpy (p, "\xff\xff", 2); 256 p += 2; 257 /* Filler */ 258 memcpy (p, "\xff\xff", 2); 259 p += 2; 260 261 /* fill in later */ 262 memset (p, 0, 16); 263 p += 16; 264 265 /* confounder + data + pad */ 266 krb5_generate_random_block(p, 8); 267 memcpy (p + 8, input_message_buffer->value, 268 input_message_buffer->length); 269 memset (p + 8 + input_message_buffer->length, padlength, padlength); 270 271 /* checksum */ 272 md5 = EVP_MD_CTX_create(); 273 EVP_DigestInit_ex(md5, EVP_md5(), NULL); 274 EVP_DigestUpdate(md5, p - 24, 8); 275 EVP_DigestUpdate(md5, p, datalen); 276 EVP_DigestFinal_ex(md5, hash, NULL); 277 EVP_MD_CTX_destroy(md5); 278 279 memset (&zero, 0, sizeof(zero)); 280 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 281 DES_set_key_unchecked (&deskey, &schedule); 282 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), 283 &schedule, &zero); 284 memcpy (p - 8, hash, 8); 285 286 des_ctx = EVP_CIPHER_CTX_new(); 287 if (des_ctx == NULL) { 288 memset (deskey, 0, sizeof(deskey)); 289 memset (&schedule, 0, sizeof(schedule)); 290 free(output_message_buffer->value); 291 output_message_buffer->value = NULL; 292 output_message_buffer->length = 0; 293 *minor_status = ENOMEM; 294 return GSS_S_FAILURE; 295 } 296 297 /* sequence number */ 298 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 299 krb5_auth_con_getlocalseqnumber (context, 300 ctx->auth_context, 301 &seq_number); 302 303 p -= 16; 304 p[0] = (seq_number >> 0) & 0xFF; 305 p[1] = (seq_number >> 8) & 0xFF; 306 p[2] = (seq_number >> 16) & 0xFF; 307 p[3] = (seq_number >> 24) & 0xFF; 308 memset (p + 4, 309 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 310 4); 311 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 315 krb5_auth_con_setlocalseqnumber (context, 316 ctx->auth_context, 317 ++seq_number); 318 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 319 320 /* encrypt the data */ 321 p += 16; 322 323 if(conf_req_flag) { 324 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 325 326 for (i = 0; i < sizeof(deskey); ++i) 327 deskey[i] ^= 0xf0; 328 329 EVP_CIPHER_CTX_reset(des_ctx); 330 EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1); 331 EVP_Cipher(des_ctx, p, p, datalen); 332 } 333 EVP_CIPHER_CTX_free(des_ctx); 334 memset (deskey, 0, sizeof(deskey)); 335 memset (&schedule, 0, sizeof(schedule)); 336 337 if(conf_state != NULL) 338 *conf_state = conf_req_flag; 339 *minor_status = 0; 340 return GSS_S_COMPLETE; 341 } 342 343 #endif 344 345 static OM_uint32 346 wrap_des3 347 (OM_uint32 * minor_status, 348 const gsskrb5_ctx ctx, 349 krb5_context context, 350 int conf_req_flag, 351 gss_qop_t qop_req, 352 const gss_buffer_t input_message_buffer, 353 int * conf_state, 354 gss_buffer_t output_message_buffer, 355 krb5_keyblock *key 356 ) 357 { 358 u_char *p; 359 u_char seq[8]; 360 int32_t seq_number; 361 size_t len, total_len, padlength, datalen; 362 uint32_t ret; 363 krb5_crypto crypto; 364 Checksum cksum; 365 krb5_data encdata; 366 367 if (IS_DCE_STYLE(ctx)) { 368 padlength = 0; 369 datalen = input_message_buffer->length; 370 len = 34 + 8; 371 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 372 total_len += datalen; 373 datalen += 8; 374 } else { 375 padlength = 8 - (input_message_buffer->length % 8); 376 datalen = input_message_buffer->length + padlength + 8; 377 len = datalen + 34; 378 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 379 } 380 381 output_message_buffer->length = total_len; 382 output_message_buffer->value = malloc (total_len); 383 if (output_message_buffer->value == NULL) { 384 output_message_buffer->length = 0; 385 *minor_status = ENOMEM; 386 return GSS_S_FAILURE; 387 } 388 389 p = _gsskrb5_make_header(output_message_buffer->value, 390 len, 391 "\x02\x01", /* TOK_ID */ 392 GSS_KRB5_MECHANISM); 393 394 /* SGN_ALG */ 395 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ 396 p += 2; 397 /* SEAL_ALG */ 398 if(conf_req_flag) 399 memcpy (p, "\x02\x00", 2); /* DES3-KD */ 400 else 401 memcpy (p, "\xff\xff", 2); 402 p += 2; 403 /* Filler */ 404 memcpy (p, "\xff\xff", 2); 405 p += 2; 406 407 /* calculate checksum (the above + confounder + data + pad) */ 408 409 memcpy (p + 20, p - 8, 8); 410 krb5_generate_random_block(p + 28, 8); 411 memcpy (p + 28 + 8, input_message_buffer->value, 412 input_message_buffer->length); 413 memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); 414 415 ret = krb5_crypto_init(context, key, 0, &crypto); 416 if (ret) { 417 free (output_message_buffer->value); 418 output_message_buffer->length = 0; 419 output_message_buffer->value = NULL; 420 *minor_status = ret; 421 return GSS_S_FAILURE; 422 } 423 424 ret = krb5_create_checksum (context, 425 crypto, 426 KRB5_KU_USAGE_SIGN, 427 0, 428 p + 20, 429 datalen + 8, 430 &cksum); 431 krb5_crypto_destroy (context, crypto); 432 if (ret) { 433 free (output_message_buffer->value); 434 output_message_buffer->length = 0; 435 output_message_buffer->value = NULL; 436 *minor_status = ret; 437 return GSS_S_FAILURE; 438 } 439 440 /* zero out SND_SEQ + SGN_CKSUM in case */ 441 memset (p, 0, 28); 442 443 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); 444 free_Checksum (&cksum); 445 446 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 447 /* sequence number */ 448 krb5_auth_con_getlocalseqnumber (context, 449 ctx->auth_context, 450 &seq_number); 451 452 seq[0] = (seq_number >> 0) & 0xFF; 453 seq[1] = (seq_number >> 8) & 0xFF; 454 seq[2] = (seq_number >> 16) & 0xFF; 455 seq[3] = (seq_number >> 24) & 0xFF; 456 memset (seq + 4, 457 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 458 4); 459 460 461 ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, 462 &crypto); 463 if (ret) { 464 free (output_message_buffer->value); 465 output_message_buffer->length = 0; 466 output_message_buffer->value = NULL; 467 *minor_status = ret; 468 return GSS_S_FAILURE; 469 } 470 471 { 472 DES_cblock ivec; 473 474 memcpy (&ivec, p + 8, 8); 475 ret = krb5_encrypt_ivec (context, 476 crypto, 477 KRB5_KU_USAGE_SEQ, 478 seq, 8, &encdata, 479 &ivec); 480 } 481 krb5_crypto_destroy (context, crypto); 482 if (ret) { 483 free (output_message_buffer->value); 484 output_message_buffer->length = 0; 485 output_message_buffer->value = NULL; 486 *minor_status = ret; 487 return GSS_S_FAILURE; 488 } 489 490 assert (encdata.length == 8); 491 492 memcpy (p, encdata.data, encdata.length); 493 krb5_data_free (&encdata); 494 495 krb5_auth_con_setlocalseqnumber (context, 496 ctx->auth_context, 497 ++seq_number); 498 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 499 500 /* encrypt the data */ 501 p += 28; 502 503 if(conf_req_flag) { 504 krb5_data tmp; 505 506 ret = krb5_crypto_init(context, key, 507 ETYPE_DES3_CBC_NONE, &crypto); 508 if (ret) { 509 free (output_message_buffer->value); 510 output_message_buffer->length = 0; 511 output_message_buffer->value = NULL; 512 *minor_status = ret; 513 return GSS_S_FAILURE; 514 } 515 ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, 516 p, datalen, &tmp); 517 krb5_crypto_destroy(context, crypto); 518 if (ret) { 519 free (output_message_buffer->value); 520 output_message_buffer->length = 0; 521 output_message_buffer->value = NULL; 522 *minor_status = ret; 523 return GSS_S_FAILURE; 524 } 525 assert (tmp.length == datalen); 526 527 memcpy (p, tmp.data, datalen); 528 krb5_data_free(&tmp); 529 } 530 if(conf_state != NULL) 531 *conf_state = conf_req_flag; 532 *minor_status = 0; 533 return GSS_S_COMPLETE; 534 } 535 536 OM_uint32 GSSAPI_CALLCONV 537 _gsskrb5_wrap 538 (OM_uint32 * minor_status, 539 const gss_ctx_id_t context_handle, 540 int conf_req_flag, 541 gss_qop_t qop_req, 542 const gss_buffer_t input_message_buffer, 543 int * conf_state, 544 gss_buffer_t output_message_buffer 545 ) 546 { 547 krb5_context context; 548 krb5_keyblock *key; 549 OM_uint32 ret; 550 krb5_keytype keytype; 551 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; 552 553 output_message_buffer->value = NULL; 554 output_message_buffer->length = 0; 555 556 GSSAPI_KRB5_INIT (&context); 557 558 if (ctx->more_flags & IS_CFX) 559 return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, 560 input_message_buffer, conf_state, 561 output_message_buffer); 562 563 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 564 ret = _gsskrb5i_get_token_key(ctx, context, &key); 565 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 566 if (ret) { 567 *minor_status = ret; 568 return GSS_S_FAILURE; 569 } 570 krb5_enctype_to_keytype (context, key->keytype, &keytype); 571 572 switch (keytype) { 573 case KEYTYPE_DES : 574 #ifdef HEIM_WEAK_CRYPTO 575 ret = wrap_des (minor_status, ctx, context, conf_req_flag, 576 qop_req, input_message_buffer, conf_state, 577 output_message_buffer, key); 578 #else 579 ret = GSS_S_FAILURE; 580 #endif 581 break; 582 case KEYTYPE_DES3 : 583 ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, 584 qop_req, input_message_buffer, conf_state, 585 output_message_buffer, key); 586 break; 587 case KEYTYPE_ARCFOUR: 588 case KEYTYPE_ARCFOUR_56: 589 ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, 590 qop_req, input_message_buffer, conf_state, 591 output_message_buffer, key); 592 break; 593 default : 594 abort(); 595 break; 596 } 597 krb5_free_keyblock (context, key); 598 return ret; 599 } 600