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