]>
Commit | Line | Data |
---|---|---|
954c0172 | 1 | /* |
2b29b718 SM |
2 | * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan |
3 | * (Royal Institute of Technology, Stockholm, Sweden). | |
4 | * All rights reserved. | |
954c0172 | 5 | * |
2b29b718 SM |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
954c0172 | 9 | * |
2b29b718 SM |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | |
954c0172 | 12 | * |
2b29b718 SM |
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. | |
954c0172 | 16 | * |
2b29b718 SM |
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. | |
954c0172 | 20 | * |
2b29b718 SM |
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. | |
954c0172 HIU |
32 | */ |
33 | ||
34 | #include "kdc_locl.h" | |
954c0172 | 35 | |
51569b31 JS |
36 | #ifdef TIME_T_SIGNED |
37 | #if SIZEOF_TIME_T == 4 | |
38 | #define MAX_TIME ((time_t)INT32_MAX) | |
39 | #elif SIZEOF_TIME_T == 8 | |
40 | #define MAX_TIME ((time_t)INT64_MAX) | |
41 | #else | |
42 | #error "Unexpected sizeof(time_t)" | |
43 | #endif | |
44 | #else | |
45 | ||
46 | #if SIZEOF_TIME_T == 4 | |
47 | #define MAX_TIME ((time_t)UINT32_MAX) | |
48 | #else | |
49 | #define MAX_TIME ((time_t)UINT64_MAX) | |
50 | #endif | |
51 | #endif | |
954c0172 | 52 | |
40b65c84 SM |
53 | #undef __attribute__ |
54 | #define __attribute__(X) | |
55 | ||
3c1e780e AB |
56 | void |
57 | _kdc_fix_time(time_t **t) | |
954c0172 HIU |
58 | { |
59 | if(*t == NULL){ | |
60 | ALLOC(*t); | |
61 | **t = MAX_TIME; | |
62 | } | |
63 | if(**t == 0) **t = MAX_TIME; /* fix for old clients */ | |
64 | } | |
65 | ||
66 | static int | |
67 | realloc_method_data(METHOD_DATA *md) | |
68 | { | |
69 | PA_DATA *pa; | |
70 | pa = realloc(md->val, (md->len + 1) * sizeof(*md->val)); | |
71 | if(pa == NULL) | |
72 | return ENOMEM; | |
73 | md->val = pa; | |
74 | md->len++; | |
75 | return 0; | |
76 | } | |
77 | ||
40b65c84 SM |
78 | static krb5_error_code |
79 | get_pa_etype_info2(krb5_context context, | |
80 | krb5_kdc_configuration *config, | |
81 | METHOD_DATA *md, Key *ckey, | |
82 | krb5_boolean include_salt); | |
83 | ||
84 | static krb5_error_code | |
85 | set_salt_padata(krb5_context context, | |
86 | krb5_kdc_configuration *config, | |
87 | METHOD_DATA *md, Key *key) | |
954c0172 | 88 | { |
51569b31 JS |
89 | if (!key->salt) |
90 | return 0; | |
40b65c84 | 91 | |
51569b31 | 92 | return get_pa_etype_info2(context, config, md, key, TRUE); |
954c0172 HIU |
93 | } |
94 | ||
91adebe7 AB |
95 | const PA_DATA* |
96 | _kdc_find_padata(const KDC_REQ *req, int *start, int type) | |
954c0172 | 97 | { |
91adebe7 AB |
98 | if (req->padata == NULL) |
99 | return NULL; | |
100 | ||
255e3e18 | 101 | while((size_t)*start < req->padata->len){ |
954c0172 | 102 | (*start)++; |
255e3e18 | 103 | if(req->padata->val[*start - 1].padata_type == (unsigned)type) |
954c0172 HIU |
104 | return &req->padata->val[*start - 1]; |
105 | } | |
106 | return NULL; | |
107 | } | |
108 | ||
243321b4 SM |
109 | /* |
110 | * This is a hack to allow predefined weak services, like afs to | |
111 | * still use weak types | |
112 | */ | |
113 | ||
114 | krb5_boolean | |
9b261c00 | 115 | _kdc_is_weak_exception(krb5_principal principal, krb5_enctype etype) |
243321b4 SM |
116 | { |
117 | if (principal->name.name_string.len > 0 && | |
118 | strcmp(principal->name.name_string.val[0], "afs") == 0 && | |
51569b31 JS |
119 | (etype == ETYPE_DES_CBC_CRC |
120 | || etype == ETYPE_DES_CBC_MD4 | |
121 | || etype == ETYPE_DES_CBC_MD5)) | |
243321b4 SM |
122 | return TRUE; |
123 | return FALSE; | |
124 | } | |
125 | ||
126 | ||
b39330c4 AB |
127 | /* |
128 | * Detect if `key' is the using the the precomputed `default_salt'. | |
129 | */ | |
130 | ||
131 | static krb5_boolean | |
132 | is_default_salt_p(const krb5_salt *default_salt, const Key *key) | |
133 | { | |
134 | if (key->salt == NULL) | |
135 | return TRUE; | |
136 | if (default_salt->salttype != key->salt->type) | |
137 | return FALSE; | |
51569b31 | 138 | if (krb5_data_cmp(&default_salt->saltvalue, &key->salt->salt) != 0) |
b39330c4 AB |
139 | return FALSE; |
140 | return TRUE; | |
141 | } | |
142 | ||
40b65c84 SM |
143 | /* |
144 | * Detect if `key' is the using the the precomputed `default_salt' | |
145 | * (for des-cbc-crc) or any salt otherwise. | |
146 | * | |
147 | * This is for avoiding Kerberos v4 (yes really) keys in AS-REQ as | |
148 | * that salt is strange, and a buggy client will try to use the | |
149 | * principal as the salt and not the returned value. | |
150 | */ | |
151 | ||
152 | static krb5_boolean | |
153 | is_good_salt_p(const krb5_salt *default_salt, const Key *key) | |
154 | { | |
51569b31 JS |
155 | if (key->key.keytype == KRB5_ENCTYPE_DES_CBC_CRC) |
156 | return is_default_salt_p(default_salt, key); | |
40b65c84 | 157 | |
51569b31 JS |
158 | return TRUE; |
159 | } | |
40b65c84 SM |
160 | |
161 | krb5_boolean | |
162 | _kdc_is_anon_request(const KDC_REQ *req) | |
163 | { | |
164 | const KDC_REQ_BODY *b = &req->req_body; | |
165 | ||
166 | /* | |
167 | * Versions of Heimdal from 0.9rc1 through 1.50 use bit 14 instead | |
168 | * of 16 for request_anonymous, as indicated in the anonymous draft | |
169 | * prior to version 11. Bit 14 is assigned to S4U2Proxy, but S4U2Proxy | |
170 | * requests are only sent to the TGS and, in any case, would have an | |
171 | * additional ticket present. | |
172 | */ | |
173 | return b->kdc_options.request_anonymous || | |
174 | (b->kdc_options.cname_in_addl_tkt && !b->additional_tickets); | |
175 | } | |
176 | ||
954c0172 HIU |
177 | /* |
178 | * return the first appropriate key of `princ' in `ret_key'. Look for | |
179 | * all the etypes in (`etypes', `len'), stopping as soon as we find | |
40b65c84 SM |
180 | * one, but preferring one that has default salt. |
181 | * | |
182 | * XXX This function does way way too much. Split it up! | |
183 | * | |
184 | * XXX `etypes' and `len' are always `b->etype.val' and `b->etype.len' -- the | |
185 | * etype list from the KDC-REQ-BODY, which is available here as | |
186 | * `r->req->req_body', so we could just stop having it passed in. | |
187 | * | |
188 | * XXX Picking an enctype(s) for PA-ETYPE-INFO* is rather different than | |
189 | * picking an enctype for a ticket's session key. The former is what we do | |
190 | * here when `(flags & KFE_IS_PREAUTH)', the latter otherwise. | |
954c0172 HIU |
191 | */ |
192 | ||
3c1e780e | 193 | krb5_error_code |
40b65c84 | 194 | _kdc_find_etype(astgs_request_t r, uint32_t flags, |
2b29b718 | 195 | krb5_enctype *etypes, unsigned len, |
40b65c84 SM |
196 | krb5_enctype *ret_enctype, Key **ret_key, |
197 | krb5_boolean *ret_default_salt) | |
954c0172 | 198 | { |
40b65c84 SM |
199 | krb5_boolean use_strongest_session_key; |
200 | krb5_boolean is_preauth = flags & KFE_IS_PREAUTH; | |
201 | krb5_boolean is_tgs = flags & KFE_IS_TGS; | |
51569b31 | 202 | hdb_entry *princ; |
40b65c84 | 203 | krb5_principal request_princ; |
255e3e18 | 204 | krb5_error_code ret; |
b39330c4 | 205 | krb5_salt def_salt; |
51569b31 | 206 | krb5_enctype enctype = ETYPE_NULL; |
40b65c84 SM |
207 | const krb5_enctype *p; |
208 | Key *key = NULL; | |
209 | size_t i, k, m; | |
210 | ||
211 | if (is_preauth && (flags & KFE_USE_CLIENT) && | |
51569b31 | 212 | r->client->flags.synthetic) |
40b65c84 SM |
213 | return KRB5KDC_ERR_ETYPE_NOSUPP; |
214 | ||
51569b31 | 215 | if ((flags & KFE_USE_CLIENT) && !r->client->flags.synthetic) { |
40b65c84 SM |
216 | princ = r->client; |
217 | request_princ = r->client_princ; | |
218 | } else { | |
219 | princ = r->server; | |
51569b31 | 220 | request_princ = r->server->principal; |
40b65c84 SM |
221 | } |
222 | ||
223 | use_strongest_session_key = | |
224 | is_preauth ? r->config->preauth_use_strongest_session_key | |
225 | : (is_tgs ? r->config->tgt_use_strongest_session_key : | |
226 | r->config->svc_use_strongest_session_key); | |
b39330c4 | 227 | |
255e3e18 | 228 | /* We'll want to avoid keys with v4 salted keys in the pre-auth case... */ |
40b65c84 | 229 | ret = krb5_get_pw_salt(r->context, request_princ, &def_salt); |
255e3e18 SM |
230 | if (ret) |
231 | return ret; | |
954c0172 | 232 | |
255e3e18 | 233 | ret = KRB5KDC_ERR_ETYPE_NOSUPP; |
954c0172 | 234 | |
40b65c84 SM |
235 | /* |
236 | * Pick an enctype that is in the intersection of: | |
237 | * | |
238 | * - permitted_enctypes (local policy) | |
239 | * - requested enctypes (KDC-REQ-BODY's etype list) | |
240 | * - the client's long-term keys' enctypes | |
241 | * OR | |
242 | * the server's configured etype list | |
243 | * | |
244 | * There are two sub-cases: | |
245 | * | |
246 | * - use local enctype preference (local policy) | |
247 | * - use the client's preference list | |
248 | */ | |
954c0172 | 249 | |
40b65c84 | 250 | if (use_strongest_session_key) { |
255e3e18 SM |
251 | /* |
252 | * Pick the strongest key that the KDC, target service, and | |
253 | * client all support, using the local cryptosystem enctype | |
254 | * list in strongest-to-weakest order to drive the search. | |
255 | * | |
256 | * This is not what RFC4120 says to do, but it encourages | |
257 | * adoption of stronger enctypes. This doesn't play well with | |
258 | * clients that have multiple Kerberos client implementations | |
40b65c84 | 259 | * with different supported enctype lists sharing the same ccache. |
255e3e18 SM |
260 | */ |
261 | ||
262 | /* drive the search with local supported enctypes list */ | |
40b65c84 SM |
263 | p = krb5_kerberos_enctypes(r->context); |
264 | for (i = 0; | |
51569b31 | 265 | p[i] != ETYPE_NULL && enctype == ETYPE_NULL; |
40b65c84 SM |
266 | i++) { |
267 | if (krb5_enctype_valid(r->context, p[i]) != 0 && | |
51569b31 | 268 | !_kdc_is_weak_exception(princ->principal, p[i])) |
954c0172 | 269 | continue; |
255e3e18 SM |
270 | |
271 | /* check that the client supports it too */ | |
51569b31 | 272 | for (k = 0; k < len && enctype == ETYPE_NULL; k++) { |
40b65c84 SM |
273 | |
274 | if (p[i] != etypes[k]) | |
255e3e18 | 275 | continue; |
40b65c84 SM |
276 | |
277 | if (!is_preauth && (flags & KFE_USE_CLIENT)) { | |
278 | /* | |
279 | * It suffices that the client says it supports this | |
280 | * enctype in its KDC-REQ-BODY's etype list, which is what | |
281 | * `etypes' is here. | |
282 | */ | |
f33f73f8 | 283 | enctype = p[i]; |
40b65c84 SM |
284 | ret = 0; |
285 | break; | |
286 | } | |
287 | ||
288 | /* check target princ support */ | |
289 | key = NULL; | |
51569b31 | 290 | if (!is_preauth && !(flags & KFE_USE_CLIENT) && princ->etypes) { |
40b65c84 SM |
291 | /* |
292 | * Use the etypes list from the server's HDB entry instead | |
293 | * of deriving it from its long-term keys. This allows an | |
294 | * entry to have just one long-term key but record support | |
295 | * for multiple enctypes. | |
296 | */ | |
51569b31 JS |
297 | for (m = 0; m < princ->etypes->len; m++) { |
298 | if (p[i] == princ->etypes->val[m]) { | |
f33f73f8 | 299 | enctype = p[i]; |
40b65c84 SM |
300 | ret = 0; |
301 | break; | |
302 | } | |
303 | } | |
304 | } else { | |
305 | /* | |
306 | * Use the entry's long-term keys as the source of its | |
307 | * supported enctypes, either because we're making | |
308 | * PA-ETYPE-INFO* or because we're selecting a session key | |
309 | * enctype. | |
310 | */ | |
51569b31 | 311 | while (hdb_next_enctype2key(r->context, princ, NULL, |
40b65c84 SM |
312 | p[i], &key) == 0) { |
313 | if (key->key.keyvalue.length == 0) { | |
314 | ret = KRB5KDC_ERR_NULL_KEY; | |
315 | continue; | |
316 | } | |
317 | enctype = p[i]; | |
318 | ret = 0; | |
319 | if (is_preauth && ret_key != NULL && | |
320 | !is_good_salt_p(&def_salt, key)) | |
321 | continue; | |
322 | } | |
323 | } | |
954c0172 | 324 | } |
255e3e18 | 325 | } |
255e3e18 SM |
326 | } else { |
327 | /* | |
328 | * Pick the first key from the client's enctype list that is | |
329 | * supported by the cryptosystem and by the given principal. | |
330 | * | |
331 | * RFC4120 says we SHOULD pick the first _strong_ key from the | |
332 | * client's list... not the first key... If the admin disallows | |
333 | * weak enctypes in krb5.conf and selects this key selection | |
334 | * algorithm, then we get exactly what RFC4120 says. | |
335 | */ | |
40b65c84 | 336 | for(i = 0; ret != 0 && i < len; i++) { |
255e3e18 | 337 | |
40b65c84 | 338 | if (krb5_enctype_valid(r->context, etypes[i]) != 0 && |
51569b31 | 339 | !_kdc_is_weak_exception(princ->principal, etypes[i])) |
255e3e18 SM |
340 | continue; |
341 | ||
40b65c84 SM |
342 | key = NULL; |
343 | while (ret != 0 && | |
51569b31 | 344 | hdb_next_enctype2key(r->context, princ, NULL, |
40b65c84 | 345 | etypes[i], &key) == 0) { |
255e3e18 SM |
346 | if (key->key.keyvalue.length == 0) { |
347 | ret = KRB5KDC_ERR_NULL_KEY; | |
348 | continue; | |
349 | } | |
40b65c84 | 350 | enctype = etypes[i]; |
255e3e18 | 351 | ret = 0; |
40b65c84 SM |
352 | if (is_preauth && ret_key != NULL && |
353 | !is_good_salt_p(&def_salt, key)) | |
354 | continue; | |
b39330c4 | 355 | } |
954c0172 HIU |
356 | } |
357 | } | |
255e3e18 | 358 | |
51569b31 | 359 | if (ret == 0 && enctype == ETYPE_NULL) { |
40b65c84 SM |
360 | /* |
361 | * if the service principal is one for which there is a known 1DES | |
362 | * exception and no other enctype matches both the client request and | |
363 | * the service key list, provide a DES-CBC-CRC key. | |
364 | */ | |
365 | if (ret_key == NULL && | |
51569b31 | 366 | _kdc_is_weak_exception(princ->principal, ETYPE_DES_CBC_CRC)) { |
40b65c84 SM |
367 | ret = 0; |
368 | enctype = ETYPE_DES_CBC_CRC; | |
369 | } else { | |
370 | ret = KRB5KDC_ERR_ETYPE_NOSUPP; | |
371 | } | |
372 | } | |
373 | ||
374 | if (ret == 0) { | |
375 | if (ret_enctype != NULL) | |
376 | *ret_enctype = enctype; | |
377 | if (ret_key != NULL) | |
378 | *ret_key = key; | |
379 | if (ret_default_salt != NULL) | |
380 | *ret_default_salt = is_default_salt_p(&def_salt, key); | |
381 | } | |
382 | ||
383 | krb5_free_salt (r->context, def_salt); | |
954c0172 HIU |
384 | return ret; |
385 | } | |
386 | ||
975e43fc AB |
387 | /* |
388 | * The principal's session_etypes must be sorted in order of strength, with | |
389 | * preferred etype first. | |
390 | */ | |
391 | krb5_error_code | |
392 | _kdc_find_session_etype(astgs_request_t r, | |
393 | krb5_enctype *etypes, size_t len, | |
394 | const hdb_entry *princ, | |
395 | krb5_enctype *ret_enctype) | |
396 | { | |
397 | size_t i; | |
398 | ||
399 | if (princ->session_etypes == NULL) { | |
400 | /* The principal must have session etypes available. */ | |
401 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
402 | } | |
403 | ||
404 | /* Loop over the client's specified etypes. */ | |
405 | for (i = 0; i < len; ++i) { | |
406 | size_t j; | |
407 | ||
408 | /* Check that the server also supports the etype. */ | |
409 | for (j = 0; j < princ->session_etypes->len; ++j) { | |
410 | if (princ->session_etypes->val[j] == etypes[i]) { | |
411 | *ret_enctype = etypes[i]; | |
412 | return 0; | |
413 | } | |
414 | } | |
415 | } | |
416 | ||
417 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
418 | } | |
419 | ||
3c1e780e AB |
420 | krb5_error_code |
421 | _kdc_make_anonymous_principalname (PrincipalName *pn) | |
954c0172 | 422 | { |
40b65c84 SM |
423 | pn->name_type = KRB5_NT_WELLKNOWN; |
424 | pn->name_string.len = 2; | |
425 | pn->name_string.val = calloc(2, sizeof(*pn->name_string.val)); | |
954c0172 | 426 | if (pn->name_string.val == NULL) |
40b65c84 SM |
427 | goto failed; |
428 | ||
429 | pn->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME); | |
430 | if (pn->name_string.val[0] == NULL) | |
431 | goto failed; | |
432 | ||
433 | pn->name_string.val[1] = strdup(KRB5_ANON_NAME); | |
434 | if (pn->name_string.val[1] == NULL) | |
435 | goto failed; | |
436 | ||
954c0172 | 437 | return 0; |
40b65c84 SM |
438 | |
439 | failed: | |
440 | free_PrincipalName(pn); | |
441 | ||
442 | pn->name_type = KRB5_NT_UNKNOWN; | |
443 | pn->name_string.len = 0; | |
444 | pn->name_string.val = NULL; | |
445 | ||
446 | return ENOMEM; | |
447 | } | |
448 | ||
449 | static void | |
450 | _kdc_r_log(astgs_request_t r, int level, const char *fmt, ...) | |
451 | __attribute__ ((__format__ (__printf__, 3, 4))) | |
452 | { | |
453 | va_list ap; | |
454 | char *s; | |
455 | va_start(ap, fmt); | |
456 | s = kdc_log_msg_va(r->context, r->config, level, fmt, ap); | |
457 | if(s) free(s); | |
458 | va_end(ap); | |
954c0172 HIU |
459 | } |
460 | ||
3c1e780e | 461 | void |
40b65c84 SM |
462 | _kdc_set_const_e_text(astgs_request_t r, const char *e_text) |
463 | { | |
464 | /* We should never see this */ | |
465 | if (r->e_text) { | |
466 | kdc_log(r->context, r->config, 1, | |
467 | "trying to replace e-text \"%s\" with \"%s\"\n", | |
468 | r->e_text, e_text); | |
469 | return; | |
470 | } | |
471 | ||
472 | r->e_text = e_text; | |
473 | kdc_log(r->context, r->config, 4, "%s", e_text); | |
474 | } | |
475 | ||
476 | void | |
477 | _kdc_set_e_text(astgs_request_t r, const char *fmt, ...) | |
478 | __attribute__ ((__format__ (__printf__, 2, 3))) | |
479 | { | |
480 | va_list ap; | |
481 | char *e_text = NULL; | |
482 | int vasprintf_ret; | |
483 | ||
484 | va_start(ap, fmt); | |
485 | vasprintf_ret = vasprintf(&e_text, fmt, ap); | |
486 | va_end(ap); | |
487 | ||
488 | if (vasprintf_ret < 0 || !e_text) { | |
489 | /* not much else to do... */ | |
490 | kdc_log(r->context, r->config, 1, | |
491 | "Could not set e_text: %s (out of memory)", fmt); | |
492 | return; | |
493 | } | |
494 | ||
495 | /* We should never see this */ | |
496 | if (r->e_text) { | |
497 | kdc_log(r->context, r->config, 1, "trying to replace e-text: %s\n", | |
498 | e_text); | |
499 | free(e_text); | |
500 | return; | |
501 | } | |
502 | ||
503 | r->e_text = e_text; | |
504 | r->e_text_buf = e_text; | |
505 | kdc_log(r->context, r->config, 4, "%s", e_text); | |
506 | } | |
507 | ||
508 | void | |
509 | _kdc_log_timestamp(astgs_request_t r, const char *type, | |
2b29b718 | 510 | KerberosTime authtime, KerberosTime *starttime, |
3c1e780e | 511 | KerberosTime endtime, KerberosTime *renew_till) |
954c0172 | 512 | { |
40b65c84 | 513 | krb5_kdc_configuration *config = r->config; |
2b29b718 | 514 | char authtime_str[100], starttime_str[100], |
55f5453b | 515 | endtime_str[100], renewtime_str[100]; |
2b29b718 | 516 | |
40b65c84 | 517 | if (authtime) |
51569b31 | 518 | kdc_audit_setkv_number((kdc_request_t)r, "auth", authtime); |
40b65c84 | 519 | if (starttime && *starttime) |
51569b31 | 520 | kdc_audit_setkv_number((kdc_request_t)r, "start", *starttime); |
40b65c84 | 521 | if (endtime) |
51569b31 | 522 | kdc_audit_setkv_number((kdc_request_t)r, "end", endtime); |
40b65c84 | 523 | if (renew_till && *renew_till) |
51569b31 | 524 | kdc_audit_setkv_number((kdc_request_t)r, "renew", *renew_till); |
40b65c84 SM |
525 | |
526 | krb5_format_time(r->context, authtime, | |
2b29b718 | 527 | authtime_str, sizeof(authtime_str), TRUE); |
954c0172 | 528 | if (starttime) |
40b65c84 | 529 | krb5_format_time(r->context, *starttime, |
2b29b718 | 530 | starttime_str, sizeof(starttime_str), TRUE); |
954c0172 | 531 | else |
c0e8144c | 532 | strlcpy(starttime_str, "unset", sizeof(starttime_str)); |
40b65c84 | 533 | krb5_format_time(r->context, endtime, |
2b29b718 | 534 | endtime_str, sizeof(endtime_str), TRUE); |
954c0172 | 535 | if (renew_till) |
40b65c84 | 536 | krb5_format_time(r->context, *renew_till, |
2b29b718 | 537 | renewtime_str, sizeof(renewtime_str), TRUE); |
954c0172 | 538 | else |
c0e8144c | 539 | strlcpy(renewtime_str, "unset", sizeof(renewtime_str)); |
2b29b718 | 540 | |
40b65c84 | 541 | kdc_log(r->context, config, 4, |
1f2f4708 | 542 | "%s authtime: %s starttime: %s endtime: %s renew till: %s", |
c0e8144c | 543 | type, authtime_str, starttime_str, endtime_str, renewtime_str); |
954c0172 HIU |
544 | } |
545 | ||
40b65c84 SM |
546 | /* |
547 | * | |
548 | */ | |
549 | ||
550 | #ifdef PKINIT | |
551 | ||
552 | static krb5_error_code | |
51569b31 | 553 | pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa) |
40b65c84 SM |
554 | { |
555 | pk_client_params *pkp = NULL; | |
556 | char *client_cert = NULL; | |
557 | krb5_error_code ret; | |
558 | ||
559 | ret = _kdc_pk_rd_padata(r, pa, &pkp); | |
560 | if (ret || pkp == NULL) { | |
81058c60 JS |
561 | if (ret == HX509_CERT_REVOKED) { |
562 | ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED; | |
563 | } else { | |
564 | ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | |
565 | } | |
40b65c84 SM |
566 | _kdc_r_log(r, 4, "Failed to decode PKINIT PA-DATA -- %s", |
567 | r->cname); | |
40b65c84 SM |
568 | goto out; |
569 | } | |
570 | ||
a25f549e JS |
571 | /* Validate the freshness token. */ |
572 | ret = _kdc_pk_validate_freshness_token(r, pkp); | |
573 | if (ret) { | |
574 | _kdc_r_log(r, 4, "Failed to validate freshness token"); | |
575 | goto out; | |
576 | } | |
577 | ||
40b65c84 | 578 | ret = _kdc_pk_check_client(r, pkp, &client_cert); |
51569b31 JS |
579 | if (client_cert) |
580 | kdc_audit_addkv((kdc_request_t)r, 0, KDC_REQUEST_KV_PKINIT_CLIENT_CERT, | |
581 | "%s", client_cert); | |
40b65c84 SM |
582 | if (ret) { |
583 | _kdc_set_e_text(r, "PKINIT certificate not allowed to " | |
584 | "impersonate principal"); | |
51569b31 JS |
585 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
586 | KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED); | |
40b65c84 SM |
587 | goto out; |
588 | } | |
40b65c84 SM |
589 | |
590 | r->pa_endtime = _kdc_pk_endtime(pkp); | |
51569b31 | 591 | if (!r->client->flags.synthetic) |
40b65c84 SM |
592 | r->pa_max_life = _kdc_pk_max_life(pkp); |
593 | ||
594 | _kdc_r_log(r, 4, "PKINIT pre-authentication succeeded -- %s using %s", | |
595 | r->cname, client_cert); | |
596 | ||
597 | ret = _kdc_pk_mk_pa_reply(r, pkp); | |
598 | if (ret) { | |
599 | _kdc_set_e_text(r, "Failed to build PK-INIT reply"); | |
600 | goto out; | |
601 | } | |
602 | ret = _kdc_add_initial_verified_cas(r->context, r->config, | |
603 | pkp, &r->et); | |
604 | ||
51569b31 JS |
605 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
606 | KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); | |
607 | ||
a25f549e JS |
608 | /* |
609 | * Match Windows by preferring the authenticator nonce over the one in the | |
610 | * request body. | |
611 | */ | |
612 | r->ek.nonce = _kdc_pk_nonce(pkp); | |
613 | ||
40b65c84 SM |
614 | out: |
615 | if (pkp) | |
616 | _kdc_pk_free_client_param(r->context, pkp); | |
51569b31 | 617 | free(client_cert); |
40b65c84 SM |
618 | |
619 | return ret; | |
620 | } | |
621 | ||
622 | #endif /* PKINIT */ | |
623 | ||
624 | static krb5_error_code | |
51569b31 | 625 | pa_gss_validate(astgs_request_t r, const PA_DATA *pa) |
40b65c84 SM |
626 | { |
627 | gss_client_params *gcp = NULL; | |
628 | char *client_name = NULL; | |
629 | krb5_error_code ret; | |
630 | int open = 0; | |
631 | ||
632 | ret = _kdc_gss_rd_padata(r, pa, &gcp, &open); | |
633 | if (ret && gcp == NULL) | |
634 | return ret; | |
635 | ||
636 | if (open) { | |
637 | ret = _kdc_gss_check_client(r, gcp, &client_name); | |
51569b31 JS |
638 | if (client_name) |
639 | kdc_audit_addkv((kdc_request_t)r, 0, KDC_REQUEST_KV_GSS_INITIATOR, | |
640 | "%s", client_name); | |
40b65c84 SM |
641 | if (ret) { |
642 | _kdc_set_e_text(r, "GSS-API client not allowed to " | |
643 | "impersonate principal"); | |
51569b31 JS |
644 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
645 | KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED); | |
40b65c84 SM |
646 | goto out; |
647 | } | |
40b65c84 SM |
648 | |
649 | r->pa_endtime = _kdc_gss_endtime(r, gcp); | |
650 | ||
651 | _kdc_r_log(r, 4, "GSS pre-authentication succeeded -- %s using %s", | |
652 | r->cname, client_name); | |
51569b31 JS |
653 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
654 | KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); | |
40b65c84 SM |
655 | |
656 | ret = _kdc_gss_mk_composite_name_ad(r, gcp); | |
657 | if (ret) { | |
658 | _kdc_set_e_text(r, "Failed to build GSS authorization data"); | |
659 | goto out; | |
660 | } | |
661 | } | |
662 | ||
663 | ret = _kdc_gss_mk_pa_reply(r, gcp); | |
664 | if (ret) { | |
665 | if (ret != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) | |
666 | _kdc_set_e_text(r, "Failed to build GSS pre-authentication reply"); | |
40b65c84 SM |
667 | goto out; |
668 | } | |
669 | ||
51569b31 JS |
670 | ret = kdc_request_set_attribute((kdc_request_t)r, |
671 | HSTR("org.h5l.pa-gss-client-params"), gcp); | |
672 | if (ret) | |
673 | goto out; | |
40b65c84 SM |
674 | |
675 | out: | |
51569b31 JS |
676 | kdc_object_release(gcp); |
677 | free(client_name); | |
40b65c84 SM |
678 | |
679 | return ret; | |
680 | } | |
681 | ||
682 | static krb5_error_code | |
683 | pa_gss_finalize_pac(astgs_request_t r) | |
684 | { | |
51569b31 JS |
685 | gss_client_params *gcp; |
686 | ||
687 | gcp = kdc_request_get_attribute((kdc_request_t)r, HSTR("org.h5l.pa-gss-client-params")); | |
40b65c84 SM |
688 | |
689 | heim_assert(gcp != NULL, "invalid GSS-API client params"); | |
690 | ||
691 | return _kdc_gss_finalize_pac(r, gcp); | |
692 | } | |
693 | ||
40b65c84 | 694 | static krb5_error_code |
75ec66c7 SM |
695 | pa_enc_chal_decrypt_kvno(astgs_request_t r, |
696 | krb5_enctype aenctype, | |
697 | krb5_data *pepper1client, | |
698 | krb5_data *pepper1kdc, | |
699 | krb5_data *pepper2, | |
700 | krb5_kvno kvno, | |
701 | EncryptedData *enc_data, | |
702 | krb5_keyblock *KDCchallengekey, | |
703 | struct Key **used_key) | |
40b65c84 | 704 | { |
75ec66c7 | 705 | unsigned int invalidKeys = 0; |
40b65c84 | 706 | krb5_error_code ret; |
75ec66c7 SM |
707 | const Keys *keys = NULL; |
708 | unsigned int i; | |
40b65c84 | 709 | |
75ec66c7 SM |
710 | if (KDCchallengekey) |
711 | krb5_keyblock_zero(KDCchallengekey); | |
712 | if (used_key) | |
713 | *used_key = NULL; | |
40b65c84 | 714 | |
75ec66c7 SM |
715 | keys = hdb_kvno2keys(r->context, r->client, kvno); |
716 | if (keys == NULL) { | |
717 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
40b65c84 SM |
718 | } |
719 | ||
75ec66c7 SM |
720 | for (i = 0; i < keys->len; i++) { |
721 | struct Key *k = &keys->val[i]; | |
40b65c84 | 722 | krb5_crypto challengecrypto, longtermcrypto; |
75ec66c7 | 723 | krb5_keyblock client_challengekey; |
40b65c84 | 724 | |
40b65c84 SM |
725 | ret = krb5_crypto_init(r->context, &k->key, 0, &longtermcrypto); |
726 | if (ret) | |
727 | continue; | |
75ec66c7 | 728 | |
40b65c84 | 729 | ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto, |
75ec66c7 SM |
730 | pepper1client, pepper2, aenctype, |
731 | &client_challengekey); | |
40b65c84 SM |
732 | if (ret) { |
733 | krb5_crypto_destroy(r->context, longtermcrypto); | |
734 | continue; | |
735 | } | |
75ec66c7 SM |
736 | |
737 | ret = krb5_crypto_init(r->context, &client_challengekey, 0, | |
40b65c84 | 738 | &challengecrypto); |
75ec66c7 | 739 | krb5_free_keyblock_contents(r->context, &client_challengekey); |
40b65c84 SM |
740 | if (ret) { |
741 | krb5_crypto_destroy(r->context, longtermcrypto); | |
742 | continue; | |
743 | } | |
744 | ||
745 | ret = _krb5_validate_pa_enc_challenge(r->context, | |
746 | challengecrypto, | |
747 | KRB5_KU_ENC_CHALLENGE_CLIENT, | |
75ec66c7 | 748 | enc_data, |
40b65c84 SM |
749 | r->cname); |
750 | krb5_crypto_destroy(r->context, challengecrypto); | |
751 | if (ret) { | |
752 | const char *msg; | |
753 | krb5_error_code ret2; | |
754 | char *str = NULL; | |
755 | ||
756 | krb5_crypto_destroy(r->context, longtermcrypto); | |
757 | ||
75ec66c7 SM |
758 | if (ret != KRB5KRB_AP_ERR_BAD_INTEGRITY) |
759 | return ret; | |
760 | ||
761 | invalidKeys += 1; | |
762 | ||
763 | if (pepper1kdc == NULL) | |
764 | /* The caller is not interessted in details */ | |
765 | continue; | |
40b65c84 SM |
766 | |
767 | ret2 = krb5_enctype_to_string(r->context, k->key.keytype, &str); | |
768 | if (ret2) | |
769 | str = NULL; | |
770 | msg = krb5_get_error_message(r->context, ret); | |
771 | _kdc_r_log(r, 2, "Failed to decrypt ENC-CHAL -- %s " | |
772 | "(enctype %s) error %s", | |
773 | r->cname, str ? str : "unknown enctype", msg); | |
774 | krb5_free_error_message(r->context, msg); | |
775 | free(str); | |
776 | ||
777 | continue; | |
778 | } | |
40b65c84 | 779 | |
75ec66c7 SM |
780 | if (pepper1kdc == NULL) { |
781 | /* The caller is not interessted in details */ | |
782 | return 0; | |
40b65c84 SM |
783 | } |
784 | ||
75ec66c7 SM |
785 | heim_assert(KDCchallengekey != NULL, |
786 | "KDCchallengekey pointer required with pepper1kdc"); | |
787 | heim_assert(used_key != NULL, | |
788 | "used_key pointer required with pepper1kdc"); | |
40b65c84 SM |
789 | |
790 | /* | |
791 | * Provide KDC authentication to the client, uses a different | |
792 | * challenge key (different pepper). | |
793 | */ | |
794 | ||
40b65c84 | 795 | ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto, |
75ec66c7 SM |
796 | pepper1kdc, pepper2, aenctype, |
797 | KDCchallengekey); | |
40b65c84 SM |
798 | krb5_crypto_destroy(r->context, longtermcrypto); |
799 | if (ret) | |
75ec66c7 SM |
800 | return ret; |
801 | ||
802 | *used_key = k; | |
803 | return 0; | |
804 | } | |
805 | ||
806 | if (invalidKeys == 0) | |
807 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
808 | ||
809 | return KRB5KDC_ERR_PREAUTH_FAILED; | |
810 | } | |
811 | ||
812 | static krb5_error_code | |
813 | pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) | |
814 | { | |
815 | krb5_kvno kvno = r->client->kvno; | |
816 | krb5_data pepper1client, pepper1kdc, pepper2; | |
817 | EncryptedData enc_data; | |
818 | krb5_enctype aenctype; | |
819 | krb5_error_code ret; | |
820 | krb5_keyblock KDCchallengekey; | |
821 | struct Key *k = NULL; | |
822 | size_t size; | |
823 | ||
824 | heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST"); | |
825 | ||
826 | if (_kdc_is_anon_request(&r->req)) { | |
827 | ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | |
828 | kdc_log(r->context, r->config, 4, "ENC-CHAL doesn't support anon"); | |
829 | return ret; | |
830 | } | |
831 | ||
832 | if (r->client->flags.locked_out) { | |
833 | ret = KRB5KDC_ERR_CLIENT_REVOKED; | |
834 | kdc_log(r->context, r->config, 0, | |
835 | "Client (%s) is locked out", r->cname); | |
836 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
837 | KDC_AUTH_EVENT_CLIENT_LOCKED_OUT); | |
838 | return ret; | |
839 | } | |
840 | ||
841 | ret = decode_EncryptedData(pa->padata_value.data, | |
842 | pa->padata_value.length, | |
843 | &enc_data, | |
844 | &size); | |
845 | if (ret) { | |
846 | ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | |
847 | _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s", | |
848 | r->cname); | |
849 | return ret; | |
850 | } | |
851 | ||
852 | pepper1client.data = "clientchallengearmor"; | |
853 | pepper1client.length = strlen(pepper1client.data); | |
854 | pepper1kdc.data = "kdcchallengearmor"; | |
855 | pepper1kdc.length = strlen(pepper1kdc.data); | |
856 | pepper2.data = "challengelongterm"; | |
857 | pepper2.length = strlen(pepper2.data); | |
858 | ||
859 | krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype); | |
860 | ||
861 | kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype); | |
862 | ||
863 | ret = pa_enc_chal_decrypt_kvno(r, aenctype, | |
864 | &pepper1client, | |
865 | &pepper1kdc, | |
866 | &pepper2, | |
867 | kvno, | |
868 | &enc_data, | |
869 | &KDCchallengekey, | |
870 | &k); | |
871 | if (ret == KRB5KDC_ERR_ETYPE_NOSUPP) { | |
872 | char *estr; | |
873 | _kdc_set_e_text(r, "No key matching entype"); | |
874 | if(krb5_enctype_to_string(r->context, enc_data.etype, &estr)) | |
875 | estr = NULL; | |
876 | if(estr == NULL) | |
877 | _kdc_r_log(r, 4, | |
878 | "No client key matching ENC-CHAL (%d) -- %s", | |
879 | enc_data.etype, r->cname); | |
880 | else | |
881 | _kdc_r_log(r, 4, | |
882 | "No client key matching ENC-CHAL (%s) -- %s", | |
883 | estr, r->cname); | |
884 | free(estr); | |
885 | free_EncryptedData(&enc_data); | |
886 | kdc_audit_setkv_number((kdc_request_t)r, | |
887 | KDC_REQUEST_KV_PA_FAILED_KVNO, | |
888 | kvno); | |
889 | return ret; | |
890 | } | |
891 | if (ret == KRB5KRB_AP_ERR_SKEW) { | |
892 | /* | |
893 | * Logging happens inside of | |
894 | * _krb5_validate_pa_enc_challenge() | |
895 | * via pa_enc_chal_decrypt_kvno() | |
896 | */ | |
897 | ||
898 | free_EncryptedData(&enc_data); | |
899 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
900 | KDC_AUTH_EVENT_CLIENT_TIME_SKEW); | |
901 | ||
902 | /* | |
903 | * The following is needed to make windows clients to | |
904 | * retry using the timestamp in the error message, if | |
905 | * there is a e_text, they become unhappy. | |
906 | */ | |
907 | r->e_text = NULL; | |
908 | return ret; | |
909 | } | |
910 | if (ret == KRB5KDC_ERR_PREAUTH_FAILED) { | |
911 | krb5_error_code hret = ret; | |
912 | int hi; | |
913 | ||
914 | /* | |
915 | * Logging happens inside of | |
916 | * via pa_enc_chal_decrypt_kvno() | |
917 | */ | |
918 | ||
919 | kdc_audit_setkv_number((kdc_request_t)r, | |
920 | KDC_REQUEST_KV_PA_FAILED_KVNO, | |
921 | kvno); | |
922 | ||
923 | /* | |
924 | * Check if old and older keys are | |
925 | * able to decrypt. | |
926 | */ | |
927 | for (hi = 1; hi < 3; hi++) { | |
928 | krb5_kvno hkvno; | |
929 | ||
930 | if (hi >= kvno) { | |
931 | break; | |
932 | } | |
933 | ||
934 | hkvno = kvno - hi; | |
935 | hret = pa_enc_chal_decrypt_kvno(r, aenctype, | |
936 | &pepper1client, | |
937 | NULL, /* pepper1kdc */ | |
938 | &pepper2, | |
939 | hkvno, | |
940 | &enc_data, | |
941 | NULL, /* KDCchallengekey */ | |
942 | NULL); /* used_key */ | |
943 | if (hret == 0) { | |
944 | kdc_audit_setkv_number((kdc_request_t)r, | |
945 | KDC_REQUEST_KV_PA_HISTORIC_KVNO, | |
946 | hkvno); | |
947 | break; | |
948 | } | |
949 | if (hret == KRB5KDC_ERR_ETYPE_NOSUPP) { | |
950 | break; | |
951 | } | |
952 | } | |
40b65c84 | 953 | |
75ec66c7 SM |
954 | free_EncryptedData(&enc_data); |
955 | ||
956 | if (hret == 0) | |
957 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
958 | KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY); | |
959 | else | |
960 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
961 | KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY); | |
962 | ||
963 | return ret; | |
964 | } | |
965 | free_EncryptedData(&enc_data); | |
966 | if (ret == 0) { | |
967 | krb5_crypto challengecrypto; | |
968 | char *estr = NULL; | |
969 | char *astr = NULL; | |
970 | char *kstr = NULL; | |
971 | ||
972 | ret = krb5_crypto_init(r->context, &KDCchallengekey, 0, &challengecrypto); | |
973 | krb5_free_keyblock_contents(r->context, &KDCchallengekey); | |
40b65c84 | 974 | if (ret) |
75ec66c7 | 975 | return ret; |
40b65c84 SM |
976 | |
977 | ret = _krb5_make_pa_enc_challenge(r->context, challengecrypto, | |
978 | KRB5_KU_ENC_CHALLENGE_KDC, | |
979 | r->rep.padata); | |
980 | krb5_crypto_destroy(r->context, challengecrypto); | |
981 | if (ret) | |
75ec66c7 SM |
982 | return ret; |
983 | ||
984 | ret = set_salt_padata(r->context, r->config, r->rep.padata, k); | |
985 | if (ret) | |
986 | return ret; | |
40b65c84 SM |
987 | |
988 | /* | |
75ec66c7 | 989 | * Found a key that the client used, lets pick that as the reply key |
40b65c84 | 990 | */ |
75ec66c7 SM |
991 | |
992 | krb5_free_keyblock_contents(r->context, &r->reply_key); | |
993 | ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key); | |
994 | if (ret) | |
995 | return ret; | |
996 | ||
997 | if (krb5_enctype_to_string(r->context, (int)aenctype, &astr)) | |
998 | astr = NULL; | |
999 | if (krb5_enctype_to_string(r->context, enc_data.etype, &estr)) | |
1000 | estr = NULL; | |
1001 | if (krb5_enctype_to_string(r->context, k->key.keytype, &kstr)) | |
1002 | kstr = NULL; | |
1003 | _kdc_r_log(r, 4, "ENC-CHAL Pre-authentication succeeded -- %s " | |
1004 | "using armor=%s enc=%s key=%s", | |
1005 | r->cname, | |
1006 | astr ? astr : "unknown enctype", | |
1007 | estr ? estr : "unknown enctype", | |
1008 | kstr ? kstr : "unknown enctype"); | |
51569b31 JS |
1009 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
1010 | KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY); | |
75ec66c7 SM |
1011 | kdc_audit_setkv_number((kdc_request_t)r, |
1012 | KDC_REQUEST_KV_PA_SUCCEEDED_KVNO, | |
1013 | kvno); | |
1014 | return 0; | |
40b65c84 SM |
1015 | } |
1016 | ||
75ec66c7 SM |
1017 | return ret; |
1018 | } | |
1019 | ||
1020 | static krb5_error_code | |
1021 | pa_enc_ts_decrypt_kvno(astgs_request_t r, | |
1022 | krb5_kvno kvno, | |
1023 | const EncryptedData *enc_data, | |
1024 | krb5_data *ts_data, | |
1025 | Key **_pa_key) | |
1026 | { | |
1027 | krb5_error_code ret; | |
1028 | krb5_crypto crypto; | |
1029 | Key *pa_key = NULL; | |
1030 | const Keys *keys = NULL; | |
1031 | ||
1032 | if (_pa_key) | |
1033 | *_pa_key = NULL; | |
1034 | ||
1035 | krb5_data_zero(ts_data); | |
1036 | ||
1037 | keys = hdb_kvno2keys(r->context, r->client, kvno); | |
1038 | if (keys == NULL) { | |
1039 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
1040 | } | |
1041 | ret = hdb_enctype2key(r->context, r->client, keys, | |
1042 | enc_data->etype, &pa_key); | |
1043 | if(ret){ | |
1044 | return KRB5KDC_ERR_ETYPE_NOSUPP; | |
40b65c84 | 1045 | } |
40b65c84 | 1046 | |
75ec66c7 SM |
1047 | try_next_key: |
1048 | ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto); | |
1049 | if (ret) { | |
1050 | const char *msg = krb5_get_error_message(r->context, ret); | |
1051 | _kdc_r_log(r, 4, "krb5_crypto_init failed: %s", msg); | |
1052 | krb5_free_error_message(r->context, msg); | |
1053 | return ret; | |
1054 | } | |
1055 | ||
1056 | ret = krb5_decrypt_EncryptedData(r->context, | |
1057 | crypto, | |
1058 | KRB5_KU_PA_ENC_TIMESTAMP, | |
1059 | enc_data, | |
1060 | ts_data); | |
1061 | krb5_crypto_destroy(r->context, crypto); | |
1062 | /* | |
1063 | * Since the user might have several keys with the same | |
f1a83798 | 1064 | * enctype but with different salting, we need to try all |
75ec66c7 SM |
1065 | * the keys with the same enctype. |
1066 | */ | |
1067 | if (ret) { | |
1068 | ret = hdb_next_enctype2key(r->context, r->client, keys, | |
1069 | enc_data->etype, &pa_key); | |
1070 | if (ret == 0) | |
1071 | goto try_next_key; | |
1072 | ||
1073 | return KRB5KDC_ERR_PREAUTH_FAILED; | |
1074 | } | |
1075 | ||
1076 | if (_pa_key) | |
1077 | *_pa_key = pa_key; | |
1078 | return 0; | |
40b65c84 SM |
1079 | } |
1080 | ||
1081 | static krb5_error_code | |
51569b31 | 1082 | pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa) |
40b65c84 | 1083 | { |
75ec66c7 | 1084 | krb5_kvno kvno = r->client->kvno; |
40b65c84 SM |
1085 | EncryptedData enc_data; |
1086 | krb5_error_code ret; | |
40b65c84 SM |
1087 | krb5_data ts_data; |
1088 | PA_ENC_TS_ENC p; | |
1089 | size_t len; | |
1090 | Key *pa_key; | |
c33f6b2c | 1091 | char *str; |
255e3e18 | 1092 | |
40b65c84 SM |
1093 | if (r->armor_crypto && !r->config->enable_armored_pa_enc_timestamp) { |
1094 | ret = KRB5KDC_ERR_POLICY; | |
1095 | kdc_log(r->context, r->config, 0, | |
1096 | "Armored encrypted timestamp pre-authentication is disabled"); | |
1097 | return ret; | |
1098 | } else if (!r->armor_crypto && !r->config->enable_unarmored_pa_enc_timestamp) { | |
1099 | ret = KRB5KDC_ERR_POLICY; | |
1100 | kdc_log(r->context, r->config, 0, | |
1101 | "Unarmored encrypted timestamp pre-authentication is disabled"); | |
1102 | return ret; | |
1103 | } | |
1104 | ||
51569b31 | 1105 | if (r->client->flags.locked_out) { |
40b65c84 SM |
1106 | ret = KRB5KDC_ERR_CLIENT_REVOKED; |
1107 | kdc_log(r->context, r->config, 0, | |
1108 | "Client (%s) is locked out", r->cname); | |
51569b31 JS |
1109 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
1110 | KDC_AUTH_EVENT_CLIENT_LOCKED_OUT); | |
40b65c84 SM |
1111 | return ret; |
1112 | } | |
1113 | ||
1114 | ret = decode_EncryptedData(pa->padata_value.data, | |
1115 | pa->padata_value.length, | |
1116 | &enc_data, | |
1117 | &len); | |
1118 | if (ret) { | |
1119 | ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | |
1120 | _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s", | |
1121 | r->cname); | |
1122 | goto out; | |
1123 | } | |
1124 | ||
75ec66c7 SM |
1125 | ret = pa_enc_ts_decrypt_kvno(r, kvno, &enc_data, &ts_data, &pa_key); |
1126 | if (ret == KRB5KDC_ERR_ETYPE_NOSUPP) { | |
40b65c84 | 1127 | char *estr; |
b12a33e2 | 1128 | _kdc_set_e_text(r, "No key matching enctype"); |
40b65c84 SM |
1129 | if(krb5_enctype_to_string(r->context, enc_data.etype, &estr)) |
1130 | estr = NULL; | |
1131 | if(estr == NULL) | |
1132 | _kdc_r_log(r, 4, | |
1133 | "No client key matching pa-data (%d) -- %s", | |
1134 | enc_data.etype, r->cname); | |
1135 | else | |
1136 | _kdc_r_log(r, 4, | |
1137 | "No client key matching pa-data (%s) -- %s", | |
1138 | estr, r->cname); | |
1139 | free(estr); | |
1140 | free_EncryptedData(&enc_data); | |
75ec66c7 SM |
1141 | kdc_audit_setkv_number((kdc_request_t)r, |
1142 | KDC_REQUEST_KV_PA_FAILED_KVNO, | |
1143 | kvno); | |
40b65c84 SM |
1144 | goto out; |
1145 | } | |
75ec66c7 | 1146 | if (ret == KRB5KDC_ERR_PREAUTH_FAILED) { |
40b65c84 SM |
1147 | krb5_error_code ret2; |
1148 | const char *msg = krb5_get_error_message(r->context, ret); | |
75ec66c7 SM |
1149 | krb5_error_code hret = ret; |
1150 | int hi; | |
1151 | ||
1152 | kdc_audit_setkv_number((kdc_request_t)r, | |
1153 | KDC_REQUEST_KV_PA_FAILED_KVNO, | |
1154 | kvno); | |
40b65c84 | 1155 | |
75ec66c7 SM |
1156 | /* |
1157 | * Check if old and older keys are | |
1158 | * able to decrypt. | |
1159 | */ | |
1160 | for (hi = 1; hi < 3; hi++) { | |
1161 | krb5_kvno hkvno; | |
1162 | ||
1163 | if (hi >= kvno) { | |
1164 | break; | |
1165 | } | |
1166 | ||
1167 | hkvno = kvno - hi; | |
1168 | hret = pa_enc_ts_decrypt_kvno(r, hkvno, | |
1169 | &enc_data, | |
1170 | &ts_data, | |
1171 | NULL); /* pa_key */ | |
1172 | if (hret == 0) { | |
1173 | krb5_data_free(&ts_data); | |
1174 | kdc_audit_setkv_number((kdc_request_t)r, | |
1175 | KDC_REQUEST_KV_PA_HISTORIC_KVNO, | |
1176 | hkvno); | |
1177 | break; | |
1178 | } | |
1179 | if (hret == KRB5KDC_ERR_ETYPE_NOSUPP) { | |
1180 | break; | |
1181 | } | |
1182 | } | |
1183 | ||
1184 | ret2 = krb5_enctype_to_string(r->context, enc_data.etype, &str); | |
40b65c84 SM |
1185 | if (ret2) |
1186 | str = NULL; | |
1187 | _kdc_r_log(r, 2, "Failed to decrypt PA-DATA -- %s " | |
1188 | "(enctype %s) error %s", | |
1189 | r->cname, str ? str : "unknown enctype", msg); | |
51569b31 | 1190 | krb5_xfree(str); |
40b65c84 | 1191 | krb5_free_error_message(r->context, msg); |
51569b31 | 1192 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_PA_ETYPE, |
75ec66c7 SM |
1193 | enc_data.etype); |
1194 | if (hret == 0) | |
1195 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
1196 | KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY); | |
1197 | else | |
1198 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
1199 | KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY); | |
40b65c84 SM |
1200 | |
1201 | free_EncryptedData(&enc_data); | |
1202 | ||
1203 | ret = KRB5KDC_ERR_PREAUTH_FAILED; | |
1204 | goto out; | |
1205 | } | |
1206 | free_EncryptedData(&enc_data); | |
40b65c84 SM |
1207 | ret = decode_PA_ENC_TS_ENC(ts_data.data, |
1208 | ts_data.length, | |
1209 | &p, | |
1210 | &len); | |
1211 | krb5_data_free(&ts_data); | |
1212 | if(ret){ | |
1213 | ret = KRB5KDC_ERR_PREAUTH_FAILED; | |
b12a33e2 | 1214 | _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS-ENC -- %s", |
40b65c84 SM |
1215 | r->cname); |
1216 | goto out; | |
1217 | } | |
1218 | if (labs(kdc_time - p.patimestamp) > r->context->max_skew) { | |
1219 | char client_time[100]; | |
1220 | ||
1221 | krb5_format_time(r->context, p.patimestamp, | |
1222 | client_time, sizeof(client_time), TRUE); | |
1223 | ||
1224 | ret = KRB5KRB_AP_ERR_SKEW; | |
1225 | _kdc_r_log(r, 4, "Too large time skew, " | |
1226 | "client time %s is out by %u > %u seconds -- %s", | |
1227 | client_time, | |
1228 | (unsigned)labs(kdc_time - p.patimestamp), | |
1229 | r->context->max_skew, | |
1230 | r->cname); | |
51569b31 JS |
1231 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
1232 | KDC_AUTH_EVENT_CLIENT_TIME_SKEW); | |
40b65c84 SM |
1233 | |
1234 | /* | |
1235 | * The following is needed to make windows clients to | |
1236 | * retry using the timestamp in the error message, if | |
1237 | * there is a e_text, they become unhappy. | |
1238 | */ | |
1239 | r->e_text = NULL; | |
1240 | free_PA_ENC_TS_ENC(&p); | |
1241 | goto out; | |
1242 | } | |
1243 | free_PA_ENC_TS_ENC(&p); | |
1244 | ||
75ec66c7 | 1245 | ret = set_salt_padata(r->context, r->config, r->rep.padata, pa_key); |
51569b31 JS |
1246 | if (ret == 0) |
1247 | ret = krb5_copy_keyblock_contents(r->context, &pa_key->key, &r->reply_key); | |
40b65c84 SM |
1248 | if (ret) |
1249 | return ret; | |
1250 | ||
1251 | ret = krb5_enctype_to_string(r->context, pa_key->key.keytype, &str); | |
1252 | if (ret) | |
1253 | str = NULL; | |
1254 | _kdc_r_log(r, 4, "ENC-TS Pre-authentication succeeded -- %s using %s", | |
1255 | r->cname, str ? str : "unknown enctype"); | |
51569b31 JS |
1256 | krb5_xfree(str); |
1257 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_PA_ETYPE, | |
1258 | pa_key->key.keytype); | |
1259 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
1260 | KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY); | |
75ec66c7 SM |
1261 | kdc_audit_setkv_number((kdc_request_t)r, |
1262 | KDC_REQUEST_KV_PA_SUCCEEDED_KVNO, | |
1263 | kvno); | |
40b65c84 SM |
1264 | |
1265 | ret = 0; | |
1266 | ||
1267 | out: | |
1268 | ||
1269 | return ret; | |
1270 | } | |
1271 | ||
a25f549e JS |
1272 | #ifdef PKINIT |
1273 | ||
1274 | static krb5_error_code | |
1275 | make_freshness_token(astgs_request_t r, const Key *krbtgt_key, unsigned krbtgt_kvno) | |
1276 | { | |
1277 | krb5_error_code ret = 0; | |
1278 | const struct timeval current_kdc_time = krb5_kdc_get_time(); | |
1279 | int usec = current_kdc_time.tv_usec; | |
1280 | const PA_ENC_TS_ENC ts_enc = { | |
1281 | .patimestamp = current_kdc_time.tv_sec, | |
1282 | .pausec = &usec, | |
1283 | }; | |
1284 | unsigned char *encoded_ts_enc = NULL; | |
1285 | size_t ts_enc_size; | |
1286 | size_t ts_enc_len = 0; | |
1287 | EncryptedData encdata; | |
1288 | krb5_crypto crypto; | |
1289 | unsigned char *token = NULL; | |
1290 | size_t token_size; | |
1291 | size_t token_len = 0; | |
1292 | size_t token_alloc_size; | |
1293 | ||
1294 | ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, | |
1295 | encoded_ts_enc, | |
1296 | ts_enc_size, | |
1297 | &ts_enc, | |
1298 | &ts_enc_len, | |
1299 | ret); | |
1300 | if (ret) | |
1301 | return ret; | |
1302 | if (ts_enc_size != ts_enc_len) | |
1303 | krb5_abortx(r->context, "internal error in ASN.1 encoder"); | |
1304 | ||
1305 | ret = krb5_crypto_init(r->context, &krbtgt_key->key, 0, &crypto); | |
1306 | if (ret) { | |
1307 | free(encoded_ts_enc); | |
1308 | return ret; | |
1309 | } | |
1310 | ||
1311 | ret = krb5_encrypt_EncryptedData(r->context, | |
1312 | crypto, | |
1313 | KRB5_KU_AS_FRESHNESS, | |
1314 | encoded_ts_enc, | |
1315 | ts_enc_len, | |
1316 | krbtgt_kvno, | |
1317 | &encdata); | |
1318 | free(encoded_ts_enc); | |
1319 | krb5_crypto_destroy(r->context, crypto); | |
1320 | if (ret) | |
1321 | return ret; | |
1322 | ||
1323 | token_size = length_EncryptedData(&encdata); | |
1324 | token_alloc_size = token_size + 2; /* Account for the two leading zero bytes. */ | |
1325 | token = calloc(1, token_alloc_size); | |
1326 | if (token == NULL) { | |
1327 | free_EncryptedData(&encdata); | |
1328 | return ENOMEM; | |
1329 | } | |
1330 | ||
1331 | ret = encode_EncryptedData(token + token_alloc_size - 1, | |
1332 | token_size, | |
1333 | &encdata, | |
1334 | &token_len); | |
1335 | free_EncryptedData(&encdata); | |
1336 | if (ret) { | |
1337 | free(token); | |
1338 | return ret; | |
1339 | } | |
1340 | if (token_size != token_len) | |
1341 | krb5_abortx(r->context, "internal error in ASN.1 encoder"); | |
1342 | ||
1343 | ret = krb5_padata_add(r->context, | |
1344 | r->rep.padata, | |
1345 | KRB5_PADATA_AS_FRESHNESS, | |
1346 | token, | |
1347 | token_alloc_size); | |
1348 | if (ret) | |
1349 | free(token); | |
1350 | return ret; | |
1351 | } | |
1352 | ||
1353 | #endif /* PKINIT */ | |
1354 | ||
1355 | static krb5_error_code | |
1356 | send_freshness_token(astgs_request_t r, const Key *krbtgt_key, unsigned krbtgt_kvno) | |
1357 | { | |
1358 | krb5_error_code ret = 0; | |
1359 | #ifdef PKINIT | |
1360 | int idx = 0; | |
1361 | const PA_DATA *freshness_padata = NULL; | |
1362 | ||
1363 | freshness_padata = _kdc_find_padata(&r->req, | |
1364 | &idx, | |
1365 | KRB5_PADATA_AS_FRESHNESS); | |
1366 | if (freshness_padata == NULL) { | |
1367 | return 0; | |
1368 | } | |
1369 | ||
1370 | ret = make_freshness_token(r, krbtgt_key, krbtgt_kvno); | |
1371 | #endif /* PKINIT */ | |
1372 | return ret; | |
1373 | } | |
1374 | ||
40b65c84 SM |
1375 | struct kdc_patypes { |
1376 | int type; | |
95c02a97 | 1377 | const char *name; |
40b65c84 SM |
1378 | unsigned int flags; |
1379 | #define PA_ANNOUNCE 1 | |
1380 | #define PA_REQ_FAST 2 /* only use inside fast */ | |
1381 | #define PA_SYNTHETIC_OK 4 | |
1382 | #define PA_REPLACE_REPLY_KEY 8 /* PA mech replaces reply key */ | |
1383 | #define PA_USES_LONG_TERM_KEY 16 /* PA mech uses client's long-term key */ | |
fc474042 | 1384 | #define PA_USES_FAST_COOKIE 32 /* Multi-step PA mech maintains state in PA-FX-COOKIE */ |
09bcd48f | 1385 | #define PA_HARDWARE_AUTH 64 /* PA mech uses hardware authentication */ |
51569b31 | 1386 | krb5_error_code (*validate)(astgs_request_t, const PA_DATA *pa); |
40b65c84 SM |
1387 | krb5_error_code (*finalize_pac)(astgs_request_t r); |
1388 | void (*cleanup)(astgs_request_t r); | |
1389 | }; | |
1390 | ||
1391 | static const struct kdc_patypes pat[] = { | |
1392 | #ifdef PKINIT | |
1393 | { | |
1394 | KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", | |
09bcd48f | 1395 | PA_ANNOUNCE | PA_SYNTHETIC_OK | PA_REPLACE_REPLY_KEY | PA_HARDWARE_AUTH, |
40b65c84 SM |
1396 | pa_pkinit_validate, NULL, NULL |
1397 | }, | |
1398 | { | |
09bcd48f | 1399 | KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE | PA_REPLACE_REPLY_KEY | PA_HARDWARE_AUTH, |
40b65c84 SM |
1400 | pa_pkinit_validate, NULL, NULL |
1401 | }, | |
1402 | { | |
1403 | KRB5_PADATA_PKINIT_KX, "Anonymous PK-INIT", PA_ANNOUNCE, | |
1404 | NULL, NULL, NULL | |
1405 | }, | |
1406 | #else | |
1407 | { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0, NULL , NULL, NULL }, | |
1408 | { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0, NULL, NULL, NULL }, | |
1409 | { KRB5_PADATA_PKINIT_KX, "Anonymous PK-INIT", 0, NULL, NULL, NULL }, | |
1410 | #endif | |
1411 | { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0, NULL, NULL, NULL }, | |
1412 | { | |
1413 | KRB5_PADATA_ENC_TIMESTAMP , "ENC-TS", | |
1414 | PA_ANNOUNCE | PA_USES_LONG_TERM_KEY, | |
1415 | pa_enc_ts_validate, NULL, NULL | |
1416 | }, | |
1417 | { | |
1418 | KRB5_PADATA_ENCRYPTED_CHALLENGE , "ENC-CHAL", | |
1419 | PA_ANNOUNCE | PA_USES_LONG_TERM_KEY | PA_REQ_FAST, | |
1420 | pa_enc_chal_validate, NULL, NULL | |
1421 | }, | |
1422 | { KRB5_PADATA_REQ_ENC_PA_REP , "REQ-ENC-PA-REP", 0, NULL, NULL, NULL }, | |
1423 | { KRB5_PADATA_FX_FAST, "FX-FAST", PA_ANNOUNCE, NULL, NULL, NULL }, | |
1424 | { KRB5_PADATA_FX_ERROR, "FX-ERROR", 0, NULL, NULL, NULL }, | |
1425 | { KRB5_PADATA_FX_COOKIE, "FX-COOKIE", 0, NULL, NULL, NULL }, | |
1426 | { | |
1427 | KRB5_PADATA_GSS , "GSS", | |
fc474042 | 1428 | PA_ANNOUNCE | PA_SYNTHETIC_OK | PA_REPLACE_REPLY_KEY | PA_USES_FAST_COOKIE, |
51569b31 | 1429 | pa_gss_validate, pa_gss_finalize_pac, NULL |
40b65c84 SM |
1430 | }, |
1431 | }; | |
1432 | ||
1433 | static void | |
1434 | log_patypes(astgs_request_t r, METHOD_DATA *padata) | |
1435 | { | |
1436 | krb5_kdc_configuration *config = r->config; | |
1437 | struct rk_strpool *p = NULL; | |
1438 | char *str; | |
1439 | size_t n, m; | |
1440 | ||
1441 | for (n = 0; n < padata->len; n++) { | |
1442 | for (m = 0; m < sizeof(pat) / sizeof(pat[0]); m++) { | |
1443 | if (padata->val[n].padata_type == pat[m].type) { | |
1444 | p = rk_strpoolprintf(p, "%s", pat[m].name); | |
1445 | break; | |
1446 | } | |
c33f6b2c | 1447 | } |
40b65c84 SM |
1448 | if (m == sizeof(pat) / sizeof(pat[0])) |
1449 | p = rk_strpoolprintf(p, "%d", padata->val[n].padata_type); | |
1450 | if (p && n + 1 < padata->len) | |
c33f6b2c AB |
1451 | p = rk_strpoolprintf(p, ", "); |
1452 | if (p == NULL) { | |
40b65c84 | 1453 | kdc_log(r->context, config, 1, "out of memory"); |
c33f6b2c AB |
1454 | return; |
1455 | } | |
1456 | } | |
835926c8 AB |
1457 | if (p == NULL) |
1458 | p = rk_strpoolprintf(p, "none"); | |
255e3e18 | 1459 | |
c33f6b2c | 1460 | str = rk_strpoolcollect(p); |
40b65c84 | 1461 | kdc_log(r->context, config, 4, "Client sent patypes: %s", str); |
51569b31 JS |
1462 | kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, |
1463 | "client-pa", "%s", str); | |
c33f6b2c AB |
1464 | free(str); |
1465 | } | |
1466 | ||
40b65c84 SM |
1467 | static krb5_boolean |
1468 | pa_used_flag_isset(astgs_request_t r, unsigned int flag) | |
1469 | { | |
1470 | if (r->pa_used == NULL) | |
1471 | return FALSE; | |
1472 | ||
1473 | return (r->pa_used->flags & flag) == flag; | |
1474 | } | |
1475 | ||
c33f6b2c AB |
1476 | /* |
1477 | * | |
1478 | */ | |
1479 | ||
3c1e780e AB |
1480 | krb5_error_code |
1481 | _kdc_encode_reply(krb5_context context, | |
1482 | krb5_kdc_configuration *config, | |
40b65c84 | 1483 | astgs_request_t r, uint32_t nonce, |
2b29b718 | 1484 | krb5_enctype etype, |
3c1e780e | 1485 | int skvno, const EncryptionKey *skey, |
40b65c84 | 1486 | int ckvno, |
4f8ba5ad | 1487 | int rk_is_subkey, |
3c1e780e | 1488 | krb5_data *reply) |
954c0172 HIU |
1489 | { |
1490 | unsigned char *buf; | |
1491 | size_t buf_size; | |
255e3e18 | 1492 | size_t len = 0; |
954c0172 HIU |
1493 | krb5_error_code ret; |
1494 | krb5_crypto crypto; | |
40b65c84 SM |
1495 | KDC_REP *rep = &r->rep; |
1496 | EncTicketPart *et = &r->et; | |
1497 | EncKDCRepPart *ek = &r->ek; | |
1498 | ||
1499 | heim_assert(rep->padata != NULL, "reply padata uninitialized"); | |
954c0172 HIU |
1500 | |
1501 | ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret); | |
1502 | if(ret) { | |
4f8ba5ad | 1503 | const char *msg = krb5_get_error_message(context, ret); |
40b65c84 | 1504 | kdc_log(context, config, 4, "Failed to encode ticket: %s", msg); |
4f8ba5ad | 1505 | krb5_free_error_message(context, msg); |
954c0172 HIU |
1506 | return ret; |
1507 | } | |
40b65c84 SM |
1508 | if(buf_size != len) |
1509 | krb5_abortx(context, "Internal error in ASN.1 encoder"); | |
954c0172 HIU |
1510 | |
1511 | ret = krb5_crypto_init(context, skey, etype, &crypto); | |
1512 | if (ret) { | |
40b65c84 SM |
1513 | const char *msg = krb5_get_error_message(context, ret); |
1514 | kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg); | |
4f8ba5ad | 1515 | krb5_free_error_message(context, msg); |
40b65c84 | 1516 | free(buf); |
954c0172 HIU |
1517 | return ret; |
1518 | } | |
1519 | ||
2b29b718 | 1520 | ret = krb5_encrypt_EncryptedData(context, |
954c0172 HIU |
1521 | crypto, |
1522 | KRB5_KU_TICKET, | |
1523 | buf, | |
1524 | len, | |
1525 | skvno, | |
1526 | &rep->ticket.enc_part); | |
1527 | free(buf); | |
1528 | krb5_crypto_destroy(context, crypto); | |
1529 | if(ret) { | |
4f8ba5ad | 1530 | const char *msg = krb5_get_error_message(context, ret); |
40b65c84 | 1531 | kdc_log(context, config, 4, "Failed to encrypt data: %s", msg); |
4f8ba5ad | 1532 | krb5_free_error_message(context, msg); |
954c0172 HIU |
1533 | return ret; |
1534 | } | |
2b29b718 | 1535 | |
40b65c84 SM |
1536 | if (r && r->armor_crypto) { |
1537 | KrbFastFinished finished; | |
1538 | krb5_data data; | |
1539 | ||
1540 | kdc_log(context, config, 4, "FAST armor protection"); | |
1541 | ||
1542 | memset(&finished, 0, sizeof(finished)); | |
1543 | krb5_data_zero(&data); | |
1544 | ||
1545 | finished.timestamp = kdc_time; | |
1546 | finished.usec = 0; | |
1547 | finished.crealm = et->crealm; | |
1548 | finished.cname = et->cname; | |
1549 | ||
1550 | ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, | |
1551 | &rep->ticket, &len, ret); | |
1552 | if (ret) | |
1553 | return ret; | |
1554 | if (data.length != len) | |
1555 | krb5_abortx(context, "internal asn.1 error"); | |
1556 | ||
1557 | ret = krb5_create_checksum(context, r->armor_crypto, | |
1558 | KRB5_KU_FAST_FINISHED, 0, | |
1559 | data.data, data.length, | |
1560 | &finished.ticket_checksum); | |
1561 | krb5_data_free(&data); | |
1562 | if (ret) | |
1563 | return ret; | |
1564 | ||
1565 | ret = _kdc_fast_mk_response(context, r->armor_crypto, | |
1566 | rep->padata, &r->strengthen_key, &finished, | |
1567 | nonce, &data); | |
1568 | free_Checksum(&finished.ticket_checksum); | |
1569 | if (ret) | |
1570 | return ret; | |
1571 | ||
1572 | free_METHOD_DATA(r->rep.padata); | |
1573 | ||
1574 | ret = krb5_padata_add(context, rep->padata, | |
1575 | KRB5_PADATA_FX_FAST, | |
1576 | data.data, data.length); | |
1577 | if (ret) | |
1578 | return ret; | |
1579 | ||
1580 | /* | |
1581 | * Hide client name for privacy reasons | |
1582 | */ | |
1583 | if (r->fast.flags.requested_hidden_names) { | |
1584 | Realm anon_realm = KRB5_ANON_REALM; | |
1585 | ||
1586 | free_Realm(&rep->crealm); | |
1587 | ret = copy_Realm(&anon_realm, &rep->crealm); | |
1588 | if (ret == 0) { | |
1589 | free_PrincipalName(&rep->cname); | |
1590 | ret = _kdc_make_anonymous_principalname(&rep->cname); | |
1591 | } | |
1592 | if (ret) | |
1593 | return ret; | |
1594 | } | |
1595 | } | |
1596 | ||
1597 | if (rep->padata->len == 0) { | |
1598 | free_METHOD_DATA(rep->padata); | |
1599 | free(rep->padata); | |
1600 | rep->padata = NULL; | |
1601 | } | |
1602 | ||
954c0172 HIU |
1603 | if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep) |
1604 | ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret); | |
1605 | else | |
1606 | ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret); | |
1607 | if(ret) { | |
4f8ba5ad | 1608 | const char *msg = krb5_get_error_message(context, ret); |
40b65c84 | 1609 | kdc_log(context, config, 4, "Failed to encode KDC-REP: %s", msg); |
4f8ba5ad | 1610 | krb5_free_error_message(context, msg); |
954c0172 HIU |
1611 | return ret; |
1612 | } | |
1613 | if(buf_size != len) { | |
1614 | free(buf); | |
40b65c84 SM |
1615 | kdc_log(context, config, 4, "Internal error in ASN.1 encoder"); |
1616 | _kdc_set_e_text(r, "KDC internal error"); | |
954c0172 HIU |
1617 | return KRB5KRB_ERR_GENERIC; |
1618 | } | |
40b65c84 | 1619 | ret = krb5_crypto_init(context, &r->reply_key, 0, &crypto); |
954c0172 | 1620 | if (ret) { |
4f8ba5ad | 1621 | const char *msg = krb5_get_error_message(context, ret); |
954c0172 | 1622 | free(buf); |
40b65c84 | 1623 | kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg); |
4f8ba5ad | 1624 | krb5_free_error_message(context, msg); |
954c0172 HIU |
1625 | return ret; |
1626 | } | |
1627 | if(rep->msg_type == krb_as_rep) { | |
51569b31 JS |
1628 | ret = krb5_encrypt_EncryptedData(context, |
1629 | crypto, | |
1630 | KRB5_KU_AS_REP_ENC_PART, | |
1631 | buf, | |
1632 | len, | |
1633 | ckvno, | |
1634 | &rep->enc_part); | |
1635 | free(buf); | |
1636 | if (ret == 0) | |
1637 | ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret); | |
954c0172 | 1638 | } else { |
51569b31 JS |
1639 | ret = krb5_encrypt_EncryptedData(context, |
1640 | crypto, | |
1641 | rk_is_subkey ? | |
1642 | KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : | |
1643 | KRB5_KU_TGS_REP_ENC_PART_SESSION, | |
1644 | buf, | |
1645 | len, | |
1646 | ckvno, | |
1647 | &rep->enc_part); | |
1648 | free(buf); | |
1649 | if (ret == 0) | |
1650 | ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret); | |
954c0172 HIU |
1651 | } |
1652 | krb5_crypto_destroy(context, crypto); | |
1653 | if(ret) { | |
4f8ba5ad | 1654 | const char *msg = krb5_get_error_message(context, ret); |
40b65c84 | 1655 | kdc_log(context, config, 4, "Failed to encode KDC-REP: %s", msg); |
4f8ba5ad | 1656 | krb5_free_error_message(context, msg); |
954c0172 HIU |
1657 | return ret; |
1658 | } | |
1659 | if(buf_size != len) { | |
1660 | free(buf); | |
40b65c84 SM |
1661 | kdc_log(context, config, 4, "Internal error in ASN.1 encoder"); |
1662 | _kdc_set_e_text(r, "KDC internal error"); | |
954c0172 HIU |
1663 | return KRB5KRB_ERR_GENERIC; |
1664 | } | |
1665 | reply->data = buf; | |
1666 | reply->length = buf_size; | |
1667 | return 0; | |
1668 | } | |
1669 | ||
b39330c4 AB |
1670 | /* |
1671 | * | |
1672 | */ | |
1673 | ||
954c0172 | 1674 | static krb5_error_code |
2b29b718 | 1675 | get_pa_etype_info(krb5_context context, |
954c0172 | 1676 | krb5_kdc_configuration *config, |
40b65c84 SM |
1677 | METHOD_DATA *md, Key *ckey, |
1678 | krb5_boolean include_salt) | |
954c0172 HIU |
1679 | { |
1680 | krb5_error_code ret = 0; | |
51569b31 JS |
1681 | ETYPE_INFO_ENTRY eie; /* do not free this one */ |
1682 | ETYPE_INFO ei; | |
1683 | PA_DATA pa; | |
954c0172 | 1684 | size_t len; |
2b29b718 | 1685 | |
51569b31 JS |
1686 | /* |
1687 | * Code moved here from what used to be make_etype_info_entry() because | |
1688 | * using the ASN.1 compiler-generated SEQUENCE OF add functions makes that | |
1689 | * old function's body and this one's small and clean. | |
1690 | * | |
1691 | * The following comment blocks were there: | |
1692 | * | |
1693 | * According to `the specs', we can't send a salt if we have AFS3 salted | |
1694 | * key, but that requires that you *know* what cell you are using (e.g by | |
1695 | * assuming that the cell is the same as the realm in lower case) | |
1696 | * | |
1697 | * We shouldn't sent salttype since it is incompatible with the | |
1698 | * specification and it breaks windows clients. The afs salting problem | |
1699 | * is solved by using KRB5-PADATA-AFS3-SALT implemented in Heimdal 0.7 and | |
1700 | * later. | |
1701 | * | |
1702 | * We return no salt type at all, as that should indicate the default salt | |
1703 | * type and make everybody happy. some systems (like w2k) dislike being | |
1704 | * told the salt type here. | |
1705 | */ | |
954c0172 | 1706 | |
51569b31 JS |
1707 | pa.padata_type = KRB5_PADATA_ETYPE_INFO; |
1708 | pa.padata_value.data = NULL; | |
1709 | pa.padata_value.length = 0; | |
1710 | ei.len = 0; | |
1711 | ei.val = NULL; | |
1712 | eie.etype = ckey->key.keytype; | |
1713 | eie.salttype = NULL; | |
1714 | eie.salt = NULL; | |
1715 | if (include_salt && ckey->salt) | |
1716 | eie.salt = &ckey->salt->salt; | |
1717 | ret = add_ETYPE_INFO(&ei, &eie); | |
1718 | if (ret == 0) | |
1719 | ASN1_MALLOC_ENCODE(ETYPE_INFO, pa.padata_value.data, pa.padata_value.length, | |
1720 | &ei, &len, ret); | |
1721 | if (ret == 0) | |
1722 | add_METHOD_DATA(md, &pa); | |
1723 | free_ETYPE_INFO(&ei); | |
1724 | free_PA_DATA(&pa); | |
1725 | return ret; | |
954c0172 HIU |
1726 | } |
1727 | ||
1728 | /* | |
1729 | * | |
1730 | */ | |
1731 | ||
a25f549e JS |
1732 | extern const int _krb5_AES_SHA1_string_to_default_iterator; |
1733 | extern const int _krb5_AES_SHA2_string_to_default_iterator; | |
954c0172 HIU |
1734 | |
1735 | static krb5_error_code | |
40b65c84 | 1736 | make_s2kparams(int value, size_t len, krb5_data **ps2kparams) |
954c0172 | 1737 | { |
40b65c84 SM |
1738 | krb5_data *s2kparams; |
1739 | krb5_error_code ret; | |
1740 | ||
1741 | ALLOC(s2kparams); | |
1742 | if (s2kparams == NULL) | |
1743 | return ENOMEM; | |
1744 | ret = krb5_data_alloc(s2kparams, len); | |
1745 | if (ret) { | |
1746 | free(s2kparams); | |
1747 | return ret; | |
1748 | } | |
1749 | _krb5_put_int(s2kparams->data, value, len); | |
1750 | *ps2kparams = s2kparams; | |
1751 | return 0; | |
1752 | } | |
1753 | ||
1754 | static krb5_error_code | |
1755 | make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, | |
1756 | Key *key, | |
1757 | krb5_boolean include_salt) | |
1758 | { | |
1759 | krb5_error_code ret; | |
1760 | ||
954c0172 | 1761 | ent->etype = key->key.keytype; |
40b65c84 | 1762 | if (key->salt && include_salt) { |
954c0172 HIU |
1763 | ALLOC(ent->salt); |
1764 | if (ent->salt == NULL) | |
1765 | return ENOMEM; | |
1766 | *ent->salt = malloc(key->salt->salt.length + 1); | |
1767 | if (*ent->salt == NULL) { | |
1768 | free(ent->salt); | |
1769 | ent->salt = NULL; | |
1770 | return ENOMEM; | |
1771 | } | |
1772 | memcpy(*ent->salt, key->salt->salt.data, key->salt->salt.length); | |
1773 | (*ent->salt)[key->salt->salt.length] = '\0'; | |
1774 | } else | |
1775 | ent->salt = NULL; | |
1776 | ||
1777 | ent->s2kparams = NULL; | |
1778 | ||
1779 | switch (key->key.keytype) { | |
c44efdaa AB |
1780 | case ETYPE_AES128_CTS_HMAC_SHA1_96: |
1781 | case ETYPE_AES256_CTS_HMAC_SHA1_96: | |
40b65c84 SM |
1782 | ret = make_s2kparams(_krb5_AES_SHA1_string_to_default_iterator, |
1783 | 4, &ent->s2kparams); | |
1784 | break; | |
1785 | case KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128: | |
1786 | case KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192: | |
1787 | ret = make_s2kparams(_krb5_AES_SHA2_string_to_default_iterator, | |
1788 | 4, &ent->s2kparams); | |
954c0172 | 1789 | break; |
c44efdaa AB |
1790 | case ETYPE_DES_CBC_CRC: |
1791 | case ETYPE_DES_CBC_MD4: | |
1792 | case ETYPE_DES_CBC_MD5: | |
1793 | /* Check if this was a AFS3 salted key */ | |
40b65c84 SM |
1794 | if(key->salt && key->salt->type == hdb_afs3_salt) |
1795 | ret = make_s2kparams(1, 1, &ent->s2kparams); | |
1796 | else | |
1797 | ret = 0; | |
c44efdaa | 1798 | break; |
954c0172 | 1799 | default: |
40b65c84 | 1800 | ret = 0; |
954c0172 HIU |
1801 | break; |
1802 | } | |
40b65c84 | 1803 | return ret; |
954c0172 HIU |
1804 | } |
1805 | ||
1806 | /* | |
b39330c4 AB |
1807 | * Return an ETYPE-INFO2. Enctypes are storted the same way as in the |
1808 | * database (client supported enctypes first, then the unsupported | |
1809 | * enctypes). | |
954c0172 HIU |
1810 | */ |
1811 | ||
1812 | static krb5_error_code | |
2b29b718 | 1813 | get_pa_etype_info2(krb5_context context, |
954c0172 | 1814 | krb5_kdc_configuration *config, |
40b65c84 SM |
1815 | METHOD_DATA *md, Key *ckey, |
1816 | krb5_boolean include_salt) | |
954c0172 HIU |
1817 | { |
1818 | krb5_error_code ret = 0; | |
954c0172 HIU |
1819 | ETYPE_INFO2 pa; |
1820 | unsigned char *buf; | |
1821 | size_t len; | |
1822 | ||
9b261c00 AB |
1823 | pa.len = 1; |
1824 | pa.val = calloc(1, sizeof(pa.val[0])); | |
954c0172 HIU |
1825 | if(pa.val == NULL) |
1826 | return ENOMEM; | |
2b29b718 | 1827 | |
40b65c84 | 1828 | ret = make_etype_info2_entry(&pa.val[0], ckey, include_salt); |
9b261c00 AB |
1829 | if (ret) { |
1830 | free_ETYPE_INFO2(&pa); | |
1831 | return ret; | |
954c0172 HIU |
1832 | } |
1833 | ||
1834 | ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret); | |
1835 | free_ETYPE_INFO2(&pa); | |
1836 | if(ret) | |
1837 | return ret; | |
1838 | ret = realloc_method_data(md); | |
1839 | if(ret) { | |
1840 | free(buf); | |
1841 | return ret; | |
1842 | } | |
1843 | md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO2; | |
1844 | md->val[md->len - 1].padata_value.length = len; | |
1845 | md->val[md->len - 1].padata_value.data = buf; | |
1846 | return 0; | |
1847 | } | |
1848 | ||
40b65c84 | 1849 | /* |
b12a33e2 | 1850 | * Return 0 if the client has only older enctypes, this is for |
40b65c84 SM |
1851 | * determining if the server should send ETYPE_INFO2 or not. |
1852 | */ | |
1853 | ||
1854 | static int | |
1855 | newer_enctype_present(krb5_context context, | |
1856 | struct KDC_REQ_BODY_etype *etype_list) | |
1857 | { | |
1858 | size_t i; | |
1859 | ||
1860 | for (i = 0; i < etype_list->len; i++) { | |
1861 | if (!krb5_is_enctype_old(context, etype_list->val[i])) | |
1862 | return 1; | |
1863 | } | |
1864 | return 0; | |
1865 | } | |
1866 | ||
1867 | static krb5_error_code | |
1868 | get_pa_etype_info_both(krb5_context context, | |
1869 | krb5_kdc_configuration *config, | |
1870 | struct KDC_REQ_BODY_etype *etype_list, | |
1871 | METHOD_DATA *md, Key *ckey, | |
1872 | krb5_boolean include_salt) | |
1873 | { | |
1874 | krb5_error_code ret; | |
1875 | ||
1876 | /* | |
1877 | * Windows 2019 (and earlier versions) always sends the salt | |
1878 | * and Samba has testsuites that check this behaviour, so a | |
1879 | * Samba AD DC will set this flag to match the AS-REP packet | |
1880 | * more closely. | |
1881 | */ | |
1882 | if (config->force_include_pa_etype_salt) | |
1883 | include_salt = TRUE; | |
1884 | ||
1885 | /* | |
1886 | * RFC4120 requires: | |
1887 | * When the AS server is to include pre-authentication data in a | |
1888 | * KRB-ERROR or in an AS-REP, it MUST use PA-ETYPE-INFO2, not | |
1889 | * PA-ETYPE-INFO, if the etype field of the client's AS-REQ lists | |
1890 | * at least one "newer" encryption type. Otherwise (when the etype | |
1891 | * field of the client's AS-REQ does not list any "newer" encryption | |
1892 | * types), it MUST send both PA-ETYPE-INFO2 and PA-ETYPE-INFO (both | |
1893 | * with an entry for each enctype). A "newer" enctype is any enctype | |
1894 | * first officially specified concurrently with or subsequent to the | |
1895 | * issue of this RFC. The enctypes DES, 3DES, or RC4 and any defined | |
1896 | * in [RFC1510] are not "newer" enctypes. | |
1897 | * | |
1898 | * It goes on to state: | |
1899 | * The preferred ordering of the "hint" pre-authentication data that | |
1900 | * affect client key selection is: ETYPE-INFO2, followed by ETYPE-INFO, | |
1901 | * followed by PW-SALT. As noted in Section 3.1.3, a KDC MUST NOT send | |
1902 | * ETYPE-INFO or PW-SALT when the client's AS-REQ includes at least one | |
1903 | * "newer" etype. | |
1904 | */ | |
1905 | ||
1906 | ret = get_pa_etype_info2(context, config, md, ckey, include_salt); | |
1907 | if (ret) | |
1908 | return ret; | |
1909 | ||
1910 | if (!newer_enctype_present(context, etype_list)) | |
1911 | ret = get_pa_etype_info(context, config, md, ckey, include_salt); | |
1912 | ||
1913 | return ret; | |
1914 | } | |
1915 | ||
f7242f64 AB |
1916 | /* |
1917 | * | |
1918 | */ | |
1919 | ||
40b65c84 SM |
1920 | void |
1921 | _log_astgs_req(astgs_request_t r, krb5_enctype setype) | |
f7242f64 | 1922 | { |
40b65c84 SM |
1923 | const KDC_REQ_BODY *b = &r->req.req_body; |
1924 | krb5_enctype cetype = r->reply_key.keytype; | |
f7242f64 | 1925 | krb5_error_code ret; |
9b261c00 | 1926 | struct rk_strpool *p; |
40b65c84 | 1927 | struct rk_strpool *s = NULL; |
f7242f64 | 1928 | char *str; |
40b65c84 SM |
1929 | char *cet; |
1930 | char *set; | |
255e3e18 | 1931 | size_t i; |
2b29b718 | 1932 | |
40b65c84 SM |
1933 | /* |
1934 | * we are collecting ``p'' and ``s''. The former is a textual | |
1935 | * representation of the enctypes as strings which will be used | |
1936 | * for debugging. The latter is a terse comma separated list of | |
1937 | * the %d's of the enctypes to emit into our audit trail to | |
1938 | * conserve space in the logs. | |
1939 | */ | |
1940 | ||
9b261c00 AB |
1941 | p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: "); |
1942 | ||
f7242f64 | 1943 | for (i = 0; i < b->etype.len; i++) { |
40b65c84 | 1944 | ret = krb5_enctype_to_string(r->context, b->etype.val[i], &str); |
f7242f64 AB |
1945 | if (ret == 0) { |
1946 | p = rk_strpoolprintf(p, "%s", str); | |
1947 | free(str); | |
1948 | } else | |
1949 | p = rk_strpoolprintf(p, "%d", b->etype.val[i]); | |
f7242f64 | 1950 | if (p == NULL) { |
40b65c84 SM |
1951 | rk_strpoolfree(s); |
1952 | _kdc_r_log(r, 4, "out of memory"); | |
f7242f64 AB |
1953 | return; |
1954 | } | |
40b65c84 SM |
1955 | s = rk_strpoolprintf(s, "%d", b->etype.val[i]); |
1956 | if (i + 1 < b->etype.len) { | |
1957 | p = rk_strpoolprintf(p, ", "); | |
1958 | s = rk_strpoolprintf(s, ","); | |
1959 | } | |
f7242f64 AB |
1960 | } |
1961 | if (p == NULL) | |
1962 | p = rk_strpoolprintf(p, "no encryption types"); | |
2b29b718 | 1963 | |
40b65c84 SM |
1964 | str = rk_strpoolcollect(s); |
1965 | if (str) | |
51569b31 JS |
1966 | kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, "etypes", "%s", |
1967 | str); | |
40b65c84 | 1968 | free(str); |
f7242f64 | 1969 | |
40b65c84 SM |
1970 | ret = krb5_enctype_to_string(r->context, cetype, &cet); |
1971 | if(ret == 0) { | |
1972 | ret = krb5_enctype_to_string(r->context, setype, &set); | |
1973 | if (ret == 0) { | |
1974 | p = rk_strpoolprintf(p, ", using %s/%s", cet, set); | |
1975 | free(set); | |
f7242f64 | 1976 | } |
40b65c84 | 1977 | free(cet); |
f7242f64 | 1978 | } |
40b65c84 SM |
1979 | if (ret != 0) |
1980 | p = rk_strpoolprintf(p, ", using enctypes %d/%d", | |
1981 | cetype, setype); | |
2b29b718 | 1982 | |
9b261c00 | 1983 | str = rk_strpoolcollect(p); |
40b65c84 SM |
1984 | if (str) |
1985 | _kdc_r_log(r, 4, "%s", str); | |
9b261c00 AB |
1986 | free(str); |
1987 | ||
51569b31 | 1988 | kdc_audit_addkv((kdc_request_t)r, 0, "etype", "%d/%d", cetype, setype); |
40b65c84 | 1989 | |
f7242f64 | 1990 | { |
91adebe7 | 1991 | char fixedstr[128]; |
40b65c84 SM |
1992 | int result; |
1993 | ||
1994 | result = unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), | |
1995 | fixedstr, sizeof(fixedstr)); | |
1996 | if (result > 0) { | |
1997 | _kdc_r_log(r, 4, "Requested flags: %s", fixedstr); | |
51569b31 JS |
1998 | kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, |
1999 | "flags", "%s", fixedstr); | |
40b65c84 | 2000 | } |
f7242f64 AB |
2001 | } |
2002 | } | |
2003 | ||
954c0172 HIU |
2004 | /* |
2005 | * verify the flags on `client' and `server', returning 0 | |
2006 | * if they are OK and generating an error messages and returning | |
2007 | * and error code otherwise. | |
2008 | */ | |
2009 | ||
51569b31 | 2010 | KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL |
40b65c84 SM |
2011 | kdc_check_flags(astgs_request_t r, |
2012 | krb5_boolean is_as_req, | |
51569b31 JS |
2013 | hdb_entry *client, |
2014 | hdb_entry *server) | |
954c0172 | 2015 | { |
51569b31 | 2016 | if (client != NULL) { |
954c0172 | 2017 | /* check client */ |
e2532553 | 2018 | if (client->flags.locked_out) { |
51569b31 | 2019 | kdc_audit_addreason((kdc_request_t)r, "Client is locked out"); |
580a705b | 2020 | return KRB5KDC_ERR_CLIENT_REVOKED; |
e2532553 AB |
2021 | } |
2022 | ||
954c0172 | 2023 | if (client->flags.invalid) { |
51569b31 JS |
2024 | kdc_audit_addreason((kdc_request_t)r, |
2025 | "Client has invalid bit set"); | |
954c0172 HIU |
2026 | return KRB5KDC_ERR_POLICY; |
2027 | } | |
255e3e18 | 2028 | |
40b65c84 | 2029 | if (!client->flags.client) { |
51569b31 JS |
2030 | kdc_audit_addreason((kdc_request_t)r, |
2031 | "Principal may not act as client"); | |
954c0172 HIU |
2032 | return KRB5KDC_ERR_POLICY; |
2033 | } | |
255e3e18 | 2034 | |
954c0172 | 2035 | if (client->valid_start && *client->valid_start > kdc_time) { |
30d164d9 | 2036 | char starttime_str[100]; |
40b65c84 | 2037 | krb5_format_time(r->context, *client->valid_start, |
2b29b718 | 2038 | starttime_str, sizeof(starttime_str), TRUE); |
51569b31 JS |
2039 | kdc_audit_addreason((kdc_request_t)r, "Client not yet valid " |
2040 | "until %s", starttime_str); | |
954c0172 HIU |
2041 | return KRB5KDC_ERR_CLIENT_NOTYET; |
2042 | } | |
255e3e18 | 2043 | |
954c0172 | 2044 | if (client->valid_end && *client->valid_end < kdc_time) { |
30d164d9 | 2045 | char endtime_str[100]; |
40b65c84 | 2046 | krb5_format_time(r->context, *client->valid_end, |
2b29b718 | 2047 | endtime_str, sizeof(endtime_str), TRUE); |
51569b31 JS |
2048 | kdc_audit_addreason((kdc_request_t)r, "Client expired at %s", |
2049 | endtime_str); | |
40b65c84 | 2050 | return KRB5KDC_ERR_NAME_EXP; |
954c0172 | 2051 | } |
255e3e18 | 2052 | |
40b65c84 | 2053 | if (client->flags.require_pwchange && |
51569b31 | 2054 | (server == NULL || !server->flags.change_pw)) |
40b65c84 SM |
2055 | return KRB5KDC_ERR_KEY_EXPIRED; |
2056 | ||
2b29b718 | 2057 | if (client->pw_end && *client->pw_end < kdc_time |
51569b31 | 2058 | && (server == NULL || !server->flags.change_pw)) { |
30d164d9 | 2059 | char pwend_str[100]; |
40b65c84 | 2060 | krb5_format_time(r->context, *client->pw_end, |
2b29b718 | 2061 | pwend_str, sizeof(pwend_str), TRUE); |
51569b31 JS |
2062 | kdc_audit_addreason((kdc_request_t)r, "Client's key has expired " |
2063 | "at %s", pwend_str); | |
954c0172 HIU |
2064 | return KRB5KDC_ERR_KEY_EXPIRED; |
2065 | } | |
2066 | } | |
2067 | ||
2068 | /* check server */ | |
2b29b718 | 2069 | |
51569b31 | 2070 | if (server != NULL) { |
e2532553 | 2071 | if (server->flags.locked_out) { |
51569b31 | 2072 | kdc_audit_addreason((kdc_request_t)r, "Server locked out"); |
40b65c84 | 2073 | return KRB5KDC_ERR_SERVICE_REVOKED; |
e2532553 | 2074 | } |
954c0172 | 2075 | if (server->flags.invalid) { |
51569b31 JS |
2076 | kdc_audit_addreason((kdc_request_t)r, |
2077 | "Server has invalid flag set"); | |
954c0172 HIU |
2078 | return KRB5KDC_ERR_POLICY; |
2079 | } | |
40b65c84 | 2080 | if (!server->flags.server) { |
51569b31 JS |
2081 | kdc_audit_addreason((kdc_request_t)r, |
2082 | "Principal may not act as server"); | |
954c0172 HIU |
2083 | return KRB5KDC_ERR_POLICY; |
2084 | } | |
2085 | ||
40b65c84 | 2086 | if (!is_as_req && server->flags.initial) { |
51569b31 JS |
2087 | kdc_audit_addreason((kdc_request_t)r, |
2088 | "AS-REQ is required for server"); | |
954c0172 HIU |
2089 | return KRB5KDC_ERR_POLICY; |
2090 | } | |
2091 | ||
2092 | if (server->valid_start && *server->valid_start > kdc_time) { | |
30d164d9 | 2093 | char starttime_str[100]; |
40b65c84 | 2094 | krb5_format_time(r->context, *server->valid_start, |
2b29b718 | 2095 | starttime_str, sizeof(starttime_str), TRUE); |
51569b31 JS |
2096 | kdc_audit_addreason((kdc_request_t)r, "Server not yet valid " |
2097 | "until %s", starttime_str); | |
954c0172 HIU |
2098 | return KRB5KDC_ERR_SERVICE_NOTYET; |
2099 | } | |
2100 | ||
2101 | if (server->valid_end && *server->valid_end < kdc_time) { | |
30d164d9 | 2102 | char endtime_str[100]; |
40b65c84 | 2103 | krb5_format_time(r->context, *server->valid_end, |
2b29b718 | 2104 | endtime_str, sizeof(endtime_str), TRUE); |
51569b31 JS |
2105 | kdc_audit_addreason((kdc_request_t)r, "Server expired at %s", |
2106 | endtime_str); | |
954c0172 HIU |
2107 | return KRB5KDC_ERR_SERVICE_EXP; |
2108 | } | |
2109 | ||
2110 | if (server->pw_end && *server->pw_end < kdc_time) { | |
30d164d9 | 2111 | char pwend_str[100]; |
40b65c84 | 2112 | krb5_format_time(r->context, *server->pw_end, |
2b29b718 | 2113 | pwend_str, sizeof(pwend_str), TRUE); |
51569b31 JS |
2114 | kdc_audit_addreason((kdc_request_t)r, "Server's key has expired " |
2115 | "at %s", pwend_str); | |
954c0172 HIU |
2116 | return KRB5KDC_ERR_KEY_EXPIRED; |
2117 | } | |
2118 | } | |
2119 | return 0; | |
2120 | } | |
2121 | ||
2122 | /* | |
2123 | * Return TRUE if `from' is part of `addresses' taking into consideration | |
2124 | * the configuration variables that tells us how strict we should be about | |
2125 | * these checks | |
2126 | */ | |
2127 | ||
3c1e780e | 2128 | krb5_boolean |
40b65c84 SM |
2129 | _kdc_check_addresses(astgs_request_t r, HostAddresses *addresses, |
2130 | const struct sockaddr *from) | |
954c0172 | 2131 | { |
40b65c84 | 2132 | krb5_kdc_configuration *config = r->config; |
954c0172 HIU |
2133 | krb5_error_code ret; |
2134 | krb5_address addr; | |
2135 | krb5_boolean result; | |
ef9ec958 | 2136 | krb5_boolean only_netbios = TRUE; |
255e3e18 | 2137 | size_t i; |
2b29b718 | 2138 | |
40b65c84 | 2139 | if (!config->check_ticket_addresses && !config->warn_ticket_addresses) |
954c0172 HIU |
2140 | return TRUE; |
2141 | ||
40b65c84 SM |
2142 | /* |
2143 | * Fields of HostAddresses type are always OPTIONAL and should be non- | |
2144 | * empty, but we check for empty just in case as our compiler doesn't | |
2145 | * support size constraints on SEQUENCE OF. | |
2146 | */ | |
2147 | if (addresses == NULL || addresses->len == 0) | |
ef9ec958 | 2148 | return config->allow_null_ticket_addresses; |
2b29b718 | 2149 | |
ef9ec958 | 2150 | for (i = 0; i < addresses->len; ++i) { |
c33f6b2c AB |
2151 | if (addresses->val[i].addr_type != KRB5_ADDRESS_NETBIOS) { |
2152 | only_netbios = FALSE; | |
2153 | } | |
ef9ec958 AB |
2154 | } |
2155 | ||
2156 | /* Windows sends it's netbios name, which I can only assume is | |
c33f6b2c AB |
2157 | * used for the 'allowed workstations' check. This is painful, |
2158 | * but we still want to check IP addresses if they happen to be | |
2159 | * present. | |
2160 | */ | |
ef9ec958 AB |
2161 | |
2162 | if(only_netbios) | |
954c0172 | 2163 | return config->allow_null_ticket_addresses; |
c33f6b2c | 2164 | |
40b65c84 | 2165 | ret = krb5_sockaddr2address (r->context, from, &addr); |
954c0172 HIU |
2166 | if(ret) |
2167 | return FALSE; | |
2168 | ||
40b65c84 SM |
2169 | result = krb5_address_search(r->context, &addr, addresses); |
2170 | krb5_free_address (r->context, &addr); | |
954c0172 HIU |
2171 | return result; |
2172 | } | |
2173 | ||
f7242f64 AB |
2174 | /* |
2175 | * | |
2176 | */ | |
40b65c84 SM |
2177 | krb5_error_code |
2178 | _kdc_check_anon_policy(astgs_request_t r) | |
2179 | { | |
2180 | if (!r->config->allow_anonymous) { | |
51569b31 JS |
2181 | kdc_audit_addreason((kdc_request_t)r, |
2182 | "Anonymous tickets denied by local policy"); | |
40b65c84 SM |
2183 | return KRB5KDC_ERR_POLICY; |
2184 | } | |
2185 | ||
2186 | return 0; | |
2187 | } | |
2188 | ||
2189 | /* | |
2190 | * Determine whether the client requested a PAC be included | |
2191 | * or excluded explictly, or whether it doesn't care. | |
2192 | */ | |
f7242f64 | 2193 | |
40b65c84 SM |
2194 | static uint64_t |
2195 | get_pac_attributes(krb5_context context, KDC_REQ *req) | |
f7242f64 AB |
2196 | { |
2197 | krb5_error_code ret; | |
2198 | PA_PAC_REQUEST pacreq; | |
91adebe7 | 2199 | const PA_DATA *pa; |
f7242f64 | 2200 | int i = 0; |
40b65c84 | 2201 | uint32_t pac_attributes; |
2f9245f2 | 2202 | |
f7242f64 AB |
2203 | pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST); |
2204 | if (pa == NULL) | |
40b65c84 | 2205 | return KRB5_PAC_WAS_GIVEN_IMPLICITLY; |
f7242f64 AB |
2206 | |
2207 | ret = decode_PA_PAC_REQUEST(pa->padata_value.data, | |
2208 | pa->padata_value.length, | |
2209 | &pacreq, | |
2210 | NULL); | |
2211 | if (ret) | |
40b65c84 SM |
2212 | return KRB5_PAC_WAS_GIVEN_IMPLICITLY; |
2213 | ||
2214 | pac_attributes = pacreq.include_pac ? KRB5_PAC_WAS_REQUESTED : 0; | |
2215 | free_PA_PAC_REQUEST(&pacreq); | |
2216 | return pac_attributes; | |
2217 | } | |
2218 | ||
2219 | /* | |
2220 | * | |
2221 | */ | |
2222 | ||
2223 | static krb5_error_code | |
2224 | generate_pac(astgs_request_t r, const Key *skey, const Key *tkey, | |
2225 | krb5_boolean is_tgs) | |
2226 | { | |
2227 | krb5_error_code ret; | |
40b65c84 SM |
2228 | uint16_t rodc_id; |
2229 | krb5_principal client; | |
2230 | krb5_const_principal canon_princ = NULL; | |
2231 | ||
2232 | r->pac_attributes = get_pac_attributes(r->context, &r->req); | |
51569b31 JS |
2233 | kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes", |
2234 | r->pac_attributes); | |
40b65c84 SM |
2235 | |
2236 | if (!is_tgs && !(r->pac_attributes & (KRB5_PAC_WAS_REQUESTED | KRB5_PAC_WAS_GIVEN_IMPLICITLY))) | |
2237 | return 0; | |
2238 | ||
2239 | /* | |
2240 | * When a PA mech does not use the client's long-term key, the PAC | |
2241 | * may include the client's long-term key (encrypted in the reply key) | |
2242 | * for use by other shared secret authentication protocols, e.g. NTLM. | |
2243 | * Validate a PA mech was actually used before doing this. | |
2244 | */ | |
2245 | ||
f33f73f8 | 2246 | ret = _kdc_pac_generate(r, |
40b65c84 SM |
2247 | r->client, |
2248 | r->server, | |
2249 | r->pa_used && !pa_used_flag_isset(r, PA_USES_LONG_TERM_KEY) | |
2250 | ? &r->reply_key : NULL, | |
2251 | r->pac_attributes, | |
2252 | &r->pac); | |
2253 | if (ret) { | |
2254 | _kdc_r_log(r, 4, "PAC generation failed for -- %s", | |
2255 | r->cname); | |
2256 | return ret; | |
2257 | } | |
2258 | if (r->pac == NULL) | |
2259 | return 0; | |
2260 | ||
51569b31 | 2261 | rodc_id = r->server->kvno >> 16; |
40b65c84 SM |
2262 | |
2263 | /* libkrb5 expects ticket and PAC client names to match */ | |
2264 | ret = _krb5_principalname2krb5_principal(r->context, &client, | |
2265 | r->et.cname, r->et.crealm); | |
2266 | if (ret) | |
2267 | return ret; | |
2268 | ||
2269 | /* | |
2270 | * Include the canonical name of the principal in the authorization | |
2271 | * data, if the realms match (if they don't, then the KDC could | |
2272 | * impersonate any realm. Windows always canonicalizes the realm, | |
2273 | * but Heimdal permits aliases between realms.) | |
2274 | */ | |
51569b31 | 2275 | if (krb5_realm_compare(r->context, client, r->canon_client_princ)) { |
40b65c84 SM |
2276 | char *cpn = NULL; |
2277 | ||
51569b31 | 2278 | canon_princ = r->canon_client_princ; |
40b65c84 | 2279 | |
51569b31 JS |
2280 | (void) krb5_unparse_name(r->context, canon_princ, &cpn); |
2281 | kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s", | |
2282 | cpn ? cpn : "<unknown>"); | |
40b65c84 SM |
2283 | krb5_xfree(cpn); |
2284 | } | |
2285 | ||
2286 | if (r->pa_used && r->pa_used->finalize_pac) { | |
2287 | ret = r->pa_used->finalize_pac(r); | |
2288 | if (ret) | |
2289 | return ret; | |
2290 | } | |
2291 | ||
09bcd48f JS |
2292 | ret = _krb5_kdc_pac_sign_ticket(r->context, |
2293 | r->pac, | |
2294 | client, | |
2295 | &skey->key, /* Server key */ | |
2296 | &tkey->key, /* TGS key */ | |
2297 | rodc_id, | |
2298 | NULL, /* UPN */ | |
2299 | canon_princ, | |
2300 | !is_tgs, /* add_ticket_sig */ | |
2301 | !is_tgs, /* add_full_sig */ | |
2302 | &r->et, | |
2303 | is_tgs ? &r->pac_attributes : NULL); | |
40b65c84 SM |
2304 | krb5_free_principal(r->context, client); |
2305 | krb5_pac_free(r->context, r->pac); | |
2306 | r->pac = NULL; | |
2307 | if (ret) { | |
2308 | _kdc_r_log(r, 4, "PAC signing failed for -- %s", | |
2309 | r->cname); | |
2310 | return ret; | |
2311 | } | |
40b65c84 SM |
2312 | |
2313 | return ret; | |
2314 | } | |
2315 | ||
2316 | /* | |
2317 | * | |
2318 | */ | |
2319 | ||
2320 | krb5_boolean | |
2321 | _kdc_is_anonymous(krb5_context context, krb5_const_principal principal) | |
2322 | { | |
2323 | return krb5_principal_is_anonymous(context, principal, KRB5_ANON_MATCH_ANY); | |
2324 | } | |
2325 | ||
2326 | /* | |
2327 | * Returns TRUE if principal is the unauthenticated anonymous identity, | |
2328 | * i.e. WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS. Unfortunately due to | |
2329 | * backwards compatibility logic in krb5_principal_is_anonymous() we | |
2330 | * have to use our own implementation. | |
2331 | */ | |
2332 | ||
2333 | krb5_boolean | |
2334 | _kdc_is_anonymous_pkinit(krb5_context context, krb5_const_principal principal) | |
2335 | { | |
2336 | return _kdc_is_anonymous(context, principal) && | |
2337 | strcmp(principal->realm, KRB5_ANON_REALM) == 0; | |
2338 | } | |
2339 | ||
2340 | static int | |
2341 | require_preauth_p(astgs_request_t r) | |
2342 | { | |
2343 | return r->config->require_preauth | |
51569b31 JS |
2344 | || r->client->flags.require_preauth |
2345 | || r->server->flags.require_preauth; | |
40b65c84 SM |
2346 | } |
2347 | ||
2348 | ||
2349 | /* | |
2350 | * | |
2351 | */ | |
2352 | ||
2353 | static krb5_error_code | |
2354 | add_enc_pa_rep(astgs_request_t r) | |
2355 | { | |
2356 | krb5_error_code ret; | |
2357 | krb5_crypto crypto; | |
2358 | Checksum checksum; | |
2359 | krb5_data cdata; | |
2360 | size_t len; | |
2361 | ||
2362 | ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto); | |
2363 | if (ret) | |
2364 | return ret; | |
2365 | ||
2366 | ret = krb5_create_checksum(r->context, crypto, | |
2367 | KRB5_KU_AS_REQ, 0, | |
2368 | r->request.data, r->request.length, | |
2369 | &checksum); | |
2370 | krb5_crypto_destroy(r->context, crypto); | |
2371 | if (ret) | |
2372 | return ret; | |
2373 | ||
2374 | ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, | |
2375 | &checksum, &len, ret); | |
2376 | free_Checksum(&checksum); | |
2377 | if (ret) | |
2378 | return ret; | |
2379 | heim_assert(cdata.length == len, "ASN.1 internal error"); | |
2380 | ||
2381 | if (r->ek.encrypted_pa_data == NULL) { | |
2382 | ALLOC(r->ek.encrypted_pa_data); | |
2383 | if (r->ek.encrypted_pa_data == NULL) | |
2384 | return ENOMEM; | |
2f9245f2 | 2385 | } |
40b65c84 SM |
2386 | ret = krb5_padata_add(r->context, r->ek.encrypted_pa_data, |
2387 | KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); | |
2388 | if (ret) | |
2389 | return ret; | |
75ec66c7 SM |
2390 | |
2391 | if (!r->config->enable_fast) | |
2392 | return 0; | |
2393 | ||
40b65c84 SM |
2394 | return krb5_padata_add(r->context, r->ek.encrypted_pa_data, |
2395 | KRB5_PADATA_FX_FAST, NULL, 0); | |
f7242f64 AB |
2396 | } |
2397 | ||
40b65c84 SM |
2398 | /* |
2399 | * Add an authorization data element indicating that a synthetic | |
2400 | * principal was used, so that the TGS does not accidentally | |
2401 | * synthesize a non-synthetic principal that has since been deleted. | |
2402 | */ | |
2403 | static krb5_error_code | |
2404 | add_synthetic_princ_ad(astgs_request_t r) | |
9b261c00 | 2405 | { |
40b65c84 SM |
2406 | krb5_data data; |
2407 | ||
2408 | krb5_data_zero(&data); | |
2409 | ||
2410 | return _kdc_tkt_add_if_relevant_ad(r->context, &r->et, | |
2411 | KRB5_AUTHDATA_SYNTHETIC_PRINC_USED, | |
2412 | &data); | |
9b261c00 AB |
2413 | } |
2414 | ||
91e684f5 LH |
2415 | static krb5_error_code |
2416 | get_local_tgs(krb5_context context, | |
2417 | krb5_kdc_configuration *config, | |
2418 | krb5_const_realm realm, | |
51569b31 JS |
2419 | HDB **krbtgtdb, |
2420 | hdb_entry **krbtgt) | |
91e684f5 LH |
2421 | { |
2422 | krb5_error_code ret; | |
2423 | krb5_principal tgs_name; | |
2424 | ||
51569b31 | 2425 | *krbtgtdb = NULL; |
91e684f5 LH |
2426 | *krbtgt = NULL; |
2427 | ||
2428 | ret = krb5_make_principal(context, | |
2429 | &tgs_name, | |
2430 | realm, | |
2431 | KRB5_TGS_NAME, | |
2432 | realm, | |
2433 | NULL); | |
a87aae52 JS |
2434 | if (ret == 0) |
2435 | ret = _kdc_db_fetch(context, config, tgs_name, | |
2436 | HDB_F_GET_KRBTGT, NULL, krbtgtdb, krbtgt); | |
91e684f5 | 2437 | |
91e684f5 | 2438 | krb5_free_principal(context, tgs_name); |
91e684f5 LH |
2439 | return ret; |
2440 | } | |
2441 | ||
f7242f64 AB |
2442 | /* |
2443 | * | |
2444 | */ | |
2445 | ||
954c0172 | 2446 | krb5_error_code |
40b65c84 | 2447 | _kdc_as_rep(astgs_request_t r) |
954c0172 | 2448 | { |
40b65c84 SM |
2449 | krb5_kdc_configuration *config = r->config; |
2450 | KDC_REQ *req = &r->req; | |
2451 | const char *from = r->from; | |
2452 | KDC_REQ_BODY *b = NULL; | |
2453 | KDC_REP *rep = &r->rep; | |
2454 | KDCOptions f; | |
2455 | krb5_enctype setype; | |
954c0172 | 2456 | krb5_error_code ret = 0; |
40b65c84 SM |
2457 | Key *skey; |
2458 | int found_pa = 0; | |
2459 | int i, flags = HDB_F_FOR_AS_REQ; | |
2460 | const PA_DATA *pa; | |
db30b71f | 2461 | krb5_boolean is_tgs; |
40b65c84 | 2462 | const char *msg; |
40b65c84 | 2463 | Key *krbtgt_key; |
a25f549e | 2464 | unsigned krbtgt_kvno; |
40b65c84 SM |
2465 | |
2466 | memset(rep, 0, sizeof(*rep)); | |
954c0172 | 2467 | |
40b65c84 SM |
2468 | ALLOC(rep->padata); |
2469 | if (rep->padata == NULL) { | |
2470 | ret = ENOMEM; | |
2471 | krb5_set_error_message(r->context, ret, N_("malloc: out of memory", "")); | |
2472 | goto out; | |
2473 | } | |
2474 | ||
2475 | /* | |
2476 | * Look for FAST armor and unwrap | |
2477 | */ | |
2478 | ret = _kdc_fast_unwrap_request(r, NULL, NULL); | |
2479 | if (ret) { | |
2480 | _kdc_r_log(r, 1, "FAST unwrap request from %s failed: %d", from, ret); | |
2481 | goto out; | |
2482 | } | |
91adebe7 | 2483 | |
95c02a97 JS |
2484 | /* Validate armor TGT, and initialize the armor client and PAC */ |
2485 | if (r->armor_ticket) { | |
2486 | ret = _kdc_fast_check_armor_pac(r, HDB_F_FOR_AS_REQ); | |
2487 | if (ret) | |
2488 | goto out; | |
2489 | } | |
2490 | ||
40b65c84 SM |
2491 | b = &req->req_body; |
2492 | f = b->kdc_options; | |
89eaef02 | 2493 | |
91adebe7 AB |
2494 | if (f.canonicalize) |
2495 | flags |= HDB_F_CANON; | |
954c0172 | 2496 | |
40b65c84 | 2497 | if (b->sname == NULL) { |
b0f4455e | 2498 | ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; |
40b65c84 SM |
2499 | _kdc_set_e_text(r, "No server in request"); |
2500 | goto out; | |
954c0172 | 2501 | } |
40b65c84 SM |
2502 | |
2503 | ret = _krb5_principalname2krb5_principal(r->context, &r->server_princ, | |
2504 | *(b->sname), b->realm); | |
2505 | if (!ret) | |
2506 | ret = krb5_unparse_name(r->context, r->server_princ, &r->sname); | |
954c0172 | 2507 | if (ret) { |
40b65c84 SM |
2508 | kdc_log(r->context, config, 2, |
2509 | "AS_REQ malformed server name from %s", from); | |
954c0172 HIU |
2510 | goto out; |
2511 | } | |
9b261c00 | 2512 | |
40b65c84 SM |
2513 | if (b->cname == NULL) { |
2514 | ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; | |
2515 | _kdc_set_e_text(r, "No client in request"); | |
2516 | goto out; | |
954c0172 | 2517 | } |
40b65c84 SM |
2518 | |
2519 | ret = _krb5_principalname2krb5_principal(r->context, &r->client_princ, | |
2520 | *(b->cname), b->realm); | |
2521 | if (!ret) | |
2522 | ret = krb5_unparse_name(r->context, r->client_princ, &r->cname); | |
954c0172 | 2523 | if (ret) { |
40b65c84 | 2524 | kdc_log(r->context, config, 2, |
3c1e780e | 2525 | "AS-REQ malformed client name from %s", from); |
954c0172 HIU |
2526 | goto out; |
2527 | } | |
2528 | ||
40b65c84 SM |
2529 | kdc_log(r->context, config, 4, "AS-REQ %s from %s for %s", |
2530 | r->cname, r->from, r->sname); | |
954c0172 | 2531 | |
40b65c84 | 2532 | is_tgs = krb5_principal_is_krbtgt(r->context, r->server_princ); |
9b261c00 | 2533 | |
40b65c84 SM |
2534 | if (_kdc_is_anonymous(r->context, r->client_princ) && |
2535 | !_kdc_is_anon_request(req)) { | |
2536 | kdc_log(r->context, config, 2, "Anonymous client w/o anonymous flag"); | |
2537 | ret = KRB5KDC_ERR_BADOPTION; | |
9b261c00 AB |
2538 | goto out; |
2539 | } | |
2540 | ||
40b65c84 SM |
2541 | ret = _kdc_db_fetch(r->context, config, r->client_princ, |
2542 | HDB_F_GET_CLIENT | HDB_F_SYNTHETIC_OK | flags, NULL, | |
2543 | &r->clientdb, &r->client); | |
2544 | switch (ret) { | |
2545 | case 0: /* Success */ | |
2546 | break; | |
2547 | case HDB_ERR_NOT_FOUND_HERE: | |
2548 | kdc_log(r->context, config, 5, "client %s does not have secrets at this KDC, need to proxy", | |
2549 | r->cname); | |
aa1c32cc | 2550 | goto out; |
40b65c84 | 2551 | case HDB_ERR_WRONG_REALM: { |
2d988002 SM |
2552 | char *fixed_client_name = NULL; |
2553 | ||
51569b31 | 2554 | ret = krb5_unparse_name(r->context, r->client->principal, |
2d988002 SM |
2555 | &fixed_client_name); |
2556 | if (ret) { | |
2557 | goto out; | |
2558 | } | |
2559 | ||
40b65c84 SM |
2560 | kdc_log(r->context, config, 4, "WRONG_REALM - %s -> %s", |
2561 | r->cname, fixed_client_name); | |
2d988002 SM |
2562 | free(fixed_client_name); |
2563 | ||
40b65c84 SM |
2564 | r->e_text = NULL; |
2565 | ret = _kdc_fast_mk_error(r, r->rep.padata, r->armor_crypto, | |
2566 | &req->req_body, | |
51569b31 JS |
2567 | r->error_code = KRB5_KDC_ERR_WRONG_REALM, |
2568 | r->client->principal, r->server_princ, | |
40b65c84 | 2569 | NULL, NULL, r->reply); |
2d988002 | 2570 | goto out; |
40b65c84 SM |
2571 | } |
2572 | default: | |
2573 | { | |
40b65c84 SM |
2574 | msg = krb5_get_error_message(r->context, ret); |
2575 | kdc_log(r->context, config, 4, "UNKNOWN -- %s: %s", r->cname, msg); | |
2576 | krb5_free_error_message(r->context, msg); | |
954c0172 | 2577 | ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; |
51569b31 JS |
2578 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
2579 | KDC_AUTH_EVENT_CLIENT_UNKNOWN); | |
954c0172 HIU |
2580 | goto out; |
2581 | } | |
40b65c84 | 2582 | } |
95c02a97 JS |
2583 | |
2584 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
2585 | KDC_AUTH_EVENT_CLIENT_FOUND); | |
2586 | ||
40b65c84 SM |
2587 | ret = _kdc_db_fetch(r->context, config, r->server_princ, |
2588 | HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | | |
2589 | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0), | |
51569b31 | 2590 | NULL, &r->serverdb, &r->server); |
40b65c84 SM |
2591 | switch (ret) { |
2592 | case 0: /* Success */ | |
2593 | break; | |
2594 | case HDB_ERR_NOT_FOUND_HERE: | |
2595 | kdc_log(r->context, config, 5, "target %s does not have secrets at this KDC, need to proxy", | |
2596 | r->sname); | |
aa1c32cc | 2597 | goto out; |
40b65c84 SM |
2598 | default: |
2599 | msg = krb5_get_error_message(r->context, ret); | |
2600 | kdc_log(r->context, config, 4, "UNKNOWN -- %s: %s", r->sname, msg); | |
2601 | krb5_free_error_message(r->context, msg); | |
954c0172 HIU |
2602 | ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; |
2603 | goto out; | |
2604 | } | |
2605 | ||
95c02a97 JS |
2606 | ret = _kdc_check_access(r); |
2607 | if(ret) | |
2608 | goto out; | |
2609 | ||
975e43fc AB |
2610 | /* |
2611 | * This has to be here (not later), because we need to have r->sessionetype | |
2612 | * set prior to calling pa_pkinit_validate(), which in turn calls | |
2613 | * _kdc_pk_mk_pa_reply(), during padata validation. | |
2614 | */ | |
2615 | ||
9b261c00 | 2616 | /* |
40b65c84 SM |
2617 | * Select an enctype for the to-be-issued ticket's session key using the |
2618 | * intersection of the client's requested enctypes and the server's (like a | |
2619 | * root krbtgt, but not necessarily) etypes from its HDB entry. | |
255e3e18 | 2620 | */ |
975e43fc AB |
2621 | ret = _kdc_find_session_etype(r, b->etype.val, b->etype.len, |
2622 | r->server, &r->sessionetype); | |
255e3e18 | 2623 | if (ret) { |
40b65c84 | 2624 | kdc_log(r->context, config, 4, |
255e3e18 SM |
2625 | "Client (%s) from %s has no common enctypes with KDC " |
2626 | "to use for the session key", | |
40b65c84 | 2627 | r->cname, from); |
255e3e18 SM |
2628 | goto out; |
2629 | } | |
954c0172 | 2630 | |
a25f549e JS |
2631 | /* |
2632 | * Select the best encryption type for the KDC without regard to | |
2633 | * the client since the client never needs to read that data. | |
2634 | */ | |
2635 | ||
2636 | ret = _kdc_get_preferred_key(r->context, config, | |
2637 | r->server, r->sname, | |
2638 | &setype, &skey); | |
2639 | if(ret) | |
2640 | goto out; | |
2641 | ||
2642 | /* If server is not krbtgt, fetch local krbtgt key for signing authdata */ | |
2643 | if (is_tgs) { | |
2644 | krbtgt_key = skey; | |
2645 | krbtgt_kvno = r->server->kvno; | |
2646 | } else { | |
2647 | ret = get_local_tgs(r->context, config, r->server_princ->realm, | |
2648 | &r->krbtgtdb, &r->krbtgt); | |
2649 | if (ret) | |
2650 | goto out; | |
2651 | ||
2652 | ret = _kdc_get_preferred_key(r->context, config, r->krbtgt, | |
2653 | r->server_princ->realm, | |
2654 | NULL, &krbtgt_key); | |
2655 | if (ret) | |
2656 | goto out; | |
2657 | ||
2658 | krbtgt_kvno = r->server->kvno; | |
2659 | } | |
2660 | ||
9b261c00 AB |
2661 | /* |
2662 | * Pre-auth processing | |
2663 | */ | |
954c0172 HIU |
2664 | |
2665 | if(req->padata){ | |
40b65c84 | 2666 | unsigned int n; |
954c0172 | 2667 | |
40b65c84 | 2668 | log_patypes(r, req->padata); |
c33f6b2c | 2669 | |
40b65c84 | 2670 | /* Check if preauth matching */ |
954c0172 | 2671 | |
40b65c84 SM |
2672 | for (n = 0; !found_pa && n < sizeof(pat) / sizeof(pat[0]); n++) { |
2673 | if (pat[n].validate == NULL) | |
2674 | continue; | |
2675 | if (r->armor_crypto == NULL && (pat[n].flags & PA_REQ_FAST)) | |
2676 | continue; | |
fc474042 JS |
2677 | if (!r->config->enable_fast_cookie && (pat[n].flags & PA_USES_FAST_COOKIE)) |
2678 | continue; | |
954c0172 | 2679 | |
40b65c84 SM |
2680 | kdc_log(r->context, config, 5, |
2681 | "Looking for %s pa-data -- %s", pat[n].name, r->cname); | |
954c0172 | 2682 | i = 0; |
40b65c84 SM |
2683 | pa = _kdc_find_padata(req, &i, pat[n].type); |
2684 | if (pa) { | |
51569b31 | 2685 | if (r->client->flags.synthetic && |
40b65c84 SM |
2686 | !(pat[n].flags & PA_SYNTHETIC_OK)) { |
2687 | kdc_log(r->context, config, 4, "UNKNOWN -- %s", r->cname); | |
51569b31 | 2688 | ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; |
40b65c84 SM |
2689 | goto out; |
2690 | } | |
09bcd48f JS |
2691 | if (!(pat[n].flags & PA_HARDWARE_AUTH)) { |
2692 | ret = _kdc_hwauth_policy(r); | |
2693 | if (ret) { | |
2694 | kdc_log(r->context, config, 4, "Hardware authentication required for %s", r->cname); | |
2695 | return ret; | |
2696 | } | |
2697 | } | |
51569b31 JS |
2698 | kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_VIS, "pa", "%s", |
2699 | pat[n].name); | |
2700 | ret = pat[n].validate(r, pa); | |
40b65c84 SM |
2701 | if (ret != 0) { |
2702 | krb5_error_code ret2; | |
2703 | Key *ckey = NULL; | |
2704 | krb5_boolean default_salt; | |
2705 | ||
51569b31 JS |
2706 | if (ret != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED && |
2707 | !kdc_audit_getkv((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT)) | |
2708 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
2709 | KDC_AUTH_EVENT_PREAUTH_FAILED); | |
40b65c84 SM |
2710 | |
2711 | /* | |
2712 | * If there is a client key, send ETYPE_INFO{,2} | |
2713 | */ | |
90436389 JS |
2714 | if (!r->client->flags.locked_out) { |
2715 | ret2 = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT, | |
2716 | b->etype.val, b->etype.len, | |
2717 | NULL, &ckey, &default_salt); | |
2718 | if (ret2 == 0) { | |
2719 | ret2 = get_pa_etype_info_both(r->context, config, &b->etype, | |
2720 | r->rep.padata, ckey, !default_salt); | |
2721 | if (ret2 != 0) | |
2722 | ret = ret2; | |
2723 | } | |
40b65c84 SM |
2724 | } |
2725 | goto out; | |
2726 | } | |
51569b31 JS |
2727 | if (!kdc_audit_getkv((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT)) |
2728 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, | |
2729 | KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); | |
40b65c84 SM |
2730 | kdc_log(r->context, config, 4, |
2731 | "%s pre-authentication succeeded -- %s", | |
2732 | pat[n].name, r->cname); | |
2733 | found_pa = 1; | |
2734 | r->pa_used = &pat[n]; | |
40b65c84 | 2735 | r->et.flags.pre_authent = 1; |
954c0172 | 2736 | } |
30bae409 | 2737 | } |
40b65c84 | 2738 | } |
30bae409 | 2739 | |
40b65c84 SM |
2740 | if (found_pa == 0) { |
2741 | Key *ckey = NULL; | |
2742 | size_t n; | |
2743 | krb5_boolean default_salt; | |
255e3e18 | 2744 | |
51569b31 | 2745 | if (r->client->flags.synthetic) { |
40b65c84 | 2746 | kdc_log(r->context, config, 4, "UNKNOWN -- %s", r->cname); |
51569b31 | 2747 | ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; |
40b65c84 SM |
2748 | goto out; |
2749 | } | |
e2532553 | 2750 | |
40b65c84 SM |
2751 | for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { |
2752 | if ((pat[n].flags & PA_ANNOUNCE) == 0) | |
954c0172 | 2753 | continue; |
954c0172 | 2754 | |
40b65c84 | 2755 | if (!r->armor_crypto && (pat[n].flags & PA_REQ_FAST)) |
954c0172 | 2756 | continue; |
75ec66c7 SM |
2757 | if (pat[n].type == KRB5_PADATA_PKINIT_KX && !r->config->allow_anonymous) |
2758 | continue; | |
40b65c84 SM |
2759 | if (pat[n].type == KRB5_PADATA_ENC_TIMESTAMP) { |
2760 | if (r->armor_crypto && !r->config->enable_armored_pa_enc_timestamp) | |
2761 | continue; | |
2762 | if (!r->armor_crypto && !r->config->enable_unarmored_pa_enc_timestamp) | |
2763 | continue; | |
954c0172 | 2764 | } |
75ec66c7 SM |
2765 | if (pat[n].type == KRB5_PADATA_FX_FAST && !r->config->enable_fast) |
2766 | continue; | |
2767 | if (pat[n].type == KRB5_PADATA_GSS && !r->config->enable_gss_preauth) | |
2768 | continue; | |
fc474042 JS |
2769 | if (!r->config->enable_fast_cookie && (pat[n].flags & PA_USES_FAST_COOKIE)) |
2770 | continue; | |
954c0172 | 2771 | |
40b65c84 SM |
2772 | ret = krb5_padata_add(r->context, r->rep.padata, |
2773 | pat[n].type, NULL, 0); | |
2774 | if (ret) | |
954c0172 | 2775 | goto out; |
40b65c84 | 2776 | } |
89eaef02 | 2777 | |
40b65c84 SM |
2778 | /* |
2779 | * If there is a client key, send ETYPE_INFO{,2} | |
2780 | */ | |
2781 | ret = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT, | |
2782 | b->etype.val, b->etype.len, | |
2783 | NULL, &ckey, &default_salt); | |
2784 | if (ret == 0) { | |
2785 | ret = get_pa_etype_info_both(r->context, config, &b->etype, | |
2786 | r->rep.padata, ckey, !default_salt); | |
c0e8144c | 2787 | if (ret) |
9b261c00 | 2788 | goto out; |
9b261c00 | 2789 | } |
255e3e18 | 2790 | |
a25f549e JS |
2791 | /* |
2792 | * If the client indicated support for PKINIT Freshness, send back a | |
2793 | * freshness token. | |
2794 | */ | |
2795 | ret = send_freshness_token(r, krbtgt_key, krbtgt_kvno); | |
2796 | if (ret) | |
2797 | goto out; | |
2798 | ||
40b65c84 SM |
2799 | /* |
2800 | * send requre preauth is its required or anon is requested, | |
2801 | * anon is today only allowed via preauth mechanisms. | |
2802 | */ | |
2803 | if (require_preauth_p(r) || _kdc_is_anon_request(&r->req)) { | |
2804 | ret = KRB5KDC_ERR_PREAUTH_REQUIRED; | |
2805 | _kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ"); | |
2806 | goto out; | |
2807 | } | |
544e1789 | 2808 | |
40b65c84 SM |
2809 | if (ckey == NULL) { |
2810 | ret = KRB5KDC_ERR_CLIENT_NOTYET; | |
2811 | _kdc_set_e_text(r, "Doesn't have a client key available"); | |
2812 | goto out; | |
2813 | } | |
2814 | krb5_free_keyblock_contents(r->context, &r->reply_key); | |
2815 | ret = krb5_copy_keyblock_contents(r->context, &ckey->key, &r->reply_key); | |
2816 | if (ret) | |
2817 | goto out; | |
954c0172 | 2818 | } |
2b29b718 | 2819 | |
51569b31 JS |
2820 | r->canon_client_princ = r->client->principal; |
2821 | ||
40b65c84 SM |
2822 | if (_kdc_is_anon_request(&r->req)) { |
2823 | ret = _kdc_check_anon_policy(r); | |
2824 | if (ret) { | |
2825 | _kdc_set_e_text(r, "Anonymous ticket requests are disabled"); | |
2826 | goto out; | |
2827 | } | |
2828 | ||
2829 | r->et.flags.anonymous = 1; | |
2830 | } | |
2831 | ||
51569b31 JS |
2832 | kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, |
2833 | KDC_AUTH_EVENT_CLIENT_AUTHORIZED); | |
d202191f | 2834 | |
40b65c84 | 2835 | if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey) { |
954c0172 | 2836 | ret = KRB5KDC_ERR_BADOPTION; |
40b65c84 | 2837 | _kdc_set_e_text(r, "Bad KDC options"); |
954c0172 HIU |
2838 | goto out; |
2839 | } | |
2b29b718 | 2840 | |
40b65c84 SM |
2841 | /* |
2842 | * Build reply | |
2843 | */ | |
2844 | rep->pvno = 5; | |
2845 | rep->msg_type = krb_as_rep; | |
2846 | ||
2847 | if (!config->historical_anon_realm && | |
2848 | _kdc_is_anonymous(r->context, r->client_princ)) { | |
2849 | Realm anon_realm = KRB5_ANON_REALM; | |
2850 | ret = copy_Realm(&anon_realm, &rep->crealm); | |
51569b31 JS |
2851 | } else if (f.canonicalize || r->client->flags.force_canonicalize) |
2852 | ret = copy_Realm(&r->canon_client_princ->realm, &rep->crealm); | |
40b65c84 SM |
2853 | else |
2854 | ret = copy_Realm(&r->client_princ->realm, &rep->crealm); | |
9b261c00 AB |
2855 | if (ret) |
2856 | goto out; | |
40b65c84 SM |
2857 | if (r->et.flags.anonymous) |
2858 | ret = _kdc_make_anonymous_principalname(&rep->cname); | |
51569b31 JS |
2859 | else if (f.canonicalize || r->client->flags.force_canonicalize) |
2860 | ret = _krb5_principal2principalname(&rep->cname, r->canon_client_princ); | |
40b65c84 SM |
2861 | else |
2862 | ret = _krb5_principal2principalname(&rep->cname, r->client_princ); | |
9b261c00 AB |
2863 | if (ret) |
2864 | goto out; | |
2865 | ||
40b65c84 | 2866 | rep->ticket.tkt_vno = 5; |
51569b31 JS |
2867 | if (f.canonicalize || r->server->flags.force_canonicalize) |
2868 | ret = copy_Realm(&r->server->principal->realm, &rep->ticket.realm); | |
40b65c84 SM |
2869 | else |
2870 | ret = copy_Realm(&r->server_princ->realm, &rep->ticket.realm); | |
2871 | if (ret) | |
2872 | goto out; | |
51569b31 | 2873 | if (f.canonicalize || r->server->flags.force_canonicalize) |
40b65c84 | 2874 | _krb5_principal2principalname(&rep->ticket.sname, |
51569b31 | 2875 | r->server->principal); |
40b65c84 SM |
2876 | else |
2877 | _krb5_principal2principalname(&rep->ticket.sname, | |
2878 | r->server_princ); | |
b39330c4 | 2879 | /* java 1.6 expects the name to be the same type, lets allow that |
41473daf AB |
2880 | * uncomplicated name-types, when f.canonicalize is not set (to |
2881 | * match Windows Server 1709). */ | |
b39330c4 | 2882 | #define CNT(sp,t) (((sp)->sname->name_type) == KRB5_NT_##t) |
41473daf AB |
2883 | if (!f.canonicalize |
2884 | && (CNT(b, UNKNOWN) || CNT(b, PRINCIPAL) || CNT(b, SRV_INST) || CNT(b, SRV_HST) || CNT(b, SRV_XHST))) { | |
40b65c84 | 2885 | rep->ticket.sname.name_type = b->sname->name_type; |
41473daf | 2886 | } |
b39330c4 | 2887 | #undef CNT |
954c0172 | 2888 | |
40b65c84 | 2889 | r->et.flags.initial = 1; |
51569b31 | 2890 | if(r->client->flags.forwardable && r->server->flags.forwardable) |
40b65c84 | 2891 | r->et.flags.forwardable = f.forwardable; |
51569b31 | 2892 | if(r->client->flags.proxiable && r->server->flags.proxiable) |
40b65c84 | 2893 | r->et.flags.proxiable = f.proxiable; |
954c0172 | 2894 | else if (f.proxiable) { |
40b65c84 | 2895 | _kdc_set_e_text(r, "Ticket may not be proxiable"); |
954c0172 | 2896 | ret = KRB5KDC_ERR_POLICY; |
954c0172 HIU |
2897 | goto out; |
2898 | } | |
51569b31 | 2899 | if(r->client->flags.postdate && r->server->flags.postdate) |
40b65c84 | 2900 | r->et.flags.may_postdate = f.allow_postdate; |
954c0172 | 2901 | else if (f.allow_postdate){ |
b12a33e2 | 2902 | _kdc_set_e_text(r, "Ticket may not be postdateable"); |
954c0172 | 2903 | ret = KRB5KDC_ERR_POLICY; |
954c0172 HIU |
2904 | goto out; |
2905 | } | |
2906 | ||
40b65c84 | 2907 | if (b->addresses) |
51569b31 | 2908 | kdc_audit_addaddrs((kdc_request_t)r, b->addresses, "reqaddrs"); |
40b65c84 | 2909 | |
954c0172 | 2910 | /* check for valid set of addresses */ |
40b65c84 SM |
2911 | if (!_kdc_check_addresses(r, b->addresses, r->addr)) { |
2912 | if (r->config->warn_ticket_addresses) { | |
51569b31 | 2913 | kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE); |
40b65c84 SM |
2914 | } else { |
2915 | _kdc_set_e_text(r, "Request from wrong address"); | |
2916 | ret = KRB5KRB_AP_ERR_BADADDR; | |
2917 | goto out; | |
2918 | } | |
954c0172 HIU |
2919 | } |
2920 | ||
40b65c84 | 2921 | ret = copy_PrincipalName(&rep->cname, &r->et.cname); |
9b261c00 AB |
2922 | if (ret) |
2923 | goto out; | |
40b65c84 | 2924 | ret = copy_Realm(&rep->crealm, &r->et.crealm); |
f7242f64 AB |
2925 | if (ret) |
2926 | goto out; | |
2b29b718 | 2927 | |
954c0172 HIU |
2928 | { |
2929 | time_t start; | |
2930 | time_t t; | |
40b65c84 SM |
2931 | |
2932 | start = r->et.authtime = kdc_time; | |
2b29b718 | 2933 | |
954c0172 | 2934 | if(f.postdated && req->req_body.from){ |
40b65c84 SM |
2935 | ALLOC(r->et.starttime); |
2936 | start = *r->et.starttime = *req->req_body.from; | |
2937 | r->et.flags.invalid = 1; | |
2938 | r->et.flags.postdated = 1; /* XXX ??? */ | |
954c0172 | 2939 | } |
3c1e780e | 2940 | _kdc_fix_time(&b->till); |
954c0172 HIU |
2941 | t = *b->till; |
2942 | ||
b12a33e2 | 2943 | /* be careful not to overflow */ |
954c0172 | 2944 | |
40b65c84 | 2945 | /* |
51569b31 | 2946 | * Pre-auth can override r->client->max_life if configured. |
40b65c84 SM |
2947 | * |
2948 | * See pre-auth methods, specifically PKINIT, which can get or derive | |
2949 | * this from the client's certificate. | |
2950 | */ | |
2951 | if (r->pa_max_life > 0) | |
51569b31 | 2952 | t = rk_time_add(start, min(rk_time_sub(t, start), r->pa_max_life)); |
eeebd488 | 2953 | else if (r->client->max_life) |
51569b31 JS |
2954 | t = rk_time_add(start, min(rk_time_sub(t, start), |
2955 | *r->client->max_life)); | |
40b65c84 | 2956 | |
eeebd488 | 2957 | if (r->server->max_life) |
51569b31 JS |
2958 | t = rk_time_add(start, min(rk_time_sub(t, start), |
2959 | *r->server->max_life)); | |
40b65c84 SM |
2960 | |
2961 | /* Pre-auth can bound endtime as well */ | |
2962 | if (r->pa_endtime > 0) | |
51569b31 | 2963 | t = rk_time_add(start, min(rk_time_sub(t, start), r->pa_endtime)); |
954c0172 | 2964 | #if 0 |
51569b31 | 2965 | t = min(t, rk_time_add(start, realm->max_life)); |
954c0172 | 2966 | #endif |
40b65c84 | 2967 | r->et.endtime = t; |
eeebd488 JS |
2968 | |
2969 | if (start > r->et.endtime) { | |
2970 | _kdc_set_e_text(r, "Requested effective lifetime is negative or too short"); | |
2971 | ret = KRB5KDC_ERR_NEVER_VALID; | |
2972 | goto out; | |
2973 | } | |
2974 | ||
40b65c84 | 2975 | if(f.renewable_ok && r->et.endtime < *b->till){ |
954c0172 HIU |
2976 | f.renewable = 1; |
2977 | if(b->rtime == NULL){ | |
2978 | ALLOC(b->rtime); | |
2979 | *b->rtime = 0; | |
2980 | } | |
2981 | if(*b->rtime < *b->till) | |
2982 | *b->rtime = *b->till; | |
2983 | } | |
2984 | if(f.renewable && b->rtime){ | |
2985 | t = *b->rtime; | |
2986 | if(t == 0) | |
2987 | t = MAX_TIME; | |
eeebd488 | 2988 | if(r->client->max_renew) |
51569b31 JS |
2989 | t = rk_time_add(start, min(rk_time_sub(t, start), |
2990 | *r->client->max_renew)); | |
eeebd488 | 2991 | if(r->server->max_renew) |
51569b31 JS |
2992 | t = rk_time_add(start, min(rk_time_sub(t, start), |
2993 | *r->server->max_renew)); | |
954c0172 | 2994 | #if 0 |
51569b31 | 2995 | t = min(t, rk_time_add(start, realm->max_renew)); |
954c0172 | 2996 | #endif |
40b65c84 SM |
2997 | ALLOC(r->et.renew_till); |
2998 | *r->et.renew_till = t; | |
2999 | r->et.flags.renewable = 1; | |
954c0172 HIU |
3000 | } |
3001 | } | |
3002 | ||
954c0172 | 3003 | if(b->addresses){ |
40b65c84 SM |
3004 | ALLOC(r->et.caddr); |
3005 | copy_HostAddresses(b->addresses, r->et.caddr); | |
954c0172 | 3006 | } |
2b29b718 | 3007 | |
40b65c84 SM |
3008 | r->et.transited.tr_type = domain_X500_Compress; |
3009 | krb5_data_zero(&r->et.transited.contents); | |
2b29b718 | 3010 | |
954c0172 HIU |
3011 | /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded |
3012 | * as 0 and as 0x80 (meaning indefinite length) apart, and is thus | |
3013 | * incapable of correctly decoding SEQUENCE OF's of zero length. | |
3014 | * | |
3015 | * To fix this, always send at least one no-op last_req | |
3016 | * | |
3017 | * If there's a pw_end or valid_end we will use that, | |
3018 | * otherwise just a dummy lr. | |
3019 | */ | |
40b65c84 SM |
3020 | r->ek.last_req.val = malloc(2 * sizeof(*r->ek.last_req.val)); |
3021 | if (r->ek.last_req.val == NULL) { | |
9e6b0c28 AB |
3022 | ret = ENOMEM; |
3023 | goto out; | |
3024 | } | |
40b65c84 | 3025 | r->ek.last_req.len = 0; |
51569b31 | 3026 | if (r->client->pw_end |
954c0172 | 3027 | && (config->kdc_warn_pwexpire == 0 |
51569b31 | 3028 | || kdc_time + config->kdc_warn_pwexpire >= *r->client->pw_end)) { |
40b65c84 | 3029 | r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_PW_EXPTIME; |
51569b31 | 3030 | r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->pw_end; |
40b65c84 SM |
3031 | ++r->ek.last_req.len; |
3032 | } | |
51569b31 | 3033 | if (r->client->valid_end) { |
40b65c84 | 3034 | r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_ACCT_EXPTIME; |
51569b31 | 3035 | r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->valid_end; |
40b65c84 SM |
3036 | ++r->ek.last_req.len; |
3037 | } | |
3038 | if (r->ek.last_req.len == 0) { | |
3039 | r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_NONE; | |
3040 | r->ek.last_req.val[r->ek.last_req.len].lr_value = 0; | |
3041 | ++r->ek.last_req.len; | |
3042 | } | |
a25f549e JS |
3043 | /* Set the nonce if it’s not already set. */ |
3044 | if (!r->ek.nonce) { | |
3045 | r->ek.nonce = b->nonce; | |
3046 | } | |
51569b31 | 3047 | if (r->client->valid_end || r->client->pw_end) { |
40b65c84 | 3048 | ALLOC(r->ek.key_expiration); |
51569b31 JS |
3049 | if (r->client->valid_end) { |
3050 | if (r->client->pw_end) | |
3051 | *r->ek.key_expiration = min(*r->client->valid_end, | |
3052 | *r->client->pw_end); | |
954c0172 | 3053 | else |
51569b31 | 3054 | *r->ek.key_expiration = *r->client->valid_end; |
954c0172 | 3055 | } else |
51569b31 | 3056 | *r->ek.key_expiration = *r->client->pw_end; |
954c0172 | 3057 | } else |
40b65c84 SM |
3058 | r->ek.key_expiration = NULL; |
3059 | r->ek.flags = r->et.flags; | |
3060 | r->ek.authtime = r->et.authtime; | |
3061 | if (r->et.starttime) { | |
3062 | ALLOC(r->ek.starttime); | |
3063 | *r->ek.starttime = *r->et.starttime; | |
954c0172 | 3064 | } |
40b65c84 SM |
3065 | r->ek.endtime = r->et.endtime; |
3066 | if (r->et.renew_till) { | |
3067 | ALLOC(r->ek.renew_till); | |
3068 | *r->ek.renew_till = *r->et.renew_till; | |
954c0172 | 3069 | } |
40b65c84 SM |
3070 | ret = copy_Realm(&rep->ticket.realm, &r->ek.srealm); |
3071 | if (ret) | |
3072 | goto out; | |
3073 | ret = copy_PrincipalName(&rep->ticket.sname, &r->ek.sname); | |
3074 | if (ret) | |
3075 | goto out; | |
3076 | if(r->et.caddr){ | |
3077 | ALLOC(r->ek.caddr); | |
3078 | copy_HostAddresses(r->et.caddr, r->ek.caddr); | |
954c0172 HIU |
3079 | } |
3080 | ||
40b65c84 | 3081 | /* |
b12a33e2 | 3082 | * Check session and reply keys |
40b65c84 | 3083 | */ |
533024be | 3084 | |
40b65c84 SM |
3085 | if (r->session_key.keytype == ETYPE_NULL) { |
3086 | ret = krb5_generate_random_keyblock(r->context, r->sessionetype, &r->session_key); | |
9b261c00 AB |
3087 | if (ret) |
3088 | goto out; | |
89eaef02 AB |
3089 | } |
3090 | ||
40b65c84 | 3091 | if (r->reply_key.keytype == ETYPE_NULL) { |
b12a33e2 | 3092 | _kdc_set_e_text(r, "Client has no reply key"); |
9b261c00 AB |
3093 | ret = KRB5KDC_ERR_CLIENT_NOTYET; |
3094 | goto out; | |
3095 | } | |
3096 | ||
40b65c84 | 3097 | ret = copy_EncryptionKey(&r->session_key, &r->et.key); |
9b261c00 AB |
3098 | if (ret) |
3099 | goto out; | |
954c0172 | 3100 | |
40b65c84 SM |
3101 | ret = copy_EncryptionKey(&r->session_key, &r->ek.key); |
3102 | if (ret) | |
3103 | goto out; | |
954c0172 | 3104 | |
51569b31 | 3105 | if (r->client->flags.synthetic) { |
40b65c84 SM |
3106 | ret = add_synthetic_princ_ad(r); |
3107 | if (ret) | |
f7242f64 | 3108 | goto out; |
918c7634 AB |
3109 | } |
3110 | ||
40b65c84 SM |
3111 | _kdc_log_timestamp(r, "AS-REQ", r->et.authtime, |
3112 | r->et.starttime, r->et.endtime, | |
3113 | r->et.renew_till); | |
3c1e780e | 3114 | |
40b65c84 | 3115 | _log_astgs_req(r, setype); |
89eaef02 | 3116 | |
40b65c84 SM |
3117 | /* |
3118 | * We always say we support FAST/enc-pa-rep | |
3119 | */ | |
3c1e780e | 3120 | |
40b65c84 | 3121 | r->et.flags.enc_pa_rep = r->ek.flags.enc_pa_rep = 1; |
3c1e780e | 3122 | |
40b65c84 SM |
3123 | /* |
3124 | * update reply-key with strengthen-key | |
3125 | */ | |
f7242f64 | 3126 | |
40b65c84 SM |
3127 | ret = _kdc_fast_strengthen_reply_key(r); |
3128 | if (ret) | |
3129 | goto out; | |
978bc868 | 3130 | |
40b65c84 SM |
3131 | /* |
3132 | * Add REQ_ENC_PA_REP if client supports it | |
3133 | */ | |
978bc868 | 3134 | |
40b65c84 SM |
3135 | i = 0; |
3136 | pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); | |
3137 | if (pa) { | |
978bc868 | 3138 | |
40b65c84 | 3139 | ret = add_enc_pa_rep(r); |
978bc868 | 3140 | if (ret) { |
40b65c84 SM |
3141 | msg = krb5_get_error_message(r->context, ret); |
3142 | _kdc_r_log(r, 4, "add_enc_pa_rep failed: %s: %d", msg, ret); | |
3143 | krb5_free_error_message(r->context, msg); | |
3144 | goto out; | |
978bc868 | 3145 | } |
40b65c84 | 3146 | } |
978bc868 | 3147 | |
09bcd48f JS |
3148 | /* Add the PAC */ |
3149 | if (!r->et.flags.anonymous) { | |
3150 | ret = generate_pac(r, skey, krbtgt_key, is_tgs); | |
3151 | if (ret) | |
3152 | goto out; | |
3153 | } | |
3154 | ||
3155 | /* | |
3156 | * No more changes to the ticket (r->et) from this point on, lest | |
3157 | * the checksums in the PAC be invalidated. | |
3158 | */ | |
3159 | ||
40b65c84 SM |
3160 | /* |
3161 | * Last chance for plugins to update reply | |
3162 | */ | |
3163 | ret = _kdc_finalize_reply(r); | |
3164 | if (ret) | |
3165 | goto out; | |
978bc868 | 3166 | |
40b65c84 SM |
3167 | /* |
3168 | * Don't send kvno from client entry if the pre-authentication | |
3169 | * mechanism replaced the reply key. | |
3170 | */ | |
978bc868 | 3171 | |
40b65c84 SM |
3172 | ret = _kdc_encode_reply(r->context, config, |
3173 | r, req->req_body.nonce, setype, | |
51569b31 JS |
3174 | r->server->kvno, &skey->key, |
3175 | pa_used_flag_isset(r, PA_REPLACE_REPLY_KEY) ? 0 : r->client->kvno, | |
40b65c84 SM |
3176 | 0, r->reply); |
3177 | if (ret) | |
3178 | goto out; | |
978bc868 | 3179 | |
40b65c84 | 3180 | /* |
b12a33e2 | 3181 | * Check if message is too large |
40b65c84 SM |
3182 | */ |
3183 | if (r->datagram_reply && r->reply->length > config->max_datagram_reply_length) { | |
3184 | krb5_data_free(r->reply); | |
3185 | ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; | |
3186 | _kdc_set_e_text(r, "Reply packet too large"); | |
3187 | } | |
978bc868 | 3188 | |
40b65c84 | 3189 | out: |
95c02a97 JS |
3190 | if (ret) { |
3191 | /* Overwrite ‘error_code’ only if we have an actual error. */ | |
3192 | r->error_code = ret; | |
3193 | } | |
f33f73f8 SM |
3194 | { |
3195 | krb5_error_code ret2 = _kdc_audit_request(r); | |
3196 | if (ret2) { | |
3197 | krb5_data_free(r->reply); | |
3198 | ret = ret2; | |
3199 | } | |
3200 | } | |
51569b31 | 3201 | |
40b65c84 SM |
3202 | /* |
3203 | * In case of a non proxy error, build an error message. | |
3204 | */ | |
f33f73f8 SM |
3205 | if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && r->reply->length == 0) { |
3206 | kdc_log(r->context, config, 5, "as-req: sending error: %d to client", ret); | |
40b65c84 SM |
3207 | ret = _kdc_fast_mk_error(r, |
3208 | r->rep.padata, | |
3209 | r->armor_crypto, | |
3210 | &req->req_body, | |
95c02a97 | 3211 | r->error_code ? r->error_code : ret, |
40b65c84 SM |
3212 | r->client_princ, |
3213 | r->server_princ, | |
3214 | NULL, NULL, | |
3215 | r->reply); | |
f33f73f8 | 3216 | } |
40b65c84 SM |
3217 | |
3218 | if (r->pa_used && r->pa_used->cleanup) | |
3219 | r->pa_used->cleanup(r); | |
3220 | ||
3221 | free_AS_REP(&r->rep); | |
3222 | free_EncTicketPart(&r->et); | |
3223 | free_EncKDCRepPart(&r->ek); | |
3224 | _kdc_free_fast_state(&r->fast); | |
3225 | ||
3226 | if (r->client_princ) { | |
3227 | krb5_free_principal(r->context, r->client_princ); | |
3228 | r->client_princ = NULL; | |
3229 | } | |
3230 | if (r->server_princ){ | |
3231 | krb5_free_principal(r->context, r->server_princ); | |
3232 | r->server_princ = NULL; | |
3233 | } | |
3234 | if (r->client) | |
51569b31 | 3235 | _kdc_free_ent(r->context, r->clientdb, r->client); |
40b65c84 | 3236 | if (r->server) |
51569b31 JS |
3237 | _kdc_free_ent(r->context, r->serverdb, r->server); |
3238 | if (r->krbtgt) | |
3239 | _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt); | |
40b65c84 SM |
3240 | if (r->armor_crypto) { |
3241 | krb5_crypto_destroy(r->context, r->armor_crypto); | |
3242 | r->armor_crypto = NULL; | |
3243 | } | |
3244 | if (r->armor_ticket) | |
3245 | krb5_free_ticket(r->context, r->armor_ticket); | |
3246 | if (r->armor_server) | |
51569b31 | 3247 | _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server); |
40b65c84 | 3248 | krb5_free_keyblock_contents(r->context, &r->reply_key); |
75ec66c7 | 3249 | krb5_free_keyblock_contents(r->context, &r->enc_ad_key); |
40b65c84 SM |
3250 | krb5_free_keyblock_contents(r->context, &r->session_key); |
3251 | krb5_free_keyblock_contents(r->context, &r->strengthen_key); | |
3252 | krb5_pac_free(r->context, r->pac); | |
978bc868 | 3253 | |
40b65c84 | 3254 | return ret; |
978bc868 | 3255 | } |