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