Line data Source code
1 : /*
2 : * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "hdb_locl.h"
35 : #ifndef O_BINARY
36 : #define O_BINARY 0
37 : #endif
38 :
39 : struct hdb_master_key_data {
40 : krb5_keytab_entry keytab;
41 : krb5_crypto crypto;
42 : struct hdb_master_key_data *next;
43 : unsigned int key_usage;
44 : };
45 :
46 : void
47 0 : hdb_free_master_key(krb5_context context, hdb_master_key mkey)
48 : {
49 0 : struct hdb_master_key_data *ptr;
50 0 : while(mkey) {
51 0 : krb5_kt_free_entry(context, &mkey->keytab);
52 0 : if (mkey->crypto)
53 0 : krb5_crypto_destroy(context, mkey->crypto);
54 0 : ptr = mkey;
55 0 : mkey = mkey->next;
56 0 : free(ptr);
57 : }
58 0 : }
59 :
60 : krb5_error_code
61 0 : hdb_process_master_key(krb5_context context,
62 : int kvno, krb5_keyblock *key, krb5_enctype etype,
63 : hdb_master_key *mkey)
64 : {
65 0 : krb5_error_code ret;
66 :
67 0 : *mkey = calloc(1, sizeof(**mkey));
68 0 : if(*mkey == NULL) {
69 0 : krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
70 0 : return ENOMEM;
71 : }
72 0 : (*mkey)->key_usage = HDB_KU_MKEY;
73 0 : (*mkey)->keytab.vno = kvno;
74 0 : ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
75 0 : if(ret)
76 0 : goto fail;
77 0 : ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
78 0 : if(ret)
79 0 : goto fail;
80 0 : if(etype != 0)
81 0 : (*mkey)->keytab.keyblock.keytype = etype;
82 0 : (*mkey)->keytab.timestamp = time(NULL);
83 0 : ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
84 0 : if(ret)
85 0 : goto fail;
86 0 : return 0;
87 0 : fail:
88 0 : hdb_free_master_key(context, *mkey);
89 0 : *mkey = NULL;
90 0 : return ret;
91 : }
92 :
93 : krb5_error_code
94 0 : hdb_add_master_key(krb5_context context, krb5_keyblock *key,
95 : hdb_master_key *inout)
96 : {
97 0 : int vno = 0;
98 0 : hdb_master_key p;
99 0 : krb5_error_code ret;
100 :
101 0 : for(p = *inout; p; p = p->next)
102 0 : vno = max(vno, p->keytab.vno);
103 0 : vno++;
104 0 : ret = hdb_process_master_key(context, vno, key, 0, &p);
105 0 : if(ret)
106 0 : return ret;
107 0 : p->next = *inout;
108 0 : *inout = p;
109 0 : return 0;
110 : }
111 :
112 : static krb5_error_code
113 0 : read_master_keytab(krb5_context context, const char *filename,
114 : hdb_master_key *mkey)
115 : {
116 0 : krb5_error_code ret;
117 0 : krb5_keytab id;
118 0 : krb5_kt_cursor cursor;
119 0 : krb5_keytab_entry entry;
120 0 : hdb_master_key p;
121 :
122 0 : *mkey = NULL;
123 0 : ret = krb5_kt_resolve(context, filename, &id);
124 0 : if(ret)
125 0 : return ret;
126 :
127 0 : ret = krb5_kt_start_seq_get(context, id, &cursor);
128 0 : if(ret)
129 0 : goto out;
130 0 : while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
131 0 : p = calloc(1, sizeof(*p));
132 0 : if (p == NULL) {
133 0 : ret = ENOMEM;
134 0 : break;
135 : }
136 0 : p->keytab = entry;
137 0 : p->next = *mkey;
138 0 : *mkey = p;
139 0 : ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
140 0 : if (ret)
141 0 : break;
142 : }
143 0 : krb5_kt_end_seq_get(context, id, &cursor);
144 0 : out:
145 0 : krb5_kt_close(context, id);
146 0 : if (ret) {
147 0 : hdb_free_master_key(context, *mkey);
148 0 : *mkey = NULL;
149 : }
150 0 : return ret;
151 : }
152 :
153 : /* read a MIT master keyfile */
154 : static krb5_error_code
155 0 : read_master_mit(krb5_context context, const char *filename,
156 : int byteorder, hdb_master_key *mkey)
157 : {
158 0 : int fd;
159 0 : krb5_error_code ret;
160 0 : krb5_storage *sp;
161 0 : int16_t enctype;
162 0 : krb5_keyblock key;
163 :
164 0 : fd = open(filename, O_RDONLY | O_BINARY);
165 0 : if(fd < 0) {
166 0 : int save_errno = errno;
167 0 : krb5_set_error_message(context, save_errno, "failed to open %s: %s",
168 : filename, strerror(save_errno));
169 0 : return save_errno;
170 : }
171 0 : sp = krb5_storage_from_fd(fd);
172 0 : if(sp == NULL) {
173 0 : close(fd);
174 0 : return errno;
175 : }
176 0 : krb5_storage_set_flags(sp, byteorder);
177 : /* could possibly use ret_keyblock here, but do it with more
178 : checks for now */
179 : {
180 0 : ret = krb5_ret_int16(sp, &enctype);
181 0 : if (ret)
182 0 : goto out;
183 0 : ret = krb5_enctype_valid(context, enctype);
184 0 : if (ret)
185 0 : goto out;
186 0 : key.keytype = enctype;
187 0 : ret = krb5_ret_data(sp, &key.keyvalue);
188 0 : if(ret)
189 0 : goto out;
190 : }
191 0 : ret = hdb_process_master_key(context, 1, &key, 0, mkey);
192 0 : krb5_free_keyblock_contents(context, &key);
193 0 : out:
194 0 : krb5_storage_free(sp);
195 0 : close(fd);
196 0 : return ret;
197 : }
198 :
199 : /* read an old master key file */
200 : static krb5_error_code
201 0 : read_master_encryptionkey(krb5_context context, const char *filename,
202 : hdb_master_key *mkey)
203 : {
204 0 : int fd;
205 0 : krb5_keyblock key;
206 0 : krb5_error_code ret;
207 0 : unsigned char buf[256];
208 0 : ssize_t len;
209 0 : size_t ret_len;
210 :
211 0 : fd = open(filename, O_RDONLY | O_BINARY);
212 0 : if(fd < 0) {
213 0 : int save_errno = errno;
214 0 : krb5_set_error_message(context, save_errno, "failed to open %s: %s",
215 : filename, strerror(save_errno));
216 0 : return save_errno;
217 : }
218 :
219 0 : len = read(fd, buf, sizeof(buf));
220 0 : close(fd);
221 0 : if(len < 0) {
222 0 : int save_errno = errno;
223 0 : krb5_set_error_message(context, save_errno, "error reading %s: %s",
224 : filename, strerror(save_errno));
225 0 : return save_errno;
226 : }
227 :
228 0 : ret = decode_EncryptionKey(buf, len, &key, &ret_len);
229 0 : memset_s(buf, sizeof(buf), 0, sizeof(buf));
230 0 : if(ret)
231 0 : return ret;
232 :
233 : /* Originally, the keytype was just that, and later it got changed
234 : to des-cbc-md5, but we always used des in cfb64 mode. This
235 : should cover all cases, but will break if someone has hacked
236 : this code to really use des-cbc-md5 -- but then that's not my
237 : problem. */
238 0 : if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5)
239 0 : key.keytype = ETYPE_DES_CFB64_NONE;
240 :
241 0 : ret = hdb_process_master_key(context, 0, &key, 0, mkey);
242 0 : krb5_free_keyblock_contents(context, &key);
243 0 : return ret;
244 : }
245 :
246 : /* read a krb4 /.k style file */
247 : static krb5_error_code
248 0 : read_master_krb4(krb5_context context, const char *filename,
249 : hdb_master_key *mkey)
250 : {
251 0 : int fd;
252 0 : krb5_keyblock key;
253 0 : krb5_error_code ret;
254 0 : unsigned char buf[256];
255 0 : ssize_t len;
256 :
257 0 : fd = open(filename, O_RDONLY | O_BINARY);
258 0 : if(fd < 0) {
259 0 : int save_errno = errno;
260 0 : krb5_set_error_message(context, save_errno, "failed to open %s: %s",
261 : filename, strerror(save_errno));
262 0 : return save_errno;
263 : }
264 :
265 0 : len = read(fd, buf, sizeof(buf));
266 0 : close(fd);
267 0 : if(len < 0) {
268 0 : int save_errno = errno;
269 0 : krb5_set_error_message(context, save_errno, "error reading %s: %s",
270 : filename, strerror(save_errno));
271 0 : return save_errno;
272 : }
273 0 : if(len != 8) {
274 0 : krb5_set_error_message(context, HEIM_ERR_EOF,
275 : "bad contents of %s", filename);
276 0 : return HEIM_ERR_EOF; /* XXX file might be too large */
277 : }
278 :
279 0 : memset(&key, 0, sizeof(key));
280 0 : key.keytype = ETYPE_DES_PCBC_NONE;
281 0 : ret = krb5_data_copy(&key.keyvalue, buf, len);
282 0 : memset_s(buf, sizeof(buf), 0, sizeof(buf));
283 0 : if(ret)
284 0 : return ret;
285 :
286 0 : ret = hdb_process_master_key(context, 0, &key, 0, mkey);
287 0 : krb5_free_keyblock_contents(context, &key);
288 0 : return ret;
289 : }
290 :
291 : krb5_error_code
292 68 : hdb_read_master_key(krb5_context context, const char *filename,
293 : hdb_master_key *mkey)
294 : {
295 0 : FILE *f;
296 0 : unsigned char buf[16];
297 0 : krb5_error_code ret;
298 :
299 0 : off_t len;
300 :
301 68 : *mkey = NULL;
302 :
303 68 : if(filename == NULL)
304 68 : filename = HDB_DB_DIR "/m-key";
305 :
306 68 : f = fopen(filename, "r");
307 68 : if(f == NULL) {
308 68 : int save_errno = errno;
309 68 : krb5_set_error_message(context, save_errno, "failed to open %s: %s",
310 : filename, strerror(save_errno));
311 68 : return save_errno;
312 : }
313 :
314 0 : if(fread(buf, 1, 2, f) != 2) {
315 0 : fclose(f);
316 0 : krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename);
317 0 : return HEIM_ERR_EOF;
318 : }
319 :
320 0 : fseek(f, 0, SEEK_END);
321 0 : len = ftell(f);
322 :
323 0 : if(fclose(f) != 0)
324 0 : return errno;
325 :
326 0 : if(len < 0)
327 0 : return errno;
328 :
329 0 : if(len == 8) {
330 0 : ret = read_master_krb4(context, filename, mkey);
331 0 : } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
332 0 : ret = read_master_encryptionkey(context, filename, mkey);
333 0 : } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
334 0 : ret = read_master_keytab(context, filename, mkey);
335 : } else {
336 : /*
337 : * Check both LittleEndian and BigEndian since they key file
338 : * might be moved from a machine with diffrent byte order, or
339 : * its running on MacOS X that always uses BE master keys.
340 : */
341 0 : ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey);
342 0 : if (ret)
343 0 : ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey);
344 : }
345 0 : return ret;
346 : }
347 :
348 : krb5_error_code
349 0 : hdb_write_master_key(krb5_context context, const char *filename,
350 : hdb_master_key mkey)
351 : {
352 0 : krb5_error_code ret;
353 0 : hdb_master_key p;
354 0 : krb5_keytab kt;
355 :
356 0 : if(filename == NULL)
357 0 : filename = HDB_DB_DIR "/m-key";
358 :
359 0 : ret = krb5_kt_resolve(context, filename, &kt);
360 0 : if(ret)
361 0 : return ret;
362 :
363 0 : for(p = mkey; p; p = p->next) {
364 0 : ret = krb5_kt_add_entry(context, kt, &p->keytab);
365 : }
366 :
367 0 : krb5_kt_close(context, kt);
368 :
369 0 : return ret;
370 : }
371 :
372 : krb5_error_code
373 0 : _hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage)
374 : {
375 0 : if (db->hdb_master_key_set == 0)
376 0 : return HDB_ERR_NO_MKEY;
377 0 : db->hdb_master_key->key_usage = key_usage;
378 0 : return 0;
379 : }
380 :
381 : hdb_master_key
382 0 : _hdb_find_master_key(unsigned int *mkvno, hdb_master_key mkey)
383 : {
384 0 : hdb_master_key ret = NULL;
385 0 : while(mkey) {
386 0 : if(ret == NULL && mkey->keytab.vno == 0)
387 0 : ret = mkey;
388 0 : if(mkvno == NULL) {
389 0 : if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
390 0 : ret = mkey;
391 0 : } else if((uint32_t)mkey->keytab.vno == *mkvno)
392 0 : return mkey;
393 0 : mkey = mkey->next;
394 : }
395 0 : return ret;
396 : }
397 :
398 : int
399 0 : _hdb_mkey_version(hdb_master_key mkey)
400 : {
401 0 : return mkey->keytab.vno;
402 : }
403 :
404 : int
405 0 : _hdb_mkey_decrypt(krb5_context context, hdb_master_key key,
406 : krb5_key_usage usage,
407 : void *ptr, size_t size, krb5_data *res)
408 : {
409 0 : return krb5_decrypt(context, key->crypto, usage,
410 : ptr, size, res);
411 : }
412 :
413 : int
414 0 : _hdb_mkey_encrypt(krb5_context context, hdb_master_key key,
415 : krb5_key_usage usage,
416 : const void *ptr, size_t size, krb5_data *res)
417 : {
418 0 : return krb5_encrypt(context, key->crypto, usage,
419 : ptr, size, res);
420 : }
421 :
422 : krb5_error_code
423 0 : hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
424 : {
425 :
426 0 : krb5_error_code ret;
427 0 : krb5_data res;
428 0 : size_t keysize;
429 :
430 0 : hdb_master_key key;
431 :
432 0 : if(k->mkvno == NULL)
433 0 : return 0;
434 :
435 0 : key = _hdb_find_master_key(k->mkvno, mkey);
436 :
437 0 : if (key == NULL)
438 0 : return HDB_ERR_NO_MKEY;
439 :
440 0 : ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
441 : k->key.keyvalue.data,
442 : k->key.keyvalue.length,
443 : &res);
444 0 : if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
445 : /* try to decrypt with MIT key usage */
446 0 : ret = _hdb_mkey_decrypt(context, key, 0,
447 : k->key.keyvalue.data,
448 : k->key.keyvalue.length,
449 : &res);
450 : }
451 0 : if (ret)
452 0 : return ret;
453 :
454 : /* fixup keylength if the key got padded when encrypting it */
455 0 : ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
456 0 : if (ret) {
457 0 : krb5_data_free(&res);
458 0 : return ret;
459 : }
460 0 : if (keysize > res.length) {
461 0 : krb5_data_free(&res);
462 0 : return KRB5_BAD_KEYSIZE;
463 : }
464 :
465 0 : memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
466 0 : free(k->key.keyvalue.data);
467 0 : k->key.keyvalue = res;
468 0 : k->key.keyvalue.length = keysize;
469 0 : free(k->mkvno);
470 0 : k->mkvno = NULL;
471 :
472 0 : return 0;
473 : }
474 :
475 : krb5_error_code
476 0 : hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
477 : {
478 0 : size_t i;
479 :
480 0 : for(i = 0; i < ent->keys.len; i++){
481 0 : krb5_error_code ret;
482 :
483 0 : ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
484 0 : if (ret)
485 0 : return ret;
486 : }
487 0 : return 0;
488 : }
489 :
490 : krb5_error_code
491 0 : hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
492 : {
493 0 : if (db->hdb_master_key_set == 0)
494 0 : return 0;
495 0 : return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
496 : }
497 :
498 : /*
499 : * Unseal the keys for the given kvno (or all of them) of entry.
500 : *
501 : * If kvno == 0 -> unseal all.
502 : * if kvno != 0 -> unseal the requested kvno and make sure it's the one listed
503 : * as the current keyset for the entry (swapping it with a
504 : * historical keyset if need be).
505 : */
506 : krb5_error_code
507 0 : hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno,
508 : unsigned flags, hdb_entry *ent)
509 : {
510 0 : krb5_error_code ret = HDB_ERR_NOENTRY;
511 0 : HDB_extension *ext;
512 0 : HDB_Ext_KeySet *hist_keys;
513 0 : Key *tmp_val;
514 0 : time_t tmp_set_time;
515 0 : unsigned int tmp_len;
516 0 : unsigned int kvno_diff = 0;
517 0 : krb5_kvno tmp_kvno;
518 0 : size_t i, k;
519 0 : int exclude_dead = 0;
520 0 : KerberosTime now = 0;
521 :
522 0 : if (kvno == 0)
523 0 : ret = 0;
524 :
525 0 : if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) {
526 0 : exclude_dead = 1;
527 0 : now = time(NULL);
528 0 : if (HDB_F_LIVE_CLNT_KVNOS)
529 0 : kvno_diff = hdb_entry_get_kvno_diff_clnt(ent);
530 : else
531 : kvno_diff = hdb_entry_get_kvno_diff_svc(ent);
532 : }
533 :
534 0 : ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
535 0 : if (ext == NULL || (&ext->data.u.hist_keys)->len == 0)
536 0 : return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
537 :
538 : /* For swapping; see below */
539 0 : tmp_len = ent->keys.len;
540 0 : tmp_val = ent->keys.val;
541 0 : tmp_kvno = ent->kvno;
542 0 : (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time);
543 :
544 0 : hist_keys = &ext->data.u.hist_keys;
545 :
546 0 : for (i = 0; i < hist_keys->len; i++) {
547 0 : if (kvno != 0 && hist_keys->val[i].kvno != kvno)
548 0 : continue;
549 :
550 0 : if (exclude_dead &&
551 0 : ((ent->max_life != NULL &&
552 0 : hist_keys->val[i].set_time != NULL &&
553 0 : (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) ||
554 0 : (hist_keys->val[i].kvno < kvno &&
555 0 : (kvno - hist_keys->val[i].kvno) > kvno_diff)))
556 : /*
557 : * The KDC may want to to check for this keyset's set_time
558 : * is within the TGS principal's max_life, say. But we stop
559 : * here.
560 : */
561 0 : continue;
562 :
563 : /* Either the keys we want, or all the keys */
564 0 : for (k = 0; k < hist_keys->val[i].keys.len; k++) {
565 0 : ret = hdb_unseal_key_mkey(context,
566 0 : &hist_keys->val[i].keys.val[k],
567 : db->hdb_master_key);
568 : /*
569 : * If kvno == 0 we might not want to bail here! E.g., if we
570 : * no longer have the right master key, so just ignore this.
571 : *
572 : * We could filter out keys that we can't decrypt here
573 : * because of HDB_ERR_NO_MKEY. However, it seems safest to
574 : * filter them out only where necessary, say, in kadm5.
575 : */
576 0 : if (ret && kvno != 0)
577 0 : return ret;
578 0 : if (ret && ret != HDB_ERR_NO_MKEY)
579 0 : return (ret);
580 : }
581 :
582 0 : if (kvno == 0)
583 0 : continue;
584 :
585 : /*
586 : * What follows is a bit of a hack.
587 : *
588 : * This is the keyset we're being asked for, but it's not the
589 : * current keyset. So we add the current keyset to the history,
590 : * leave the one we were asked for in the history, and pretend
591 : * the one we were asked for is also the current keyset.
592 : *
593 : * This is a bit of a defensive hack in case an entry fetched
594 : * this way ever gets modified then stored: if the keyset is not
595 : * changed we can detect this and put things back, else we won't
596 : * drop any keysets from history by accident.
597 : *
598 : * Note too that we only ever get called with a non-zero kvno
599 : * either in the KDC or in cases where we aren't changing the
600 : * HDB entry anyways, which is why this is just a defensive
601 : * hack. We also don't fetch specific kvnos in the dump case,
602 : * so there's no danger that we'll dump this entry and load it
603 : * again, repeatedly causing the history to grow boundelessly.
604 : */
605 :
606 : /* Swap key sets */
607 0 : ent->kvno = hist_keys->val[i].kvno;
608 0 : ent->keys.val = hist_keys->val[i].keys.val;
609 0 : ent->keys.len = hist_keys->val[i].keys.len;
610 0 : if (hist_keys->val[i].set_time != NULL)
611 : /* Sloppy, but the callers we expect won't care */
612 0 : (void) hdb_entry_set_pw_change_time(context, ent,
613 0 : *hist_keys->val[i].set_time);
614 0 : hist_keys->val[i].kvno = tmp_kvno;
615 0 : hist_keys->val[i].keys.val = tmp_val;
616 0 : hist_keys->val[i].keys.len = tmp_len;
617 0 : if (hist_keys->val[i].set_time != NULL)
618 : /* Sloppy, but the callers we expect won't care */
619 0 : *hist_keys->val[i].set_time = tmp_set_time;
620 :
621 0 : return 0;
622 : }
623 :
624 0 : return (ret);
625 : }
626 :
627 : krb5_error_code
628 0 : hdb_unseal_key(krb5_context context, HDB *db, Key *k)
629 : {
630 0 : if (db->hdb_master_key_set == 0)
631 0 : return 0;
632 0 : return hdb_unseal_key_mkey(context, k, db->hdb_master_key);
633 : }
634 :
635 : krb5_error_code
636 0 : hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
637 : {
638 0 : krb5_error_code ret;
639 0 : krb5_data res;
640 0 : hdb_master_key key;
641 :
642 0 : if(k->mkvno != NULL)
643 0 : return 0;
644 :
645 0 : key = _hdb_find_master_key(k->mkvno, mkey);
646 :
647 0 : if (key == NULL)
648 0 : return HDB_ERR_NO_MKEY;
649 :
650 0 : ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
651 0 : k->key.keyvalue.data,
652 : k->key.keyvalue.length,
653 : &res);
654 0 : if (ret)
655 0 : return ret;
656 :
657 0 : memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
658 0 : free(k->key.keyvalue.data);
659 0 : k->key.keyvalue = res;
660 :
661 0 : if (k->mkvno == NULL) {
662 0 : k->mkvno = malloc(sizeof(*k->mkvno));
663 0 : if (k->mkvno == NULL)
664 0 : return ENOMEM;
665 : }
666 0 : *k->mkvno = key->keytab.vno;
667 :
668 0 : return 0;
669 : }
670 :
671 : krb5_error_code
672 0 : hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
673 : {
674 0 : HDB_extension *ext;
675 0 : HDB_Ext_KeySet *hist_keys;
676 0 : size_t i, k;
677 0 : krb5_error_code ret;
678 :
679 0 : for(i = 0; i < ent->keys.len; i++){
680 0 : ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
681 0 : if (ret)
682 0 : return ret;
683 : }
684 :
685 0 : ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
686 0 : if (ext == NULL)
687 0 : return 0;
688 0 : hist_keys = &ext->data.u.hist_keys;
689 :
690 0 : for (i = 0; i < hist_keys->len; i++) {
691 0 : for (k = 0; k < hist_keys->val[i].keys.len; k++) {
692 0 : ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k],
693 : mkey);
694 0 : if (ret)
695 0 : return ret;
696 : }
697 : }
698 :
699 0 : return 0;
700 : }
701 :
702 : krb5_error_code
703 0 : hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
704 : {
705 0 : if (db->hdb_master_key_set == 0)
706 0 : return 0;
707 :
708 0 : return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);
709 : }
710 :
711 : krb5_error_code
712 0 : hdb_seal_key(krb5_context context, HDB *db, Key *k)
713 : {
714 0 : if (db->hdb_master_key_set == 0)
715 0 : return 0;
716 :
717 0 : return hdb_seal_key_mkey(context, k, db->hdb_master_key);
718 : }
719 :
720 : krb5_error_code
721 0 : hdb_set_master_key(krb5_context context,
722 : HDB *db,
723 : krb5_keyblock *key)
724 : {
725 0 : krb5_error_code ret;
726 0 : hdb_master_key mkey;
727 :
728 0 : ret = hdb_process_master_key(context, 0, key, 0, &mkey);
729 0 : if (ret)
730 0 : return ret;
731 0 : db->hdb_master_key = mkey;
732 : #if 0 /* XXX - why? */
733 : des_set_random_generator_seed(key.keyvalue.data);
734 : #endif
735 0 : db->hdb_master_key_set = 1;
736 0 : db->hdb_master_key->key_usage = HDB_KU_MKEY;
737 0 : return 0;
738 : }
739 :
740 : krb5_error_code
741 68 : hdb_set_master_keyfile (krb5_context context,
742 : HDB *db,
743 : const char *keyfile)
744 : {
745 0 : hdb_master_key key;
746 0 : krb5_error_code ret;
747 :
748 68 : ret = hdb_read_master_key(context, keyfile, &key);
749 68 : if (ret) {
750 68 : if (ret != ENOENT)
751 0 : return ret;
752 68 : krb5_clear_error_message(context);
753 68 : return 0;
754 : }
755 0 : db->hdb_master_key = key;
756 0 : db->hdb_master_key_set = 1;
757 0 : return ret;
758 : }
759 :
760 : krb5_error_code
761 0 : hdb_clear_master_key (krb5_context context,
762 : HDB *db)
763 : {
764 0 : if (db->hdb_master_key_set) {
765 0 : hdb_free_master_key(context, db->hdb_master_key);
766 0 : db->hdb_master_key_set = 0;
767 : }
768 0 : return 0;
769 : }
|