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