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 /* sequence number */ 287 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 288 krb5_auth_con_getlocalseqnumber (context, 289 ctx->auth_context, 290 &seq_number); 291 292 p -= 16; 293 p[0] = (seq_number >> 0) & 0xFF; 294 p[1] = (seq_number >> 8) & 0xFF; 295 p[2] = (seq_number >> 16) & 0xFF; 296 p[3] = (seq_number >> 24) & 0xFF; 297 memset (p + 4, 298 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 299 4); 300 301 EVP_CIPHER_CTX_init(&des_ctx); 302 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); 303 EVP_Cipher(&des_ctx, p, p, 8); 304 EVP_CIPHER_CTX_cleanup(&des_ctx); 305 306 krb5_auth_con_setlocalseqnumber (context, 307 ctx->auth_context, 308 ++seq_number); 309 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 310 311 /* encrypt the data */ 312 p += 16; 313 314 if(conf_req_flag) { 315 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 316 317 for (i = 0; i < sizeof(deskey); ++i) 318 deskey[i] ^= 0xf0; 319 320 EVP_CIPHER_CTX_init(&des_ctx); 321 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1); 322 EVP_Cipher(&des_ctx, p, p, datalen); 323 EVP_CIPHER_CTX_cleanup(&des_ctx); 324 } 325 memset (deskey, 0, sizeof(deskey)); 326 memset (&schedule, 0, sizeof(schedule)); 327 328 if(conf_state != NULL) 329 *conf_state = conf_req_flag; 330 *minor_status = 0; 331 return GSS_S_COMPLETE; 332 } 333 334 #endif 335 336 static OM_uint32 337 wrap_des3 338 (OM_uint32 * minor_status, 339 const gsskrb5_ctx ctx, 340 krb5_context context, 341 int conf_req_flag, 342 gss_qop_t qop_req, 343 const gss_buffer_t input_message_buffer, 344 int * conf_state, 345 gss_buffer_t output_message_buffer, 346 krb5_keyblock *key 347 ) 348 { 349 u_char *p; 350 u_char seq[8]; 351 int32_t seq_number; 352 size_t len, total_len, padlength, datalen; 353 uint32_t ret; 354 krb5_crypto crypto; 355 Checksum cksum; 356 krb5_data encdata; 357 358 if (IS_DCE_STYLE(ctx)) { 359 padlength = 0; 360 datalen = input_message_buffer->length; 361 len = 34 + 8; 362 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 363 total_len += datalen; 364 datalen += 8; 365 } else { 366 padlength = 8 - (input_message_buffer->length % 8); 367 datalen = input_message_buffer->length + padlength + 8; 368 len = datalen + 34; 369 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); 370 } 371 372 output_message_buffer->length = total_len; 373 output_message_buffer->value = malloc (total_len); 374 if (output_message_buffer->value == NULL) { 375 output_message_buffer->length = 0; 376 *minor_status = ENOMEM; 377 return GSS_S_FAILURE; 378 } 379 380 p = _gsskrb5_make_header(output_message_buffer->value, 381 len, 382 "\x02\x01", /* TOK_ID */ 383 GSS_KRB5_MECHANISM); 384 385 /* SGN_ALG */ 386 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ 387 p += 2; 388 /* SEAL_ALG */ 389 if(conf_req_flag) 390 memcpy (p, "\x02\x00", 2); /* DES3-KD */ 391 else 392 memcpy (p, "\xff\xff", 2); 393 p += 2; 394 /* Filler */ 395 memcpy (p, "\xff\xff", 2); 396 p += 2; 397 398 /* calculate checksum (the above + confounder + data + pad) */ 399 400 memcpy (p + 20, p - 8, 8); 401 krb5_generate_random_block(p + 28, 8); 402 memcpy (p + 28 + 8, input_message_buffer->value, 403 input_message_buffer->length); 404 memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); 405 406 ret = krb5_crypto_init(context, key, 0, &crypto); 407 if (ret) { 408 free (output_message_buffer->value); 409 output_message_buffer->length = 0; 410 output_message_buffer->value = NULL; 411 *minor_status = ret; 412 return GSS_S_FAILURE; 413 } 414 415 ret = krb5_create_checksum (context, 416 crypto, 417 KRB5_KU_USAGE_SIGN, 418 0, 419 p + 20, 420 datalen + 8, 421 &cksum); 422 krb5_crypto_destroy (context, crypto); 423 if (ret) { 424 free (output_message_buffer->value); 425 output_message_buffer->length = 0; 426 output_message_buffer->value = NULL; 427 *minor_status = ret; 428 return GSS_S_FAILURE; 429 } 430 431 /* zero out SND_SEQ + SGN_CKSUM in case */ 432 memset (p, 0, 28); 433 434 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); 435 free_Checksum (&cksum); 436 437 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 438 /* sequence number */ 439 krb5_auth_con_getlocalseqnumber (context, 440 ctx->auth_context, 441 &seq_number); 442 443 seq[0] = (seq_number >> 0) & 0xFF; 444 seq[1] = (seq_number >> 8) & 0xFF; 445 seq[2] = (seq_number >> 16) & 0xFF; 446 seq[3] = (seq_number >> 24) & 0xFF; 447 memset (seq + 4, 448 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 449 4); 450 451 452 ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, 453 &crypto); 454 if (ret) { 455 free (output_message_buffer->value); 456 output_message_buffer->length = 0; 457 output_message_buffer->value = NULL; 458 *minor_status = ret; 459 return GSS_S_FAILURE; 460 } 461 462 { 463 DES_cblock ivec; 464 465 memcpy (&ivec, p + 8, 8); 466 ret = krb5_encrypt_ivec (context, 467 crypto, 468 KRB5_KU_USAGE_SEQ, 469 seq, 8, &encdata, 470 &ivec); 471 } 472 krb5_crypto_destroy (context, crypto); 473 if (ret) { 474 free (output_message_buffer->value); 475 output_message_buffer->length = 0; 476 output_message_buffer->value = NULL; 477 *minor_status = ret; 478 return GSS_S_FAILURE; 479 } 480 481 assert (encdata.length == 8); 482 483 memcpy (p, encdata.data, encdata.length); 484 krb5_data_free (&encdata); 485 486 krb5_auth_con_setlocalseqnumber (context, 487 ctx->auth_context, 488 ++seq_number); 489 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 490 491 /* encrypt the data */ 492 p += 28; 493 494 if(conf_req_flag) { 495 krb5_data tmp; 496 497 ret = krb5_crypto_init(context, key, 498 ETYPE_DES3_CBC_NONE, &crypto); 499 if (ret) { 500 free (output_message_buffer->value); 501 output_message_buffer->length = 0; 502 output_message_buffer->value = NULL; 503 *minor_status = ret; 504 return GSS_S_FAILURE; 505 } 506 ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, 507 p, datalen, &tmp); 508 krb5_crypto_destroy(context, crypto); 509 if (ret) { 510 free (output_message_buffer->value); 511 output_message_buffer->length = 0; 512 output_message_buffer->value = NULL; 513 *minor_status = ret; 514 return GSS_S_FAILURE; 515 } 516 assert (tmp.length == datalen); 517 518 memcpy (p, tmp.data, datalen); 519 krb5_data_free(&tmp); 520 } 521 if(conf_state != NULL) 522 *conf_state = conf_req_flag; 523 *minor_status = 0; 524 return GSS_S_COMPLETE; 525 } 526 527 OM_uint32 GSSAPI_CALLCONV 528 _gsskrb5_wrap 529 (OM_uint32 * minor_status, 530 const gss_ctx_id_t context_handle, 531 int conf_req_flag, 532 gss_qop_t qop_req, 533 const gss_buffer_t input_message_buffer, 534 int * conf_state, 535 gss_buffer_t output_message_buffer 536 ) 537 { 538 krb5_context context; 539 krb5_keyblock *key; 540 OM_uint32 ret; 541 krb5_keytype keytype; 542 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; 543 544 output_message_buffer->value = NULL; 545 output_message_buffer->length = 0; 546 547 GSSAPI_KRB5_INIT (&context); 548 549 if (ctx->more_flags & IS_CFX) 550 return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, 551 input_message_buffer, conf_state, 552 output_message_buffer); 553 554 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 555 ret = _gsskrb5i_get_token_key(ctx, context, &key); 556 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 557 if (ret) { 558 *minor_status = ret; 559 return GSS_S_FAILURE; 560 } 561 krb5_enctype_to_keytype (context, key->keytype, &keytype); 562 563 switch (keytype) { 564 case KEYTYPE_DES : 565 #ifdef HEIM_WEAK_CRYPTO 566 ret = wrap_des (minor_status, ctx, context, conf_req_flag, 567 qop_req, input_message_buffer, conf_state, 568 output_message_buffer, key); 569 #else 570 ret = GSS_S_FAILURE; 571 #endif 572 break; 573 case KEYTYPE_DES3 : 574 ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, 575 qop_req, input_message_buffer, conf_state, 576 output_message_buffer, key); 577 break; 578 case KEYTYPE_ARCFOUR: 579 case KEYTYPE_ARCFOUR_56: 580 ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, 581 qop_req, input_message_buffer, conf_state, 582 output_message_buffer, key); 583 break; 584 default : 585 abort(); 586 break; 587 } 588 krb5_free_keyblock (context, key); 589 return ret; 590 } 591