1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/gssapi/krb5/k5sealv3.c 10 * 11 * Copyright 2003,2004 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * 34 */ 35 /* draft-ietf-krb-wg-gssapi-cfx-05 */ 36 37 #ifndef _KERNEL 38 #include <assert.h> 39 #include <stdarg.h> 40 41 #define ASSERT assert 42 #endif 43 44 #include <k5-int.h> 45 #include <gssapiP_krb5.h> 46 #include <sys/int_limits.h> 47 #include <k5-platform.h> 48 49 static int 50 rotate_left (void *ptr, size_t bufsiz, size_t rc) 51 { 52 /* Optimize for receiving. After some debugging is done, the MIT 53 implementation won't do any rotates on sending, and while 54 debugging, they'll be randomly chosen. 55 56 Return 1 for success, 0 for failure (ENOMEM). */ 57 void *tbuf; 58 59 if (bufsiz == 0) 60 return 1; 61 rc = rc % bufsiz; 62 if (rc == 0) 63 return 1; 64 65 tbuf = MALLOC(rc); 66 if (tbuf == 0) 67 return 0; 68 (void) memcpy(tbuf, ptr, rc); 69 (void) memmove(ptr, (char *)ptr + rc, bufsiz - rc); 70 (void) memcpy((char *)ptr + bufsiz - rc, tbuf, rc); 71 FREE(tbuf, rc); 72 return 1; 73 } 74 75 static const gss_buffer_desc empty_message = { 0, 0 }; 76 77 #define FLAG_SENDER_IS_ACCEPTOR 0x01 78 #define FLAG_WRAP_CONFIDENTIAL 0x02 79 #define FLAG_ACCEPTOR_SUBKEY 0x04 80 81 krb5_error_code 82 gss_krb5int_make_seal_token_v3 (krb5_context context, 83 krb5_gss_ctx_id_rec *ctx, 84 const gss_buffer_desc * message, 85 gss_buffer_t token, 86 int conf_req_flag, int toktype) 87 { 88 size_t bufsize = 16; 89 unsigned char *outbuf = 0; 90 krb5_error_code err; 91 int key_usage; 92 unsigned char acceptor_flag; 93 const gss_buffer_desc *message2 = message; 94 size_t ec; 95 unsigned short tok_id; 96 krb5_checksum sum; 97 krb5_keyblock *key; 98 99 ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0); 100 ASSERT(ctx->big_endian == 0); 101 102 acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR; 103 key_usage = (toktype == KG_TOK_WRAP_MSG 104 ? (ctx->initiate 105 ? KG_USAGE_INITIATOR_SEAL 106 : KG_USAGE_ACCEPTOR_SEAL) 107 : (ctx->initiate 108 ? KG_USAGE_INITIATOR_SIGN 109 : KG_USAGE_ACCEPTOR_SIGN)); 110 if (ctx->have_acceptor_subkey) { 111 key = ctx->acceptor_subkey; 112 } else { 113 key = ctx->enc; 114 } 115 116 #ifdef _KERNEL 117 context->kef_cipher_mt = get_cipher_mech_type(context, key); 118 context->kef_hash_mt = get_hash_mech_type(context, key); 119 120 if ((err = init_key_kef(context->kef_cipher_mt, key))) { 121 return (GSS_S_FAILURE); 122 } 123 124 #endif /* _KERNEL */ 125 126 #ifdef CFX_EXERCISE 127 { 128 static int initialized = 0; 129 if (!initialized) { 130 srand(time(0)); 131 initialized = 1; 132 } 133 } 134 #endif 135 136 if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) { 137 krb5_data plain; 138 krb5_enc_data cipher; 139 size_t ec_max; 140 size_t tlen; 141 142 /* 300: Adds some slop. */ 143 if (SIZE_MAX - 300 < message->length) 144 return ENOMEM; 145 ec_max = SIZE_MAX - message->length - 300; 146 if (ec_max > 0xffff) 147 ec_max = 0xffff; 148 /* 149 * EC should really be a multiple (1) of the number of octets that 150 * the cryptosystem would pad by if we didn't have the filler. 151 * 152 * For AES-CTS this will always be 0 and we expect no further 153 * enctypes, so there should be no issue here. 154 */ 155 ec = 0; 156 plain.length = message->length + 16 + ec; 157 plain.data = MALLOC(plain.length); 158 if (plain.data == NULL) 159 return ENOMEM; 160 161 /* Get size of ciphertext. */ 162 if ((err = krb5_c_encrypt_length(context, 163 ctx->enc->enctype, plain.length, &tlen))) { 164 FREE(plain.data, plain.length); 165 return (err); 166 } 167 168 bufsize = 16 + tlen; 169 /* Allocate space for header plus encrypted data. */ 170 outbuf = MALLOC(bufsize); 171 if (outbuf == NULL) { 172 FREE(plain.data, plain.length); 173 return ENOMEM; 174 } 175 176 /* TOK_ID */ 177 store_16_be(0x0504, outbuf); 178 /* flags */ 179 outbuf[2] = (acceptor_flag 180 | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0) 181 | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); 182 /* filler */ 183 outbuf[3] = 0xff; 184 /* EC */ 185 store_16_be(ec, outbuf+4); 186 /* RRC */ 187 store_16_be(0, outbuf+6); 188 store_64_be(ctx->seq_send, outbuf+8); 189 190 (void) memcpy(plain.data, message->value, message->length); 191 (void) memset(plain.data + message->length, 'x', ec); 192 (void) memcpy(plain.data + message->length + ec, outbuf, 16); 193 194 /* Should really use scatter/gather crypto interfaces */ 195 cipher.ciphertext.data = (char *)outbuf + 16; 196 cipher.ciphertext.length = bufsize - 16; 197 cipher.enctype = key->enctype; 198 err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher); 199 (void) bzero(plain.data, plain.length); 200 FREE(plain.data, plain.length); 201 plain.data = 0; 202 if (err) 203 goto error; 204 205 /* Now that we know we're returning a valid token.... */ 206 ctx->seq_send++; 207 208 #ifdef CFX_EXERCISE 209 rrc = rand() & 0xffff; 210 if (rotate_left(outbuf+16, bufsize-16, 211 (bufsize-16) - (rrc % (bufsize - 16)))) 212 store_16_be(rrc, outbuf+6); 213 /* If the rotate fails, don't worry about it. */ 214 #endif 215 } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) { 216 krb5_data plain; 217 218 /* Here, message is the application-supplied data; message2 is 219 what goes into the output token. They may be the same, or 220 message2 may be empty (for MIC). */ 221 222 tok_id = 0x0504; 223 224 wrap_with_checksum: 225 plain.length = message->length + 16; 226 plain.data = MALLOC(message->length + 16); 227 if (plain.data == NULL) 228 return ENOMEM; 229 230 if (ctx->cksum_size > 0xffff) { 231 FREE(plain.data, plain.length); 232 return EINVAL; 233 } 234 235 bufsize = 16 + message2->length + ctx->cksum_size; 236 outbuf = MALLOC(bufsize); 237 if (outbuf == NULL) { 238 FREE(plain.data, plain.length); 239 plain.data = 0; 240 err = ENOMEM; 241 goto error; 242 } 243 244 /* TOK_ID */ 245 store_16_be(tok_id, outbuf); 246 /* flags */ 247 outbuf[2] = (acceptor_flag 248 | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); 249 /* filler */ 250 outbuf[3] = 0xff; 251 if (toktype == KG_TOK_WRAP_MSG) { 252 /* Use 0 for checksum calculation, substitute 253 checksum length later. */ 254 /* EC */ 255 store_16_be(0, outbuf+4); 256 /* RRC */ 257 store_16_be(0, outbuf+6); 258 } else { 259 /* MIC and DEL store 0xFF in EC and RRC. */ 260 store_16_be(0xffff, outbuf+4); 261 store_16_be(0xffff, outbuf+6); 262 } 263 store_64_be(ctx->seq_send, outbuf+8); 264 265 (void) memcpy(plain.data, message->value, message->length); 266 (void) memcpy(plain.data + message->length, outbuf, 16); 267 268 /* Fill in the output token -- data contents, if any, and 269 space for the checksum. */ 270 if (message2->length) 271 (void) memcpy(outbuf + 16, message2->value, message2->length); 272 273 sum.contents = outbuf + 16 + message2->length; 274 sum.length = ctx->cksum_size; 275 276 err = krb5_c_make_checksum(context, ctx->cksumtype, key, 277 key_usage, &plain, &sum); 278 279 bzero(plain.data, plain.length); 280 FREE(plain.data, plain.length); 281 plain.data = 0; 282 if (err) { 283 bzero(outbuf,bufsize); 284 err = KRB5KRB_AP_ERR_BAD_INTEGRITY; 285 goto error; 286 } 287 if (sum.length != ctx->cksum_size) { 288 err = KRB5KRB_AP_ERR_BAD_INTEGRITY; 289 goto error; 290 } 291 (void) memcpy(outbuf + 16 + message2->length, sum.contents, 292 ctx->cksum_size); 293 krb5_free_checksum_contents(context, &sum); 294 sum.contents = 0; 295 /* Now that we know we're actually generating the token... */ 296 ctx->seq_send++; 297 298 if (toktype == KG_TOK_WRAP_MSG) { 299 #ifdef CFX_EXERCISE 300 rrc = rand() & 0xffff; 301 /* If the rotate fails, don't worry about it. */ 302 if (rotate_left(outbuf+16, bufsize-16, 303 (bufsize-16) - (rrc % (bufsize - 16)))) 304 store_16_be(rrc, outbuf+6); 305 #endif 306 /* Fix up EC field. */ 307 store_16_be(ctx->cksum_size, outbuf+4); 308 } else { 309 store_16_be(0xffff, outbuf+6); 310 } 311 } else if (toktype == KG_TOK_MIC_MSG) { 312 tok_id = 0x0404; 313 message2 = &empty_message; 314 goto wrap_with_checksum; 315 } else if (toktype == KG_TOK_DEL_CTX) { 316 tok_id = 0x0405; 317 message = message2 = &empty_message; 318 goto wrap_with_checksum; 319 } else { 320 err = KRB5KRB_AP_ERR_BAD_INTEGRITY; 321 goto error; 322 } 323 324 token->value = outbuf; 325 token->length = bufsize; 326 return 0; 327 328 error: 329 FREE(outbuf, bufsize); 330 token->value = NULL; 331 token->length = 0; 332 return err; 333 } 334 335 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX 336 conf_state is only valid if SEAL. */ 337 338 OM_uint32 339 gss_krb5int_unseal_token_v3(krb5_context context, 340 OM_uint32 *minor_status, 341 krb5_gss_ctx_id_rec *ctx, 342 unsigned char *ptr, int bodysize, 343 gss_buffer_t message_buffer, 344 int *conf_state, int *qop_state, int toktype) 345 { 346 krb5_data plain; 347 gssint_uint64 seqnum; 348 size_t ec, rrc; 349 int key_usage; 350 unsigned char acceptor_flag; 351 krb5_checksum sum; 352 krb5_error_code err; 353 krb5_boolean valid; 354 krb5_keyblock *key; 355 356 ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0); 357 ASSERT(ctx->big_endian == 0); 358 ASSERT(ctx->proto == 1); 359 360 if (qop_state) 361 *qop_state = GSS_C_QOP_DEFAULT; 362 363 acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0; 364 key_usage = (toktype == KG_TOK_WRAP_MSG 365 ? (!ctx->initiate 366 ? KG_USAGE_INITIATOR_SEAL 367 : KG_USAGE_ACCEPTOR_SEAL) 368 : (!ctx->initiate 369 ? KG_USAGE_INITIATOR_SIGN 370 : KG_USAGE_ACCEPTOR_SIGN)); 371 372 /* Oops. I wrote this code assuming ptr would be at the start of 373 the token header. */ 374 ptr -= 2; 375 bodysize += 2; 376 377 if (bodysize < 16) { 378 defective: 379 *minor_status = 0; 380 return GSS_S_DEFECTIVE_TOKEN; 381 } 382 if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) { 383 *minor_status = (OM_uint32)G_BAD_DIRECTION; 384 return GSS_S_BAD_SIG; 385 } 386 387 /* Two things to note here. 388 389 First, we can't really enforce the use of the acceptor's subkey, 390 if we're the acceptor; the initiator may have sent messages 391 before getting the subkey. We could probably enforce it if 392 we're the initiator. 393 394 Second, if someone tweaks the code to not set the flag telling 395 the krb5 library to generate a new subkey in the AP-REP 396 message, the MIT library may include a subkey anyways -- 397 namely, a copy of the AP-REQ subkey, if it was provided. So 398 the initiator may think we wanted a subkey, and set the flag, 399 even though we weren't trying to set the subkey. The "other" 400 key, the one not ASSERTed by the acceptor, will have the same 401 value in that case, though, so we can just ignore the flag. */ 402 if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) { 403 key = ctx->acceptor_subkey; 404 } else { 405 key = ctx->enc; 406 } 407 408 #ifdef _KERNEL 409 context->kef_cipher_mt = get_cipher_mech_type(context, key); 410 context->kef_hash_mt = get_hash_mech_type(context, key); 411 412 if ((err = init_key_kef(context->kef_cipher_mt, key))) { 413 return (GSS_S_FAILURE); 414 } 415 #endif /* _KERNEL */ 416 417 if (toktype == KG_TOK_WRAP_MSG) { 418 if (load_16_be(ptr) != 0x0504) 419 goto defective; 420 if (ptr[3] != 0xff) 421 goto defective; 422 ec = load_16_be(ptr+4); 423 rrc = load_16_be(ptr+6); 424 seqnum = load_64_be(ptr+8); 425 if (!rotate_left(ptr+16, bodysize-16, rrc)) { 426 no_mem: 427 *minor_status = ENOMEM; 428 return GSS_S_FAILURE; 429 } 430 if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) { 431 /* confidentiality */ 432 krb5_enc_data cipher; 433 unsigned char *althdr; 434 size_t plainlen; 435 436 if (conf_state) 437 *conf_state = 1; 438 /* Do we have no decrypt_size function? 439 440 For all current cryptosystems, the ciphertext size will 441 be larger than the plaintext size. */ 442 cipher.enctype = key->enctype; 443 cipher.ciphertext.length = bodysize - 16; 444 cipher.ciphertext.data = (char *)ptr + 16; 445 plain.length = plainlen = bodysize - 16; 446 plain.data = MALLOC(plain.length); 447 if (plain.data == NULL) 448 goto no_mem; 449 err = krb5_c_decrypt(context, key, key_usage, 0, 450 &cipher, &plain); 451 if (err) { 452 goto error; 453 } 454 /* Don't use bodysize here! Use the fact that 455 plain.length has been adjusted to the 456 correct length. */ 457 althdr = (uchar_t *)plain.data + plain.length - 16; 458 if (load_16_be(althdr) != 0x0504 459 || althdr[2] != ptr[2] 460 || althdr[3] != ptr[3] 461 || memcmp(althdr+8, ptr+8, 8)) { 462 FREE(plain.data, plainlen); 463 goto defective; 464 } 465 message_buffer->length = plain.length - ec - 16; 466 message_buffer->value = MALLOC(message_buffer->length); 467 if (message_buffer->value == NULL) { 468 FREE(plain.data, plainlen); 469 goto no_mem; 470 } 471 (void) memcpy(message_buffer->value, plain.data, 472 message_buffer->length); 473 FREE(plain.data, plainlen); 474 } else { 475 /* no confidentiality */ 476 if (conf_state) 477 *conf_state = 0; 478 if (ec + 16 < ec) 479 /* overflow check */ 480 goto defective; 481 if (ec + 16 > bodysize) 482 goto defective; 483 /* We have: header | msg | cksum. 484 We need cksum(msg | header). 485 Rotate the first two. */ 486 store_16_be(0, ptr+4); 487 store_16_be(0, ptr+6); 488 plain.length = bodysize - ec; 489 plain.data = (char *)ptr; 490 if (!rotate_left(ptr, bodysize-ec, 16)) 491 goto no_mem; 492 sum.length = ec; 493 if (sum.length != ctx->cksum_size) { 494 *minor_status = 0; 495 return GSS_S_BAD_SIG; 496 } 497 sum.contents = ptr+bodysize-ec; 498 sum.checksum_type = ctx->cksumtype; 499 err = krb5_c_verify_checksum(context, key, key_usage, 500 &plain, &sum, &valid); 501 if (err) { 502 *minor_status = err; 503 return GSS_S_BAD_SIG; 504 } 505 if (!valid) { 506 *minor_status = 0; 507 return GSS_S_BAD_SIG; 508 } 509 message_buffer->length = plain.length - 16; 510 message_buffer->value = MALLOC(message_buffer->length); 511 if (message_buffer->value == NULL) 512 goto no_mem; 513 (void) memcpy(message_buffer->value, 514 plain.data, message_buffer->length); 515 } 516 err = g_order_check(&ctx->seqstate, seqnum); 517 *minor_status = 0; 518 return err; 519 } else if (toktype == KG_TOK_MIC_MSG) { 520 /* wrap token, no confidentiality */ 521 if (load_16_be(ptr) != 0x0404) 522 goto defective; 523 verify_mic_1: 524 if (ptr[3] != 0xff) 525 goto defective; 526 if (load_32_be(ptr+4) != (ulong_t)0xffffffffU) 527 goto defective; 528 seqnum = load_64_be(ptr+8); 529 plain.length = message_buffer->length + 16; 530 plain.data = MALLOC(plain.length); 531 if (plain.data == NULL) 532 goto no_mem; 533 if (message_buffer->length) 534 (void) memcpy(plain.data, 535 message_buffer->value, message_buffer->length); 536 (void) memcpy(plain.data + message_buffer->length, ptr, 16); 537 sum.length = bodysize - 16; 538 sum.contents = ptr + 16; 539 sum.checksum_type = ctx->cksumtype; 540 err = krb5_c_verify_checksum(context, key, key_usage, 541 &plain, &sum, &valid); 542 if (err) { 543 error: 544 FREE(plain.data, plain.length); 545 *minor_status = err; 546 return GSS_S_BAD_SIG; /* XXX */ 547 } 548 FREE(plain.data, plain.length); 549 if (!valid) { 550 *minor_status = 0; 551 return GSS_S_BAD_SIG; 552 } 553 err = g_order_check(&ctx->seqstate, seqnum); 554 *minor_status = 0; 555 return err; 556 } else if (toktype == KG_TOK_DEL_CTX) { 557 if (load_16_be(ptr) != 0x0405) 558 goto defective; 559 message_buffer = (gss_buffer_t)&empty_message; 560 goto verify_mic_1; 561 } else { 562 goto defective; 563 } 564 } 565