xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hdb/mkey.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
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