1 /* 2 * Copyright (c) 1997 - 2008 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_locl.h" 35 36 struct _krb5_key_usage { 37 unsigned usage; 38 struct _krb5_key_data key; 39 }; 40 41 42 #ifndef HEIMDAL_SMALLER 43 #define DES3_OLD_ENCTYPE 1 44 #endif 45 46 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, 47 unsigned, struct _krb5_key_data**); 48 static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage); 49 50 static void free_key_schedule(krb5_context, 51 struct _krb5_key_data *, 52 struct _krb5_encryption_type *); 53 54 /* 55 * Converts etype to a user readable string and sets as a side effect 56 * the krb5_error_message containing this string. Returns 57 * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in 58 * which case the error code of the etype convesion is returned. 59 */ 60 61 static krb5_error_code 62 unsupported_enctype(krb5_context context, krb5_enctype etype) 63 { 64 krb5_error_code ret; 65 char *name; 66 67 ret = krb5_enctype_to_string(context, etype, &name); 68 if (ret) 69 return ret; 70 71 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 72 N_("Encryption type %s not supported", ""), 73 name); 74 free(name); 75 return KRB5_PROG_ETYPE_NOSUPP; 76 } 77 78 /* 79 * 80 */ 81 82 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 83 krb5_enctype_keysize(krb5_context context, 84 krb5_enctype type, 85 size_t *keysize) 86 { 87 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 88 if(et == NULL) { 89 return unsupported_enctype (context, type); 90 } 91 *keysize = et->keytype->size; 92 return 0; 93 } 94 95 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 96 krb5_enctype_keybits(krb5_context context, 97 krb5_enctype type, 98 size_t *keybits) 99 { 100 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 101 if(et == NULL) { 102 return unsupported_enctype (context, type); 103 } 104 *keybits = et->keytype->bits; 105 return 0; 106 } 107 108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 109 krb5_generate_random_keyblock(krb5_context context, 110 krb5_enctype type, 111 krb5_keyblock *key) 112 { 113 krb5_error_code ret; 114 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 115 if(et == NULL) { 116 return unsupported_enctype (context, type); 117 } 118 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); 119 if(ret) 120 return ret; 121 key->keytype = type; 122 if(et->keytype->random_key) 123 (*et->keytype->random_key)(context, key); 124 else 125 krb5_generate_random_block(key->keyvalue.data, 126 key->keyvalue.length); 127 return 0; 128 } 129 130 static krb5_error_code 131 _key_schedule(krb5_context context, 132 struct _krb5_key_data *key) 133 { 134 krb5_error_code ret; 135 struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype); 136 struct _krb5_key_type *kt; 137 138 if (et == NULL) { 139 return unsupported_enctype (context, 140 key->key->keytype); 141 } 142 143 kt = et->keytype; 144 145 if(kt->schedule == NULL) 146 return 0; 147 if (key->schedule != NULL) 148 return 0; 149 ALLOC(key->schedule, 1); 150 if(key->schedule == NULL) { 151 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 152 return ENOMEM; 153 } 154 ret = krb5_data_alloc(key->schedule, kt->schedule_size); 155 if(ret) { 156 free(key->schedule); 157 key->schedule = NULL; 158 return ret; 159 } 160 (*kt->schedule)(context, kt, key); 161 return 0; 162 } 163 164 /************************************************************ 165 * * 166 ************************************************************/ 167 168 static krb5_error_code 169 SHA1_checksum(krb5_context context, 170 struct _krb5_key_data *key, 171 const void *data, 172 size_t len, 173 unsigned usage, 174 Checksum *C) 175 { 176 if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1) 177 krb5_abortx(context, "sha1 checksum failed"); 178 return 0; 179 } 180 181 /* HMAC according to RFC2104 */ 182 krb5_error_code 183 _krb5_internal_hmac(krb5_context context, 184 struct _krb5_checksum_type *cm, 185 const void *data, 186 size_t len, 187 unsigned usage, 188 struct _krb5_key_data *keyblock, 189 Checksum *result) 190 { 191 unsigned char *ipad, *opad; 192 unsigned char *key; 193 size_t key_len; 194 size_t i; 195 196 ipad = malloc(cm->blocksize + len); 197 if (ipad == NULL) 198 return ENOMEM; 199 opad = malloc(cm->blocksize + cm->checksumsize); 200 if (opad == NULL) { 201 free(ipad); 202 return ENOMEM; 203 } 204 memset(ipad, 0x36, cm->blocksize); 205 memset(opad, 0x5c, cm->blocksize); 206 207 if(keyblock->key->keyvalue.length > cm->blocksize){ 208 (*cm->checksum)(context, 209 keyblock, 210 keyblock->key->keyvalue.data, 211 keyblock->key->keyvalue.length, 212 usage, 213 result); 214 key = result->checksum.data; 215 key_len = result->checksum.length; 216 } else { 217 key = keyblock->key->keyvalue.data; 218 key_len = keyblock->key->keyvalue.length; 219 } 220 for(i = 0; i < key_len; i++){ 221 ipad[i] ^= key[i]; 222 opad[i] ^= key[i]; 223 } 224 memcpy(ipad + cm->blocksize, data, len); 225 (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len, 226 usage, result); 227 memcpy(opad + cm->blocksize, result->checksum.data, 228 result->checksum.length); 229 (*cm->checksum)(context, keyblock, opad, 230 cm->blocksize + cm->checksumsize, usage, result); 231 memset(ipad, 0, cm->blocksize + len); 232 free(ipad); 233 memset(opad, 0, cm->blocksize + cm->checksumsize); 234 free(opad); 235 236 return 0; 237 } 238 239 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 240 krb5_hmac(krb5_context context, 241 krb5_cksumtype cktype, 242 const void *data, 243 size_t len, 244 unsigned usage, 245 krb5_keyblock *key, 246 Checksum *result) 247 { 248 struct _krb5_checksum_type *c = _krb5_find_checksum(cktype); 249 struct _krb5_key_data kd; 250 krb5_error_code ret; 251 252 if (c == NULL) { 253 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 254 N_("checksum type %d not supported", ""), 255 cktype); 256 return KRB5_PROG_SUMTYPE_NOSUPP; 257 } 258 259 kd.key = key; 260 kd.schedule = NULL; 261 262 ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result); 263 264 if (kd.schedule) 265 krb5_free_data(context, kd.schedule); 266 267 return ret; 268 } 269 270 krb5_error_code 271 _krb5_SP_HMAC_SHA1_checksum(krb5_context context, 272 struct _krb5_key_data *key, 273 const void *data, 274 size_t len, 275 unsigned usage, 276 Checksum *result) 277 { 278 struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); 279 Checksum res; 280 char sha1_data[20]; 281 krb5_error_code ret; 282 283 res.checksum.data = sha1_data; 284 res.checksum.length = sizeof(sha1_data); 285 286 ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res); 287 if (ret) 288 krb5_abortx(context, "hmac failed"); 289 memcpy(result->checksum.data, res.checksum.data, result->checksum.length); 290 return 0; 291 } 292 293 struct _krb5_checksum_type _krb5_checksum_sha1 = { 294 CKSUMTYPE_SHA1, 295 "sha1", 296 64, 297 20, 298 F_CPROOF, 299 SHA1_checksum, 300 NULL 301 }; 302 303 struct _krb5_checksum_type * 304 _krb5_find_checksum(krb5_cksumtype type) 305 { 306 int i; 307 for(i = 0; i < _krb5_num_checksums; i++) 308 if(_krb5_checksum_types[i]->type == type) 309 return _krb5_checksum_types[i]; 310 return NULL; 311 } 312 313 static krb5_error_code 314 get_checksum_key(krb5_context context, 315 krb5_crypto crypto, 316 unsigned usage, /* not krb5_key_usage */ 317 struct _krb5_checksum_type *ct, 318 struct _krb5_key_data **key) 319 { 320 krb5_error_code ret = 0; 321 322 if(ct->flags & F_DERIVED) 323 ret = _get_derived_key(context, crypto, usage, key); 324 else if(ct->flags & F_VARIANT) { 325 size_t i; 326 327 *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */); 328 if(*key == NULL) { 329 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 330 return ENOMEM; 331 } 332 ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key); 333 if(ret) 334 return ret; 335 for(i = 0; i < (*key)->key->keyvalue.length; i++) 336 ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0; 337 } else { 338 *key = &crypto->key; 339 } 340 if(ret == 0) 341 ret = _key_schedule(context, *key); 342 return ret; 343 } 344 345 static krb5_error_code 346 create_checksum (krb5_context context, 347 struct _krb5_checksum_type *ct, 348 krb5_crypto crypto, 349 unsigned usage, 350 void *data, 351 size_t len, 352 Checksum *result) 353 { 354 krb5_error_code ret; 355 struct _krb5_key_data *dkey; 356 int keyed_checksum; 357 358 if (ct->flags & F_DISABLED) { 359 krb5_clear_error_message (context); 360 return KRB5_PROG_SUMTYPE_NOSUPP; 361 } 362 keyed_checksum = (ct->flags & F_KEYED) != 0; 363 if(keyed_checksum && crypto == NULL) { 364 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 365 N_("Checksum type %s is keyed but no " 366 "crypto context (key) was passed in", ""), 367 ct->name); 368 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 369 } 370 if(keyed_checksum) { 371 ret = get_checksum_key(context, crypto, usage, ct, &dkey); 372 if (ret) 373 return ret; 374 } else 375 dkey = NULL; 376 result->cksumtype = ct->type; 377 ret = krb5_data_alloc(&result->checksum, ct->checksumsize); 378 if (ret) 379 return (ret); 380 return (*ct->checksum)(context, dkey, data, len, usage, result); 381 } 382 383 static int 384 arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto) 385 { 386 return (ct->type == CKSUMTYPE_HMAC_MD5) && 387 (crypto->key.key->keytype == KEYTYPE_ARCFOUR); 388 } 389 390 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 391 krb5_create_checksum(krb5_context context, 392 krb5_crypto crypto, 393 krb5_key_usage usage, 394 int type, 395 void *data, 396 size_t len, 397 Checksum *result) 398 { 399 struct _krb5_checksum_type *ct = NULL; 400 unsigned keyusage; 401 402 /* type 0 -> pick from crypto */ 403 if (type) { 404 ct = _krb5_find_checksum(type); 405 } else if (crypto) { 406 ct = crypto->et->keyed_checksum; 407 if (ct == NULL) 408 ct = crypto->et->checksum; 409 } 410 411 if(ct == NULL) { 412 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 413 N_("checksum type %d not supported", ""), 414 type); 415 return KRB5_PROG_SUMTYPE_NOSUPP; 416 } 417 418 if (arcfour_checksum_p(ct, crypto)) { 419 keyusage = usage; 420 _krb5_usage2arcfour(context, &keyusage); 421 } else 422 keyusage = CHECKSUM_USAGE(usage); 423 424 return create_checksum(context, ct, crypto, keyusage, 425 data, len, result); 426 } 427 428 static krb5_error_code 429 verify_checksum(krb5_context context, 430 krb5_crypto crypto, 431 unsigned usage, /* not krb5_key_usage */ 432 void *data, 433 size_t len, 434 Checksum *cksum) 435 { 436 krb5_error_code ret; 437 struct _krb5_key_data *dkey; 438 int keyed_checksum; 439 Checksum c; 440 struct _krb5_checksum_type *ct; 441 442 ct = _krb5_find_checksum(cksum->cksumtype); 443 if (ct == NULL || (ct->flags & F_DISABLED)) { 444 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 445 N_("checksum type %d not supported", ""), 446 cksum->cksumtype); 447 return KRB5_PROG_SUMTYPE_NOSUPP; 448 } 449 if(ct->checksumsize != cksum->checksum.length) { 450 krb5_clear_error_message (context); 451 krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY, 452 N_("Decrypt integrity check failed for checksum type %s, " 453 "length was %u, expected %u", ""), 454 ct->name, (unsigned)cksum->checksum.length, 455 (unsigned)ct->checksumsize); 456 457 return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ 458 } 459 keyed_checksum = (ct->flags & F_KEYED) != 0; 460 if(keyed_checksum) { 461 struct _krb5_checksum_type *kct; 462 if (crypto == NULL) { 463 krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, 464 N_("Checksum type %s is keyed but no " 465 "crypto context (key) was passed in", ""), 466 ct->name); 467 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 468 } 469 kct = crypto->et->keyed_checksum; 470 if (kct == NULL || kct->type != ct->type) { 471 krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, 472 N_("Checksum type %s is keyed, but " 473 "the key type %s passed didnt have that checksum " 474 "type as the keyed type", ""), 475 ct->name, crypto->et->name); 476 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 477 } 478 479 ret = get_checksum_key(context, crypto, usage, ct, &dkey); 480 if (ret) 481 return ret; 482 } else 483 dkey = NULL; 484 485 /* 486 * If checksum have a verify function, lets use that instead of 487 * calling ->checksum and then compare result. 488 */ 489 490 if(ct->verify) { 491 ret = (*ct->verify)(context, dkey, data, len, usage, cksum); 492 if (ret) 493 krb5_set_error_message(context, ret, 494 N_("Decrypt integrity check failed for checksum " 495 "type %s, key type %s", ""), 496 ct->name, (crypto != NULL)? crypto->et->name : "(none)"); 497 return ret; 498 } 499 500 ret = krb5_data_alloc (&c.checksum, ct->checksumsize); 501 if (ret) 502 return ret; 503 504 ret = (*ct->checksum)(context, dkey, data, len, usage, &c); 505 if (ret) { 506 krb5_data_free(&c.checksum); 507 return ret; 508 } 509 510 if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) { 511 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 512 krb5_set_error_message(context, ret, 513 N_("Decrypt integrity check failed for checksum " 514 "type %s, key type %s", ""), 515 ct->name, crypto ? crypto->et->name : "(unkeyed)"); 516 } else { 517 ret = 0; 518 } 519 krb5_data_free (&c.checksum); 520 return ret; 521 } 522 523 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 524 krb5_verify_checksum(krb5_context context, 525 krb5_crypto crypto, 526 krb5_key_usage usage, 527 void *data, 528 size_t len, 529 Checksum *cksum) 530 { 531 struct _krb5_checksum_type *ct; 532 unsigned keyusage; 533 534 ct = _krb5_find_checksum(cksum->cksumtype); 535 if(ct == NULL) { 536 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 537 N_("checksum type %d not supported", ""), 538 cksum->cksumtype); 539 return KRB5_PROG_SUMTYPE_NOSUPP; 540 } 541 542 if (arcfour_checksum_p(ct, crypto)) { 543 keyusage = usage; 544 _krb5_usage2arcfour(context, &keyusage); 545 } else 546 keyusage = CHECKSUM_USAGE(usage); 547 548 return verify_checksum(context, crypto, keyusage, 549 data, len, cksum); 550 } 551 552 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 553 krb5_crypto_get_checksum_type(krb5_context context, 554 krb5_crypto crypto, 555 krb5_cksumtype *type) 556 { 557 struct _krb5_checksum_type *ct = NULL; 558 559 if (crypto != NULL) { 560 ct = crypto->et->keyed_checksum; 561 if (ct == NULL) 562 ct = crypto->et->checksum; 563 } 564 565 if (ct == NULL) { 566 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 567 N_("checksum type not found", "")); 568 return KRB5_PROG_SUMTYPE_NOSUPP; 569 } 570 571 *type = ct->type; 572 573 return 0; 574 } 575 576 577 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 578 krb5_checksumsize(krb5_context context, 579 krb5_cksumtype type, 580 size_t *size) 581 { 582 struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 583 if(ct == NULL) { 584 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 585 N_("checksum type %d not supported", ""), 586 type); 587 return KRB5_PROG_SUMTYPE_NOSUPP; 588 } 589 *size = ct->checksumsize; 590 return 0; 591 } 592 593 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 594 krb5_checksum_is_keyed(krb5_context context, 595 krb5_cksumtype type) 596 { 597 struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 598 if(ct == NULL) { 599 if (context) 600 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 601 N_("checksum type %d not supported", ""), 602 type); 603 return KRB5_PROG_SUMTYPE_NOSUPP; 604 } 605 return ct->flags & F_KEYED; 606 } 607 608 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 609 krb5_checksum_is_collision_proof(krb5_context context, 610 krb5_cksumtype type) 611 { 612 struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 613 if(ct == NULL) { 614 if (context) 615 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 616 N_("checksum type %d not supported", ""), 617 type); 618 return KRB5_PROG_SUMTYPE_NOSUPP; 619 } 620 return ct->flags & F_CPROOF; 621 } 622 623 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 624 krb5_checksum_disable(krb5_context context, 625 krb5_cksumtype type) 626 { 627 struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 628 if(ct == NULL) { 629 if (context) 630 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 631 N_("checksum type %d not supported", ""), 632 type); 633 return KRB5_PROG_SUMTYPE_NOSUPP; 634 } 635 ct->flags |= F_DISABLED; 636 return 0; 637 } 638 639 /************************************************************ 640 * * 641 ************************************************************/ 642 643 struct _krb5_encryption_type * 644 _krb5_find_enctype(krb5_enctype type) 645 { 646 int i; 647 for(i = 0; i < _krb5_num_etypes; i++) 648 if(_krb5_etypes[i]->type == type) 649 return _krb5_etypes[i]; 650 return NULL; 651 } 652 653 654 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 655 krb5_enctype_to_string(krb5_context context, 656 krb5_enctype etype, 657 char **string) 658 { 659 struct _krb5_encryption_type *e; 660 e = _krb5_find_enctype(etype); 661 if(e == NULL) { 662 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 663 N_("encryption type %d not supported", ""), 664 etype); 665 *string = NULL; 666 return KRB5_PROG_ETYPE_NOSUPP; 667 } 668 *string = strdup(e->name); 669 if(*string == NULL) { 670 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 671 return ENOMEM; 672 } 673 return 0; 674 } 675 676 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 677 krb5_string_to_enctype(krb5_context context, 678 const char *string, 679 krb5_enctype *etype) 680 { 681 int i; 682 for(i = 0; i < _krb5_num_etypes; i++) 683 if(strcasecmp(_krb5_etypes[i]->name, string) == 0){ 684 *etype = _krb5_etypes[i]->type; 685 return 0; 686 } 687 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 688 N_("encryption type %s not supported", ""), 689 string); 690 return KRB5_PROG_ETYPE_NOSUPP; 691 } 692 693 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 694 krb5_enctype_to_keytype(krb5_context context, 695 krb5_enctype etype, 696 krb5_keytype *keytype) 697 { 698 struct _krb5_encryption_type *e = _krb5_find_enctype(etype); 699 if(e == NULL) { 700 return unsupported_enctype (context, etype); 701 } 702 *keytype = e->keytype->type; /* XXX */ 703 return 0; 704 } 705 706 /** 707 * Check if a enctype is valid, return 0 if it is. 708 * 709 * @param context Kerberos context 710 * @param etype enctype to check if its valid or not 711 * 712 * @return Return an error code for an failure or 0 on success (enctype valid). 713 * @ingroup krb5_crypto 714 */ 715 716 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 717 krb5_enctype_valid(krb5_context context, 718 krb5_enctype etype) 719 { 720 struct _krb5_encryption_type *e = _krb5_find_enctype(etype); 721 if(e && (e->flags & F_DISABLED) == 0) 722 return 0; 723 if (context == NULL) 724 return KRB5_PROG_ETYPE_NOSUPP; 725 if(e == NULL) { 726 return unsupported_enctype (context, etype); 727 } 728 /* Must be (e->flags & F_DISABLED) */ 729 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 730 N_("encryption type %s is disabled", ""), 731 e->name); 732 return KRB5_PROG_ETYPE_NOSUPP; 733 } 734 735 /** 736 * Return the coresponding encryption type for a checksum type. 737 * 738 * @param context Kerberos context 739 * @param ctype The checksum type to get the result enctype for 740 * @param etype The returned encryption, when the matching etype is 741 * not found, etype is set to ETYPE_NULL. 742 * 743 * @return Return an error code for an failure or 0 on success. 744 * @ingroup krb5_crypto 745 */ 746 747 748 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 749 krb5_cksumtype_to_enctype(krb5_context context, 750 krb5_cksumtype ctype, 751 krb5_enctype *etype) 752 { 753 int i; 754 755 *etype = ETYPE_NULL; 756 757 for(i = 0; i < _krb5_num_etypes; i++) { 758 if(_krb5_etypes[i]->keyed_checksum && 759 _krb5_etypes[i]->keyed_checksum->type == ctype) 760 { 761 *etype = _krb5_etypes[i]->type; 762 return 0; 763 } 764 } 765 766 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 767 N_("checksum type %d not supported", ""), 768 (int)ctype); 769 return KRB5_PROG_SUMTYPE_NOSUPP; 770 } 771 772 773 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 774 krb5_cksumtype_valid(krb5_context context, 775 krb5_cksumtype ctype) 776 { 777 struct _krb5_checksum_type *c = _krb5_find_checksum(ctype); 778 if (c == NULL) { 779 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 780 N_("checksum type %d not supported", ""), 781 ctype); 782 return KRB5_PROG_SUMTYPE_NOSUPP; 783 } 784 if (c->flags & F_DISABLED) { 785 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 786 N_("checksum type %s is disabled", ""), 787 c->name); 788 return KRB5_PROG_SUMTYPE_NOSUPP; 789 } 790 return 0; 791 } 792 793 794 static krb5_boolean 795 derived_crypto(krb5_context context, 796 krb5_crypto crypto) 797 { 798 return (crypto->et->flags & F_DERIVED) != 0; 799 } 800 801 static krb5_boolean 802 special_crypto(krb5_context context, 803 krb5_crypto crypto) 804 { 805 return (crypto->et->flags & F_SPECIAL) != 0; 806 } 807 808 #define CHECKSUMSIZE(C) ((C)->checksumsize) 809 #define CHECKSUMTYPE(C) ((C)->type) 810 811 static krb5_error_code 812 encrypt_internal_derived(krb5_context context, 813 krb5_crypto crypto, 814 unsigned usage, 815 const void *data, 816 size_t len, 817 krb5_data *result, 818 void *ivec) 819 { 820 size_t sz, block_sz, checksum_sz, total_sz; 821 Checksum cksum; 822 unsigned char *p, *q; 823 krb5_error_code ret; 824 struct _krb5_key_data *dkey; 825 const struct _krb5_encryption_type *et = crypto->et; 826 827 checksum_sz = CHECKSUMSIZE(et->keyed_checksum); 828 829 sz = et->confoundersize + len; 830 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 831 total_sz = block_sz + checksum_sz; 832 p = calloc(1, total_sz); 833 if(p == NULL) { 834 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 835 return ENOMEM; 836 } 837 838 q = p; 839 krb5_generate_random_block(q, et->confoundersize); /* XXX */ 840 q += et->confoundersize; 841 memcpy(q, data, len); 842 843 ret = create_checksum(context, 844 et->keyed_checksum, 845 crypto, 846 INTEGRITY_USAGE(usage), 847 p, 848 block_sz, 849 &cksum); 850 if(ret == 0 && cksum.checksum.length != checksum_sz) { 851 free_Checksum (&cksum); 852 krb5_clear_error_message (context); 853 ret = KRB5_CRYPTO_INTERNAL; 854 } 855 if(ret) 856 goto fail; 857 memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); 858 free_Checksum (&cksum); 859 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 860 if(ret) 861 goto fail; 862 ret = _key_schedule(context, dkey); 863 if(ret) 864 goto fail; 865 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); 866 if (ret) 867 goto fail; 868 result->data = p; 869 result->length = total_sz; 870 return 0; 871 fail: 872 memset(p, 0, total_sz); 873 free(p); 874 return ret; 875 } 876 877 878 static krb5_error_code 879 encrypt_internal(krb5_context context, 880 krb5_crypto crypto, 881 const void *data, 882 size_t len, 883 krb5_data *result, 884 void *ivec) 885 { 886 size_t sz, block_sz, checksum_sz; 887 Checksum cksum; 888 unsigned char *p, *q; 889 krb5_error_code ret; 890 const struct _krb5_encryption_type *et = crypto->et; 891 892 checksum_sz = CHECKSUMSIZE(et->checksum); 893 894 sz = et->confoundersize + checksum_sz + len; 895 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 896 p = calloc(1, block_sz); 897 if(p == NULL) { 898 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 899 return ENOMEM; 900 } 901 902 q = p; 903 krb5_generate_random_block(q, et->confoundersize); /* XXX */ 904 q += et->confoundersize; 905 memset(q, 0, checksum_sz); 906 q += checksum_sz; 907 memcpy(q, data, len); 908 909 ret = create_checksum(context, 910 et->checksum, 911 crypto, 912 0, 913 p, 914 block_sz, 915 &cksum); 916 if(ret == 0 && cksum.checksum.length != checksum_sz) { 917 krb5_clear_error_message (context); 918 free_Checksum(&cksum); 919 ret = KRB5_CRYPTO_INTERNAL; 920 } 921 if(ret) 922 goto fail; 923 memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length); 924 free_Checksum(&cksum); 925 ret = _key_schedule(context, &crypto->key); 926 if(ret) 927 goto fail; 928 ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec); 929 if (ret) { 930 memset(p, 0, block_sz); 931 free(p); 932 return ret; 933 } 934 result->data = p; 935 result->length = block_sz; 936 return 0; 937 fail: 938 memset(p, 0, block_sz); 939 free(p); 940 return ret; 941 } 942 943 static krb5_error_code 944 encrypt_internal_special(krb5_context context, 945 krb5_crypto crypto, 946 int usage, 947 const void *data, 948 size_t len, 949 krb5_data *result, 950 void *ivec) 951 { 952 struct _krb5_encryption_type *et = crypto->et; 953 size_t cksum_sz = CHECKSUMSIZE(et->checksum); 954 size_t sz = len + cksum_sz + et->confoundersize; 955 char *tmp, *p; 956 krb5_error_code ret; 957 958 tmp = malloc (sz); 959 if (tmp == NULL) { 960 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 961 return ENOMEM; 962 } 963 p = tmp; 964 memset (p, 0, cksum_sz); 965 p += cksum_sz; 966 krb5_generate_random_block(p, et->confoundersize); 967 p += et->confoundersize; 968 memcpy (p, data, len); 969 ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec); 970 if (ret) { 971 memset(tmp, 0, sz); 972 free(tmp); 973 return ret; 974 } 975 result->data = tmp; 976 result->length = sz; 977 return 0; 978 } 979 980 static krb5_error_code 981 decrypt_internal_derived(krb5_context context, 982 krb5_crypto crypto, 983 unsigned usage, 984 void *data, 985 size_t len, 986 krb5_data *result, 987 void *ivec) 988 { 989 size_t checksum_sz; 990 Checksum cksum; 991 unsigned char *p; 992 krb5_error_code ret; 993 struct _krb5_key_data *dkey; 994 struct _krb5_encryption_type *et = crypto->et; 995 unsigned long l; 996 997 checksum_sz = CHECKSUMSIZE(et->keyed_checksum); 998 if (len < checksum_sz + et->confoundersize) { 999 krb5_set_error_message(context, KRB5_BAD_MSIZE, 1000 N_("Encrypted data shorter then " 1001 "checksum + confunder", "")); 1002 return KRB5_BAD_MSIZE; 1003 } 1004 1005 if (((len - checksum_sz) % et->padsize) != 0) { 1006 krb5_clear_error_message(context); 1007 return KRB5_BAD_MSIZE; 1008 } 1009 1010 p = malloc(len); 1011 if(len != 0 && p == NULL) { 1012 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1013 return ENOMEM; 1014 } 1015 memcpy(p, data, len); 1016 1017 len -= checksum_sz; 1018 1019 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 1020 if(ret) { 1021 free(p); 1022 return ret; 1023 } 1024 ret = _key_schedule(context, dkey); 1025 if(ret) { 1026 free(p); 1027 return ret; 1028 } 1029 ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); 1030 if (ret) { 1031 free(p); 1032 return ret; 1033 } 1034 1035 cksum.checksum.data = p + len; 1036 cksum.checksum.length = checksum_sz; 1037 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 1038 1039 ret = verify_checksum(context, 1040 crypto, 1041 INTEGRITY_USAGE(usage), 1042 p, 1043 len, 1044 &cksum); 1045 if(ret) { 1046 free(p); 1047 return ret; 1048 } 1049 l = len - et->confoundersize; 1050 memmove(p, p + et->confoundersize, l); 1051 result->data = realloc(p, l); 1052 if(result->data == NULL && l != 0) { 1053 free(p); 1054 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1055 return ENOMEM; 1056 } 1057 result->length = l; 1058 return 0; 1059 } 1060 1061 static krb5_error_code 1062 decrypt_internal(krb5_context context, 1063 krb5_crypto crypto, 1064 void *data, 1065 size_t len, 1066 krb5_data *result, 1067 void *ivec) 1068 { 1069 krb5_error_code ret; 1070 unsigned char *p; 1071 Checksum cksum; 1072 size_t checksum_sz, l; 1073 struct _krb5_encryption_type *et = crypto->et; 1074 1075 if ((len % et->padsize) != 0) { 1076 krb5_clear_error_message(context); 1077 return KRB5_BAD_MSIZE; 1078 } 1079 checksum_sz = CHECKSUMSIZE(et->checksum); 1080 if (len < checksum_sz + et->confoundersize) { 1081 krb5_set_error_message(context, KRB5_BAD_MSIZE, 1082 N_("Encrypted data shorter then " 1083 "checksum + confunder", "")); 1084 return KRB5_BAD_MSIZE; 1085 } 1086 1087 p = malloc(len); 1088 if(len != 0 && p == NULL) { 1089 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1090 return ENOMEM; 1091 } 1092 memcpy(p, data, len); 1093 1094 ret = _key_schedule(context, &crypto->key); 1095 if(ret) { 1096 free(p); 1097 return ret; 1098 } 1099 ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec); 1100 if (ret) { 1101 free(p); 1102 return ret; 1103 } 1104 ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz); 1105 if(ret) { 1106 free(p); 1107 return ret; 1108 } 1109 memset(p + et->confoundersize, 0, checksum_sz); 1110 cksum.cksumtype = CHECKSUMTYPE(et->checksum); 1111 ret = verify_checksum(context, NULL, 0, p, len, &cksum); 1112 free_Checksum(&cksum); 1113 if(ret) { 1114 free(p); 1115 return ret; 1116 } 1117 l = len - et->confoundersize - checksum_sz; 1118 memmove(p, p + et->confoundersize + checksum_sz, l); 1119 result->data = realloc(p, l); 1120 if(result->data == NULL && l != 0) { 1121 free(p); 1122 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1123 return ENOMEM; 1124 } 1125 result->length = l; 1126 return 0; 1127 } 1128 1129 static krb5_error_code 1130 decrypt_internal_special(krb5_context context, 1131 krb5_crypto crypto, 1132 int usage, 1133 void *data, 1134 size_t len, 1135 krb5_data *result, 1136 void *ivec) 1137 { 1138 struct _krb5_encryption_type *et = crypto->et; 1139 size_t cksum_sz = CHECKSUMSIZE(et->checksum); 1140 size_t sz = len - cksum_sz - et->confoundersize; 1141 unsigned char *p; 1142 krb5_error_code ret; 1143 1144 if ((len % et->padsize) != 0) { 1145 krb5_clear_error_message(context); 1146 return KRB5_BAD_MSIZE; 1147 } 1148 if (len < cksum_sz + et->confoundersize) { 1149 krb5_set_error_message(context, KRB5_BAD_MSIZE, 1150 N_("Encrypted data shorter then " 1151 "checksum + confunder", "")); 1152 return KRB5_BAD_MSIZE; 1153 } 1154 1155 p = malloc (len); 1156 if (p == NULL) { 1157 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1158 return ENOMEM; 1159 } 1160 memcpy(p, data, len); 1161 1162 ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec); 1163 if (ret) { 1164 free(p); 1165 return ret; 1166 } 1167 1168 memmove (p, p + cksum_sz + et->confoundersize, sz); 1169 result->data = realloc(p, sz); 1170 if(result->data == NULL && sz != 0) { 1171 free(p); 1172 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1173 return ENOMEM; 1174 } 1175 result->length = sz; 1176 return 0; 1177 } 1178 1179 static krb5_crypto_iov * 1180 find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type) 1181 { 1182 size_t i; 1183 for (i = 0; i < num_data; i++) 1184 if (data[i].flags == type) 1185 return &data[i]; 1186 return NULL; 1187 } 1188 1189 /** 1190 * Inline encrypt a kerberos message 1191 * 1192 * @param context Kerberos context 1193 * @param crypto Kerberos crypto context 1194 * @param usage Key usage for this buffer 1195 * @param data array of buffers to process 1196 * @param num_data length of array 1197 * @param ivec initial cbc/cts vector 1198 * 1199 * @return Return an error code or 0. 1200 * @ingroup krb5_crypto 1201 * 1202 * Kerberos encrypted data look like this: 1203 * 1204 * 1. KRB5_CRYPTO_TYPE_HEADER 1205 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...] 1206 * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver 1207 * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is 1208 * commonly used headers and trailers. 1209 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1 1210 * 4. KRB5_CRYPTO_TYPE_TRAILER 1211 */ 1212 1213 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1214 krb5_encrypt_iov_ivec(krb5_context context, 1215 krb5_crypto crypto, 1216 unsigned usage, 1217 krb5_crypto_iov *data, 1218 int num_data, 1219 void *ivec) 1220 { 1221 size_t headersz, trailersz, len; 1222 int i; 1223 size_t sz, block_sz, pad_sz; 1224 Checksum cksum; 1225 unsigned char *p, *q; 1226 krb5_error_code ret; 1227 struct _krb5_key_data *dkey; 1228 const struct _krb5_encryption_type *et = crypto->et; 1229 krb5_crypto_iov *tiv, *piv, *hiv; 1230 1231 if (num_data < 0) { 1232 krb5_clear_error_message(context); 1233 return KRB5_CRYPTO_INTERNAL; 1234 } 1235 1236 if(!derived_crypto(context, crypto)) { 1237 krb5_clear_error_message(context); 1238 return KRB5_CRYPTO_INTERNAL; 1239 } 1240 1241 headersz = et->confoundersize; 1242 trailersz = CHECKSUMSIZE(et->keyed_checksum); 1243 1244 for (len = 0, i = 0; i < num_data; i++) { 1245 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1246 continue; 1247 len += data[i].data.length; 1248 } 1249 1250 sz = headersz + len; 1251 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 1252 1253 pad_sz = block_sz - sz; 1254 1255 /* header */ 1256 1257 hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); 1258 if (hiv == NULL || hiv->data.length != headersz) 1259 return KRB5_BAD_MSIZE; 1260 1261 krb5_generate_random_block(hiv->data.data, hiv->data.length); 1262 1263 /* padding */ 1264 piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING); 1265 /* its ok to have no TYPE_PADDING if there is no padding */ 1266 if (piv == NULL && pad_sz != 0) 1267 return KRB5_BAD_MSIZE; 1268 if (piv) { 1269 if (piv->data.length < pad_sz) 1270 return KRB5_BAD_MSIZE; 1271 piv->data.length = pad_sz; 1272 if (pad_sz) 1273 memset(piv->data.data, pad_sz, pad_sz); 1274 else 1275 piv = NULL; 1276 } 1277 1278 /* trailer */ 1279 tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); 1280 if (tiv == NULL || tiv->data.length != trailersz) 1281 return KRB5_BAD_MSIZE; 1282 1283 /* 1284 * XXX replace with EVP_Sign? at least make create_checksum an iov 1285 * function. 1286 * XXX CTS EVP is broken, can't handle multi buffers :( 1287 */ 1288 1289 len = block_sz; 1290 for (i = 0; i < num_data; i++) { 1291 if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1292 continue; 1293 len += data[i].data.length; 1294 } 1295 1296 p = q = malloc(len); 1297 1298 memcpy(q, hiv->data.data, hiv->data.length); 1299 q += hiv->data.length; 1300 for (i = 0; i < num_data; i++) { 1301 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1302 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1303 continue; 1304 memcpy(q, data[i].data.data, data[i].data.length); 1305 q += data[i].data.length; 1306 } 1307 if (piv) 1308 memset(q, 0, piv->data.length); 1309 1310 ret = create_checksum(context, 1311 et->keyed_checksum, 1312 crypto, 1313 INTEGRITY_USAGE(usage), 1314 p, 1315 len, 1316 &cksum); 1317 free(p); 1318 if(ret == 0 && cksum.checksum.length != trailersz) { 1319 free_Checksum (&cksum); 1320 krb5_clear_error_message (context); 1321 ret = KRB5_CRYPTO_INTERNAL; 1322 } 1323 if(ret) 1324 return ret; 1325 1326 /* save cksum at end */ 1327 memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length); 1328 free_Checksum (&cksum); 1329 1330 /* XXX replace with EVP_Cipher */ 1331 p = q = malloc(block_sz); 1332 if(p == NULL) 1333 return ENOMEM; 1334 1335 memcpy(q, hiv->data.data, hiv->data.length); 1336 q += hiv->data.length; 1337 1338 for (i = 0; i < num_data; i++) { 1339 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1340 continue; 1341 memcpy(q, data[i].data.data, data[i].data.length); 1342 q += data[i].data.length; 1343 } 1344 if (piv) 1345 memset(q, 0, piv->data.length); 1346 1347 1348 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 1349 if(ret) { 1350 free(p); 1351 return ret; 1352 } 1353 ret = _key_schedule(context, dkey); 1354 if(ret) { 1355 free(p); 1356 return ret; 1357 } 1358 1359 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); 1360 if (ret) { 1361 free(p); 1362 return ret; 1363 } 1364 1365 /* now copy data back to buffers */ 1366 q = p; 1367 1368 memcpy(hiv->data.data, q, hiv->data.length); 1369 q += hiv->data.length; 1370 1371 for (i = 0; i < num_data; i++) { 1372 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1373 continue; 1374 memcpy(data[i].data.data, q, data[i].data.length); 1375 q += data[i].data.length; 1376 } 1377 if (piv) 1378 memcpy(piv->data.data, q, pad_sz); 1379 1380 free(p); 1381 1382 return ret; 1383 } 1384 1385 /** 1386 * Inline decrypt a Kerberos message. 1387 * 1388 * @param context Kerberos context 1389 * @param crypto Kerberos crypto context 1390 * @param usage Key usage for this buffer 1391 * @param data array of buffers to process 1392 * @param num_data length of array 1393 * @param ivec initial cbc/cts vector 1394 * 1395 * @return Return an error code or 0. 1396 * @ingroup krb5_crypto 1397 * 1398 * 1. KRB5_CRYPTO_TYPE_HEADER 1399 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in 1400 * any order, however the receiver have to aware of the 1401 * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted 1402 * protocol headers and trailers. The output data will be of same 1403 * size as the input data or shorter. 1404 */ 1405 1406 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1407 krb5_decrypt_iov_ivec(krb5_context context, 1408 krb5_crypto crypto, 1409 unsigned usage, 1410 krb5_crypto_iov *data, 1411 unsigned int num_data, 1412 void *ivec) 1413 { 1414 unsigned int i; 1415 size_t headersz, trailersz, len; 1416 Checksum cksum; 1417 unsigned char *p, *q; 1418 krb5_error_code ret; 1419 struct _krb5_key_data *dkey; 1420 struct _krb5_encryption_type *et = crypto->et; 1421 krb5_crypto_iov *tiv, *hiv; 1422 1423 if(!derived_crypto(context, crypto)) { 1424 krb5_clear_error_message(context); 1425 return KRB5_CRYPTO_INTERNAL; 1426 } 1427 1428 headersz = et->confoundersize; 1429 1430 hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); 1431 if (hiv == NULL || hiv->data.length != headersz) 1432 return KRB5_BAD_MSIZE; 1433 1434 /* trailer */ 1435 trailersz = CHECKSUMSIZE(et->keyed_checksum); 1436 1437 tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); 1438 if (tiv->data.length != trailersz) 1439 return KRB5_BAD_MSIZE; 1440 1441 /* Find length of data we will decrypt */ 1442 1443 len = headersz; 1444 for (i = 0; i < num_data; i++) { 1445 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1446 continue; 1447 len += data[i].data.length; 1448 } 1449 1450 if ((len % et->padsize) != 0) { 1451 krb5_clear_error_message(context); 1452 return KRB5_BAD_MSIZE; 1453 } 1454 1455 /* XXX replace with EVP_Cipher */ 1456 1457 p = q = malloc(len); 1458 if (p == NULL) 1459 return ENOMEM; 1460 1461 memcpy(q, hiv->data.data, hiv->data.length); 1462 q += hiv->data.length; 1463 1464 for (i = 0; i < num_data; i++) { 1465 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1466 continue; 1467 memcpy(q, data[i].data.data, data[i].data.length); 1468 q += data[i].data.length; 1469 } 1470 1471 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 1472 if(ret) { 1473 free(p); 1474 return ret; 1475 } 1476 ret = _key_schedule(context, dkey); 1477 if(ret) { 1478 free(p); 1479 return ret; 1480 } 1481 1482 ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); 1483 if (ret) { 1484 free(p); 1485 return ret; 1486 } 1487 1488 /* copy data back to buffers */ 1489 memcpy(hiv->data.data, p, hiv->data.length); 1490 q = p + hiv->data.length; 1491 for (i = 0; i < num_data; i++) { 1492 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1493 continue; 1494 memcpy(data[i].data.data, q, data[i].data.length); 1495 q += data[i].data.length; 1496 } 1497 1498 free(p); 1499 1500 /* check signature */ 1501 for (i = 0; i < num_data; i++) { 1502 if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1503 continue; 1504 len += data[i].data.length; 1505 } 1506 1507 p = q = malloc(len); 1508 if (p == NULL) 1509 return ENOMEM; 1510 1511 memcpy(q, hiv->data.data, hiv->data.length); 1512 q += hiv->data.length; 1513 for (i = 0; i < num_data; i++) { 1514 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1515 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1516 continue; 1517 memcpy(q, data[i].data.data, data[i].data.length); 1518 q += data[i].data.length; 1519 } 1520 1521 cksum.checksum.data = tiv->data.data; 1522 cksum.checksum.length = tiv->data.length; 1523 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 1524 1525 ret = verify_checksum(context, 1526 crypto, 1527 INTEGRITY_USAGE(usage), 1528 p, 1529 len, 1530 &cksum); 1531 free(p); 1532 return ret; 1533 } 1534 1535 /** 1536 * Create a Kerberos message checksum. 1537 * 1538 * @param context Kerberos context 1539 * @param crypto Kerberos crypto context 1540 * @param usage Key usage for this buffer 1541 * @param data array of buffers to process 1542 * @param num_data length of array 1543 * @param type output data 1544 * 1545 * @return Return an error code or 0. 1546 * @ingroup krb5_crypto 1547 */ 1548 1549 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1550 krb5_create_checksum_iov(krb5_context context, 1551 krb5_crypto crypto, 1552 unsigned usage, 1553 krb5_crypto_iov *data, 1554 unsigned int num_data, 1555 krb5_cksumtype *type) 1556 { 1557 Checksum cksum; 1558 krb5_crypto_iov *civ; 1559 krb5_error_code ret; 1560 size_t i; 1561 size_t len; 1562 char *p, *q; 1563 1564 if(!derived_crypto(context, crypto)) { 1565 krb5_clear_error_message(context); 1566 return KRB5_CRYPTO_INTERNAL; 1567 } 1568 1569 civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); 1570 if (civ == NULL) 1571 return KRB5_BAD_MSIZE; 1572 1573 len = 0; 1574 for (i = 0; i < num_data; i++) { 1575 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1576 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1577 continue; 1578 len += data[i].data.length; 1579 } 1580 1581 p = q = malloc(len); 1582 1583 for (i = 0; i < num_data; i++) { 1584 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1585 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1586 continue; 1587 memcpy(q, data[i].data.data, data[i].data.length); 1588 q += data[i].data.length; 1589 } 1590 1591 ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum); 1592 free(p); 1593 if (ret) 1594 return ret; 1595 1596 if (type) 1597 *type = cksum.cksumtype; 1598 1599 if (cksum.checksum.length > civ->data.length) { 1600 krb5_set_error_message(context, KRB5_BAD_MSIZE, 1601 N_("Checksum larger then input buffer", "")); 1602 free_Checksum(&cksum); 1603 return KRB5_BAD_MSIZE; 1604 } 1605 1606 civ->data.length = cksum.checksum.length; 1607 memcpy(civ->data.data, cksum.checksum.data, civ->data.length); 1608 free_Checksum(&cksum); 1609 1610 return 0; 1611 } 1612 1613 /** 1614 * Verify a Kerberos message checksum. 1615 * 1616 * @param context Kerberos context 1617 * @param crypto Kerberos crypto context 1618 * @param usage Key usage for this buffer 1619 * @param data array of buffers to process 1620 * @param num_data length of array 1621 * @param type return checksum type if not NULL 1622 * 1623 * @return Return an error code or 0. 1624 * @ingroup krb5_crypto 1625 */ 1626 1627 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1628 krb5_verify_checksum_iov(krb5_context context, 1629 krb5_crypto crypto, 1630 unsigned usage, 1631 krb5_crypto_iov *data, 1632 unsigned int num_data, 1633 krb5_cksumtype *type) 1634 { 1635 struct _krb5_encryption_type *et = crypto->et; 1636 Checksum cksum; 1637 krb5_crypto_iov *civ; 1638 krb5_error_code ret; 1639 size_t i; 1640 size_t len; 1641 char *p, *q; 1642 1643 if(!derived_crypto(context, crypto)) { 1644 krb5_clear_error_message(context); 1645 return KRB5_CRYPTO_INTERNAL; 1646 } 1647 1648 civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); 1649 if (civ == NULL) 1650 return KRB5_BAD_MSIZE; 1651 1652 len = 0; 1653 for (i = 0; i < num_data; i++) { 1654 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1655 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1656 continue; 1657 len += data[i].data.length; 1658 } 1659 1660 p = q = malloc(len); 1661 1662 for (i = 0; i < num_data; i++) { 1663 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1664 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1665 continue; 1666 memcpy(q, data[i].data.data, data[i].data.length); 1667 q += data[i].data.length; 1668 } 1669 1670 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 1671 cksum.checksum.length = civ->data.length; 1672 cksum.checksum.data = civ->data.data; 1673 1674 ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum); 1675 free(p); 1676 1677 if (ret == 0 && type) 1678 *type = cksum.cksumtype; 1679 1680 return ret; 1681 } 1682 1683 1684 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1685 krb5_crypto_length(krb5_context context, 1686 krb5_crypto crypto, 1687 int type, 1688 size_t *len) 1689 { 1690 if (!derived_crypto(context, crypto)) { 1691 krb5_set_error_message(context, EINVAL, "not a derived crypto"); 1692 return EINVAL; 1693 } 1694 1695 switch(type) { 1696 case KRB5_CRYPTO_TYPE_EMPTY: 1697 *len = 0; 1698 return 0; 1699 case KRB5_CRYPTO_TYPE_HEADER: 1700 *len = crypto->et->blocksize; 1701 return 0; 1702 case KRB5_CRYPTO_TYPE_DATA: 1703 case KRB5_CRYPTO_TYPE_SIGN_ONLY: 1704 /* len must already been filled in */ 1705 return 0; 1706 case KRB5_CRYPTO_TYPE_PADDING: 1707 if (crypto->et->padsize > 1) 1708 *len = crypto->et->padsize; 1709 else 1710 *len = 0; 1711 return 0; 1712 case KRB5_CRYPTO_TYPE_TRAILER: 1713 *len = CHECKSUMSIZE(crypto->et->keyed_checksum); 1714 return 0; 1715 case KRB5_CRYPTO_TYPE_CHECKSUM: 1716 if (crypto->et->keyed_checksum) 1717 *len = CHECKSUMSIZE(crypto->et->keyed_checksum); 1718 else 1719 *len = CHECKSUMSIZE(crypto->et->checksum); 1720 return 0; 1721 } 1722 krb5_set_error_message(context, EINVAL, 1723 "%d not a supported type", type); 1724 return EINVAL; 1725 } 1726 1727 1728 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1729 krb5_crypto_length_iov(krb5_context context, 1730 krb5_crypto crypto, 1731 krb5_crypto_iov *data, 1732 unsigned int num_data) 1733 { 1734 krb5_error_code ret; 1735 size_t i; 1736 1737 for (i = 0; i < num_data; i++) { 1738 ret = krb5_crypto_length(context, crypto, 1739 data[i].flags, 1740 &data[i].data.length); 1741 if (ret) 1742 return ret; 1743 } 1744 return 0; 1745 } 1746 1747 1748 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1749 krb5_encrypt_ivec(krb5_context context, 1750 krb5_crypto crypto, 1751 unsigned usage, 1752 const void *data, 1753 size_t len, 1754 krb5_data *result, 1755 void *ivec) 1756 { 1757 if(derived_crypto(context, crypto)) 1758 return encrypt_internal_derived(context, crypto, usage, 1759 data, len, result, ivec); 1760 else if (special_crypto(context, crypto)) 1761 return encrypt_internal_special (context, crypto, usage, 1762 data, len, result, ivec); 1763 else 1764 return encrypt_internal(context, crypto, data, len, result, ivec); 1765 } 1766 1767 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1768 krb5_encrypt(krb5_context context, 1769 krb5_crypto crypto, 1770 unsigned usage, 1771 const void *data, 1772 size_t len, 1773 krb5_data *result) 1774 { 1775 return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL); 1776 } 1777 1778 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1779 krb5_encrypt_EncryptedData(krb5_context context, 1780 krb5_crypto crypto, 1781 unsigned usage, 1782 void *data, 1783 size_t len, 1784 int kvno, 1785 EncryptedData *result) 1786 { 1787 result->etype = CRYPTO_ETYPE(crypto); 1788 if(kvno){ 1789 ALLOC(result->kvno, 1); 1790 *result->kvno = kvno; 1791 }else 1792 result->kvno = NULL; 1793 return krb5_encrypt(context, crypto, usage, data, len, &result->cipher); 1794 } 1795 1796 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1797 krb5_decrypt_ivec(krb5_context context, 1798 krb5_crypto crypto, 1799 unsigned usage, 1800 void *data, 1801 size_t len, 1802 krb5_data *result, 1803 void *ivec) 1804 { 1805 if(derived_crypto(context, crypto)) 1806 return decrypt_internal_derived(context, crypto, usage, 1807 data, len, result, ivec); 1808 else if (special_crypto (context, crypto)) 1809 return decrypt_internal_special(context, crypto, usage, 1810 data, len, result, ivec); 1811 else 1812 return decrypt_internal(context, crypto, data, len, result, ivec); 1813 } 1814 1815 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1816 krb5_decrypt(krb5_context context, 1817 krb5_crypto crypto, 1818 unsigned usage, 1819 void *data, 1820 size_t len, 1821 krb5_data *result) 1822 { 1823 return krb5_decrypt_ivec (context, crypto, usage, data, len, result, 1824 NULL); 1825 } 1826 1827 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1828 krb5_decrypt_EncryptedData(krb5_context context, 1829 krb5_crypto crypto, 1830 unsigned usage, 1831 const EncryptedData *e, 1832 krb5_data *result) 1833 { 1834 return krb5_decrypt(context, crypto, usage, 1835 e->cipher.data, e->cipher.length, result); 1836 } 1837 1838 /************************************************************ 1839 * * 1840 ************************************************************/ 1841 1842 krb5_error_code 1843 _krb5_derive_key(krb5_context context, 1844 struct _krb5_encryption_type *et, 1845 struct _krb5_key_data *key, 1846 const void *constant, 1847 size_t len) 1848 { 1849 unsigned char *k = NULL; 1850 unsigned int nblocks = 0, i; 1851 krb5_error_code ret = 0; 1852 struct _krb5_key_type *kt = et->keytype; 1853 1854 ret = _key_schedule(context, key); 1855 if(ret) 1856 return ret; 1857 if(et->blocksize * 8 < kt->bits || len != et->blocksize) { 1858 nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); 1859 k = malloc(nblocks * et->blocksize); 1860 if(k == NULL) { 1861 ret = ENOMEM; 1862 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1863 goto out; 1864 } 1865 ret = _krb5_n_fold(constant, len, k, et->blocksize); 1866 if (ret) { 1867 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1868 goto out; 1869 } 1870 1871 for(i = 0; i < nblocks; i++) { 1872 if(i > 0) 1873 memcpy(k + i * et->blocksize, 1874 k + (i - 1) * et->blocksize, 1875 et->blocksize); 1876 (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize, 1877 1, 0, NULL); 1878 } 1879 } else { 1880 /* this case is probably broken, but won't be run anyway */ 1881 void *c = malloc(len); 1882 size_t res_len = (kt->bits + 7) / 8; 1883 1884 if(len != 0 && c == NULL) { 1885 ret = ENOMEM; 1886 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1887 goto out; 1888 } 1889 memcpy(c, constant, len); 1890 (*et->encrypt)(context, key, c, len, 1, 0, NULL); 1891 k = malloc(res_len); 1892 if(res_len != 0 && k == NULL) { 1893 free(c); 1894 ret = ENOMEM; 1895 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1896 goto out; 1897 } 1898 ret = _krb5_n_fold(c, len, k, res_len); 1899 free(c); 1900 if (ret) { 1901 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1902 goto out; 1903 } 1904 } 1905 1906 /* XXX keytype dependent post-processing */ 1907 switch(kt->type) { 1908 case ETYPE_OLD_DES3_CBC_SHA1: 1909 _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); 1910 break; 1911 case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 1912 case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 1913 memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); 1914 break; 1915 default: 1916 ret = KRB5_CRYPTO_INTERNAL; 1917 krb5_set_error_message(context, ret, 1918 N_("derive_key() called with unknown keytype (%u)", ""), 1919 kt->type); 1920 break; 1921 } 1922 out: 1923 if (key->schedule) { 1924 free_key_schedule(context, key, et); 1925 key->schedule = NULL; 1926 } 1927 if (k) { 1928 memset(k, 0, nblocks * et->blocksize); 1929 free(k); 1930 } 1931 return ret; 1932 } 1933 1934 static struct _krb5_key_data * 1935 _new_derived_key(krb5_crypto crypto, unsigned usage) 1936 { 1937 struct _krb5_key_usage *d = crypto->key_usage; 1938 d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d)); 1939 if(d == NULL) 1940 return NULL; 1941 crypto->key_usage = d; 1942 d += crypto->num_key_usage++; 1943 memset(d, 0, sizeof(*d)); 1944 d->usage = usage; 1945 return &d->key; 1946 } 1947 1948 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1949 krb5_derive_key(krb5_context context, 1950 const krb5_keyblock *key, 1951 krb5_enctype etype, 1952 const void *constant, 1953 size_t constant_len, 1954 krb5_keyblock **derived_key) 1955 { 1956 krb5_error_code ret; 1957 struct _krb5_encryption_type *et; 1958 struct _krb5_key_data d; 1959 1960 *derived_key = NULL; 1961 1962 et = _krb5_find_enctype (etype); 1963 if (et == NULL) { 1964 return unsupported_enctype (context, etype); 1965 } 1966 1967 ret = krb5_copy_keyblock(context, key, &d.key); 1968 if (ret) 1969 return ret; 1970 1971 d.schedule = NULL; 1972 ret = _krb5_derive_key(context, et, &d, constant, constant_len); 1973 if (ret == 0) 1974 ret = krb5_copy_keyblock(context, d.key, derived_key); 1975 _krb5_free_key_data(context, &d, et); 1976 return ret; 1977 } 1978 1979 static krb5_error_code 1980 _get_derived_key(krb5_context context, 1981 krb5_crypto crypto, 1982 unsigned usage, 1983 struct _krb5_key_data **key) 1984 { 1985 int i; 1986 struct _krb5_key_data *d; 1987 unsigned char constant[5]; 1988 1989 for(i = 0; i < crypto->num_key_usage; i++) 1990 if(crypto->key_usage[i].usage == usage) { 1991 *key = &crypto->key_usage[i].key; 1992 return 0; 1993 } 1994 d = _new_derived_key(crypto, usage); 1995 if(d == NULL) { 1996 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1997 return ENOMEM; 1998 } 1999 krb5_copy_keyblock(context, crypto->key.key, &d->key); 2000 _krb5_put_int(constant, usage, 5); 2001 _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant)); 2002 *key = d; 2003 return 0; 2004 } 2005 2006 /** 2007 * Create a crypto context used for all encryption and signature 2008 * operation. The encryption type to use is taken from the key, but 2009 * can be overridden with the enctype parameter. This can be useful 2010 * for encryptions types which is compatiable (DES for example). 2011 * 2012 * To free the crypto context, use krb5_crypto_destroy(). 2013 * 2014 * @param context Kerberos context 2015 * @param key the key block information with all key data 2016 * @param etype the encryption type 2017 * @param crypto the resulting crypto context 2018 * 2019 * @return Return an error code or 0. 2020 * 2021 * @ingroup krb5_crypto 2022 */ 2023 2024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2025 krb5_crypto_init(krb5_context context, 2026 const krb5_keyblock *key, 2027 krb5_enctype etype, 2028 krb5_crypto *crypto) 2029 { 2030 krb5_error_code ret; 2031 ALLOC(*crypto, 1); 2032 if(*crypto == NULL) { 2033 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 2034 return ENOMEM; 2035 } 2036 if(etype == ETYPE_NULL) 2037 etype = key->keytype; 2038 (*crypto)->et = _krb5_find_enctype(etype); 2039 if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) { 2040 free(*crypto); 2041 *crypto = NULL; 2042 return unsupported_enctype(context, etype); 2043 } 2044 if((*crypto)->et->keytype->size != key->keyvalue.length) { 2045 free(*crypto); 2046 *crypto = NULL; 2047 krb5_set_error_message (context, KRB5_BAD_KEYSIZE, 2048 "encryption key has bad length"); 2049 return KRB5_BAD_KEYSIZE; 2050 } 2051 ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key); 2052 if(ret) { 2053 free(*crypto); 2054 *crypto = NULL; 2055 return ret; 2056 } 2057 (*crypto)->key.schedule = NULL; 2058 (*crypto)->num_key_usage = 0; 2059 (*crypto)->key_usage = NULL; 2060 return 0; 2061 } 2062 2063 static void 2064 free_key_schedule(krb5_context context, 2065 struct _krb5_key_data *key, 2066 struct _krb5_encryption_type *et) 2067 { 2068 if (et->keytype->cleanup) 2069 (*et->keytype->cleanup)(context, key); 2070 memset(key->schedule->data, 0, key->schedule->length); 2071 krb5_free_data(context, key->schedule); 2072 } 2073 2074 void 2075 _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key, 2076 struct _krb5_encryption_type *et) 2077 { 2078 krb5_free_keyblock(context, key->key); 2079 if(key->schedule) { 2080 free_key_schedule(context, key, et); 2081 key->schedule = NULL; 2082 } 2083 } 2084 2085 static void 2086 free_key_usage(krb5_context context, struct _krb5_key_usage *ku, 2087 struct _krb5_encryption_type *et) 2088 { 2089 _krb5_free_key_data(context, &ku->key, et); 2090 } 2091 2092 /** 2093 * Free a crypto context created by krb5_crypto_init(). 2094 * 2095 * @param context Kerberos context 2096 * @param crypto crypto context to free 2097 * 2098 * @return Return an error code or 0. 2099 * 2100 * @ingroup krb5_crypto 2101 */ 2102 2103 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2104 krb5_crypto_destroy(krb5_context context, 2105 krb5_crypto crypto) 2106 { 2107 int i; 2108 2109 for(i = 0; i < crypto->num_key_usage; i++) 2110 free_key_usage(context, &crypto->key_usage[i], crypto->et); 2111 free(crypto->key_usage); 2112 _krb5_free_key_data(context, &crypto->key, crypto->et); 2113 free (crypto); 2114 return 0; 2115 } 2116 2117 /** 2118 * Return the blocksize used algorithm referenced by the crypto context 2119 * 2120 * @param context Kerberos context 2121 * @param crypto crypto context to query 2122 * @param blocksize the resulting blocksize 2123 * 2124 * @return Return an error code or 0. 2125 * 2126 * @ingroup krb5_crypto 2127 */ 2128 2129 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2130 krb5_crypto_getblocksize(krb5_context context, 2131 krb5_crypto crypto, 2132 size_t *blocksize) 2133 { 2134 *blocksize = crypto->et->blocksize; 2135 return 0; 2136 } 2137 2138 /** 2139 * Return the encryption type used by the crypto context 2140 * 2141 * @param context Kerberos context 2142 * @param crypto crypto context to query 2143 * @param enctype the resulting encryption type 2144 * 2145 * @return Return an error code or 0. 2146 * 2147 * @ingroup krb5_crypto 2148 */ 2149 2150 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2151 krb5_crypto_getenctype(krb5_context context, 2152 krb5_crypto crypto, 2153 krb5_enctype *enctype) 2154 { 2155 *enctype = crypto->et->type; 2156 return 0; 2157 } 2158 2159 /** 2160 * Return the padding size used by the crypto context 2161 * 2162 * @param context Kerberos context 2163 * @param crypto crypto context to query 2164 * @param padsize the return padding size 2165 * 2166 * @return Return an error code or 0. 2167 * 2168 * @ingroup krb5_crypto 2169 */ 2170 2171 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2172 krb5_crypto_getpadsize(krb5_context context, 2173 krb5_crypto crypto, 2174 size_t *padsize) 2175 { 2176 *padsize = crypto->et->padsize; 2177 return 0; 2178 } 2179 2180 /** 2181 * Return the confounder size used by the crypto context 2182 * 2183 * @param context Kerberos context 2184 * @param crypto crypto context to query 2185 * @param confoundersize the returned confounder size 2186 * 2187 * @return Return an error code or 0. 2188 * 2189 * @ingroup krb5_crypto 2190 */ 2191 2192 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2193 krb5_crypto_getconfoundersize(krb5_context context, 2194 krb5_crypto crypto, 2195 size_t *confoundersize) 2196 { 2197 *confoundersize = crypto->et->confoundersize; 2198 return 0; 2199 } 2200 2201 2202 /** 2203 * Disable encryption type 2204 * 2205 * @param context Kerberos 5 context 2206 * @param enctype encryption type to disable 2207 * 2208 * @return Return an error code or 0. 2209 * 2210 * @ingroup krb5_crypto 2211 */ 2212 2213 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2214 krb5_enctype_disable(krb5_context context, 2215 krb5_enctype enctype) 2216 { 2217 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); 2218 if(et == NULL) { 2219 if (context) 2220 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 2221 N_("encryption type %d not supported", ""), 2222 enctype); 2223 return KRB5_PROG_ETYPE_NOSUPP; 2224 } 2225 et->flags |= F_DISABLED; 2226 return 0; 2227 } 2228 2229 /** 2230 * Enable encryption type 2231 * 2232 * @param context Kerberos 5 context 2233 * @param enctype encryption type to enable 2234 * 2235 * @return Return an error code or 0. 2236 * 2237 * @ingroup krb5_crypto 2238 */ 2239 2240 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2241 krb5_enctype_enable(krb5_context context, 2242 krb5_enctype enctype) 2243 { 2244 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); 2245 if(et == NULL) { 2246 if (context) 2247 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 2248 N_("encryption type %d not supported", ""), 2249 enctype); 2250 return KRB5_PROG_ETYPE_NOSUPP; 2251 } 2252 et->flags &= ~F_DISABLED; 2253 return 0; 2254 } 2255 2256 /** 2257 * Enable or disable all weak encryption types 2258 * 2259 * @param context Kerberos 5 context 2260 * @param enable true to enable, false to disable 2261 * 2262 * @return Return an error code or 0. 2263 * 2264 * @ingroup krb5_crypto 2265 */ 2266 2267 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2268 krb5_allow_weak_crypto(krb5_context context, 2269 krb5_boolean enable) 2270 { 2271 int i; 2272 2273 for(i = 0; i < _krb5_num_etypes; i++) 2274 if(_krb5_etypes[i]->flags & F_WEAK) { 2275 if(enable) 2276 _krb5_etypes[i]->flags &= ~F_DISABLED; 2277 else 2278 _krb5_etypes[i]->flags |= F_DISABLED; 2279 } 2280 return 0; 2281 } 2282 2283 static size_t 2284 wrapped_length (krb5_context context, 2285 krb5_crypto crypto, 2286 size_t data_len) 2287 { 2288 struct _krb5_encryption_type *et = crypto->et; 2289 size_t padsize = et->padsize; 2290 size_t checksumsize = CHECKSUMSIZE(et->checksum); 2291 size_t res; 2292 2293 res = et->confoundersize + checksumsize + data_len; 2294 res = (res + padsize - 1) / padsize * padsize; 2295 return res; 2296 } 2297 2298 static size_t 2299 wrapped_length_dervied (krb5_context context, 2300 krb5_crypto crypto, 2301 size_t data_len) 2302 { 2303 struct _krb5_encryption_type *et = crypto->et; 2304 size_t padsize = et->padsize; 2305 size_t res; 2306 2307 res = et->confoundersize + data_len; 2308 res = (res + padsize - 1) / padsize * padsize; 2309 if (et->keyed_checksum) 2310 res += et->keyed_checksum->checksumsize; 2311 else 2312 res += et->checksum->checksumsize; 2313 return res; 2314 } 2315 2316 /* 2317 * Return the size of an encrypted packet of length `data_len' 2318 */ 2319 2320 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 2321 krb5_get_wrapped_length (krb5_context context, 2322 krb5_crypto crypto, 2323 size_t data_len) 2324 { 2325 if (derived_crypto (context, crypto)) 2326 return wrapped_length_dervied (context, crypto, data_len); 2327 else 2328 return wrapped_length (context, crypto, data_len); 2329 } 2330 2331 /* 2332 * Return the size of an encrypted packet of length `data_len' 2333 */ 2334 2335 static size_t 2336 crypto_overhead (krb5_context context, 2337 krb5_crypto crypto) 2338 { 2339 struct _krb5_encryption_type *et = crypto->et; 2340 size_t res; 2341 2342 res = CHECKSUMSIZE(et->checksum); 2343 res += et->confoundersize; 2344 if (et->padsize > 1) 2345 res += et->padsize; 2346 return res; 2347 } 2348 2349 static size_t 2350 crypto_overhead_dervied (krb5_context context, 2351 krb5_crypto crypto) 2352 { 2353 struct _krb5_encryption_type *et = crypto->et; 2354 size_t res; 2355 2356 if (et->keyed_checksum) 2357 res = CHECKSUMSIZE(et->keyed_checksum); 2358 else 2359 res = CHECKSUMSIZE(et->checksum); 2360 res += et->confoundersize; 2361 if (et->padsize > 1) 2362 res += et->padsize; 2363 return res; 2364 } 2365 2366 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 2367 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto) 2368 { 2369 if (derived_crypto (context, crypto)) 2370 return crypto_overhead_dervied (context, crypto); 2371 else 2372 return crypto_overhead (context, crypto); 2373 } 2374 2375 /** 2376 * Converts the random bytestring to a protocol key according to 2377 * Kerberos crypto frame work. It may be assumed that all the bits of 2378 * the input string are equally random, even though the entropy 2379 * present in the random source may be limited. 2380 * 2381 * @param context Kerberos 5 context 2382 * @param type the enctype resulting key will be of 2383 * @param data input random data to convert to a key 2384 * @param size size of input random data, at least krb5_enctype_keysize() long 2385 * @param key key, output key, free with krb5_free_keyblock_contents() 2386 * 2387 * @return Return an error code or 0. 2388 * 2389 * @ingroup krb5_crypto 2390 */ 2391 2392 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2393 krb5_random_to_key(krb5_context context, 2394 krb5_enctype type, 2395 const void *data, 2396 size_t size, 2397 krb5_keyblock *key) 2398 { 2399 krb5_error_code ret; 2400 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 2401 if(et == NULL) { 2402 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2403 N_("encryption type %d not supported", ""), 2404 type); 2405 return KRB5_PROG_ETYPE_NOSUPP; 2406 } 2407 if ((et->keytype->bits + 7) / 8 > size) { 2408 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2409 N_("encryption key %s needs %d bytes " 2410 "of random to make an encryption key " 2411 "out of it", ""), 2412 et->name, (int)et->keytype->size); 2413 return KRB5_PROG_ETYPE_NOSUPP; 2414 } 2415 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); 2416 if(ret) 2417 return ret; 2418 key->keytype = type; 2419 if (et->keytype->random_to_key) 2420 (*et->keytype->random_to_key)(context, key, data, size); 2421 else 2422 memcpy(key->keyvalue.data, data, et->keytype->size); 2423 2424 return 0; 2425 } 2426 2427 2428 2429 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2430 krb5_crypto_prf_length(krb5_context context, 2431 krb5_enctype type, 2432 size_t *length) 2433 { 2434 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 2435 2436 if(et == NULL || et->prf_length == 0) { 2437 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2438 N_("encryption type %d not supported", ""), 2439 type); 2440 return KRB5_PROG_ETYPE_NOSUPP; 2441 } 2442 2443 *length = et->prf_length; 2444 return 0; 2445 } 2446 2447 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2448 krb5_crypto_prf(krb5_context context, 2449 const krb5_crypto crypto, 2450 const krb5_data *input, 2451 krb5_data *output) 2452 { 2453 struct _krb5_encryption_type *et = crypto->et; 2454 2455 krb5_data_zero(output); 2456 2457 if(et->prf == NULL) { 2458 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2459 "kerberos prf for %s not supported", 2460 et->name); 2461 return KRB5_PROG_ETYPE_NOSUPP; 2462 } 2463 2464 return (*et->prf)(context, crypto, input, output); 2465 } 2466 2467 static krb5_error_code 2468 krb5_crypto_prfplus(krb5_context context, 2469 const krb5_crypto crypto, 2470 const krb5_data *input, 2471 size_t length, 2472 krb5_data *output) 2473 { 2474 krb5_error_code ret; 2475 krb5_data input2; 2476 unsigned char i = 1; 2477 unsigned char *p; 2478 2479 krb5_data_zero(&input2); 2480 krb5_data_zero(output); 2481 2482 krb5_clear_error_message(context); 2483 2484 ret = krb5_data_alloc(output, length); 2485 if (ret) goto out; 2486 ret = krb5_data_alloc(&input2, input->length + 1); 2487 if (ret) goto out; 2488 2489 krb5_clear_error_message(context); 2490 2491 memcpy(((unsigned char *)input2.data) + 1, input->data, input->length); 2492 2493 p = output->data; 2494 2495 while (length) { 2496 krb5_data block; 2497 2498 ((unsigned char *)input2.data)[0] = i++; 2499 2500 ret = krb5_crypto_prf(context, crypto, &input2, &block); 2501 if (ret) 2502 goto out; 2503 2504 if (block.length < length) { 2505 memcpy(p, block.data, block.length); 2506 length -= block.length; 2507 } else { 2508 memcpy(p, block.data, length); 2509 length = 0; 2510 } 2511 p += block.length; 2512 krb5_data_free(&block); 2513 } 2514 2515 out: 2516 krb5_data_free(&input2); 2517 if (ret) 2518 krb5_data_free(output); 2519 return 0; 2520 } 2521 2522 /** 2523 * The FX-CF2 key derivation function, used in FAST and preauth framework. 2524 * 2525 * @param context Kerberos 5 context 2526 * @param crypto1 first key to combine 2527 * @param crypto2 second key to combine 2528 * @param pepper1 factor to combine with first key to garante uniqueness 2529 * @param pepper2 factor to combine with second key to garante uniqueness 2530 * @param enctype the encryption type of the resulting key 2531 * @param res allocated key, free with krb5_free_keyblock_contents() 2532 * 2533 * @return Return an error code or 0. 2534 * 2535 * @ingroup krb5_crypto 2536 */ 2537 2538 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2539 krb5_crypto_fx_cf2(krb5_context context, 2540 const krb5_crypto crypto1, 2541 const krb5_crypto crypto2, 2542 krb5_data *pepper1, 2543 krb5_data *pepper2, 2544 krb5_enctype enctype, 2545 krb5_keyblock *res) 2546 { 2547 krb5_error_code ret; 2548 krb5_data os1, os2; 2549 size_t i, keysize; 2550 2551 memset(res, 0, sizeof(*res)); 2552 2553 ret = krb5_enctype_keysize(context, enctype, &keysize); 2554 if (ret) 2555 return ret; 2556 2557 ret = krb5_data_alloc(&res->keyvalue, keysize); 2558 if (ret) 2559 goto out; 2560 ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1); 2561 if (ret) 2562 goto out; 2563 ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2); 2564 if (ret) 2565 goto out; 2566 2567 res->keytype = enctype; 2568 { 2569 unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data; 2570 for (i = 0; i < keysize; i++) 2571 p3[i] = p1[i] ^ p2[i]; 2572 } 2573 out: 2574 if (ret) 2575 krb5_data_free(&res->keyvalue); 2576 krb5_data_free(&os1); 2577 krb5_data_free(&os2); 2578 2579 return ret; 2580 } 2581 2582 2583 2584 #ifndef HEIMDAL_SMALLER 2585 2586 /** 2587 * Deprecated: keytypes doesn't exists, they are really enctypes. 2588 * 2589 * @ingroup krb5_deprecated 2590 */ 2591 2592 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2593 krb5_keytype_to_enctypes (krb5_context context, 2594 krb5_keytype keytype, 2595 unsigned *len, 2596 krb5_enctype **val) 2597 KRB5_DEPRECATED_FUNCTION("Use X instead") 2598 { 2599 int i; 2600 unsigned n = 0; 2601 krb5_enctype *ret; 2602 2603 for (i = _krb5_num_etypes - 1; i >= 0; --i) { 2604 if (_krb5_etypes[i]->keytype->type == keytype 2605 && !(_krb5_etypes[i]->flags & F_PSEUDO) 2606 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) 2607 ++n; 2608 } 2609 if (n == 0) { 2610 krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, 2611 "Keytype have no mapping"); 2612 return KRB5_PROG_KEYTYPE_NOSUPP; 2613 } 2614 2615 ret = malloc(n * sizeof(*ret)); 2616 if (ret == NULL && n != 0) { 2617 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 2618 return ENOMEM; 2619 } 2620 n = 0; 2621 for (i = _krb5_num_etypes - 1; i >= 0; --i) { 2622 if (_krb5_etypes[i]->keytype->type == keytype 2623 && !(_krb5_etypes[i]->flags & F_PSEUDO) 2624 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) 2625 ret[n++] = _krb5_etypes[i]->type; 2626 } 2627 *len = n; 2628 *val = ret; 2629 return 0; 2630 } 2631 2632 /** 2633 * Deprecated: keytypes doesn't exists, they are really enctypes. 2634 * 2635 * @ingroup krb5_deprecated 2636 */ 2637 2638 /* if two enctypes have compatible keys */ 2639 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 2640 krb5_enctypes_compatible_keys(krb5_context context, 2641 krb5_enctype etype1, 2642 krb5_enctype etype2) 2643 KRB5_DEPRECATED_FUNCTION("Use X instead") 2644 { 2645 struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1); 2646 struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2); 2647 return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; 2648 } 2649 2650 #endif /* HEIMDAL_SMALLER */ 2651