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