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 #ifndef O_BINARY 36 #define O_BINARY 0 37 #endif 38 39 struct hdb_master_key_data { 40 krb5_keytab_entry keytab; 41 krb5_crypto crypto; 42 struct hdb_master_key_data *next; 43 }; 44 45 void 46 hdb_free_master_key(krb5_context context, hdb_master_key mkey) 47 { 48 struct hdb_master_key_data *ptr; 49 while(mkey) { 50 krb5_kt_free_entry(context, &mkey->keytab); 51 if (mkey->crypto) 52 krb5_crypto_destroy(context, mkey->crypto); 53 ptr = mkey; 54 mkey = mkey->next; 55 free(ptr); 56 } 57 } 58 59 krb5_error_code 60 hdb_process_master_key(krb5_context context, 61 int kvno, krb5_keyblock *key, krb5_enctype etype, 62 hdb_master_key *mkey) 63 { 64 krb5_error_code ret; 65 66 *mkey = calloc(1, sizeof(**mkey)); 67 if(*mkey == NULL) { 68 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 69 return ENOMEM; 70 } 71 (*mkey)->keytab.vno = kvno; 72 ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); 73 if(ret) 74 goto fail; 75 ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock); 76 if(ret) 77 goto fail; 78 if(etype != 0) 79 (*mkey)->keytab.keyblock.keytype = etype; 80 (*mkey)->keytab.timestamp = time(NULL); 81 ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto); 82 if(ret) 83 goto fail; 84 return 0; 85 fail: 86 hdb_free_master_key(context, *mkey); 87 *mkey = NULL; 88 return ret; 89 } 90 91 krb5_error_code 92 hdb_add_master_key(krb5_context context, krb5_keyblock *key, 93 hdb_master_key *inout) 94 { 95 int vno = 0; 96 hdb_master_key p; 97 krb5_error_code ret; 98 99 for(p = *inout; p; p = p->next) 100 vno = max(vno, p->keytab.vno); 101 vno++; 102 ret = hdb_process_master_key(context, vno, key, 0, &p); 103 if(ret) 104 return ret; 105 p->next = *inout; 106 *inout = p; 107 return 0; 108 } 109 110 static krb5_error_code 111 read_master_keytab(krb5_context context, const char *filename, 112 hdb_master_key *mkey) 113 { 114 krb5_error_code ret; 115 krb5_keytab id; 116 krb5_kt_cursor cursor; 117 krb5_keytab_entry entry; 118 hdb_master_key p; 119 120 ret = krb5_kt_resolve(context, filename, &id); 121 if(ret) 122 return ret; 123 124 ret = krb5_kt_start_seq_get(context, id, &cursor); 125 if(ret) 126 goto out; 127 *mkey = NULL; 128 while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { 129 p = calloc(1, sizeof(*p)); 130 if(p == NULL) { 131 krb5_kt_end_seq_get(context, id, &cursor); 132 ret = ENOMEM; 133 goto out; 134 } 135 p->keytab = entry; 136 ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); 137 p->next = *mkey; 138 *mkey = p; 139 } 140 krb5_kt_end_seq_get(context, id, &cursor); 141 out: 142 krb5_kt_close(context, id); 143 return ret; 144 } 145 146 /* read a MIT master keyfile */ 147 static krb5_error_code 148 read_master_mit(krb5_context context, const char *filename, 149 int byteorder, hdb_master_key *mkey) 150 { 151 int fd; 152 krb5_error_code ret; 153 krb5_storage *sp; 154 int16_t enctype; 155 krb5_keyblock key; 156 157 fd = open(filename, O_RDONLY | O_BINARY); 158 if(fd < 0) { 159 int save_errno = errno; 160 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 161 filename, strerror(save_errno)); 162 return save_errno; 163 } 164 sp = krb5_storage_from_fd(fd); 165 if(sp == NULL) { 166 close(fd); 167 return errno; 168 } 169 krb5_storage_set_flags(sp, byteorder); 170 /* could possibly use ret_keyblock here, but do it with more 171 checks for now */ 172 { 173 ret = krb5_ret_int16(sp, &enctype); 174 if (ret) 175 goto out; 176 ret = krb5_enctype_valid(context, enctype); 177 if (ret) 178 goto out; 179 key.keytype = enctype; 180 ret = krb5_ret_data(sp, &key.keyvalue); 181 if(ret) 182 goto out; 183 } 184 ret = hdb_process_master_key(context, 1, &key, 0, mkey); 185 krb5_free_keyblock_contents(context, &key); 186 out: 187 krb5_storage_free(sp); 188 close(fd); 189 return ret; 190 } 191 192 /* read an old master key file */ 193 static krb5_error_code 194 read_master_encryptionkey(krb5_context context, const char *filename, 195 hdb_master_key *mkey) 196 { 197 int fd; 198 krb5_keyblock key; 199 krb5_error_code ret; 200 unsigned char buf[256]; 201 ssize_t len; 202 size_t ret_len; 203 204 fd = open(filename, O_RDONLY | O_BINARY); 205 if(fd < 0) { 206 int save_errno = errno; 207 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 208 filename, strerror(save_errno)); 209 return save_errno; 210 } 211 212 len = read(fd, buf, sizeof(buf)); 213 close(fd); 214 if(len < 0) { 215 int save_errno = errno; 216 krb5_set_error_message(context, save_errno, "error reading %s: %s", 217 filename, strerror(save_errno)); 218 return save_errno; 219 } 220 221 ret = decode_EncryptionKey(buf, len, &key, &ret_len); 222 memset(buf, 0, sizeof(buf)); 223 if(ret) 224 return ret; 225 226 /* Originally, the keytype was just that, and later it got changed 227 to des-cbc-md5, but we always used des in cfb64 mode. This 228 should cover all cases, but will break if someone has hacked 229 this code to really use des-cbc-md5 -- but then that's not my 230 problem. */ 231 if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5) 232 key.keytype = ETYPE_DES_CFB64_NONE; 233 234 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 235 krb5_free_keyblock_contents(context, &key); 236 return ret; 237 } 238 239 /* read a krb4 /.k style file */ 240 static krb5_error_code 241 read_master_krb4(krb5_context context, const char *filename, 242 hdb_master_key *mkey) 243 { 244 int fd; 245 krb5_keyblock key; 246 krb5_error_code ret; 247 unsigned char buf[256]; 248 ssize_t len; 249 250 fd = open(filename, O_RDONLY | O_BINARY); 251 if(fd < 0) { 252 int save_errno = errno; 253 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 254 filename, strerror(save_errno)); 255 return save_errno; 256 } 257 258 len = read(fd, buf, sizeof(buf)); 259 close(fd); 260 if(len < 0) { 261 int save_errno = errno; 262 krb5_set_error_message(context, save_errno, "error reading %s: %s", 263 filename, strerror(save_errno)); 264 return save_errno; 265 } 266 if(len != 8) { 267 krb5_set_error_message(context, HEIM_ERR_EOF, 268 "bad contents of %s", filename); 269 return HEIM_ERR_EOF; /* XXX file might be too large */ 270 } 271 272 memset(&key, 0, sizeof(key)); 273 key.keytype = ETYPE_DES_PCBC_NONE; 274 ret = krb5_data_copy(&key.keyvalue, buf, len); 275 memset(buf, 0, sizeof(buf)); 276 if(ret) 277 return ret; 278 279 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 280 krb5_free_keyblock_contents(context, &key); 281 return ret; 282 } 283 284 krb5_error_code 285 hdb_read_master_key(krb5_context context, const char *filename, 286 hdb_master_key *mkey) 287 { 288 FILE *f; 289 unsigned char buf[16]; 290 krb5_error_code ret; 291 292 off_t len; 293 294 *mkey = NULL; 295 296 if(filename == NULL) 297 filename = HDB_DB_DIR "/m-key"; 298 299 f = fopen(filename, "r"); 300 if(f == NULL) { 301 int save_errno = errno; 302 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 303 filename, strerror(save_errno)); 304 return save_errno; 305 } 306 307 if(fread(buf, 1, 2, f) != 2) { 308 fclose(f); 309 krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename); 310 return HEIM_ERR_EOF; 311 } 312 313 fseek(f, 0, SEEK_END); 314 len = ftell(f); 315 316 if(fclose(f) != 0) 317 return errno; 318 319 if(len < 0) 320 return errno; 321 322 if(len == 8) { 323 ret = read_master_krb4(context, filename, mkey); 324 } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) { 325 ret = read_master_encryptionkey(context, filename, mkey); 326 } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) { 327 ret = read_master_keytab(context, filename, mkey); 328 } else { 329 /* 330 * Check both LittleEndian and BigEndian since they key file 331 * might be moved from a machine with diffrent byte order, or 332 * its running on MacOS X that always uses BE master keys. 333 */ 334 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey); 335 if (ret) 336 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey); 337 } 338 return ret; 339 } 340 341 krb5_error_code 342 hdb_write_master_key(krb5_context context, const char *filename, 343 hdb_master_key mkey) 344 { 345 krb5_error_code ret; 346 hdb_master_key p; 347 krb5_keytab kt; 348 349 if(filename == NULL) 350 filename = HDB_DB_DIR "/m-key"; 351 352 ret = krb5_kt_resolve(context, filename, &kt); 353 if(ret) 354 return ret; 355 356 for(p = mkey; p; p = p->next) { 357 ret = krb5_kt_add_entry(context, kt, &p->keytab); 358 } 359 360 krb5_kt_close(context, kt); 361 362 return ret; 363 } 364 365 hdb_master_key 366 _hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey) 367 { 368 hdb_master_key ret = NULL; 369 while(mkey) { 370 if(ret == NULL && mkey->keytab.vno == 0) 371 ret = mkey; 372 if(mkvno == NULL) { 373 if(ret == NULL || mkey->keytab.vno > ret->keytab.vno) 374 ret = mkey; 375 } else if((uint32_t)mkey->keytab.vno == *mkvno) 376 return mkey; 377 mkey = mkey->next; 378 } 379 return ret; 380 } 381 382 int 383 _hdb_mkey_version(hdb_master_key mkey) 384 { 385 return mkey->keytab.vno; 386 } 387 388 int 389 _hdb_mkey_decrypt(krb5_context context, hdb_master_key key, 390 krb5_key_usage usage, 391 void *ptr, size_t size, krb5_data *res) 392 { 393 return krb5_decrypt(context, key->crypto, usage, 394 ptr, size, res); 395 } 396 397 int 398 _hdb_mkey_encrypt(krb5_context context, hdb_master_key key, 399 krb5_key_usage usage, 400 const void *ptr, size_t size, krb5_data *res) 401 { 402 return krb5_encrypt(context, key->crypto, usage, 403 ptr, size, res); 404 } 405 406 krb5_error_code 407 hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 408 { 409 410 krb5_error_code ret; 411 krb5_data res; 412 size_t keysize; 413 414 hdb_master_key key; 415 416 if(k->mkvno == NULL) 417 return 0; 418 419 key = _hdb_find_master_key(k->mkvno, mkey); 420 421 if (key == NULL) 422 return HDB_ERR_NO_MKEY; 423 424 ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, 425 k->key.keyvalue.data, 426 k->key.keyvalue.length, 427 &res); 428 if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 429 /* try to decrypt with MIT key usage */ 430 ret = _hdb_mkey_decrypt(context, key, 0, 431 k->key.keyvalue.data, 432 k->key.keyvalue.length, 433 &res); 434 } 435 if (ret) 436 return ret; 437 438 /* fixup keylength if the key got padded when encrypting it */ 439 ret = krb5_enctype_keysize(context, k->key.keytype, &keysize); 440 if (ret) { 441 krb5_data_free(&res); 442 return ret; 443 } 444 if (keysize > res.length) { 445 krb5_data_free(&res); 446 return KRB5_BAD_KEYSIZE; 447 } 448 449 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); 450 free(k->key.keyvalue.data); 451 k->key.keyvalue = res; 452 k->key.keyvalue.length = keysize; 453 free(k->mkvno); 454 k->mkvno = NULL; 455 456 return 0; 457 } 458 459 krb5_error_code 460 hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 461 { 462 size_t i; 463 464 for(i = 0; i < ent->keys.len; i++){ 465 krb5_error_code ret; 466 467 ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey); 468 if (ret) 469 return ret; 470 } 471 return 0; 472 } 473 474 krb5_error_code 475 hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) 476 { 477 if (db->hdb_master_key_set == 0) 478 return 0; 479 return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); 480 } 481 482 krb5_error_code 483 hdb_unseal_key(krb5_context context, HDB *db, Key *k) 484 { 485 if (db->hdb_master_key_set == 0) 486 return 0; 487 return hdb_unseal_key_mkey(context, k, db->hdb_master_key); 488 } 489 490 krb5_error_code 491 hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 492 { 493 krb5_error_code ret; 494 krb5_data res; 495 hdb_master_key key; 496 497 if(k->mkvno != NULL) 498 return 0; 499 500 key = _hdb_find_master_key(k->mkvno, mkey); 501 502 if (key == NULL) 503 return HDB_ERR_NO_MKEY; 504 505 ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, 506 k->key.keyvalue.data, 507 k->key.keyvalue.length, 508 &res); 509 if (ret) 510 return ret; 511 512 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); 513 free(k->key.keyvalue.data); 514 k->key.keyvalue = res; 515 516 if (k->mkvno == NULL) { 517 k->mkvno = malloc(sizeof(*k->mkvno)); 518 if (k->mkvno == NULL) 519 return ENOMEM; 520 } 521 *k->mkvno = key->keytab.vno; 522 523 return 0; 524 } 525 526 krb5_error_code 527 hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 528 { 529 size_t i; 530 for(i = 0; i < ent->keys.len; i++){ 531 krb5_error_code ret; 532 533 ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); 534 if (ret) 535 return ret; 536 } 537 return 0; 538 } 539 540 krb5_error_code 541 hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent) 542 { 543 if (db->hdb_master_key_set == 0) 544 return 0; 545 546 return hdb_seal_keys_mkey(context, ent, db->hdb_master_key); 547 } 548 549 krb5_error_code 550 hdb_seal_key(krb5_context context, HDB *db, Key *k) 551 { 552 if (db->hdb_master_key_set == 0) 553 return 0; 554 555 return hdb_seal_key_mkey(context, k, db->hdb_master_key); 556 } 557 558 krb5_error_code 559 hdb_set_master_key (krb5_context context, 560 HDB *db, 561 krb5_keyblock *key) 562 { 563 krb5_error_code ret; 564 hdb_master_key mkey; 565 566 ret = hdb_process_master_key(context, 0, key, 0, &mkey); 567 if (ret) 568 return ret; 569 db->hdb_master_key = mkey; 570 #if 0 /* XXX - why? */ 571 des_set_random_generator_seed(key.keyvalue.data); 572 #endif 573 db->hdb_master_key_set = 1; 574 return 0; 575 } 576 577 krb5_error_code 578 hdb_set_master_keyfile (krb5_context context, 579 HDB *db, 580 const char *keyfile) 581 { 582 hdb_master_key key; 583 krb5_error_code ret; 584 585 ret = hdb_read_master_key(context, keyfile, &key); 586 if (ret) { 587 if (ret != ENOENT) 588 return ret; 589 krb5_clear_error_message(context); 590 return 0; 591 } 592 db->hdb_master_key = key; 593 db->hdb_master_key_set = 1; 594 return ret; 595 } 596 597 krb5_error_code 598 hdb_clear_master_key (krb5_context context, 599 HDB *db) 600 { 601 if (db->hdb_master_key_set) { 602 hdb_free_master_key(context, db->hdb_master_key); 603 db->hdb_master_key_set = 0; 604 } 605 return 0; 606 } 607