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