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