1 /* 2 * Copyright (c) 2000 - 2004 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 "hdb_locl.h" 35 #include <assert.h> 36 #ifndef O_BINARY 37 #define O_BINARY 0 38 #endif 39 40 struct hdb_master_key_data { 41 krb5_keytab_entry keytab; 42 krb5_crypto crypto; 43 struct hdb_master_key_data *next; 44 unsigned int key_usage; 45 }; 46 47 void 48 hdb_free_master_key(krb5_context context, hdb_master_key mkey) 49 { 50 struct hdb_master_key_data *ptr; 51 while(mkey) { 52 krb5_kt_free_entry(context, &mkey->keytab); 53 if (mkey->crypto) 54 krb5_crypto_destroy(context, mkey->crypto); 55 ptr = mkey; 56 mkey = mkey->next; 57 free(ptr); 58 } 59 } 60 61 krb5_error_code 62 hdb_process_master_key(krb5_context context, 63 int kvno, krb5_keyblock *key, krb5_enctype etype, 64 hdb_master_key *mkey) 65 { 66 krb5_error_code ret; 67 68 *mkey = calloc(1, sizeof(**mkey)); 69 if(*mkey == NULL) { 70 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 71 return ENOMEM; 72 } 73 (*mkey)->key_usage = HDB_KU_MKEY; 74 (*mkey)->keytab.vno = kvno; 75 ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); 76 if(ret) 77 goto fail; 78 ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock); 79 if(ret) 80 goto fail; 81 if(etype != 0) 82 (*mkey)->keytab.keyblock.keytype = etype; 83 (*mkey)->keytab.timestamp = time(NULL); 84 ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto); 85 if(ret) 86 goto fail; 87 return 0; 88 fail: 89 hdb_free_master_key(context, *mkey); 90 *mkey = NULL; 91 return ret; 92 } 93 94 krb5_error_code 95 hdb_add_master_key(krb5_context context, krb5_keyblock *key, 96 hdb_master_key *inout) 97 { 98 int vno = 0; 99 hdb_master_key p; 100 krb5_error_code ret; 101 102 for(p = *inout; p; p = p->next) 103 vno = max(vno, p->keytab.vno); 104 vno++; 105 ret = hdb_process_master_key(context, vno, key, 0, &p); 106 if(ret) 107 return ret; 108 p->next = *inout; 109 *inout = p; 110 return 0; 111 } 112 113 static krb5_error_code 114 read_master_keytab(krb5_context context, const char *filename, 115 hdb_master_key *mkey) 116 { 117 krb5_error_code ret; 118 krb5_keytab id; 119 krb5_kt_cursor cursor; 120 krb5_keytab_entry entry; 121 hdb_master_key p; 122 123 ret = krb5_kt_resolve(context, filename, &id); 124 if(ret) 125 return ret; 126 127 ret = krb5_kt_start_seq_get(context, id, &cursor); 128 if(ret) 129 goto out; 130 *mkey = NULL; 131 while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { 132 p = calloc(1, sizeof(*p)); 133 if(p == NULL) { 134 krb5_kt_end_seq_get(context, id, &cursor); 135 ret = ENOMEM; 136 goto out; 137 } 138 p->keytab = entry; 139 ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); 140 p->next = *mkey; 141 *mkey = p; 142 } 143 krb5_kt_end_seq_get(context, id, &cursor); 144 out: 145 krb5_kt_close(context, id); 146 return ret; 147 } 148 149 /* read a MIT master keyfile */ 150 static krb5_error_code 151 read_master_mit(krb5_context context, const char *filename, 152 int byteorder, hdb_master_key *mkey) 153 { 154 int fd; 155 krb5_error_code ret; 156 krb5_storage *sp; 157 int16_t enctype; 158 krb5_keyblock key; 159 160 fd = open(filename, O_RDONLY | O_BINARY); 161 if(fd < 0) { 162 int save_errno = errno; 163 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 164 filename, strerror(save_errno)); 165 return save_errno; 166 } 167 sp = krb5_storage_from_fd(fd); 168 if(sp == NULL) { 169 close(fd); 170 return errno; 171 } 172 krb5_storage_set_flags(sp, byteorder); 173 /* could possibly use ret_keyblock here, but do it with more 174 checks for now */ 175 { 176 ret = krb5_ret_int16(sp, &enctype); 177 if (ret) 178 goto out; 179 ret = krb5_enctype_valid(context, enctype); 180 if (ret) 181 goto out; 182 key.keytype = enctype; 183 ret = krb5_ret_data(sp, &key.keyvalue); 184 if(ret) 185 goto out; 186 } 187 ret = hdb_process_master_key(context, 1, &key, 0, mkey); 188 krb5_free_keyblock_contents(context, &key); 189 out: 190 krb5_storage_free(sp); 191 close(fd); 192 return ret; 193 } 194 195 /* read an old master key file */ 196 static krb5_error_code 197 read_master_encryptionkey(krb5_context context, const char *filename, 198 hdb_master_key *mkey) 199 { 200 int fd; 201 krb5_keyblock key; 202 krb5_error_code ret; 203 unsigned char buf[256]; 204 ssize_t len; 205 size_t ret_len; 206 207 fd = open(filename, O_RDONLY | O_BINARY); 208 if(fd < 0) { 209 int save_errno = errno; 210 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 211 filename, strerror(save_errno)); 212 return save_errno; 213 } 214 215 len = read(fd, buf, sizeof(buf)); 216 close(fd); 217 if(len < 0) { 218 int save_errno = errno; 219 krb5_set_error_message(context, save_errno, "error reading %s: %s", 220 filename, strerror(save_errno)); 221 return save_errno; 222 } 223 224 ret = decode_EncryptionKey(buf, len, &key, &ret_len); 225 memset(buf, 0, sizeof(buf)); 226 if(ret) 227 return ret; 228 229 /* Originally, the keytype was just that, and later it got changed 230 to des-cbc-md5, but we always used des in cfb64 mode. This 231 should cover all cases, but will break if someone has hacked 232 this code to really use des-cbc-md5 -- but then that's not my 233 problem. */ 234 if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5) 235 key.keytype = ETYPE_DES_CFB64_NONE; 236 237 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 238 krb5_free_keyblock_contents(context, &key); 239 return ret; 240 } 241 242 /* read a krb4 /.k style file */ 243 static krb5_error_code 244 read_master_krb4(krb5_context context, const char *filename, 245 hdb_master_key *mkey) 246 { 247 int fd; 248 krb5_keyblock key; 249 krb5_error_code ret; 250 unsigned char buf[256]; 251 ssize_t len; 252 253 fd = open(filename, O_RDONLY | O_BINARY); 254 if(fd < 0) { 255 int save_errno = errno; 256 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 257 filename, strerror(save_errno)); 258 return save_errno; 259 } 260 261 len = read(fd, buf, sizeof(buf)); 262 close(fd); 263 if(len < 0) { 264 int save_errno = errno; 265 krb5_set_error_message(context, save_errno, "error reading %s: %s", 266 filename, strerror(save_errno)); 267 return save_errno; 268 } 269 if(len != 8) { 270 krb5_set_error_message(context, HEIM_ERR_EOF, 271 "bad contents of %s", filename); 272 return HEIM_ERR_EOF; /* XXX file might be too large */ 273 } 274 275 memset(&key, 0, sizeof(key)); 276 key.keytype = ETYPE_DES_PCBC_NONE; 277 ret = krb5_data_copy(&key.keyvalue, buf, len); 278 memset(buf, 0, sizeof(buf)); 279 if(ret) 280 return ret; 281 282 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 283 krb5_free_keyblock_contents(context, &key); 284 return ret; 285 } 286 287 krb5_error_code 288 hdb_read_master_key(krb5_context context, const char *filename, 289 hdb_master_key *mkey) 290 { 291 FILE *f; 292 unsigned char buf[16]; 293 krb5_error_code ret; 294 295 off_t len; 296 297 *mkey = NULL; 298 299 if(filename == NULL) 300 filename = HDB_DB_DIR "/m-key"; 301 302 f = fopen(filename, "r"); 303 if(f == NULL) { 304 int save_errno = errno; 305 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 306 filename, strerror(save_errno)); 307 return save_errno; 308 } 309 310 if(fread(buf, 1, 2, f) != 2) { 311 fclose(f); 312 krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename); 313 return HEIM_ERR_EOF; 314 } 315 316 fseek(f, 0, SEEK_END); 317 len = ftell(f); 318 319 if(fclose(f) != 0) 320 return errno; 321 322 if(len < 0) 323 return errno; 324 325 if(len == 8) { 326 ret = read_master_krb4(context, filename, mkey); 327 } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) { 328 ret = read_master_encryptionkey(context, filename, mkey); 329 } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) { 330 ret = read_master_keytab(context, filename, mkey); 331 } else { 332 /* 333 * Check both LittleEndian and BigEndian since they key file 334 * might be moved from a machine with diffrent byte order, or 335 * its running on MacOS X that always uses BE master keys. 336 */ 337 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey); 338 if (ret) 339 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey); 340 } 341 return ret; 342 } 343 344 krb5_error_code 345 hdb_write_master_key(krb5_context context, const char *filename, 346 hdb_master_key mkey) 347 { 348 krb5_error_code ret; 349 hdb_master_key p; 350 krb5_keytab kt; 351 352 if(filename == NULL) 353 filename = HDB_DB_DIR "/m-key"; 354 355 ret = krb5_kt_resolve(context, filename, &kt); 356 if(ret) 357 return ret; 358 359 for(p = mkey; p; p = p->next) { 360 ret = krb5_kt_add_entry(context, kt, &p->keytab); 361 } 362 363 krb5_kt_close(context, kt); 364 365 return ret; 366 } 367 368 krb5_error_code 369 _hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage) 370 { 371 if (db->hdb_master_key_set == 0) 372 return HDB_ERR_NO_MKEY; 373 db->hdb_master_key->key_usage = key_usage; 374 return 0; 375 } 376 377 hdb_master_key 378 _hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey) 379 { 380 hdb_master_key ret = NULL; 381 while(mkey) { 382 if(ret == NULL && mkey->keytab.vno == 0) 383 ret = mkey; 384 if(mkvno == NULL) { 385 if(ret == NULL || mkey->keytab.vno > ret->keytab.vno) 386 ret = mkey; 387 } else if((uint32_t)mkey->keytab.vno == *mkvno) 388 return mkey; 389 mkey = mkey->next; 390 } 391 return ret; 392 } 393 394 int 395 _hdb_mkey_version(hdb_master_key mkey) 396 { 397 return mkey->keytab.vno; 398 } 399 400 int 401 _hdb_mkey_decrypt(krb5_context context, hdb_master_key key, 402 krb5_key_usage usage, 403 void *ptr, size_t size, krb5_data *res) 404 { 405 return krb5_decrypt(context, key->crypto, usage, 406 ptr, size, res); 407 } 408 409 int 410 _hdb_mkey_encrypt(krb5_context context, hdb_master_key key, 411 krb5_key_usage usage, 412 const void *ptr, size_t size, krb5_data *res) 413 { 414 return krb5_encrypt(context, key->crypto, usage, 415 ptr, size, res); 416 } 417 418 /* 419 * Unseal and optionally reseal the key in the MIT KDC master key. 420 * If mit_key != NULL, the key is sealed using this key. 421 */ 422 static krb5_error_code 423 _hdb_reseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey, 424 hdb_master_key mit_key) 425 { 426 427 krb5_error_code ret; 428 krb5_data mitres, res; 429 size_t keysize; 430 431 hdb_master_key key, mitkey; 432 433 if(k->mkvno == NULL) 434 return 0; 435 436 key = _hdb_find_master_key(k->mkvno, mkey); 437 438 if (key == NULL) 439 return HDB_ERR_NO_MKEY; 440 441 ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, 442 k->key.keyvalue.data, 443 k->key.keyvalue.length, 444 &res); 445 if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 446 /* try to decrypt with MIT key usage */ 447 ret = _hdb_mkey_decrypt(context, key, 0, 448 k->key.keyvalue.data, 449 k->key.keyvalue.length, 450 &res); 451 } 452 if (ret) 453 return ret; 454 455 /* fixup keylength if the key got padded when encrypting it */ 456 ret = krb5_enctype_keysize(context, k->key.keytype, &keysize); 457 if (ret) { 458 krb5_data_free(&res); 459 return ret; 460 } 461 if (keysize > res.length) { 462 krb5_data_free(&res); 463 return KRB5_BAD_KEYSIZE; 464 } 465 466 /* For mit_key != NULL, re-encrypt the key using the mitkey. */ 467 if (mit_key != NULL) { 468 mitkey = _hdb_find_master_key(NULL, mit_key); 469 if (mitkey == NULL) { 470 krb5_data_free(&res); 471 return HDB_ERR_NO_MKEY; 472 } 473 474 ret = _hdb_mkey_encrypt(context, mitkey, 0, 475 res.data, 476 keysize, 477 &mitres); 478 krb5_data_free(&res); 479 if (ret) 480 return ret; 481 } 482 483 krb5_data_free(&k->key.keyvalue); 484 if (mit_key == NULL) { 485 k->key.keyvalue = res; 486 k->key.keyvalue.length = keysize; 487 free(k->mkvno); 488 k->mkvno = NULL; 489 } else { 490 k->key.keyvalue = mitres; 491 *k->mkvno = mitkey->keytab.vno; 492 } 493 494 return 0; 495 } 496 497 krb5_error_code 498 hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 499 { 500 501 krb5_error_code ret; 502 503 ret = _hdb_reseal_key_mkey(context, k, mkey, NULL); 504 return ret; 505 } 506 507 static krb5_error_code 508 _hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey, 509 hdb_master_key mitkey) 510 { 511 krb5_error_code ret; 512 size_t i; 513 int got_one = 0; 514 515 for(i = 0; i < ent->keys.len; i++){ 516 if (mitkey == NULL || mit_strong_etype(ent->keys.val[i].key.keytype)) { 517 ret = _hdb_reseal_key_mkey(context, &ent->keys.val[i], mkey, 518 mitkey); 519 if (ret) 520 return ret; 521 got_one = 1; 522 } 523 } 524 525 /* 526 * If none of the keys were string enough, create a strong key, 527 * but one that is not encrypted in the MIT master key. As such, 528 * it will require a "change_password" once in the MIT KDC to 529 * make it work. 530 */ 531 if (got_one == 0 && mitkey != NULL && ent->keys.len > 0) { 532 krb5_keyblock key; 533 krb5_salt salt; 534 535 krb5_free_keyblock_contents(context, &ent->keys.val[0].key); 536 salt.salttype = KRB5_PW_SALT; 537 salt.saltvalue.data = NULL; 538 salt.saltvalue.length = 0; 539 ret = krb5_string_to_key_salt(context, ETYPE_AES256_CTS_HMAC_SHA1_96, 540 "XXXX", salt, &ent->keys.val[0].key); 541 if (ret) 542 return ret; 543 } 544 return 0; 545 } 546 547 krb5_error_code 548 hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 549 { 550 krb5_error_code ret; 551 552 ret = _hdb_unseal_keys_mkey(context, ent, mkey, NULL); 553 return ret; 554 } 555 556 krb5_error_code 557 hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) 558 { 559 if (db->hdb_master_key_set == 0) 560 return 0; 561 if (db->hdb_mit_key_set != 0) 562 return _hdb_unseal_keys_mkey(context, ent, db->hdb_master_key, 563 db->hdb_mit_key); 564 else 565 return _hdb_unseal_keys_mkey(context, ent, db->hdb_master_key, 566 NULL); 567 } 568 569 #ifdef notnow 570 krb5_error_code 571 hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, 572 hdb_entry *ent) 573 { 574 krb5_error_code ret = KRB5KRB_AP_ERR_NOKEY; /* XXX need a better code? */ 575 HDB_extension *tmp; 576 HDB_Ext_KeySet *hist_keys; 577 hdb_keyset *tmp_keys; 578 Key *tmp_val; 579 unsigned int tmp_len; 580 krb5_kvno tmp_kvno; 581 int i, k; 582 583 assert(kvno == 0 || kvno < ent->kvno); 584 585 tmp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); 586 if (tmp == NULL) 587 return ret; 588 589 tmp_len = ent->keys.len; 590 tmp_val = ent->keys.val; 591 tmp_kvno = ent->kvno; 592 593 hist_keys = &tmp->data.u.hist_keys; 594 595 for (i = hist_keys->len - 1; i >= 0; i++) { 596 if (kvno != 0 && hist_keys->val[i].kvno != kvno) 597 continue; 598 for (k = 0; k < hist_keys->val[i].keys.len; k++) { 599 ret = _hdb_reseal_key_mkey(context, 600 &hist_keys->val[i].keys.val[k], 601 db->hdb_master_key, NULL); 602 if (ret) 603 return (ret); 604 } 605 606 if (kvno == 0) 607 continue; 608 609 /* 610 * NOTE: What follows is a bit of an ugly hack. 611 * 612 * This is the keyset we're being asked for, so we add the 613 * current keyset to the history, leave the one we were asked 614 * for in the history, and pretend the one we were asked for is 615 * also the current keyset. 616 * 617 * This is a bit of a defensive hack in case an entry fetched 618 * this way ever gets modified then stored: if the keyset is not 619 * changed we can detect this and put things back, else we won't 620 * drop any keysets from history by accident. 621 * 622 * Note too that we only ever get called with a non-zero kvno 623 * either in the KDC or in cases where we aren't changing the 624 * HDB entry anyways, which is why this is just a defensive 625 * hack. We also don't fetch specific kvnos in the dump case, 626 * so there's no danger that we'll dump this entry and load it 627 * again, repeatedly causing the history to grow boundelessly. 628 */ 629 tmp_keys = realloc(hist_keys->val, 630 sizeof (*hist_keys->val) * (hist_keys->len + 1)); 631 if (tmp_keys == NULL) 632 return ENOMEM; 633 634 memmove(&tmp_keys[1], tmp_keys, 635 sizeof (*hist_keys->val) * hist_keys->len++); 636 tmp_keys[0].keys.len = ent->keys.len; 637 tmp_keys[0].keys.val = ent->keys.val; 638 tmp_keys[0].kvno = ent->kvno; 639 tmp_keys[0].replace_time = time(NULL); 640 i++; 641 ent->keys.len = hist_keys->val[i].keys.len; 642 ent->keys.val = hist_keys->val[i].keys.val; 643 ent->kvno = kvno; 644 } 645 646 return (ret); 647 } 648 #endif 649 650 krb5_error_code 651 hdb_unseal_key(krb5_context context, HDB *db, Key *k) 652 { 653 if (db->hdb_master_key_set == 0) 654 return 0; 655 return _hdb_reseal_key_mkey(context, k, db->hdb_master_key, NULL); 656 } 657 658 krb5_error_code 659 hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 660 { 661 krb5_error_code ret; 662 krb5_data res; 663 hdb_master_key key; 664 665 if(k->mkvno != NULL) 666 return 0; 667 668 key = _hdb_find_master_key(k->mkvno, mkey); 669 670 if (key == NULL) 671 return HDB_ERR_NO_MKEY; 672 673 ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, 674 k->key.keyvalue.data, 675 k->key.keyvalue.length, 676 &res); 677 if (ret) 678 return ret; 679 680 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); 681 free(k->key.keyvalue.data); 682 k->key.keyvalue = res; 683 684 if (k->mkvno == NULL) { 685 k->mkvno = malloc(sizeof(*k->mkvno)); 686 if (k->mkvno == NULL) 687 return ENOMEM; 688 } 689 *k->mkvno = key->keytab.vno; 690 691 return 0; 692 } 693 694 krb5_error_code 695 hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 696 { 697 size_t i; 698 for(i = 0; i < ent->keys.len; i++){ 699 krb5_error_code ret; 700 701 ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); 702 if (ret) 703 return ret; 704 } 705 return 0; 706 } 707 708 krb5_error_code 709 hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent) 710 { 711 if (db->hdb_master_key_set == 0) 712 return 0; 713 714 return hdb_seal_keys_mkey(context, ent, db->hdb_master_key); 715 } 716 717 krb5_error_code 718 hdb_seal_key(krb5_context context, HDB *db, Key *k) 719 { 720 if (db->hdb_master_key_set == 0) 721 return 0; 722 723 return hdb_seal_key_mkey(context, k, db->hdb_master_key); 724 } 725 726 krb5_error_code 727 hdb_set_master_key(krb5_context context, 728 HDB *db, 729 krb5_keyblock *key) 730 { 731 krb5_error_code ret; 732 hdb_master_key mkey; 733 734 ret = hdb_process_master_key(context, 0, key, 0, &mkey); 735 if (ret) 736 return ret; 737 db->hdb_master_key = mkey; 738 #if 0 /* XXX - why? */ 739 des_set_random_generator_seed(key.keyvalue.data); 740 #endif 741 db->hdb_master_key_set = 1; 742 db->hdb_master_key->key_usage = HDB_KU_MKEY; 743 return 0; 744 } 745 746 krb5_error_code 747 hdb_set_master_keyfile (krb5_context context, 748 HDB *db, 749 const char *keyfile) 750 { 751 hdb_master_key key; 752 krb5_error_code ret; 753 754 ret = hdb_read_master_key(context, keyfile, &key); 755 if (ret) { 756 if (ret != ENOENT) 757 return ret; 758 krb5_clear_error_message(context); 759 return 0; 760 } 761 db->hdb_master_key = key; 762 db->hdb_master_key_set = 1; 763 return ret; 764 } 765 766 krb5_error_code 767 hdb_clear_master_key (krb5_context context, 768 HDB *db) 769 { 770 if (db->hdb_master_key_set) { 771 hdb_free_master_key(context, db->hdb_master_key); 772 db->hdb_master_key_set = 0; 773 } 774 return 0; 775 } 776