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