1 /* $NetBSD: mkey.c,v 1.3 2019/12/15 22:50:49 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
hdb_free_master_key(krb5_context context,hdb_master_key mkey)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
hdb_process_master_key(krb5_context context,int kvno,krb5_keyblock * key,krb5_enctype etype,hdb_master_key * mkey)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
hdb_add_master_key(krb5_context context,krb5_keyblock * key,hdb_master_key * inout)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
read_master_keytab(krb5_context context,const char * filename,hdb_master_key * mkey)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
read_master_mit(krb5_context context,const char * filename,int byteorder,hdb_master_key * mkey)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
read_master_encryptionkey(krb5_context context,const char * filename,hdb_master_key * mkey)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_s(buf, sizeof(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
read_master_krb4(krb5_context context,const char * filename,hdb_master_key * mkey)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_s(buf, sizeof(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
hdb_read_master_key(krb5_context context,const char * filename,hdb_master_key * mkey)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
hdb_write_master_key(krb5_context context,const char * filename,hdb_master_key mkey)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
_hdb_set_master_key_usage(krb5_context context,HDB * db,unsigned int key_usage)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
_hdb_find_master_key(unsigned int * mkvno,hdb_master_key mkey)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
_hdb_mkey_version(hdb_master_key mkey)401 _hdb_mkey_version(hdb_master_key mkey)
402 {
403 return mkey->keytab.vno;
404 }
405
406 int
_hdb_mkey_decrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,void * ptr,size_t size,krb5_data * res)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
_hdb_mkey_encrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,const void * ptr,size_t size,krb5_data * res)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
hdb_unseal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)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
hdb_unseal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)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
hdb_unseal_keys(krb5_context context,HDB * db,hdb_entry * ent)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
hdb_unseal_keys_kvno(krb5_context context,HDB * db,krb5_kvno kvno,unsigned flags,hdb_entry * ent)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
hdb_unseal_key(krb5_context context,HDB * db,Key * k)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
hdb_seal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)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
hdb_seal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)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
hdb_seal_keys(krb5_context context,HDB * db,hdb_entry * ent)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
hdb_seal_key(krb5_context context,HDB * db,Key * k)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
hdb_set_master_key(krb5_context context,HDB * db,krb5_keyblock * key)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
hdb_set_master_keyfile(krb5_context context,HDB * db,const char * keyfile)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
hdb_clear_master_key(krb5_context context,HDB * db)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