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