Line data Source code
1 : /*
2 : * Copyright (c) 1997-2002 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 "krb5_locl.h"
35 : #include "hdb_locl.h"
36 :
37 : int
38 0 : hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
39 : {
40 : Principal new;
41 0 : size_t len = 0;
42 : int ret;
43 :
44 0 : ret = copy_Principal(p, &new);
45 0 : if(ret)
46 0 : return ret;
47 0 : new.name.name_type = 0;
48 :
49 0 : ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
50 0 : if (ret == 0 && key->length != len)
51 0 : krb5_abortx(context, "internal asn.1 encoder error");
52 0 : free_Principal(&new);
53 0 : return ret;
54 : }
55 :
56 : int
57 0 : hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
58 : {
59 0 : return decode_Principal(key->data, key->length, p, NULL);
60 : }
61 :
62 : int
63 0 : hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
64 : {
65 0 : size_t len = 0;
66 : int ret;
67 :
68 0 : ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret);
69 0 : if (ret == 0 && value->length != len)
70 0 : krb5_abortx(context, "internal asn.1 encoder error");
71 0 : return ret;
72 : }
73 :
74 : int
75 0 : hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
76 : {
77 0 : return decode_HDB_entry(value->data, value->length, ent, NULL);
78 : }
79 :
80 : int
81 0 : hdb_entry_alias2value(krb5_context context,
82 : const hdb_entry_alias *alias,
83 : krb5_data *value)
84 : {
85 0 : size_t len = 0;
86 : int ret;
87 :
88 0 : ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length,
89 : alias, &len, ret);
90 0 : if (ret == 0 && value->length != len)
91 0 : krb5_abortx(context, "internal asn.1 encoder error");
92 0 : return ret;
93 : }
94 :
95 : int
96 0 : hdb_value2entry_alias(krb5_context context, krb5_data *value,
97 : hdb_entry_alias *ent)
98 : {
99 0 : return decode_HDB_entry_alias(value->data, value->length, ent, NULL);
100 : }
101 :
102 : /*
103 : * Some old databases may not have stored the salt with each key, which will
104 : * break clients when aliases or canonicalization are used. Generate a
105 : * default salt based on the real principal name in the entry to handle
106 : * this case.
107 : */
108 : static krb5_error_code
109 0 : add_default_salts(krb5_context context, HDB *db, hdb_entry *entry)
110 : {
111 : krb5_error_code ret;
112 : size_t i;
113 : krb5_salt pwsalt;
114 :
115 0 : ret = krb5_get_pw_salt(context, entry->principal, &pwsalt);
116 0 : if (ret)
117 0 : return ret;
118 :
119 0 : for (i = 0; i < entry->keys.len; i++) {
120 0 : Key *key = &entry->keys.val[i];
121 :
122 0 : if (key->salt != NULL ||
123 0 : _krb5_enctype_requires_random_salt(context, key->key.keytype))
124 0 : continue;
125 :
126 0 : key->salt = calloc(1, sizeof(*key->salt));
127 0 : if (key->salt == NULL) {
128 0 : ret = krb5_enomem(context);
129 0 : break;
130 : }
131 :
132 0 : key->salt->type = KRB5_PADATA_PW_SALT;
133 :
134 0 : ret = krb5_data_copy(&key->salt->salt,
135 0 : pwsalt.saltvalue.data,
136 : pwsalt.saltvalue.length);
137 0 : if (ret)
138 0 : break;
139 : }
140 :
141 0 : krb5_free_salt(context, pwsalt);
142 :
143 0 : return ret;
144 : }
145 :
146 : static krb5_error_code
147 0 : fetch_entry_or_alias(krb5_context context,
148 : HDB *db,
149 : krb5_const_principal principal,
150 : unsigned flags,
151 : hdb_entry *entry)
152 : {
153 : HDB_EntryOrAlias eoa;
154 0 : krb5_principal enterprise_principal = NULL;
155 : krb5_data key, value;
156 : krb5_error_code ret;
157 :
158 0 : value.length = 0;
159 0 : value.data = 0;
160 0 : key = value;
161 :
162 0 : if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
163 0 : if (principal->name.name_string.len != 1) {
164 0 : ret = KRB5_PARSE_MALFORMED;
165 0 : krb5_set_error_message(context, ret, "malformed principal: "
166 : "enterprise name with %d name components",
167 : principal->name.name_string.len);
168 0 : return ret;
169 : }
170 0 : ret = krb5_parse_name(context, principal->name.name_string.val[0],
171 : &enterprise_principal);
172 0 : if (ret)
173 0 : return ret;
174 0 : principal = enterprise_principal;
175 : }
176 :
177 0 : ret = hdb_principal2key(context, principal, &key);
178 0 : if (ret == 0)
179 0 : ret = db->hdb__get(context, db, key, &value);
180 0 : if (ret == 0)
181 0 : ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
182 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) {
183 0 : *entry = eoa.u.entry;
184 0 : } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) {
185 0 : krb5_data_free(&key);
186 0 : ret = hdb_principal2key(context, eoa.u.alias.principal, &key);
187 0 : if (ret == 0) {
188 0 : krb5_data_free(&value);
189 0 : ret = db->hdb__get(context, db, key, &value);
190 : }
191 0 : if (ret == 0)
192 : /* No alias chaining */
193 0 : ret = hdb_value2entry(context, &value, entry);
194 0 : krb5_free_principal(context, eoa.u.alias.principal);
195 0 : } else if (ret == 0)
196 0 : ret = ENOTSUP;
197 0 : if (ret == 0 && enterprise_principal) {
198 : /*
199 : * Whilst Windows does not canonicalize enterprise principal names if
200 : * the canonicalize flag is unset, the original specification in
201 : * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
202 : */
203 0 : entry->flags.force_canonicalize = 1;
204 : }
205 :
206 : /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
207 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
208 0 : (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) {
209 :
210 : /* `principal' was alias but canon not req'd */
211 0 : free_HDB_entry(entry);
212 0 : ret = HDB_ERR_NOENTRY;
213 : }
214 :
215 0 : krb5_free_principal(context, enterprise_principal);
216 0 : krb5_data_free(&value);
217 0 : krb5_data_free(&key);
218 0 : principal = enterprise_principal = NULL;
219 0 : return ret;
220 : }
221 :
222 : krb5_error_code
223 0 : _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
224 : unsigned flags, krb5_kvno kvno, hdb_entry *entry)
225 : {
226 : krb5_error_code ret;
227 :
228 0 : ret = fetch_entry_or_alias(context, db, principal, flags, entry);
229 0 : if (ret)
230 0 : return ret;
231 :
232 0 : if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
233 : /* Decrypt the current keys */
234 0 : ret = hdb_unseal_keys(context, db, entry);
235 0 : if (ret) {
236 0 : hdb_free_entry(context, db, entry);
237 0 : return ret;
238 : }
239 : /* Decrypt the key history too */
240 0 : ret = hdb_unseal_keys_kvno(context, db, 0, flags, entry);
241 0 : if (ret) {
242 0 : hdb_free_entry(context, db, entry);
243 0 : return ret;
244 : }
245 0 : } else if ((flags & HDB_F_DECRYPT)) {
246 0 : if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->kvno) {
247 : /* Decrypt the current keys */
248 0 : ret = hdb_unseal_keys(context, db, entry);
249 0 : if (ret) {
250 0 : hdb_free_entry(context, db, entry);
251 0 : return ret;
252 : }
253 : } else {
254 0 : if ((flags & HDB_F_ALL_KVNOS))
255 0 : kvno = 0;
256 : /*
257 : * Find and decrypt the keys from the history that we want,
258 : * and swap them with the current keys
259 : */
260 0 : ret = hdb_unseal_keys_kvno(context, db, kvno, flags, entry);
261 0 : if (ret) {
262 0 : hdb_free_entry(context, db, entry);
263 0 : return ret;
264 : }
265 : }
266 : }
267 0 : if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) {
268 : /*
269 : * Generate default salt for any principals missing one; note such
270 : * principals could include those for which a random (non-password)
271 : * key was generated, but given the salt will be ignored by a keytab
272 : * client it doesn't hurt to include the default salt.
273 : */
274 0 : ret = add_default_salts(context, db, entry);
275 0 : if (ret) {
276 0 : hdb_free_entry(context, db, entry);
277 0 : return ret;
278 : }
279 : }
280 :
281 0 : return 0;
282 : }
283 :
284 : static krb5_error_code
285 0 : hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
286 : {
287 : const HDB_Ext_Aliases *aliases;
288 : krb5_error_code code;
289 : hdb_entry oldentry;
290 : krb5_data value;
291 : size_t i;
292 :
293 0 : code = db->hdb__get(context, db, *key, &value);
294 0 : if (code == HDB_ERR_NOENTRY)
295 0 : return 0;
296 0 : else if (code)
297 0 : return code;
298 :
299 0 : code = hdb_value2entry(context, &value, &oldentry);
300 0 : krb5_data_free(&value);
301 0 : if (code)
302 0 : return code;
303 :
304 0 : code = hdb_entry_get_aliases(&oldentry, &aliases);
305 0 : if (code || aliases == NULL) {
306 0 : free_HDB_entry(&oldentry);
307 0 : return code;
308 : }
309 0 : for (i = 0; i < aliases->aliases.len; i++) {
310 : krb5_data akey;
311 :
312 0 : code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
313 0 : if (code == 0) {
314 0 : code = db->hdb__del(context, db, akey);
315 0 : krb5_data_free(&akey);
316 : }
317 0 : if (code) {
318 0 : free_HDB_entry(&oldentry);
319 0 : return code;
320 : }
321 : }
322 0 : free_HDB_entry(&oldentry);
323 0 : return 0;
324 : }
325 :
326 : static krb5_error_code
327 0 : hdb_add_aliases(krb5_context context, HDB *db,
328 : unsigned flags, hdb_entry *entry)
329 : {
330 : const HDB_Ext_Aliases *aliases;
331 : krb5_error_code code;
332 : krb5_data key, value;
333 : size_t i;
334 :
335 0 : code = hdb_entry_get_aliases(entry, &aliases);
336 0 : if (code || aliases == NULL)
337 0 : return code;
338 :
339 0 : for (i = 0; i < aliases->aliases.len; i++) {
340 : hdb_entry_alias entryalias;
341 0 : entryalias.principal = entry->principal;
342 :
343 0 : code = hdb_entry_alias2value(context, &entryalias, &value);
344 0 : if (code)
345 0 : return code;
346 :
347 0 : code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
348 0 : if (code == 0) {
349 0 : code = db->hdb__put(context, db, flags, key, value);
350 0 : krb5_data_free(&key);
351 : }
352 0 : krb5_data_free(&value);
353 0 : if (code)
354 0 : return code;
355 : }
356 0 : return 0;
357 : }
358 :
359 : /* Check if new aliases are already used for other entries */
360 : static krb5_error_code
361 0 : hdb_check_aliases(krb5_context context, HDB *db, hdb_entry *entry)
362 : {
363 0 : const HDB_Ext_Aliases *aliases = NULL;
364 : HDB_EntryOrAlias eoa;
365 : krb5_data akey, value;
366 : size_t i;
367 : int ret;
368 :
369 0 : memset(&eoa, 0, sizeof(eoa));
370 0 : krb5_data_zero(&value);
371 0 : akey = value;
372 :
373 0 : ret = hdb_entry_get_aliases(entry, &aliases);
374 0 : for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) {
375 0 : ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
376 0 : if (ret == 0)
377 0 : ret = db->hdb__get(context, db, akey, &value);
378 0 : if (ret == 0)
379 0 : ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
380 0 : if (ret == 0 && eoa.element != choice_HDB_EntryOrAlias_entry &&
381 0 : eoa.element != choice_HDB_EntryOrAlias_alias)
382 0 : ret = ENOTSUP;
383 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry)
384 : /* New alias names an existing non-alias entry in the HDB */
385 0 : ret = HDB_ERR_EXISTS;
386 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
387 0 : !krb5_principal_compare(context, eoa.u.alias.principal,
388 0 : entry->principal))
389 : /* New alias names an existing alias of a different entry */
390 0 : ret = HDB_ERR_EXISTS;
391 0 : if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */
392 : /* New alias is a name that doesn't exist in the HDB */
393 0 : ret = 0;
394 :
395 0 : free_HDB_EntryOrAlias(&eoa);
396 0 : krb5_data_free(&value);
397 0 : krb5_data_free(&akey);
398 : }
399 0 : return ret;
400 : }
401 :
402 : /*
403 : * Many HDB entries don't have `etypes' setup. Historically we use the
404 : * enctypes of the selected keyset as the entry's supported enctypes, but that
405 : * is problematic. By doing this at store time and, if need be, at fetch time,
406 : * we can make sure to stop deriving supported etypes from keys in the long
407 : * run. We also need kadm5/kadmin support for etypes. We'll use this function
408 : * there to derive etypes when using a kadm5_principal_ent_t that lacks the new
409 : * TL data for etypes.
410 : */
411 : krb5_error_code
412 0 : hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys)
413 : {
414 0 : krb5_error_code ret = 0;
415 : size_t i, k, netypes;
416 : HDB_extension *ext;
417 :
418 0 : if (!base_keys &&
419 : (ext = hdb_find_extension(e, choice_HDB_extension_data_hist_keys)))
420 0 : base_keys = &ext->data.u.hist_keys;
421 :
422 0 : netypes = e->keys.len;
423 0 : if (netypes == 0 && base_keys) {
424 : /* There's no way that base_keys->val[i].keys.len == 0, but hey */
425 0 : for (i = 0; netypes == 0 && i < base_keys->len; i++)
426 0 : netypes = base_keys->val[i].keys.len;
427 : }
428 :
429 0 : if (netypes == 0)
430 0 : return 0;
431 :
432 0 : if (e->etypes != NULL) {
433 0 : free(e->etypes->val);
434 0 : e->etypes->len = 0;
435 0 : e->etypes->val = 0;
436 0 : } else if ((e->etypes = calloc(1, sizeof(e->etypes[0]))) == NULL) {
437 0 : ret = krb5_enomem(context);
438 : }
439 0 : if (ret == 0 &&
440 0 : (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL)
441 0 : ret = krb5_enomem(context);
442 0 : if (ret) {
443 0 : free(e->etypes);
444 0 : e->etypes = 0;
445 0 : return ret;
446 : }
447 0 : e->etypes->len = netypes;
448 0 : for (i = 0; i < e->keys.len && i < netypes; i++)
449 0 : e->etypes->val[i] = e->keys.val[i].key.keytype;
450 0 : if (!base_keys || i)
451 0 : return 0;
452 0 : for (k = 0; i == 0 && k < base_keys->len; k++) {
453 0 : if (!base_keys->val[k].keys.len)
454 0 : continue;
455 0 : for (; i < base_keys->val[k].keys.len; i++)
456 0 : e->etypes->val[i] = base_keys->val[k].keys.val[i].key.keytype;
457 : }
458 0 : return 0;
459 : }
460 :
461 : krb5_error_code
462 0 : _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
463 : {
464 : krb5_data key, value;
465 : int code;
466 :
467 0 : if (entry->flags.do_not_store ||
468 : entry->flags.force_canonicalize)
469 0 : return HDB_ERR_MISUSE;
470 : /* check if new aliases already is used */
471 0 : code = hdb_check_aliases(context, db, entry);
472 0 : if (code)
473 0 : return code;
474 :
475 0 : if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
476 0 : return 0;
477 :
478 0 : if ((flags & HDB_F_PRECHECK)) {
479 0 : code = hdb_principal2key(context, entry->principal, &key);
480 0 : if (code)
481 0 : return code;
482 0 : code = db->hdb__get(context, db, key, &value);
483 0 : krb5_data_free(&key);
484 0 : if (code == 0)
485 0 : krb5_data_free(&value);
486 0 : if (code == HDB_ERR_NOENTRY)
487 0 : return 0;
488 0 : return code ? code : HDB_ERR_EXISTS;
489 : }
490 :
491 0 : if ((entry->etypes == NULL || entry->etypes->len == 0) &&
492 : (code = hdb_derive_etypes(context, entry, NULL)))
493 0 : return code;
494 :
495 0 : if (entry->generation == NULL) {
496 : struct timeval t;
497 0 : entry->generation = malloc(sizeof(*entry->generation));
498 0 : if(entry->generation == NULL) {
499 0 : krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
500 0 : return ENOMEM;
501 : }
502 0 : gettimeofday(&t, NULL);
503 0 : entry->generation->time = t.tv_sec;
504 0 : entry->generation->usec = t.tv_usec;
505 0 : entry->generation->gen = 0;
506 : } else
507 0 : entry->generation->gen++;
508 :
509 0 : code = hdb_seal_keys(context, db, entry);
510 0 : if (code)
511 0 : return code;
512 :
513 0 : code = hdb_principal2key(context, entry->principal, &key);
514 0 : if (code)
515 0 : return code;
516 :
517 : /* remove aliases */
518 0 : code = hdb_remove_aliases(context, db, &key);
519 0 : if (code) {
520 0 : krb5_data_free(&key);
521 0 : return code;
522 : }
523 0 : code = hdb_entry2value(context, entry, &value);
524 0 : if (code == 0)
525 0 : code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
526 0 : krb5_data_free(&value);
527 0 : krb5_data_free(&key);
528 0 : if (code)
529 0 : return code;
530 :
531 0 : code = hdb_add_aliases(context, db, flags, entry);
532 :
533 0 : return code;
534 : }
535 :
536 : krb5_error_code
537 0 : _hdb_remove(krb5_context context, HDB *db,
538 : unsigned flags, krb5_const_principal principal)
539 : {
540 : krb5_data key, value;
541 : HDB_EntryOrAlias eoa;
542 0 : int is_alias = -1;
543 : int code;
544 :
545 : /*
546 : * We only allow deletion of entries by canonical name. To remove an
547 : * alias use kadm5_modify_principal().
548 : *
549 : * We need to determine if this is an alias. We decode as a
550 : * HDB_EntryOrAlias, which is expensive -- we could decode as a
551 : * HDB_entry_alias instead and assume it's an entry if decoding fails...
552 : */
553 :
554 0 : code = hdb_principal2key(context, principal, &key);
555 0 : if (code == 0)
556 0 : code = db->hdb__get(context, db, key, &value);
557 0 : if (code == 0) {
558 0 : code = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
559 0 : krb5_data_free(&value);
560 : }
561 0 : if (code == 0) {
562 0 : is_alias = eoa.element == choice_HDB_EntryOrAlias_entry ? 0 : 1;
563 0 : free_HDB_EntryOrAlias(&eoa);
564 : }
565 :
566 0 : if ((flags & HDB_F_PRECHECK)) {
567 0 : if (code == 0 && is_alias)
568 0 : krb5_set_error_message(context, code = HDB_ERR_NOENTRY,
569 : "Cannot delete alias of principal");
570 0 : krb5_data_free(&key);
571 0 : return code;
572 : }
573 :
574 0 : if (code == 0)
575 0 : code = hdb_remove_aliases(context, db, &key);
576 0 : if (code == 0)
577 0 : code = db->hdb__del(context, db, key);
578 0 : krb5_data_free(&key);
579 0 : return code;
580 : }
581 :
582 : /* PRF+(K_base, pad, keylen(etype)) */
583 : static krb5_error_code
584 0 : derive_Key1(krb5_context context,
585 : krb5_data *pad,
586 : EncryptionKey *base,
587 : krb5int32 etype,
588 : EncryptionKey *nk)
589 : {
590 : krb5_error_code ret;
591 0 : krb5_crypto crypto = NULL;
592 : krb5_data out;
593 : size_t len;
594 :
595 0 : out.data = 0;
596 0 : out.length = 0;
597 :
598 0 : ret = krb5_enctype_keysize(context, base->keytype, &len);
599 0 : if (ret == 0)
600 0 : ret = krb5_crypto_init(context, base, 0, &crypto);
601 0 : if (ret == 0)
602 0 : ret = krb5_crypto_prfplus(context, crypto, pad, len, &out);
603 0 : if (crypto)
604 0 : krb5_crypto_destroy(context, crypto);
605 0 : if (ret == 0)
606 0 : ret = krb5_random_to_key(context, etype, out.data, out.length, nk);
607 0 : krb5_data_free(&out);
608 0 : return ret;
609 : }
610 :
611 : /* PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) */
612 : /* XXX Make it PRF+(PRF+(K_base, princ, keylen(K_base.etype)), and lift it, kvno, keylen(etype)) */
613 : static krb5_error_code
614 0 : derive_Key(krb5_context context,
615 : const char *princ,
616 : krb5uint32 kvno,
617 : EncryptionKey *base,
618 : krb5int32 etype,
619 : Key *nk)
620 : {
621 0 : krb5_error_code ret = 0;
622 : EncryptionKey intermediate;
623 : krb5_data pad;
624 :
625 0 : nk->salt = NULL;
626 0 : nk->mkvno = NULL;
627 0 : nk->key.keytype = 0;
628 0 : nk->key.keyvalue.data = 0;
629 0 : nk->key.keyvalue.length = 0;
630 :
631 0 : intermediate.keytype = 0;
632 0 : intermediate.keyvalue.data = 0;
633 0 : intermediate.keyvalue.length = 0;
634 0 : if (princ) {
635 : /* Derive intermediate key for the given principal */
636 : /* XXX Lift to optimize? */
637 0 : pad.data = (void *)(uintptr_t)princ;
638 0 : pad.length = strlen(princ);
639 0 : ret = derive_Key1(context, &pad, base, etype, &intermediate);
640 0 : if (ret == 0)
641 0 : base = &intermediate;
642 : } /* else `base' is already an intermediate key for the desired princ */
643 :
644 : /* Derive final key for `kvno' from intermediate key */
645 0 : kvno = htonl(kvno);
646 0 : pad.data = &kvno;
647 0 : pad.length = sizeof(kvno);
648 0 : if (ret == 0)
649 0 : ret = derive_Key1(context, &pad, base, etype, &nk->key);
650 0 : free_EncryptionKey(&intermediate);
651 0 : return ret;
652 : }
653 :
654 : /*
655 : * PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) for one
656 : * enctype.
657 : */
658 : static krb5_error_code
659 0 : derive_Keys(krb5_context context,
660 : const char *princ,
661 : krb5uint32 kvno,
662 : krb5int32 etype,
663 : const Keys *base,
664 : Keys *dk)
665 :
666 : {
667 0 : krb5_error_code ret = 0;
668 : size_t i;
669 : Key nk;
670 :
671 0 : dk->len = 0;
672 0 : dk->val = 0;
673 :
674 : /*
675 : * The enctypes of the base keys is the list of enctypes to derive keys
676 : * for. Still, we derive all keys from the first base key.
677 : */
678 0 : for (i = 0; ret == 0 && i < base->len; i++) {
679 0 : if (etype != KRB5_ENCTYPE_NULL && etype != base->val[i].key.keytype)
680 0 : continue;
681 0 : ret = derive_Key(context, princ, kvno, &base->val[0].key,
682 0 : base->val[i].key.keytype, &nk);
683 0 : if (ret)
684 0 : break;
685 0 : ret = add_Keys(dk, &nk);
686 0 : free_Key(&nk);
687 : /*
688 : * FIXME We need to finish kdc/kadm5/kadmin support for the `etypes' so
689 : * we can reduce the number of keys in keytabs to just those in current
690 : * use and only of *one* enctype.
691 : *
692 : * What we could do is derive *one* key and for the others output a
693 : * one-byte key of the intended enctype (which will never work).
694 : *
695 : * We'll never need any keys but the first one...
696 : */
697 : }
698 :
699 0 : if (ret)
700 0 : free_Keys(dk);
701 0 : return ret;
702 : }
703 :
704 : /* Helper for derive_keys_for_kr() */
705 : static krb5_error_code
706 0 : derive_keyset(krb5_context context,
707 : const Keys *base_keys,
708 : const char *princ,
709 : krb5int32 etype,
710 : krb5uint32 kvno,
711 : KerberosTime set_time, /* "now" */
712 : hdb_keyset *dks)
713 : {
714 0 : dks->kvno = kvno;
715 0 : dks->keys.val = 0;
716 0 : dks->set_time = malloc(sizeof(*(dks->set_time)));
717 0 : if (dks->set_time == NULL)
718 0 : return krb5_enomem(context);
719 0 : *dks->set_time = set_time;
720 0 : return derive_Keys(context, princ, kvno, etype, base_keys, &dks->keys);
721 : }
722 :
723 : /* Possibly derive and install in `h' a keyset identified by `t' */
724 : static krb5_error_code
725 0 : derive_keys_for_kr(krb5_context context,
726 : hdb_entry *h,
727 : HDB_Ext_KeySet *base_keys,
728 : int is_current_keyset,
729 : int rotation_period_offset,
730 : const char *princ,
731 : krb5int32 etype,
732 : krb5uint32 kvno_wanted,
733 : KerberosTime t,
734 : struct KeyRotation *krp)
735 : {
736 : krb5_error_code ret;
737 : hdb_keyset dks;
738 : KerberosTime set_time, n;
739 : krb5uint32 kvno;
740 : size_t i;
741 :
742 0 : if (rotation_period_offset < -1 || rotation_period_offset > 1)
743 0 : return EINVAL; /* wat */
744 :
745 : /*
746 : * Compute `kvno' and `set_time' given `t' and `krp'.
747 : *
748 : * There be signed 32-bit time_t dragons here.
749 : *
750 : * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more
751 : * tolerant of signed 32-bit time_t here near 2038. Of course, we have
752 : * signed 32-bit time_t dragons elsewhere.
753 : */
754 0 : if (t - krp->epoch < 0)
755 0 : return 0; /* This KR is not relevant yet */
756 0 : n = (t - krp->epoch) / krp->period;
757 0 : n += rotation_period_offset;
758 0 : set_time = krp->epoch + krp->period * n;
759 0 : kvno = krp->base_kvno + n;
760 :
761 :
762 : /*
763 : * Do not waste cycles computing keys not wanted or needed.
764 : * A past kvno is too old if its set_time + rotation period is in the past
765 : * by more than half a rotation period, since then no service ticket
766 : * encrypted with keys of that kvno can still be extant.
767 : *
768 : * A future kvno is not coming up soon enough if we're more than a quarter
769 : * of the rotation period away from it.
770 : *
771 : * Recall: the assumption for virtually-keyed principals is that services
772 : * fetch their future keys frequently enough that they'll never miss having
773 : * the keys they need.
774 : */
775 0 : if (!is_current_keyset || rotation_period_offset != 0) {
776 0 : if ((kvno_wanted && kvno != kvno_wanted) ||
777 0 : t - (set_time + krp->period + (krp->period >> 1)) > 0 ||
778 0 : (set_time - t > 0 && (set_time - t) > (krp->period >> 2)))
779 0 : return 0;
780 : }
781 :
782 0 : for (i = 0; i < base_keys->len; i++) {
783 0 : if (base_keys->val[i].kvno == krp->base_key_kvno)
784 0 : break;
785 : }
786 0 : if (i == base_keys->len) {
787 : /* Base key not found! */
788 0 : if (kvno_wanted || is_current_keyset) {
789 0 : krb5_set_error_message(context, ret = HDB_ERR_KVNO_NOT_FOUND,
790 : "Base key version %u not found for %s",
791 : krp->base_key_kvno, princ);
792 0 : return ret;
793 : }
794 0 : return 0;
795 : }
796 :
797 0 : ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno,
798 : set_time, &dks);
799 0 : if (ret == 0)
800 0 : ret = hdb_install_keyset(context, h, is_current_keyset, &dks);
801 :
802 0 : free_HDB_keyset(&dks);
803 0 : return ret;
804 : }
805 :
806 : /* Derive and install current keys, and possibly preceding or next keys */
807 : static krb5_error_code
808 0 : derive_keys_for_current_kr(krb5_context context,
809 : hdb_entry *h,
810 : HDB_Ext_KeySet *base_keys,
811 : const char *princ,
812 : unsigned int flags,
813 : krb5int32 etype,
814 : krb5uint32 kvno_wanted,
815 : KerberosTime t,
816 : struct KeyRotation *krp,
817 : KerberosTime future_epoch)
818 : {
819 : krb5_error_code ret;
820 :
821 : /* derive_keys_for_kr() for current kvno and install as the current keys */
822 0 : ret = derive_keys_for_kr(context, h, base_keys, 1, 0, princ, etype,
823 : kvno_wanted, t, krp);
824 0 : if (!(flags & HDB_F_ALL_KVNOS))
825 0 : return ret;
826 :
827 : /* */
828 :
829 :
830 : /*
831 : * derive_keys_for_kr() for prev kvno if still needed -- it can only be
832 : * needed if the prev kvno's start time is within this KR's epoch.
833 : *
834 : * Note that derive_keys_for_kr() can return without doing anything if this
835 : * is isn't the current keyset. So these conditions need not be
836 : * sufficiently narrow.
837 : */
838 0 : if (ret == 0 && t - krp->epoch >= krp->period)
839 0 : ret = derive_keys_for_kr(context, h, base_keys, 0, -1, princ, etype,
840 : kvno_wanted, t, krp);
841 : /*
842 : * derive_keys_for_kr() for next kvno if near enough, but only if it
843 : * doesn't start after the next KR's epoch.
844 : */
845 0 : if (future_epoch &&
846 0 : t - krp->epoch >= 0 /* We know! Hint to the compiler */) {
847 : KerberosTime next_kvno_start, n;
848 :
849 0 : n = (t - krp->epoch) / krp->period;
850 0 : next_kvno_start = krp->epoch + krp->period * (n + 1);
851 0 : if (future_epoch - next_kvno_start <= 0)
852 0 : return ret;
853 : }
854 0 : if (ret == 0)
855 0 : ret = derive_keys_for_kr(context, h, base_keys, 0, 1, princ, etype,
856 : kvno_wanted, t, krp);
857 0 : return ret;
858 : }
859 :
860 : /*
861 : * Derive and install all keysets in `h' that `princ' needs at time `now'.
862 : *
863 : * This mutates the entry `h' to
864 : *
865 : * a) not have base keys,
866 : * b) have keys derived from the base keys according to
867 : * c) the key rotation periods for the base principal (possibly the same
868 : * principal if it's a concrete principal with virtual keys), and the
869 : * requested time, enctype, and kvno (all of which are optional, with zero
870 : * implying some default).
871 : *
872 : * Arguments:
873 : *
874 : * - `flags' is the flags passed to `hdb_fetch_kvno()'
875 : * - `princ' is the name of the principal we'll end up with in `entry'
876 : * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete
877 : * principal (that might nonetheless have virtual/derived keys)
878 : * - `t' is the time such that the derived keys are for kvnos needed at `t'
879 : * - `etype' indicates what enctype to derive keys for (0 for all enctypes in
880 : * `entry->etypes')
881 : * - `kvno' requests a particular kvno, or all if zero
882 : *
883 : * The caller doesn't know if the principal needs key derivation -- we make
884 : * that determination in this function.
885 : *
886 : * Note that this function is fully deterministic for any given set of
887 : * arguments and HDB contents.
888 : *
889 : * Definitions:
890 : *
891 : * - A keyset is a set of keys for a single kvno.
892 : * - A keyset is relevant IFF:
893 : * - it is the keyset for a time period identified by `t' in a
894 : * corresponding KR
895 : * - it is a keyset for a past time period for which there may be extant,
896 : * not-yet-expired tickets that a service may need to decrypt
897 : * - it is a keyset for an upcoming time period that a service will need to
898 : * fetch before that time period becomes current, that way the service
899 : * can have keytab entries for those keys in time for when the KDC starts
900 : * encrypting service tickets to those keys
901 : *
902 : * This function derives the keyset(s) for the current KR first. The idea is
903 : * to optimize the order of resulting keytabs so that the most likely keys to
904 : * be used come first.
905 : *
906 : * Invariants:
907 : *
908 : * - KR metadata is sane because sanity is checked for when storing HDB
909 : * entries
910 : * - KRs are sorted by epoch in descending order; KR #0's epoch is the most
911 : * recent
912 : * - KR periods are non-zero (we divide by period)
913 : * - kvnos are numerically ordered and correspond to time periods
914 : * - within each KR, the kvnos for larger times are larger than (or equal
915 : * to) the kvnos of earlier times
916 : * - at KR boundaries, the first kvno of the newer boundary is larger than
917 : * the kvno of the last time period of the previous KR
918 : * - the time `t' must fall into exactly one KR period
919 : * - the time `t' must fall into exactly one period within a KR period
920 : * - at most two kvnos will be relevant from the KR that `t' falls into
921 : * (the current kvno for `t', and possibly either the preceding, or the
922 : * next)
923 : * - at most one kvno from non-current KRs will be derived: possibly one for a
924 : * preceding KR, and possibly one from an upcoming KR
925 : *
926 : * There can be:
927 : *
928 : * - no KR extension (not a namespace principal, and no virtual keys)
929 : * - 1, 2, or 3 KRs (see above)
930 : * - the newest KR may have the `deleted' flag, meaning "does not exist after
931 : * this epoch"
932 : *
933 : * Note that the last time period in any older KR can be partial.
934 : *
935 : * Timeline diagram:
936 : *
937 : * .......|--+--+...+--|---+---+---+...+--|----+...
938 : * T20 T10 T11 RT12 T1n T01
939 : * ^ ^ ^ ^ ^ ^ ^ T00
940 : * | | | T22 T2n | | ^
941 : * ^ | T21 | | |
942 : * princ | | epoch of | epoch of
943 : * did | | middle KR | newest epoch
944 : * not | | |
945 : * exist! | start of Note that T1n
946 : * | second kvno is shown as shorter
947 : * | in 1st epoch than preceding periods
948 : * |
949 : * ^
950 : * first KR's
951 : * epoch, and start
952 : * of its first kvno
953 : *
954 : * Tmn == the start of the Mth KR's Nth time period.
955 : * (higher M -> older KR; lower M -> newer KR)
956 : * (N is the reverse: lower N -> older time period in KR)
957 : * T20 == start of oldest KR -- no keys before this time will be derived.
958 : * T2n == last time period in oldest KR
959 : * T10 == start of middle KR
960 : * T1n == last time period in middle KR
961 : * T00 == start of newest KR
962 : * T0n == current time period in newest KR for wall clock time
963 : */
964 : static krb5_error_code
965 208720 : derive_keys(krb5_context context,
966 : unsigned flags,
967 : krb5_const_principal princ,
968 : int h_is_namespace,
969 : krb5_timestamp t,
970 : krb5int32 etype,
971 : krb5uint32 kvno,
972 : hdb_entry *h)
973 : {
974 : HDB_Ext_KeyRotation kr;
975 : HDB_Ext_KeySet base_keys;
976 208720 : krb5_error_code ret = 0;
977 : size_t current_kr, future_kr, past_kr, i;
978 208720 : char *p = NULL;
979 208720 : int valid = 1;
980 :
981 208720 : if (!h_is_namespace && !h->flags.virtual_keys)
982 208720 : return 0;
983 0 : h->flags.virtual = 1;
984 :
985 0 : kr.len = 0;
986 0 : kr.val = 0;
987 0 : if (ret == 0) {
988 : const HDB_Ext_KeyRotation *ckr;
989 :
990 : /* Installing keys invalidates `ckr', so we copy it */
991 0 : ret = hdb_entry_get_key_rotation(context, h, &ckr);
992 0 : if (!ckr)
993 0 : return ret;
994 0 : if (ret == 0)
995 0 : ret = copy_HDB_Ext_KeyRotation(ckr, &kr);
996 : }
997 :
998 : /* Get the base keys from the entry, and remove them */
999 0 : base_keys.val = 0;
1000 0 : base_keys.len = 0;
1001 0 : if (ret == 0)
1002 0 : ret = _hdb_remove_base_keys(context, h, &base_keys, &kr);
1003 :
1004 : /* Make sure we have h->etypes */
1005 0 : if (ret == 0 && !h->etypes)
1006 0 : ret = hdb_derive_etypes(context, h, &base_keys);
1007 :
1008 : /* Keys not desired? Don't derive them! */
1009 0 : if (ret || !(flags & HDB_F_DECRYPT)) {
1010 0 : free_HDB_Ext_KeyRotation(&kr);
1011 0 : free_HDB_Ext_KeySet(&base_keys);
1012 0 : return ret;
1013 : }
1014 :
1015 : /* The principal name will be used in key derivation and error messages */
1016 0 : if (ret == 0)
1017 0 : ret = krb5_unparse_name(context, princ, &p);
1018 :
1019 : /* Sanity check key rotations, determine current & last kr */
1020 0 : if (ret == 0 && kr.len < 1)
1021 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1022 : "no key rotation periods for %s", p);
1023 0 : if (ret == 0)
1024 0 : current_kr = future_kr = past_kr = kr.len;
1025 : else
1026 0 : current_kr = future_kr = past_kr = 1;
1027 :
1028 : /*
1029 : * Identify a current, next, and previous KRs if there are any.
1030 : *
1031 : * There can be up to three KRs, ordered by epoch, descending, making up a
1032 : * timeline like:
1033 : *
1034 : * ...|---------|--------|------>
1035 : * ^ | | |
1036 : * | | | |
1037 : * | | | Newest KR (kr.val[0])
1038 : * | | Middle KR (kr.val[1])
1039 : * | Oldest (last) KR (kr.val[2])
1040 : * |
1041 : * Before the begging of time for this namespace
1042 : *
1043 : * We step through these from future towards past looking for the best
1044 : * future, current, and past KRs. The best current KR is one that has its
1045 : * epoch nearest to `t' but in the past of `t'.
1046 : *
1047 : * We validate KRs before storing HDB entries with the KR extension, so we
1048 : * can assume they are valid here. However, we do some validity checking,
1049 : * and if they're not valid, we pick the best current KR and ignore the
1050 : * others.
1051 : *
1052 : * In principle there cannot be two future KRs, but this function is
1053 : * deterministic and takes a time value, so it should not enforce this just
1054 : * so we can test. Enforcement of such rules should be done at store time.
1055 : */
1056 0 : for (i = 0; ret == 0 && i < kr.len; i++) {
1057 : /* Minimal validation: order and period */
1058 0 : if (i && kr.val[i - 1].epoch - kr.val[i].epoch <= 0) {
1059 0 : future_kr = past_kr = kr.len;
1060 0 : valid = 0;
1061 : }
1062 0 : if (!kr.val[i].period) {
1063 0 : future_kr = past_kr = kr.len;
1064 0 : valid = 0;
1065 0 : continue;
1066 : }
1067 0 : if (t - kr.val[i].epoch >= 0) {
1068 : /*
1069 : * `t' is in the future of this KR's epoch, so it's a candidate for
1070 : * either current or past KR.
1071 : */
1072 0 : if (current_kr == kr.len)
1073 0 : current_kr = i; /* First curr KR candidate; should be best */
1074 0 : else if (kr.val[current_kr].epoch - kr.val[i].epoch < 0)
1075 0 : current_kr = i; /* Invalid KRs, but better curr KR cand. */
1076 0 : else if (valid && past_kr == kr.len)
1077 0 : past_kr = i;
1078 0 : } else if (valid) {
1079 : /* This KR is in the future of `t', a candidate for next KR */
1080 0 : future_kr = i;
1081 : }
1082 : }
1083 0 : if (ret == 0 && current_kr == kr.len)
1084 : /* No current KR -> too soon */
1085 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1086 : "Too soon for virtual principal to exist");
1087 :
1088 : /* Check that the principal has not been marked deleted */
1089 0 : if (ret == 0 && current_kr < kr.len && kr.val[current_kr].flags.deleted)
1090 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1091 : "virtual principal %s does not exist "
1092 : "because last key rotation period "
1093 : "marks deletion", p);
1094 :
1095 : /*
1096 : * Derive and set in `h' its current kvno and current keys.
1097 : *
1098 : * This will set h->kvno as well.
1099 : *
1100 : * This may set up to TWO keysets for the current key rotation period:
1101 : * - current keys (h->keys and h->kvno)
1102 : * - possibly one future
1103 : * OR
1104 : * possibly one past keyset in hist_keys for the current_kr
1105 : */
1106 0 : if (ret == 0 && current_kr < kr.len)
1107 0 : ret = derive_keys_for_current_kr(context, h, &base_keys, p, flags,
1108 0 : etype, kvno, t, &kr.val[current_kr],
1109 0 : current_kr ? kr.val[0].epoch : 0);
1110 :
1111 : /*
1112 : * Derive and set in `h' its future keys for next KR if it is soon to be
1113 : * current.
1114 : *
1115 : * We want to derive keys for the first kvno of the next (future) KR if
1116 : * it's sufficiently close to `t', meaning within 1 period of the current
1117 : * KR, but we want these keys to be available sooner, so 1.5 of the current
1118 : * period.
1119 : */
1120 0 : if (ret == 0 && future_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1121 0 : ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1122 0 : kr.val[future_kr].epoch, &kr.val[future_kr]);
1123 :
1124 : /*
1125 : * Derive and set in `h' its past keys for the previous KR if its last time
1126 : * period could still have extant, unexpired service tickets encrypted in
1127 : * its keys.
1128 : */
1129 0 : if (ret == 0 && past_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1130 0 : ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1131 0 : kr.val[current_kr].epoch - 1, &kr.val[past_kr]);
1132 :
1133 : /*
1134 : * Impose a bound on h->max_life so that [when the KDC is the caller]
1135 : * the KDC won't issue tickets longer lived than this.
1136 : */
1137 0 : if (ret == 0 && !h->max_life &&
1138 0 : (h->max_life = calloc(1, sizeof(h->max_life[0]))) == NULL)
1139 0 : ret = krb5_enomem(context);
1140 0 : if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1)
1141 0 : *h->max_life = kr.val[current_kr].period >> 1;
1142 :
1143 0 : free_HDB_Ext_KeyRotation(&kr);
1144 0 : free_HDB_Ext_KeySet(&base_keys);
1145 0 : free(p);
1146 0 : return ret;
1147 : }
1148 :
1149 : /*
1150 : * Pick a best kvno for the given principal at the given time.
1151 : *
1152 : * Implements the [hdb] new_service_key_delay configuration parameter.
1153 : *
1154 : * In order for disparate keytab provisioning systems such as OSKT and our own
1155 : * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able
1156 : * to force keys set by the former to not become current keys until users of
1157 : * the latter have had a chance to fetch those keys into their keytabs. To do
1158 : * this we have to search the list of keys in the entry looking for the newest
1159 : * keys older than `now - db->new_service_key_delay'.
1160 : *
1161 : * The context is that OSKT's krb5_keytab is very happy to change keys in a way
1162 : * that requires all members of a cluster to rekey together. If one also
1163 : * wishes to have cluster members that opt out of this and just fetch current,
1164 : * past, and future keys periodically, then the keys set by OSKT must not come
1165 : * into effect until all the opt-out members have had a chance to fetch the new
1166 : * keys.
1167 : *
1168 : * The assumption is that services will fetch new keys periodically, say, every
1169 : * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the
1170 : * configuration and new keys set by OSKT will not be used until 8h after they
1171 : * are set.
1172 : *
1173 : * Naturally, this applies only to concrete principals with concrete keys.
1174 : */
1175 : static krb5_error_code
1176 208720 : pick_kvno(krb5_context context,
1177 : HDB *db,
1178 : unsigned flags,
1179 : krb5_timestamp now,
1180 : krb5uint32 kvno,
1181 : hdb_entry *h)
1182 : {
1183 : HDB_extension *ext;
1184 : HDB_Ext_KeySet keys;
1185 208720 : time_t current = 0;
1186 : time_t best;
1187 : size_t i;
1188 :
1189 : /*
1190 : * If we want a specific kvno, or if the caller doesn't want new keys
1191 : * delayed, or if there's no new-key delay configured, or we're not
1192 : * fetching for use as a service principal, then we're out.
1193 : */
1194 208720 : if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->flags.virtual ||
1195 66206 : h->flags.virtual_keys || db->new_service_key_delay <= 0)
1196 208720 : return 0;
1197 :
1198 : /* No history -> current keyset is the only one and therefore the best */
1199 0 : ext = hdb_find_extension(h, choice_HDB_extension_data_hist_keys);
1200 0 : if (!ext)
1201 0 : return 0;
1202 :
1203 : /* Assume the current keyset is the best to start with */
1204 0 : (void) hdb_entry_get_pw_change_time(h, ¤t);
1205 0 : if (current == 0 && h->modified_by)
1206 0 : current = h->modified_by->time;
1207 0 : if (current == 0)
1208 0 : current = h->created_by.time;
1209 :
1210 : /* Current keyset starts out as best */
1211 0 : best = current;
1212 0 : kvno = h->kvno;
1213 :
1214 : /* Look for a better keyset in the history */
1215 0 : keys = ext->data.u.hist_keys;
1216 0 : for (i = 0; i < keys.len; i++) {
1217 : /* No set_time? Ignore. Too new? Ignore */
1218 0 : if (!keys.val[i].set_time ||
1219 0 : keys.val[i].set_time[0] + db->new_service_key_delay > now)
1220 0 : continue;
1221 :
1222 : /*
1223 : * Ignore the keyset with kvno 1 when the entry has better kvnos
1224 : * because kadmin's `ank -r' command immediately changes the keys.
1225 : */
1226 0 : if (kvno > 1 && keys.val[i].kvno == 1)
1227 0 : continue;
1228 :
1229 : /*
1230 : * This keyset's set_time older than the previous best? Ignore.
1231 : * However, if the current best is the entry's current and that one
1232 : * is too new, then don't ignore this one.
1233 : */
1234 0 : if (keys.val[i].set_time[0] < best &&
1235 0 : (best != current || current + db->new_service_key_delay < now))
1236 0 : continue;
1237 :
1238 : /*
1239 : * If two good enough keysets have the same set_time, take the keyset
1240 : * with the highest kvno.
1241 : */
1242 0 : if (keys.val[i].set_time[0] == best && keys.val[i].kvno <= kvno)
1243 0 : continue;
1244 :
1245 : /*
1246 : * This keyset is clearly more current than the previous best keyset
1247 : * but still old enough to use for encrypting tickets with.
1248 : */
1249 0 : best = keys.val[i].set_time[0];
1250 0 : kvno = keys.val[i].kvno;
1251 : }
1252 0 : return hdb_change_kvno(context, kvno, h);
1253 : }
1254 :
1255 : /*
1256 : * Make a WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname} or
1257 : * WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname}/${domainname} principal
1258 : * object, with the service and hostname components take from `wanted', but if
1259 : * the service name is not in the list `db->virtual_hostbased_princ_svcs[]'
1260 : * then use "_" (wildcard) instead. This way we can have different attributes
1261 : * for different services in the same namespaces.
1262 : *
1263 : * For example, virtual hostbased service names for the "host" service might
1264 : * have ok-as-delegate set, but ones for the "HTTP" service might not.
1265 : */
1266 : static krb5_error_code
1267 0 : make_namespace_princ(krb5_context context,
1268 : HDB *db,
1269 : krb5_const_principal wanted,
1270 : krb5_principal *namespace)
1271 : {
1272 0 : krb5_error_code ret = 0;
1273 0 : const char *realm = krb5_principal_get_realm(context, wanted);
1274 0 : const char *comp0 = krb5_principal_get_comp_string(context, wanted, 0);
1275 0 : const char *comp1 = krb5_principal_get_comp_string(context, wanted, 1);
1276 0 : const char *comp2 = krb5_principal_get_comp_string(context, wanted, 2);
1277 0 : char * const *svcs = db->virtual_hostbased_princ_svcs;
1278 : size_t i;
1279 :
1280 0 : *namespace = NULL;
1281 0 : if (comp0 == NULL || comp1 == NULL)
1282 0 : return EINVAL;
1283 0 : if (strcmp(comp0, "krbtgt") == 0)
1284 0 : return 0;
1285 :
1286 0 : for (i = 0; svcs && svcs[i]; i++) {
1287 0 : if (strcmp(comp0, svcs[i]) == 0) {
1288 0 : comp0 = svcs[i];
1289 0 : break;
1290 : }
1291 : }
1292 0 : if (!svcs || !svcs[i])
1293 0 : comp0 = "_";
1294 :
1295 : /* First go around, need a namespace princ. Make it! */
1296 0 : ret = krb5_build_principal(context, namespace, strlen(realm),
1297 : realm, KRB5_WELLKNOWN_NAME,
1298 : HDB_WK_NAMESPACE, comp0, NULL);
1299 0 : if (ret == 0)
1300 0 : ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1);
1301 0 : if (ret == 0 && comp2)
1302 : /* Support domain-based names */
1303 0 : ret = krb5_principal_set_comp_string(context, *namespace, 4, comp2);
1304 : /* Caller frees `*namespace' on error */
1305 0 : return ret;
1306 : }
1307 :
1308 : static int
1309 0 : is_namespace_princ_p(krb5_context context,
1310 : krb5_const_principal princ)
1311 : {
1312 : return
1313 0 : krb5_principal_get_num_comp(context, princ) >= 4
1314 0 : && strcmp(krb5_principal_get_comp_string(context, princ, 0),
1315 : KRB5_WELLKNOWN_NAME) == 0
1316 0 : && strcmp(krb5_principal_get_comp_string(context, princ, 1),
1317 : HDB_WK_NAMESPACE) == 0;
1318 : }
1319 :
1320 : /* See call site */
1321 : static krb5_error_code
1322 0 : rewrite_hostname(krb5_context context,
1323 : krb5_const_principal wanted_princ,
1324 : krb5_const_principal ns_princ,
1325 : krb5_const_principal found_ns_princ,
1326 : char **s)
1327 : {
1328 : const char *ns_host_part, *wanted_host_part, *found_host_part;
1329 : const char *p, *r;
1330 : size_t ns_host_part_len, wanted_host_part_len;
1331 :
1332 0 : wanted_host_part = krb5_principal_get_comp_string(context, wanted_princ, 1);
1333 0 : wanted_host_part_len = strlen(wanted_host_part);
1334 0 : if (wanted_host_part_len > 256) {
1335 0 : krb5_set_error_message(context, HDB_ERR_NOENTRY,
1336 : "Aliases of host-based principals longer than "
1337 : "256 bytes not supported");
1338 0 : return HDB_ERR_NOENTRY;
1339 : }
1340 :
1341 0 : ns_host_part = krb5_principal_get_comp_string(context, ns_princ, 3);
1342 0 : ns_host_part_len = strlen(ns_host_part);
1343 :
1344 : /* Find `ns_host_part' as the tail of `wanted_host_part' */
1345 0 : for (r = p = strstr(wanted_host_part, ns_host_part);
1346 0 : r && strnlen(r, ns_host_part_len + 1) > ns_host_part_len;
1347 0 : p = (r = strstr(r, ns_host_part)) ? r : p)
1348 : ;
1349 0 : if (!p || strnlen(p, ns_host_part_len + 1) != ns_host_part_len)
1350 0 : return HDB_ERR_NOENTRY; /* Can't happen */
1351 0 : if (p == wanted_host_part || p[-1] != '.')
1352 0 : return HDB_ERR_NOENTRY;
1353 :
1354 0 : found_host_part =
1355 : krb5_principal_get_comp_string(context, found_ns_princ, 3);
1356 : return
1357 0 : asprintf(s, "%.*s%s", (int)(p - wanted_host_part), wanted_host_part,
1358 0 : found_host_part) < 0 ||
1359 0 : *s == NULL ? krb5_enomem(context) : 0;
1360 : }
1361 :
1362 : /*
1363 : * Fix `h->principal' to match the desired `princ' in the namespace
1364 : * `nsprinc' (which is either the same as `h->principal' or an alias
1365 : * of it).
1366 : */
1367 : static krb5_error_code
1368 208720 : fix_princ_name(krb5_context context,
1369 : krb5_const_principal princ,
1370 : krb5_const_principal nsprinc,
1371 : hdb_entry *h)
1372 : {
1373 208720 : krb5_error_code ret = 0;
1374 208720 : char *s = NULL;
1375 :
1376 208720 : if (!nsprinc)
1377 208720 : return 0;
1378 0 : if (krb5_principal_get_num_comp(context, princ) < 2)
1379 0 : return HDB_ERR_NOENTRY;
1380 :
1381 : /* `nsprinc' must be a namespace principal */
1382 :
1383 0 : if (krb5_principal_compare(context, nsprinc, h->principal)) {
1384 : /*
1385 : * `h' is the HDB entry for `nsprinc', and `nsprinc' is its canonical
1386 : * name.
1387 : *
1388 : * Set the entry's principal name to the desired name. The keys will
1389 : * be fixed next (upstairs, but don't forget to!).
1390 : */
1391 0 : free_Principal(h->principal);
1392 0 : return copy_Principal(princ, h->principal);
1393 : }
1394 :
1395 0 : if (!is_namespace_princ_p(context, h->principal)) {
1396 : /*
1397 : * The alias is a namespace, but the canonical name is not. WAT.
1398 : *
1399 : * Well, the KDC will just issue a referral anyways, so we can leave
1400 : * `h->principal' as is...
1401 : *
1402 : * Remove all of `h's keys just in case, and leave
1403 : * `h->principal' as-is.
1404 : */
1405 0 : free_Keys(&h->keys);
1406 0 : (void) hdb_entry_clear_password(context, h);
1407 0 : return hdb_clear_extension(context, h,
1408 : choice_HDB_extension_data_hist_keys);
1409 : }
1410 :
1411 : /*
1412 : * A namespace alias of a namespace entry.
1413 : *
1414 : * We'll want to rewrite the original principal accordingly.
1415 : *
1416 : * E.g., if the caller wanted host/foo.ns.test.h5l.se and we
1417 : * found WELLKNOWN/HOSTBASED-NAMESPACE/ns.test.h5l.se is an
1418 : * alias of WELLKNOWN/HOSTBASED-NAMESPACE/ns.example.org, then
1419 : * we'll want to treat host/foo.ns.test.h5l.se as an alias of
1420 : * host/foo.ns.example.org.
1421 : */
1422 0 : if (krb5_principal_get_num_comp(context, h->principal) !=
1423 0 : 2 + krb5_principal_get_num_comp(context, princ))
1424 0 : ret = HDB_ERR_NOENTRY; /* Only host-based services for now */
1425 0 : if (ret == 0)
1426 0 : ret = rewrite_hostname(context, princ, nsprinc, h->principal, &s);
1427 0 : if (ret == 0) {
1428 0 : krb5_free_principal(context, h->principal);
1429 0 : h->principal = NULL;
1430 0 : ret = krb5_make_principal(context, &h->principal,
1431 : krb5_principal_get_realm(context, princ),
1432 : krb5_principal_get_comp_string(context,
1433 : princ, 0),
1434 : s,
1435 : NULL);
1436 : }
1437 0 : return ret;
1438 : }
1439 :
1440 : /* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */
1441 : static krb5_error_code
1442 214156 : fetch_it(krb5_context context,
1443 : HDB *db,
1444 : krb5_const_principal princ,
1445 : unsigned flags,
1446 : krb5_timestamp t,
1447 : krb5int32 etype,
1448 : krb5uint32 kvno,
1449 : hdb_entry *ent)
1450 : {
1451 214156 : krb5_const_principal tmpprinc = princ;
1452 214156 : krb5_principal nsprinc = NULL;
1453 214156 : krb5_error_code ret = 0;
1454 214156 : const char *comp0 = krb5_principal_get_comp_string(context, princ, 0);
1455 214156 : const char *comp1 = krb5_principal_get_comp_string(context, princ, 1);
1456 : const char *tmp;
1457 214156 : size_t mindots = db->virtual_hostbased_princ_ndots;
1458 214156 : size_t maxdots = db->virtual_hostbased_princ_maxdots;
1459 214156 : size_t hdots = 0;
1460 214156 : char *host = NULL;
1461 214156 : int do_search = 0;
1462 :
1463 214156 : if (!db->enable_virtual_hostbased_princs)
1464 214156 : maxdots = mindots = 0;
1465 214156 : if (db->enable_virtual_hostbased_princs && comp1 &&
1466 0 : strcmp("krbtgt", comp0) != 0 && strcmp(KRB5_WELLKNOWN_NAME, comp0) != 0) {
1467 : char *htmp;
1468 :
1469 0 : if ((host = strdup(comp1)) == NULL)
1470 0 : return krb5_enomem(context);
1471 :
1472 : /* Strip out any :port */
1473 0 : htmp = strchr(host, ':');
1474 0 : if (htmp) {
1475 0 : if (strchr(htmp + 1, ':')) {
1476 : /* Extra ':'s? No virtualization for you! */
1477 0 : free(host);
1478 0 : host = NULL;
1479 0 : htmp = NULL;
1480 : } else {
1481 0 : *htmp = '\0';
1482 : }
1483 : }
1484 : /* Count dots in `host' */
1485 0 : for (hdots = 0, htmp = host; htmp && *htmp; htmp++)
1486 0 : if (*htmp == '.')
1487 0 : hdots++;
1488 :
1489 0 : do_search = 1;
1490 : }
1491 :
1492 214156 : tmp = host ? host : comp1;
1493 214156 : for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = nsprinc) {
1494 214156 : krb5_error_code ret2 = 0;
1495 :
1496 : /*
1497 : * We break out of this loop with ret == 0 only if we found the HDB
1498 : * entry we were looking for or the HDB entry for a matching namespace.
1499 : *
1500 : * Otherwise we break out with ret != 0, typically HDB_ERR_NOENTRY.
1501 : *
1502 : * First time through we lookup the principal as given.
1503 : *
1504 : * Next we lookup a namespace principal, stripping off hostname labels
1505 : * from the left until we find one or get tired of looking or run out
1506 : * of labels.
1507 : */
1508 214156 : ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent);
1509 214156 : if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp ||
1510 : !do_search)
1511 : break;
1512 :
1513 : /*
1514 : * Breadcrumb:
1515 : *
1516 : * - if we found a concrete principal, but it's been marked
1517 : * as now-virtual, then we must keep going
1518 : *
1519 : * But this will be coded in the future.
1520 : *
1521 : * Maybe we can take attributes from the concrete principal...
1522 : */
1523 :
1524 : /*
1525 : * The namespace's hostname will not have more labels than maxdots + 1.
1526 : * Thus we truncate immediately down to maxdots + 1 if we haven't yet.
1527 : *
1528 : * Example: with maxdots == 3,
1529 : * foo.bar.baz.app.blah.example -> baz.app.blah.example
1530 : */
1531 0 : while (maxdots && hdots > maxdots && tmp) {
1532 0 : tmp = strchr(tmp, '.');
1533 : /* tmp != NULL because maxdots > 0; we check to quiet linters */
1534 0 : if (tmp == NULL) {
1535 0 : ret = HDB_ERR_NOENTRY;
1536 0 : goto out;
1537 : }
1538 0 : tmp++;
1539 0 : hdots--;
1540 : }
1541 :
1542 0 : if (nsprinc == NULL)
1543 : /* First go around, need a namespace princ. Make it! */
1544 0 : ret2 = make_namespace_princ(context, db, tmpprinc, &nsprinc);
1545 :
1546 : /* Update the hostname component of the namespace principal */
1547 0 : if (ret2 == 0)
1548 0 : ret2 = krb5_principal_set_comp_string(context, nsprinc, 3, tmp);
1549 0 : if (ret2)
1550 0 : ret = ret2;
1551 :
1552 0 : if (tmp) {
1553 : /* Strip off left-most label for the next go-around */
1554 0 : if ((tmp = strchr(tmp, '.')))
1555 0 : tmp++;
1556 0 : hdots--;
1557 : } /* else we'll break out after the next db->hdb_fetch_kvno() call */
1558 : }
1559 :
1560 : /*
1561 : * If unencrypted keys were requested, derive them. There may not be any
1562 : * key derivation to do, but that's decided in derive_keys().
1563 : */
1564 214156 : if (ret == 0) {
1565 : /* Fix the principal name if namespaced */
1566 208720 : ret = fix_princ_name(context, princ, nsprinc, ent);
1567 :
1568 : /* Derive keys if namespaced or virtual */
1569 208720 : if (ret == 0)
1570 208720 : ret = derive_keys(context, flags, princ, !!nsprinc, t, etype, kvno,
1571 : ent);
1572 : /* Pick the best kvno for this principal at the given time */
1573 208720 : if (ret == 0)
1574 208720 : ret = pick_kvno(context, db, flags, t, kvno, ent);
1575 : }
1576 :
1577 219592 : out:
1578 214156 : if (ret != 0 && ret != HDB_ERR_WRONG_REALM)
1579 4577 : hdb_free_entry(context, db, ent);
1580 214156 : krb5_free_principal(context, nsprinc);
1581 214156 : free(host);
1582 214156 : return ret;
1583 : }
1584 :
1585 : /**
1586 : * Fetch a principal's HDB entry, possibly generating virtual keys from base
1587 : * keys according to strict key rotation schedules. If a time is given, other
1588 : * than HDB I/O, this function is pure, thus usable for testing.
1589 : *
1590 : * HDB writers should use `db->hdb_fetch_kvno()' to avoid materializing virtual
1591 : * principals.
1592 : *
1593 : * HDB readers should use this function rather than `db->hdb_fetch_kvno()'
1594 : * unless they only want to see concrete principals and not bother generating
1595 : * any virtual keys.
1596 : *
1597 : * @param context Context
1598 : * @param db HDB
1599 : * @param principal Principal name
1600 : * @param flags Fetch flags
1601 : * @param t For virtual keys, use this as the point in time (use zero to mean "now")
1602 : * @param etype Key enctype (use KRB5_ENCTYPE_NULL to mean "preferred")
1603 : * @param kvno Key version number (use zero to mean "current")
1604 : * @param h Output HDB entry
1605 : *
1606 : * @return Zero on success, an error code otherwise.
1607 : */
1608 : krb5_error_code
1609 214156 : hdb_fetch_kvno(krb5_context context,
1610 : HDB *db,
1611 : krb5_const_principal principal,
1612 : unsigned int flags,
1613 : krb5_timestamp t,
1614 : krb5int32 etype,
1615 : krb5uint32 kvno,
1616 : hdb_entry *h)
1617 : {
1618 214156 : krb5_error_code ret = HDB_ERR_NOENTRY;
1619 :
1620 214156 : flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */
1621 214156 : if (t == 0)
1622 214156 : krb5_timeofday(context, &t);
1623 214156 : ret = fetch_it(context, db, principal, flags, t, etype, kvno, h);
1624 214156 : if (ret == HDB_ERR_NOENTRY)
1625 1550 : krb5_set_error_message(context, ret, "no such entry found in hdb");
1626 :
1627 : /*
1628 : * This check is to support aliases in HDB; the force_canonicalize
1629 : * check is to allow HDB backends to support realm name canon
1630 : * independently of principal aliases (used by Samba).
1631 : */
1632 422876 : if (ret == 0 && !(flags & HDB_F_ADMIN_DATA) &&
1633 211044 : !h->flags.force_canonicalize &&
1634 2324 : !krb5_realm_compare(context, principal, h->principal))
1635 0 : ret = HDB_ERR_WRONG_REALM;
1636 214156 : return ret;
1637 : }
1638 :
1639 : size_t ASN1CALL
1640 0 : length_hdb_keyset(HDB_keyset *data)
1641 : {
1642 0 : return length_HDB_keyset(data);
1643 : }
1644 :
1645 : size_t ASN1CALL
1646 0 : length_hdb_entry(HDB_entry *data)
1647 : {
1648 0 : return length_HDB_entry(data);
1649 : }
1650 :
1651 : size_t ASN1CALL
1652 0 : length_hdb_entry_alias(HDB_entry_alias *data)
1653 : {
1654 0 : return length_HDB_entry_alias(data);
1655 : }
1656 :
1657 : void ASN1CALL
1658 0 : free_hdb_keyset(HDB_keyset *data)
1659 : {
1660 0 : free_HDB_keyset(data);
1661 0 : }
1662 :
1663 : void ASN1CALL
1664 0 : free_hdb_entry(HDB_entry *data)
1665 : {
1666 0 : free_HDB_entry(data);
1667 0 : }
1668 :
1669 : void ASN1CALL
1670 0 : free_hdb_entry_alias(HDB_entry_alias *data)
1671 : {
1672 0 : free_HDB_entry_alias(data);
1673 0 : }
1674 :
1675 : size_t ASN1CALL
1676 0 : copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to)
1677 : {
1678 0 : return copy_HDB_keyset(from, to);
1679 : }
1680 :
1681 : size_t ASN1CALL
1682 0 : copy_hdb_entry(const HDB_entry *from, HDB_entry *to)
1683 : {
1684 0 : return copy_HDB_entry(from, to);
1685 : }
1686 :
1687 : size_t ASN1CALL
1688 0 : copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to)
1689 : {
1690 0 : return copy_HDB_entry_alias(from, to);
1691 : }
1692 :
1693 : int ASN1CALL
1694 0 : decode_hdb_keyset(const unsigned char *p,
1695 : size_t len,
1696 : HDB_keyset *data,
1697 : size_t *size)
1698 : {
1699 0 : return decode_HDB_keyset(p, len, data, size);
1700 : }
1701 :
1702 : int ASN1CALL
1703 0 : decode_hdb_entry(const unsigned char *p,
1704 : size_t len,
1705 : HDB_entry *data,
1706 : size_t *size)
1707 : {
1708 0 : return decode_HDB_entry(p, len, data, size);
1709 : }
1710 :
1711 : int ASN1CALL
1712 0 : decode_hdb_entry_alias(const unsigned char *p,
1713 : size_t len,
1714 : HDB_entry_alias *data,
1715 : size_t *size)
1716 : {
1717 0 : return decode_HDB_entry_alias(p, len, data, size);
1718 : }
1719 :
1720 : int ASN1CALL
1721 0 : encode_hdb_keyset(unsigned char *p,
1722 : size_t len,
1723 : const HDB_keyset *data,
1724 : size_t *size)
1725 : {
1726 0 : return encode_HDB_keyset(p, len, data, size);
1727 : }
1728 :
1729 : int ASN1CALL
1730 0 : encode_hdb_entry(unsigned char *p,
1731 : size_t len,
1732 : const HDB_entry *data,
1733 : size_t *size)
1734 : {
1735 0 : return encode_HDB_entry(p, len, data, size);
1736 : }
1737 :
1738 : int ASN1CALL
1739 0 : encode_hdb_entry_alias(unsigned char *p,
1740 : size_t len,
1741 : const HDB_entry_alias *data,
1742 : size_t *size)
1743 : {
1744 0 : return encode_HDB_entry_alias(p, len, data, size);
1745 : }
|