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