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