Line data Source code
1 : /*
2 : * Copyright (c) 1997-2011 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2010 - 2011 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include "kdc_locl.h"
37 :
38 : static krb5_error_code
39 0 : salt_fastuser_crypto(astgs_request_t r,
40 : krb5_const_principal salt_principal,
41 : krb5_enctype enctype,
42 : krb5_crypto fast_crypto,
43 : krb5_crypto *salted_crypto)
44 : {
45 0 : krb5_error_code ret;
46 0 : krb5_principal client_princ = NULL;
47 0 : krb5_data salt;
48 0 : krb5_keyblock dkey;
49 0 : size_t size;
50 :
51 0 : *salted_crypto = NULL;
52 :
53 0 : krb5_data_zero(&salt);
54 0 : krb5_keyblock_zero(&dkey);
55 :
56 0 : if (salt_principal == NULL) {
57 0 : if (r->req.req_body.cname == NULL) {
58 0 : ret = KRB5KRB_ERR_GENERIC;
59 0 : goto out;
60 : }
61 :
62 0 : ret = _krb5_principalname2krb5_principal(r->context, &client_princ,
63 0 : *(r->req.req_body.cname),
64 : r->req.req_body.realm);
65 0 : if (ret)
66 0 : goto out;
67 :
68 0 : salt_principal = client_princ;
69 : }
70 :
71 0 : ret = krb5_unparse_name(r->context, salt_principal, (char **)&salt.data);
72 0 : if (ret)
73 0 : goto out;
74 :
75 0 : salt.length = strlen(salt.data);
76 :
77 0 : kdc_log(r->context, r->config, 10,
78 : "salt_fastuser_crypto: salt principal is %s (%d)",
79 0 : (char *)salt.data, enctype);
80 :
81 0 : ret = krb5_enctype_keysize(r->context, enctype, &size);
82 0 : if (ret)
83 0 : goto out;
84 :
85 0 : ret = krb5_crypto_prfplus(r->context, fast_crypto, &salt,
86 : size, &dkey.keyvalue);
87 0 : if (ret)
88 0 : goto out;
89 :
90 0 : dkey.keytype = enctype;
91 :
92 0 : ret = krb5_crypto_init(r->context, &dkey, ENCTYPE_NULL, salted_crypto);
93 0 : if (ret)
94 0 : goto out;
95 :
96 0 : out:
97 0 : krb5_free_keyblock_contents(r->context, &dkey);
98 0 : krb5_data_free(&salt);
99 0 : krb5_free_principal(r->context, client_princ);
100 :
101 0 : return ret;
102 : }
103 :
104 : static krb5_error_code
105 0 : get_fastuser_crypto(astgs_request_t r,
106 : krb5_const_principal ticket_client,
107 : krb5_enctype enctype,
108 : krb5_crypto *crypto)
109 : {
110 0 : krb5_principal fast_princ;
111 0 : HDB *fast_db;
112 0 : hdb_entry *fast_user = NULL;
113 0 : Key *cookie_key = NULL;
114 0 : krb5_crypto fast_crypto = NULL;
115 0 : krb5_error_code ret;
116 :
117 0 : *crypto = NULL;
118 :
119 0 : ret = krb5_make_principal(r->context, &fast_princ,
120 : KRB5_WELLKNOWN_ORG_H5L_REALM,
121 : KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL);
122 0 : if (ret)
123 0 : goto out;
124 :
125 0 : ret = _kdc_db_fetch(r->context, r->config, fast_princ,
126 : HDB_F_GET_FAST_COOKIE, NULL, &fast_db, &fast_user);
127 0 : if (ret)
128 0 : goto out;
129 :
130 0 : if (enctype == KRB5_ENCTYPE_NULL)
131 0 : ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
132 : "fast-cookie", &enctype, &cookie_key);
133 : else
134 0 : ret = hdb_enctype2key(r->context, fast_user, NULL,
135 : enctype, &cookie_key);
136 0 : if (ret)
137 0 : goto out;
138 :
139 0 : ret = krb5_crypto_init(r->context, &cookie_key->key,
140 : ENCTYPE_NULL, &fast_crypto);
141 0 : if (ret)
142 0 : goto out;
143 :
144 0 : ret = salt_fastuser_crypto(r, ticket_client,
145 0 : cookie_key->key.keytype,
146 : fast_crypto, crypto);
147 0 : if (ret)
148 0 : goto out;
149 :
150 0 : out:
151 0 : if (fast_user)
152 0 : _kdc_free_ent(r->context, fast_db, fast_user);
153 0 : if (fast_crypto)
154 0 : krb5_crypto_destroy(r->context, fast_crypto);
155 0 : krb5_free_principal(r->context, fast_princ);
156 :
157 0 : return ret;
158 : }
159 :
160 :
161 : static krb5_error_code
162 0 : fast_parse_cookie(astgs_request_t r,
163 : krb5_const_principal ticket_client,
164 : const PA_DATA *pa)
165 : {
166 0 : krb5_crypto crypto = NULL;
167 0 : krb5_error_code ret;
168 0 : KDCFastCookie data;
169 0 : krb5_data d1;
170 0 : size_t len;
171 :
172 0 : ret = decode_KDCFastCookie(pa->padata_value.data,
173 0 : pa->padata_value.length,
174 : &data, &len);
175 0 : if (ret)
176 0 : return ret;
177 :
178 0 : if (len != pa->padata_value.length || strcmp("H5L1", data.version) != 0) {
179 0 : free_KDCFastCookie(&data);
180 0 : return KRB5KDC_ERR_POLICY;
181 : }
182 :
183 0 : ret = get_fastuser_crypto(r, ticket_client, data.cookie.etype, &crypto);
184 0 : if (ret)
185 0 : goto out;
186 :
187 0 : ret = krb5_decrypt_EncryptedData(r->context, crypto,
188 : KRB5_KU_H5L_COOKIE,
189 : &data.cookie, &d1);
190 0 : krb5_crypto_destroy(r->context, crypto);
191 0 : if (ret)
192 0 : goto out;
193 :
194 0 : ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len);
195 0 : krb5_data_free(&d1);
196 0 : if (ret)
197 0 : goto out;
198 :
199 0 : if (r->fast.expiration < kdc_time) {
200 0 : kdc_log(r->context, r->config, 2, "FAST cookie expired");
201 0 : ret = KRB5KDC_ERR_POLICY;
202 0 : goto out;
203 : }
204 :
205 0 : out:
206 0 : free_KDCFastCookie(&data);
207 :
208 0 : return ret;
209 : }
210 :
211 : static krb5_error_code
212 0 : fast_add_cookie(astgs_request_t r,
213 : krb5_const_principal ticket_client,
214 : METHOD_DATA *method_data)
215 : {
216 0 : krb5_crypto crypto = NULL;
217 0 : KDCFastCookie shell;
218 0 : krb5_error_code ret;
219 0 : krb5_data data;
220 0 : size_t size;
221 :
222 0 : memset(&shell, 0, sizeof(shell));
223 :
224 0 : r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME;
225 :
226 0 : ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length,
227 : &r->fast, &size, ret);
228 0 : if (ret)
229 0 : return ret;
230 0 : heim_assert(size == data.length, "internal asn.1 encoder error");
231 :
232 0 : ret = get_fastuser_crypto(r, ticket_client, KRB5_ENCTYPE_NULL, &crypto);
233 0 : if (ret) {
234 0 : kdc_log(r->context, r->config, 0,
235 : "Failed to find FAST principal for cookie encryption: %d", ret);
236 0 : goto out;
237 : }
238 :
239 0 : ret = krb5_encrypt_EncryptedData(r->context, crypto,
240 : KRB5_KU_H5L_COOKIE,
241 : data.data, data.length, 0,
242 : &shell.cookie);
243 0 : krb5_crypto_destroy(r->context, crypto);
244 0 : if (ret)
245 0 : goto out;
246 :
247 0 : krb5_data_free(&data);
248 :
249 0 : shell.version = "H5L1";
250 :
251 0 : ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length,
252 : &shell, &size, ret);
253 0 : free_EncryptedData(&shell.cookie);
254 0 : if (ret)
255 0 : goto out;
256 0 : heim_assert(size == data.length, "internal asn.1 encoder error");
257 :
258 0 : ret = krb5_padata_add(r->context, method_data,
259 : KRB5_PADATA_FX_COOKIE,
260 : data.data, data.length);
261 0 : if (ret == 0)
262 0 : krb5_data_zero(&data);
263 :
264 0 : out:
265 0 : krb5_data_free(&data);
266 0 : return ret;
267 : }
268 :
269 : static krb5_error_code
270 1567 : fast_add_dummy_cookie(astgs_request_t r,
271 : METHOD_DATA *method_data)
272 : {
273 0 : krb5_error_code ret;
274 0 : krb5_data data;
275 1567 : const krb5_data *dummy_fast_cookie = &r->config->dummy_fast_cookie;
276 :
277 1567 : if (dummy_fast_cookie->data == NULL)
278 0 : return 0;
279 :
280 1567 : ret = krb5_data_copy(&data,
281 1567 : dummy_fast_cookie->data,
282 1567 : dummy_fast_cookie->length);
283 1567 : if (ret)
284 0 : return ret;
285 :
286 1567 : ret = krb5_padata_add(r->context, method_data,
287 : KRB5_PADATA_FX_COOKIE,
288 : data.data, data.length);
289 1567 : if (ret) {
290 0 : krb5_data_free(&data);
291 : }
292 :
293 1567 : return ret;
294 : }
295 :
296 : krb5_error_code
297 44697 : _kdc_fast_mk_response(krb5_context context,
298 : krb5_crypto armor_crypto,
299 : METHOD_DATA *pa_data,
300 : krb5_keyblock *strengthen_key,
301 : KrbFastFinished *finished,
302 : krb5uint32 nonce,
303 : krb5_data *data)
304 : {
305 1658 : PA_FX_FAST_REPLY fxfastrep;
306 1658 : KrbFastResponse fastrep;
307 1658 : krb5_error_code ret;
308 1658 : krb5_data buf;
309 1658 : size_t size;
310 :
311 44697 : memset(&fxfastrep, 0, sizeof(fxfastrep));
312 44697 : memset(&fastrep, 0, sizeof(fastrep));
313 44697 : krb5_data_zero(data);
314 :
315 44697 : if (pa_data) {
316 44697 : fastrep.padata.val = pa_data->val;
317 44697 : fastrep.padata.len = pa_data->len;
318 : }
319 44697 : fastrep.strengthen_key = strengthen_key;
320 44697 : fastrep.finished = finished;
321 44697 : fastrep.nonce = nonce;
322 :
323 44697 : ASN1_MALLOC_ENCODE(KrbFastResponse, buf.data, buf.length,
324 : &fastrep, &size, ret);
325 44697 : if (ret)
326 0 : return ret;
327 44697 : heim_assert(size == buf.length, "internal asn.1 encoder error");
328 :
329 44697 : fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data;
330 :
331 44697 : ret = krb5_encrypt_EncryptedData(context,
332 : armor_crypto,
333 : KRB5_KU_FAST_REP,
334 : buf.data,
335 : buf.length,
336 : 0,
337 : &fxfastrep.u.armored_data.enc_fast_rep);
338 44697 : krb5_data_free(&buf);
339 44697 : if (ret)
340 0 : return ret;
341 :
342 44697 : ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, data->data, data->length,
343 : &fxfastrep, &size, ret);
344 44697 : free_PA_FX_FAST_REPLY(&fxfastrep);
345 44697 : if (ret)
346 0 : return ret;
347 44697 : heim_assert(size == data->length, "internal asn.1 encoder error");
348 :
349 43039 : return 0;
350 : }
351 :
352 :
353 : static krb5_error_code
354 34494 : _kdc_fast_mk_e_data(astgs_request_t r,
355 : METHOD_DATA *error_method,
356 : krb5_crypto armor_crypto,
357 : const KDC_REQ_BODY *req_body,
358 : krb5_error_code outer_error,
359 : krb5_principal error_client,
360 : krb5_principal error_server,
361 : time_t *csec, int *cusec,
362 : krb5_data *e_data)
363 : {
364 34494 : krb5_error_code ret = 0;
365 1170 : size_t size;
366 :
367 : /*
368 : * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
369 : */
370 34494 : if (armor_crypto || r->fast.fast_state.len) {
371 1567 : if (r->config->enable_fast_cookie) {
372 0 : kdc_log(r->context, r->config, 5, "Adding FAST cookie for KRB-ERROR");
373 0 : ret = fast_add_cookie(r, error_client, error_method);
374 0 : if (ret) {
375 0 : kdc_log(r->context, r->config, 1,
376 : "Failed to add FAST cookie: %d", ret);
377 0 : free_METHOD_DATA(error_method);
378 0 : return ret;
379 : }
380 : } else {
381 1567 : kdc_log(r->context, r->config, 5, "Adding dummy FAST cookie for KRB-ERROR");
382 1567 : ret = fast_add_dummy_cookie(r, error_method);
383 1567 : if (ret) {
384 0 : kdc_log(r->context, r->config, 1,
385 : "Failed to add dummy FAST cookie: %d", ret);
386 0 : free_METHOD_DATA(error_method);
387 0 : return ret;
388 : }
389 : }
390 : }
391 :
392 34494 : if (armor_crypto) {
393 0 : PA_FX_FAST_REPLY fxfastrep;
394 0 : KrbFastResponse fastrep;
395 :
396 1567 : memset(&fxfastrep, 0, sizeof(fxfastrep));
397 1567 : memset(&fastrep, 0, sizeof(fastrep));
398 :
399 1567 : kdc_log(r->context, r->config, 5, "Making FAST inner KRB-ERROR");
400 :
401 : /* first add the KRB-ERROR to the fast errors */
402 :
403 1567 : ret = krb5_mk_error(r->context,
404 : outer_error,
405 : r->e_text,
406 : NULL,
407 : error_client,
408 : error_server,
409 : csec,
410 : cusec,
411 : e_data);
412 1567 : if (ret) {
413 0 : kdc_log(r->context, r->config, 1,
414 : "Failed to make inner KRB-ERROR: %d", ret);
415 0 : return ret;
416 : }
417 :
418 1567 : ret = krb5_padata_add(r->context, error_method,
419 : KRB5_PADATA_FX_ERROR,
420 : e_data->data, e_data->length);
421 1567 : if (ret) {
422 0 : kdc_log(r->context, r->config, 1,
423 : "Failed to make add FAST PADATA to inner KRB-ERROR: %d", ret);
424 0 : krb5_data_free(e_data);
425 0 : return ret;
426 : }
427 :
428 1567 : r->e_text = NULL;
429 :
430 1567 : ret = _kdc_fast_mk_response(r->context, armor_crypto,
431 : error_method, NULL, NULL,
432 1567 : req_body->nonce, e_data);
433 1567 : free_METHOD_DATA(error_method);
434 1567 : if (ret) {
435 0 : kdc_log(r->context, r->config, 1,
436 : "Failed to make outer KRB-ERROR: %d", ret);
437 0 : return ret;
438 : }
439 :
440 1567 : ret = krb5_padata_add(r->context, error_method,
441 : KRB5_PADATA_FX_FAST,
442 : e_data->data, e_data->length);
443 1567 : if (ret) {
444 0 : kdc_log(r->context, r->config, 1,
445 : "Failed to make add FAST PADATA to outer KRB-ERROR: %d", ret);
446 0 : return ret;
447 : }
448 : } else
449 32927 : kdc_log(r->context, r->config, 5, "Making non-FAST KRB-ERROR");
450 :
451 34494 : if (error_method && error_method->len) {
452 32265 : ASN1_MALLOC_ENCODE(METHOD_DATA, e_data->data, e_data->length,
453 : error_method, &size, ret);
454 32265 : if (ret) {
455 0 : kdc_log(r->context, r->config, 1,
456 : "Failed to make encode METHOD-DATA: %d", ret);
457 0 : return ret;
458 : }
459 32265 : heim_assert(size == e_data->length, "internal asn.1 encoder error");
460 : }
461 :
462 33324 : return ret;
463 : }
464 :
465 :
466 : krb5_error_code
467 34609 : _kdc_fast_mk_error(astgs_request_t r,
468 : METHOD_DATA *error_method,
469 : krb5_crypto armor_crypto,
470 : const KDC_REQ_BODY *req_body,
471 : krb5_error_code outer_error,
472 : krb5_principal error_client,
473 : krb5_principal error_server,
474 : time_t *csec, int *cusec,
475 : krb5_data *error_msg)
476 : {
477 1170 : krb5_error_code ret;
478 1170 : krb5_data _e_data;
479 34609 : krb5_data *e_data = NULL;
480 :
481 34609 : krb5_data_zero(&_e_data);
482 :
483 34609 : heim_assert(r != NULL, "invalid request in _kdc_fast_mk_error");
484 :
485 34609 : if (r->e_data.length) {
486 115 : e_data = &r->e_data;
487 : } else {
488 34494 : ret = _kdc_fast_mk_e_data(r,
489 : error_method,
490 : armor_crypto,
491 : req_body,
492 : outer_error,
493 : error_client,
494 : error_server,
495 : csec, cusec,
496 : &_e_data);
497 34494 : if (ret) {
498 0 : kdc_log(r->context, r->config, 1,
499 : "Failed to make FAST e-data: %d", ret);
500 0 : return ret;
501 : }
502 :
503 33324 : e_data = &_e_data;
504 : }
505 :
506 34609 : if (armor_crypto) {
507 1632 : if (r->fast.flags.requested_hidden_names) {
508 1237 : error_client = NULL;
509 1237 : error_server = NULL;
510 : }
511 1632 : csec = NULL;
512 1632 : cusec = NULL;
513 : }
514 :
515 34609 : ret = krb5_mk_error(r->context,
516 : outer_error,
517 : r->e_text,
518 34609 : (e_data->length ? e_data : NULL),
519 : error_client,
520 : error_server,
521 : csec,
522 : cusec,
523 : error_msg);
524 34609 : krb5_data_free(&_e_data);
525 :
526 34609 : if (ret)
527 0 : kdc_log(r->context, r->config, 1,
528 : "Failed to make encode KRB-ERROR: %d", ret);
529 :
530 33439 : return ret;
531 : }
532 :
533 : static krb5_error_code
534 97665 : fast_unwrap_request(astgs_request_t r,
535 : krb5_ticket *tgs_ticket,
536 : krb5_auth_context tgs_ac)
537 : {
538 97665 : krb5_principal armor_server_principal = NULL;
539 97665 : char *armor_client_principal_name = NULL;
540 97665 : char *armor_server_principal_name = NULL;
541 3413 : PA_FX_FAST_REQUEST fxreq;
542 97665 : krb5_auth_context ac = NULL;
543 97665 : krb5_ticket *ticket = NULL;
544 3413 : krb5_flags ap_req_options;
545 3413 : krb5_keyblock armorkey;
546 3413 : krb5_keyblock explicit_armorkey;
547 3413 : krb5_error_code ret;
548 3413 : krb5_ap_req ap_req;
549 3413 : KrbFastReq fastreq;
550 3413 : const PA_DATA *pa;
551 3413 : krb5_data data;
552 3413 : size_t len;
553 97665 : int i = 0;
554 :
555 97665 : memset(&fxreq, 0, sizeof(fxreq));
556 97665 : memset(&fastreq, 0, sizeof(fastreq));
557 :
558 97665 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST);
559 97665 : if (pa == NULL) {
560 52850 : if (tgs_ac && r->fast_asserted) {
561 1 : kdc_log(r->context, r->config, 1,
562 : "Client asserted FAST but did not include FX-FAST pa-data");
563 1 : ret = KRB5KRB_AP_ERR_MODIFIED;
564 1 : goto out;
565 : }
566 :
567 52849 : kdc_log(r->context, r->config, 10, "Not a FAST request");
568 52849 : return 0;
569 : }
570 :
571 46473 : ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data,
572 44815 : pa->padata_value.length,
573 : &fxreq,
574 : &len);
575 44815 : if (ret) {
576 0 : kdc_log(r->context, r->config, 4,
577 : "Failed to decode PA-FX-FAST-REQUEST: %d", ret);
578 0 : goto out;
579 : }
580 :
581 44815 : if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) {
582 1 : kdc_log(r->context, r->config, 4,
583 : "PA-FX-FAST-REQUEST contains unknown type: %d",
584 1 : (int)fxreq.element);
585 1 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
586 1 : goto out;
587 : }
588 :
589 : /*
590 : * If check for armor data or it's not a TGS-REQ with implicit
591 : * armor.
592 : */
593 44814 : if (fxreq.u.armored_data.armor == NULL && tgs_ac == NULL) {
594 1 : kdc_log(r->context, r->config, 4,
595 : "AS-REQ armor missing");
596 1 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
597 1 : goto out;
598 : }
599 :
600 44813 : r->explicit_armor_present = fxreq.u.armored_data.armor != NULL && tgs_ac != NULL;
601 :
602 : /*
603 : *
604 : */
605 44813 : if (fxreq.u.armored_data.armor != NULL) {
606 0 : krb5uint32 kvno;
607 801 : krb5uint32 *kvno_ptr = NULL;
608 :
609 801 : if (fxreq.u.armored_data.armor->armor_type != 1) {
610 2 : kdc_log(r->context, r->config, 4,
611 : "Incorrect AS-REQ armor type");
612 2 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
613 8 : goto out;
614 : }
615 :
616 799 : ret = krb5_decode_ap_req(r->context,
617 799 : &fxreq.u.armored_data.armor->armor_value,
618 : &ap_req);
619 799 : if(ret) {
620 0 : kdc_log(r->context, r->config, 4, "Failed to decode AP-REQ");
621 0 : goto out;
622 : }
623 :
624 : /* Save that principal that was in the request */
625 799 : ret = _krb5_principalname2krb5_principal(r->context,
626 : &armor_server_principal,
627 : ap_req.ticket.sname,
628 : ap_req.ticket.realm);
629 799 : if (ret) {
630 0 : free_AP_REQ(&ap_req);
631 0 : goto out;
632 : }
633 :
634 799 : if (ap_req.ticket.enc_part.kvno != NULL) {
635 799 : kvno = *ap_req.ticket.enc_part.kvno;
636 799 : kvno_ptr = &kvno;
637 : }
638 :
639 799 : ret = _kdc_db_fetch(r->context, r->config, armor_server_principal,
640 : HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS,
641 : kvno_ptr,
642 : &r->armor_serverdb, &r->armor_server);
643 799 : if(ret == HDB_ERR_NOT_FOUND_HERE) {
644 0 : free_AP_REQ(&ap_req);
645 0 : kdc_log(r->context, r->config, 5,
646 : "Armor key does not have secrets at this KDC, "
647 : "need to proxy");
648 0 : goto out;
649 799 : } else if (ret) {
650 4 : free_AP_REQ(&ap_req);
651 4 : ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
652 4 : goto out;
653 : }
654 :
655 795 : ret = hdb_enctype2key(r->context, r->armor_server, NULL,
656 : ap_req.ticket.enc_part.etype,
657 : &r->armor_key);
658 795 : if (ret) {
659 1 : free_AP_REQ(&ap_req);
660 1 : goto out;
661 : }
662 :
663 794 : ret = krb5_verify_ap_req2(r->context, &ac,
664 : &ap_req,
665 : armor_server_principal,
666 794 : &r->armor_key->key,
667 : 0,
668 : &ap_req_options,
669 : &r->armor_ticket,
670 : KRB5_KU_AP_REQ_AUTH);
671 794 : free_AP_REQ(&ap_req);
672 794 : if (ret)
673 1 : goto out;
674 :
675 793 : ret = krb5_unparse_name(r->context, armor_server_principal,
676 : &armor_server_principal_name);
677 793 : if (ret)
678 0 : goto out;
679 :
680 : /* FIXME krb5_verify_ap_req2() also checks this */
681 793 : ret = _kdc_verify_flags(r->context, r->config,
682 793 : &r->armor_ticket->ticket,
683 : armor_server_principal_name);
684 793 : if (ret) {
685 0 : kdc_audit_addreason((kdc_request_t)r,
686 : "Armor TGT expired or invalid");
687 0 : goto out;
688 : }
689 793 : ticket = r->armor_ticket;
690 : } else {
691 44012 : heim_assert(tgs_ticket != NULL, "TGS authentication context without ticket");
692 44012 : ac = tgs_ac;
693 44012 : ticket = tgs_ticket;
694 : }
695 :
696 44805 : (void) krb5_unparse_name(r->context, ticket->client, &armor_client_principal_name);
697 44805 : kdc_audit_addkv((kdc_request_t)r, 0, "armor_client_name", "%s",
698 44805 : armor_client_principal_name ?
699 : armor_client_principal_name :
700 : "<out of memory>");
701 :
702 44805 : if (ac->remote_subkey == NULL) {
703 1 : krb5_auth_con_free(r->context, ac);
704 1 : kdc_log(r->context, r->config, 2,
705 : "FAST AP-REQ remote subkey missing");
706 1 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
707 1 : goto out;
708 : }
709 :
710 46462 : r->fast.flags.kdc_verified =
711 44804 : !_kdc_is_anonymous_pkinit(r->context, ticket->client);
712 :
713 44804 : ret = _krb5_fast_armor_key(r->context,
714 44804 : ac->remote_subkey,
715 44804 : &ticket->ticket.key,
716 : &armorkey,
717 44804 : r->explicit_armor_present ? NULL : &r->armor_crypto);
718 44804 : if (ret)
719 0 : goto out;
720 :
721 44804 : if (r->explicit_armor_present) {
722 324 : ret = _krb5_fast_explicit_armor_key(r->context,
723 : &armorkey,
724 : tgs_ac->remote_subkey,
725 : &explicit_armorkey,
726 : &r->armor_crypto);
727 324 : if (ret)
728 0 : goto out;
729 :
730 324 : krb5_free_keyblock_contents(r->context, &explicit_armorkey);
731 : }
732 :
733 44804 : krb5_free_keyblock_contents(r->context, &armorkey);
734 :
735 44804 : ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto,
736 : KRB5_KU_FAST_ENC,
737 : &fxreq.u.armored_data.enc_fast_req,
738 : &data);
739 44804 : if (ret) {
740 0 : kdc_log(r->context, r->config, 2,
741 : "Failed to decrypt FAST request");
742 0 : goto out;
743 : }
744 :
745 44804 : ret = decode_KrbFastReq(data.data, data.length, &fastreq, NULL);
746 44804 : krb5_data_free(&data);
747 44804 : if (ret)
748 0 : goto out;
749 :
750 : /*
751 : * verify req-checksum of the outer body
752 : */
753 44804 : if (tgs_ac) {
754 : /*
755 : * -- For TGS, contains the checksum performed over the type
756 : * -- AP-REQ in the PA-TGS-REQ padata.
757 : */
758 44335 : i = 0;
759 44335 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ);
760 44335 : if (pa == NULL) {
761 0 : kdc_log(r->context, r->config, 4,
762 : "FAST TGS request missing TGS-REQ padata");
763 0 : ret = KRB5KRB_ERR_GENERIC;
764 0 : goto out;
765 : }
766 :
767 45993 : ret = _kdc_verify_checksum(r->context, r->armor_crypto,
768 : KRB5_KU_FAST_REQ_CHKSUM,
769 44335 : &pa->padata_value,
770 : &fxreq.u.armored_data.req_checksum);
771 44335 : if (ret) {
772 0 : kdc_log(r->context, r->config, 2,
773 : "Bad checksum in FAST TGS request");
774 0 : goto out;
775 : }
776 : } else {
777 : /*
778 : * -- For AS, contains the checksum performed over the type
779 : * -- KDC-REQ-BODY for the req-body field of the KDC-REQ
780 : * -- structure;
781 : */
782 469 : ret = _kdc_verify_checksum(r->context, r->armor_crypto,
783 : KRB5_KU_FAST_REQ_CHKSUM,
784 469 : &r->req.req_body._save,
785 : &fxreq.u.armored_data.req_checksum);
786 469 : if (ret) {
787 0 : kdc_log(r->context, r->config, 2,
788 : "Bad checksum in FAST AS request");
789 0 : goto out;
790 : }
791 : }
792 :
793 : /*
794 : * check for unsupported mandatory options
795 : */
796 44804 : if (FastOptions2int(fastreq.fast_options) & 0xfffc) {
797 1 : kdc_log(r->context, r->config, 2,
798 : "FAST unsupported mandatory option set");
799 1 : ret = KRB5_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS;
800 1 : goto out;
801 : }
802 :
803 44803 : r->fast.flags.requested_hidden_names = fastreq.fast_options.hide_client_names;
804 :
805 : /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */
806 44803 : if (r->req.padata)
807 44803 : free_METHOD_DATA(r->req.padata);
808 : else
809 0 : ALLOC(r->req.padata);
810 :
811 44803 : ret = copy_METHOD_DATA(&fastreq.padata, r->req.padata);
812 44803 : if (ret)
813 0 : goto out;
814 :
815 44803 : free_KDC_REQ_BODY(&r->req.req_body);
816 44803 : ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body);
817 44803 : if (ret)
818 0 : goto out;
819 :
820 44803 : kdc_log(r->context, r->config, 5, "Client selected FAST");
821 :
822 44816 : out:
823 44816 : if (ac && ac != tgs_ac)
824 793 : krb5_auth_con_free(r->context, ac);
825 :
826 44816 : krb5_free_principal(r->context, armor_server_principal);
827 44816 : krb5_xfree(armor_client_principal_name);
828 44816 : krb5_xfree(armor_server_principal_name);
829 :
830 44816 : free_KrbFastReq(&fastreq);
831 44816 : free_PA_FX_FAST_REQUEST(&fxreq);
832 :
833 44816 : return ret;
834 : }
835 :
836 : /*
837 : *
838 : */
839 : krb5_error_code
840 103321 : _kdc_fast_unwrap_request(astgs_request_t r,
841 : krb5_ticket *tgs_ticket,
842 : krb5_auth_context tgs_ac)
843 : {
844 3413 : krb5_error_code ret;
845 3413 : const PA_DATA *pa;
846 103321 : int i = 0;
847 :
848 103321 : if (!r->config->enable_fast)
849 5656 : return 0;
850 :
851 97665 : ret = fast_unwrap_request(r, tgs_ticket, tgs_ac);
852 97665 : if (ret)
853 13 : return ret;
854 :
855 97652 : if (r->config->enable_fast_cookie) {
856 : /*
857 : * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
858 : */
859 0 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE);
860 0 : if (pa) {
861 0 : krb5_const_principal ticket_client = NULL;
862 :
863 0 : if (tgs_ticket)
864 0 : ticket_client = tgs_ticket->client;
865 :
866 0 : ret = fast_parse_cookie(r, ticket_client, pa);
867 : }
868 : }
869 :
870 94239 : return ret;
871 : }
872 :
873 : /*
874 : * Strengthen reply key by mixing with a random key that is
875 : * protected by FAST.
876 : */
877 : krb5_error_code
878 81457 : _kdc_fast_strengthen_reply_key(astgs_request_t r)
879 : {
880 81457 : if (r->armor_crypto) {
881 1658 : krb5_keyblock new_reply_key;
882 1658 : krb5_error_code ret;
883 :
884 44495 : kdc_log(r->context, r->config, 5,
885 : "FAST strengthen reply key with strengthen-key");
886 :
887 44495 : heim_assert(r->reply_key.keytype != KRB5_ENCTYPE_NULL, "NULL reply key enctype");
888 :
889 44495 : ret = krb5_generate_random_keyblock(r->context, r->reply_key.keytype,
890 : &r->strengthen_key);
891 44495 : if (ret) {
892 0 : kdc_log(r->context, r->config, 0, "failed to prepare random keyblock");
893 0 : return ret;
894 : }
895 :
896 44495 : ret = _krb5_fast_cf2(r->context,
897 : &r->strengthen_key, "strengthenkey",
898 : &r->reply_key, "replykey",
899 : &new_reply_key, NULL);
900 44495 : if (ret)
901 0 : return ret;
902 :
903 44495 : krb5_free_keyblock_contents(r->context, &r->reply_key);
904 44495 : r->reply_key = new_reply_key;
905 : }
906 :
907 78629 : return 0;
908 : }
909 :
910 : /*
911 : * Zero and free KDCFastState
912 : */
913 : void
914 104689 : _kdc_free_fast_state(KDCFastState *state)
915 : {
916 3413 : size_t i;
917 :
918 104689 : for (i = 0; i < state->fast_state.len; i++) {
919 0 : PA_DATA *pa = &state->fast_state.val[i];
920 :
921 0 : if (pa->padata_value.data)
922 0 : memset_s(pa->padata_value.data, 0,
923 0 : pa->padata_value.length, pa->padata_value.length);
924 : }
925 104689 : free_KDCFastState(state);
926 104689 : }
927 :
928 : krb5_error_code
929 792 : _kdc_fast_check_armor_pac(astgs_request_t r, int flags)
930 : {
931 0 : krb5_error_code ret;
932 792 : krb5_boolean ad_kdc_issued = FALSE;
933 792 : krb5_pac mspac = NULL;
934 792 : krb5_principal armor_client_principal = NULL;
935 0 : HDB *armor_db;
936 792 : hdb_entry *armor_client = NULL;
937 792 : char *armor_client_principal_name = NULL;
938 :
939 792 : flags |= HDB_F_ARMOR_PRINCIPAL;
940 792 : if (_kdc_synthetic_princ_used_p(r->context, r->armor_ticket))
941 0 : flags |= HDB_F_SYNTHETIC_OK;
942 792 : if (r->req.req_body.kdc_options.canonicalize)
943 71 : flags |= HDB_F_CANON;
944 :
945 792 : ret = _krb5_principalname2krb5_principal(r->context,
946 : &armor_client_principal,
947 792 : r->armor_ticket->ticket.cname,
948 792 : r->armor_ticket->ticket.crealm);
949 792 : if (ret)
950 0 : goto out;
951 :
952 792 : ret = krb5_unparse_name(r->context, armor_client_principal,
953 : &armor_client_principal_name);
954 792 : if (ret)
955 0 : goto out;
956 :
957 792 : ret = _kdc_db_fetch_client(r->context, r->config, flags,
958 : armor_client_principal, armor_client_principal_name,
959 792 : r->req.req_body.realm, &armor_db, &armor_client);
960 792 : if (ret)
961 0 : goto out;
962 :
963 792 : ret = kdc_check_flags(r, FALSE, armor_client, NULL);
964 792 : if (ret)
965 0 : goto out;
966 :
967 792 : ret = _kdc_check_pac(r, armor_client_principal, NULL,
968 : armor_client, r->armor_server,
969 : r->armor_server, r->armor_server,
970 792 : &r->armor_key->key, &r->armor_key->key,
971 792 : &r->armor_ticket->ticket, &ad_kdc_issued, &mspac, NULL, NULL);
972 792 : if (ret) {
973 16 : const char *msg = krb5_get_error_message(r->context, ret);
974 :
975 16 : kdc_log(r->context, r->config, 4,
976 : "Verify armor PAC (%s) failed for %s (%s) from %s with %s (%s)",
977 : armor_client_principal_name, r->cname, r->sname,
978 16 : r->from, msg, mspac ? "Ticket unsigned" : "No PAC");
979 :
980 16 : krb5_free_error_message(r->context, msg);
981 :
982 16 : goto out;
983 : }
984 :
985 776 : r->armor_clientdb = armor_db;
986 776 : armor_db = NULL;
987 :
988 776 : r->armor_client = armor_client;
989 776 : armor_client = NULL;
990 :
991 776 : r->armor_pac = mspac;
992 776 : mspac = NULL;
993 :
994 792 : out:
995 792 : krb5_xfree(armor_client_principal_name);
996 792 : if (armor_client)
997 16 : _kdc_free_ent(r->context, armor_db, armor_client);
998 792 : krb5_free_principal(r->context, armor_client_principal);
999 792 : krb5_pac_free(r->context, mspac);
1000 :
1001 792 : return ret;
1002 : }
|