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