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