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
hdb_free_master_key(krb5_context context,hdb_master_key mkey)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
hdb_process_master_key(krb5_context context,int kvno,krb5_keyblock * key,krb5_enctype etype,hdb_master_key * mkey)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
hdb_add_master_key(krb5_context context,krb5_keyblock * key,hdb_master_key * inout)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
read_master_keytab(krb5_context context,const char * filename,hdb_master_key * mkey)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
read_master_mit(krb5_context context,const char * filename,int byteorder,hdb_master_key * mkey)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
read_master_encryptionkey(krb5_context context,const char * filename,hdb_master_key * mkey)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
read_master_krb4(krb5_context context,const char * filename,hdb_master_key * mkey)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
hdb_read_master_key(krb5_context context,const char * filename,hdb_master_key * mkey)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
hdb_write_master_key(krb5_context context,const char * filename,hdb_master_key mkey)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
_hdb_set_master_key_usage(krb5_context context,HDB * db,unsigned int key_usage)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
_hdb_find_master_key(uint32_t * mkvno,hdb_master_key mkey)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
_hdb_mkey_version(hdb_master_key mkey)395 _hdb_mkey_version(hdb_master_key mkey)
396 {
397 return mkey->keytab.vno;
398 }
399
400 int
_hdb_mkey_decrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,void * ptr,size_t size,krb5_data * res)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
_hdb_mkey_encrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,const void * ptr,size_t size,krb5_data * res)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
_hdb_reseal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey,hdb_master_key mit_key)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
hdb_unseal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)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
_hdb_unseal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey,hdb_master_key mitkey)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
hdb_unseal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)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
hdb_unseal_keys(krb5_context context,HDB * db,hdb_entry * ent)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
hdb_unseal_keys_kvno(krb5_context context,HDB * db,krb5_kvno kvno,hdb_entry * ent)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
hdb_unseal_key(krb5_context context,HDB * db,Key * k)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
hdb_seal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)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
hdb_seal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)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
hdb_seal_keys(krb5_context context,HDB * db,hdb_entry * ent)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
hdb_seal_key(krb5_context context,HDB * db,Key * k)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
hdb_set_master_key(krb5_context context,HDB * db,krb5_keyblock * key)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
hdb_set_master_keyfile(krb5_context context,HDB * db,const char * keyfile)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
hdb_clear_master_key(krb5_context context,HDB * db)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