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 1177 : 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 : krb5_error_code ret;
46 1177 : krb5_principal client_princ = NULL;
47 : krb5_data salt;
48 : krb5_keyblock dkey;
49 : size_t size;
50 :
51 1177 : *salted_crypto = NULL;
52 :
53 1177 : krb5_data_zero(&salt);
54 1177 : krb5_keyblock_zero(&dkey);
55 :
56 1177 : if (salt_principal == NULL) {
57 1 : if (r->req.req_body.cname == NULL) {
58 0 : ret = KRB5KRB_ERR_GENERIC;
59 0 : goto out;
60 : }
61 :
62 2 : ret = _krb5_principalname2krb5_principal(r->context, &client_princ,
63 1 : *(r->req.req_body.cname),
64 : r->req.req_body.realm);
65 1 : if (ret)
66 0 : goto out;
67 :
68 1 : salt_principal = client_princ;
69 : }
70 :
71 1177 : ret = krb5_unparse_name(r->context, salt_principal, (char **)&salt.data);
72 1177 : if (ret)
73 0 : goto out;
74 :
75 1177 : salt.length = strlen(salt.data);
76 :
77 1177 : kdc_log(r->context, r->config, 10,
78 : "salt_fastuser_crypto: salt principal is %s (%d)",
79 1177 : (char *)salt.data, enctype);
80 :
81 1177 : ret = krb5_enctype_keysize(r->context, enctype, &size);
82 1177 : if (ret)
83 0 : goto out;
84 :
85 1177 : ret = krb5_crypto_prfplus(r->context, fast_crypto, &salt,
86 : size, &dkey.keyvalue);
87 1177 : if (ret)
88 0 : goto out;
89 :
90 1177 : dkey.keytype = enctype;
91 :
92 1177 : ret = krb5_crypto_init(r->context, &dkey, ENCTYPE_NULL, salted_crypto);
93 1177 : if (ret)
94 0 : goto out;
95 :
96 2354 : out:
97 1177 : krb5_free_keyblock_contents(r->context, &dkey);
98 1177 : krb5_data_free(&salt);
99 1177 : krb5_free_principal(r->context, client_princ);
100 :
101 1177 : return ret;
102 : }
103 :
104 : static krb5_error_code
105 1177 : get_fastuser_crypto(astgs_request_t r,
106 : krb5_const_principal ticket_client,
107 : krb5_enctype enctype,
108 : krb5_crypto *crypto)
109 : {
110 : krb5_principal fast_princ;
111 : HDB *fast_db;
112 1177 : hdb_entry *fast_user = NULL;
113 1177 : Key *cookie_key = NULL;
114 1177 : krb5_crypto fast_crypto = NULL;
115 : krb5_error_code ret;
116 :
117 1177 : *crypto = NULL;
118 :
119 1177 : ret = krb5_make_principal(r->context, &fast_princ,
120 : KRB5_WELLKNOWN_ORG_H5L_REALM,
121 : KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL);
122 1177 : if (ret)
123 0 : goto out;
124 :
125 1177 : ret = _kdc_db_fetch(r->context, r->config, fast_princ,
126 : HDB_F_GET_FAST_COOKIE, NULL, &fast_db, &fast_user);
127 1177 : if (ret)
128 0 : goto out;
129 :
130 1177 : if (enctype == KRB5_ENCTYPE_NULL)
131 1176 : ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
132 : "fast-cookie", &enctype, &cookie_key);
133 : else
134 1 : ret = hdb_enctype2key(r->context, fast_user, NULL,
135 : enctype, &cookie_key);
136 1177 : if (ret)
137 0 : goto out;
138 :
139 1177 : ret = krb5_crypto_init(r->context, &cookie_key->key,
140 : ENCTYPE_NULL, &fast_crypto);
141 1177 : if (ret)
142 0 : goto out;
143 :
144 2354 : ret = salt_fastuser_crypto(r, ticket_client,
145 1177 : cookie_key->key.keytype,
146 : fast_crypto, crypto);
147 1177 : if (ret)
148 0 : goto out;
149 :
150 2354 : out:
151 1177 : if (fast_user)
152 1177 : _kdc_free_ent(r->context, fast_db, fast_user);
153 1177 : if (fast_crypto)
154 1177 : krb5_crypto_destroy(r->context, fast_crypto);
155 1177 : krb5_free_principal(r->context, fast_princ);
156 :
157 1177 : return ret;
158 : }
159 :
160 :
161 : static krb5_error_code
162 1 : fast_parse_cookie(astgs_request_t r,
163 : krb5_const_principal ticket_client,
164 : const PA_DATA *pa)
165 : {
166 1 : krb5_crypto crypto = NULL;
167 : krb5_error_code ret;
168 : KDCFastCookie data;
169 : krb5_data d1;
170 : size_t len;
171 :
172 1 : ret = decode_KDCFastCookie(pa->padata_value.data,
173 : pa->padata_value.length,
174 : &data, &len);
175 1 : if (ret)
176 0 : return ret;
177 :
178 1 : 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 1 : ret = get_fastuser_crypto(r, ticket_client, data.cookie.etype, &crypto);
184 1 : if (ret)
185 0 : goto out;
186 :
187 1 : ret = krb5_decrypt_EncryptedData(r->context, crypto,
188 : KRB5_KU_H5L_COOKIE,
189 : &data.cookie, &d1);
190 1 : krb5_crypto_destroy(r->context, crypto);
191 1 : if (ret)
192 0 : goto out;
193 :
194 1 : ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len);
195 1 : krb5_data_free(&d1);
196 1 : if (ret)
197 0 : goto out;
198 :
199 1 : 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 2 : out:
206 1 : free_KDCFastCookie(&data);
207 :
208 1 : return ret;
209 : }
210 :
211 : static krb5_error_code
212 1176 : fast_add_cookie(astgs_request_t r,
213 : krb5_const_principal ticket_client,
214 : METHOD_DATA *method_data)
215 : {
216 1176 : krb5_crypto crypto = NULL;
217 : KDCFastCookie shell;
218 : krb5_error_code ret;
219 : krb5_data data;
220 : size_t size;
221 :
222 1176 : memset(&shell, 0, sizeof(shell));
223 :
224 1176 : r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME;
225 :
226 1176 : ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length,
227 : &r->fast, &size, ret);
228 1176 : if (ret)
229 0 : return ret;
230 1176 : heim_assert(size == data.length, "internal asn.1 encoder error");
231 :
232 1176 : ret = get_fastuser_crypto(r, ticket_client, KRB5_ENCTYPE_NULL, &crypto);
233 1176 : 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 1176 : ret = krb5_encrypt_EncryptedData(r->context, crypto,
240 : KRB5_KU_H5L_COOKIE,
241 : data.data, data.length, 0,
242 : &shell.cookie);
243 1176 : krb5_crypto_destroy(r->context, crypto);
244 1176 : if (ret)
245 0 : goto out;
246 :
247 1176 : krb5_data_free(&data);
248 :
249 1176 : shell.version = "H5L1";
250 :
251 1176 : ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length,
252 : &shell, &size, ret);
253 1176 : free_EncryptedData(&shell.cookie);
254 1176 : if (ret)
255 0 : goto out;
256 1176 : heim_assert(size == data.length, "internal asn.1 encoder error");
257 :
258 1176 : ret = krb5_padata_add(r->context, method_data,
259 : KRB5_PADATA_FX_COOKIE,
260 : data.data, data.length);
261 1176 : if (ret == 0)
262 1176 : krb5_data_zero(&data);
263 :
264 1176 : out:
265 1176 : krb5_data_free(&data);
266 1176 : return ret;
267 : }
268 :
269 : krb5_error_code
270 32108 : _kdc_fast_mk_response(krb5_context context,
271 : krb5_crypto armor_crypto,
272 : METHOD_DATA *pa_data,
273 : krb5_keyblock *strengthen_key,
274 : KrbFastFinished *finished,
275 : krb5uint32 nonce,
276 : krb5_data *data)
277 : {
278 : PA_FX_FAST_REPLY fxfastrep;
279 : KrbFastResponse fastrep;
280 : krb5_error_code ret;
281 : krb5_data buf;
282 : size_t size;
283 :
284 32108 : memset(&fxfastrep, 0, sizeof(fxfastrep));
285 32108 : memset(&fastrep, 0, sizeof(fastrep));
286 32108 : krb5_data_zero(data);
287 :
288 32108 : if (pa_data) {
289 32108 : fastrep.padata.val = pa_data->val;
290 32108 : fastrep.padata.len = pa_data->len;
291 : }
292 32108 : fastrep.strengthen_key = strengthen_key;
293 32108 : fastrep.finished = finished;
294 32108 : fastrep.nonce = nonce;
295 :
296 32108 : ASN1_MALLOC_ENCODE(KrbFastResponse, buf.data, buf.length,
297 : &fastrep, &size, ret);
298 32108 : if (ret)
299 0 : return ret;
300 32108 : heim_assert(size == buf.length, "internal asn.1 encoder error");
301 :
302 32108 : fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data;
303 :
304 32108 : ret = krb5_encrypt_EncryptedData(context,
305 : armor_crypto,
306 : KRB5_KU_FAST_REP,
307 : buf.data,
308 : buf.length,
309 : 0,
310 : &fxfastrep.u.armored_data.enc_fast_rep);
311 32108 : krb5_data_free(&buf);
312 32108 : if (ret)
313 0 : return ret;
314 :
315 32108 : ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, data->data, data->length,
316 : &fxfastrep, &size, ret);
317 32108 : free_PA_FX_FAST_REPLY(&fxfastrep);
318 32108 : if (ret)
319 0 : return ret;
320 32108 : heim_assert(size == data->length, "internal asn.1 encoder error");
321 :
322 32108 : return 0;
323 : }
324 :
325 :
326 : krb5_error_code
327 21649 : _kdc_fast_mk_error(astgs_request_t r,
328 : METHOD_DATA *error_method,
329 : krb5_crypto armor_crypto,
330 : const KDC_REQ_BODY *req_body,
331 : krb5_error_code outer_error,
332 : krb5_principal error_client,
333 : krb5_principal error_server,
334 : time_t *csec, int *cusec,
335 : krb5_data *error_msg)
336 : {
337 : krb5_error_code ret;
338 : krb5_data e_data;
339 : size_t size;
340 :
341 21649 : krb5_data_zero(&e_data);
342 :
343 21649 : heim_assert(r != NULL, "invalid request in _kdc_fast_mk_error");
344 :
345 : /*
346 : * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
347 : */
348 21649 : if (armor_crypto || r->fast.fast_state.len) {
349 1176 : kdc_log(r->context, r->config, 5, "Adding FAST cookie for KRB-ERROR");
350 1176 : ret = fast_add_cookie(r, error_client, error_method);
351 1176 : if (ret) {
352 0 : kdc_log(r->context, r->config, 1,
353 : "Failed to add FAST cookie: %d", ret);
354 0 : free_METHOD_DATA(error_method);
355 0 : return ret;
356 : }
357 : }
358 :
359 21649 : if (armor_crypto) {
360 : PA_FX_FAST_REPLY fxfastrep;
361 : KrbFastResponse fastrep;
362 :
363 1176 : memset(&fxfastrep, 0, sizeof(fxfastrep));
364 1176 : memset(&fastrep, 0, sizeof(fastrep));
365 :
366 1176 : kdc_log(r->context, r->config, 5, "Making FAST inner KRB-ERROR");
367 :
368 : /* first add the KRB-ERROR to the fast errors */
369 :
370 1176 : ret = krb5_mk_error(r->context,
371 : outer_error,
372 : r->e_text,
373 : NULL,
374 : error_client,
375 : error_server,
376 : NULL,
377 : NULL,
378 : &e_data);
379 1176 : if (ret) {
380 0 : kdc_log(r->context, r->config, 1,
381 : "Failed to make inner KRB-ERROR: %d", ret);
382 0 : return ret;
383 : }
384 :
385 1176 : ret = krb5_padata_add(r->context, error_method,
386 : KRB5_PADATA_FX_ERROR,
387 : e_data.data, e_data.length);
388 1176 : if (ret) {
389 0 : kdc_log(r->context, r->config, 1,
390 : "Failed to make add FAST PADATA to inner KRB-ERROR: %d", ret);
391 0 : krb5_data_free(&e_data);
392 0 : return ret;
393 : }
394 :
395 1176 : r->e_text = NULL;
396 1176 : if (r->fast.flags.requested_hidden_names) {
397 1175 : error_client = NULL;
398 1175 : error_server = NULL;
399 : }
400 1176 : csec = 0;
401 1176 : cusec = 0;
402 :
403 1176 : ret = _kdc_fast_mk_response(r->context, armor_crypto,
404 : error_method, NULL, NULL,
405 1176 : req_body->nonce, &e_data);
406 1176 : free_METHOD_DATA(error_method);
407 1176 : if (ret) {
408 0 : kdc_log(r->context, r->config, 1,
409 : "Failed to make outer KRB-ERROR: %d", ret);
410 0 : return ret;
411 : }
412 :
413 1176 : ret = krb5_padata_add(r->context, error_method,
414 : KRB5_PADATA_FX_FAST,
415 : e_data.data, e_data.length);
416 1176 : if (ret) {
417 0 : kdc_log(r->context, r->config, 1,
418 : "Failed to make add FAST PADATA to outer KRB-ERROR: %d", ret);
419 0 : return ret;
420 : }
421 : } else
422 20473 : kdc_log(r->context, r->config, 5, "Making non-FAST KRB-ERROR");
423 :
424 21649 : if (error_method && error_method->len) {
425 20169 : ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length,
426 : error_method, &size, ret);
427 20169 : if (ret) {
428 0 : kdc_log(r->context, r->config, 1,
429 : "Failed to make encode METHOD-DATA: %d", ret);
430 0 : return ret;
431 : }
432 20169 : heim_assert(size == e_data.length, "internal asn.1 encoder error");
433 : }
434 :
435 21649 : ret = krb5_mk_error(r->context,
436 : outer_error,
437 : r->e_text,
438 21649 : (e_data.length ? &e_data : NULL),
439 : error_client,
440 : error_server,
441 : csec,
442 : cusec,
443 : error_msg);
444 21649 : krb5_data_free(&e_data);
445 :
446 21649 : if (ret)
447 0 : kdc_log(r->context, r->config, 1,
448 : "Failed to make encode KRB-ERROR: %d", ret);
449 :
450 21649 : return ret;
451 : }
452 :
453 : static krb5_error_code
454 64111 : fast_unwrap_request(astgs_request_t r,
455 : krb5_ticket *tgs_ticket,
456 : krb5_auth_context tgs_ac)
457 : {
458 64111 : krb5_principal armor_server_principal = NULL;
459 64111 : char *armor_client_principal_name = NULL;
460 64111 : char *armor_server_principal_name = NULL;
461 : PA_FX_FAST_REQUEST fxreq;
462 64111 : krb5_auth_context ac = NULL;
463 64111 : krb5_ticket *ticket = NULL;
464 : krb5_flags ap_req_options;
465 : krb5_keyblock armorkey;
466 : krb5_keyblock explicit_armorkey;
467 : krb5_error_code ret;
468 : krb5_ap_req ap_req;
469 : KrbFastReq fastreq;
470 : const PA_DATA *pa;
471 : krb5_data data;
472 : size_t len;
473 64111 : int i = 0;
474 :
475 64111 : memset(&fxreq, 0, sizeof(fxreq));
476 64111 : memset(&fastreq, 0, sizeof(fastreq));
477 :
478 64111 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST);
479 64111 : if (pa == NULL) {
480 31956 : if (tgs_ac && r->fast_asserted) {
481 0 : kdc_log(r->context, r->config, 1,
482 : "Client asserted FAST but did not include FX-FAST pa-data");
483 0 : ret = KRB5KRB_AP_ERR_MODIFIED;
484 0 : goto out;
485 : }
486 :
487 31956 : kdc_log(r->context, r->config, 10, "Not a FAST request");
488 31956 : return 0;
489 : }
490 :
491 32155 : ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data,
492 : pa->padata_value.length,
493 : &fxreq,
494 : &len);
495 32155 : if (ret) {
496 0 : kdc_log(r->context, r->config, 4,
497 : "Failed to decode PA-FX-FAST-REQUEST: %d", ret);
498 0 : goto out;
499 : }
500 :
501 32155 : if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) {
502 0 : kdc_log(r->context, r->config, 4,
503 : "PA-FX-FAST-REQUEST contains unknown type: %d",
504 0 : (int)fxreq.element);
505 0 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
506 0 : goto out;
507 : }
508 :
509 : /*
510 : * If check for armor data or it's not a TGS-REQ with implicit
511 : * armor.
512 : */
513 32155 : if (fxreq.u.armored_data.armor == NULL && tgs_ac == NULL) {
514 0 : kdc_log(r->context, r->config, 4,
515 : "AS-REQ armor missing");
516 0 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
517 0 : goto out;
518 : }
519 :
520 32155 : r->explicit_armor_present = fxreq.u.armored_data.armor != NULL && tgs_ac != NULL;
521 :
522 : /*
523 : *
524 : */
525 32155 : if (fxreq.u.armored_data.armor != NULL) {
526 2 : if (fxreq.u.armored_data.armor->armor_type != 1) {
527 0 : kdc_log(r->context, r->config, 4,
528 : "Incorrect AS-REQ armor type");
529 0 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
530 0 : goto out;
531 : }
532 :
533 2 : ret = krb5_decode_ap_req(r->context,
534 2 : &fxreq.u.armored_data.armor->armor_value,
535 : &ap_req);
536 2 : if(ret) {
537 0 : kdc_log(r->context, r->config, 4, "Failed to decode AP-REQ");
538 0 : goto out;
539 : }
540 :
541 : /* Save that principal that was in the request */
542 2 : ret = _krb5_principalname2krb5_principal(r->context,
543 : &armor_server_principal,
544 : ap_req.ticket.sname,
545 : ap_req.ticket.realm);
546 2 : if (ret) {
547 0 : free_AP_REQ(&ap_req);
548 0 : goto out;
549 : }
550 :
551 4 : ret = _kdc_db_fetch(r->context, r->config, armor_server_principal,
552 : HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS,
553 2 : (krb5uint32 *)ap_req.ticket.enc_part.kvno,
554 : &r->armor_serverdb, &r->armor_server);
555 2 : if(ret == HDB_ERR_NOT_FOUND_HERE) {
556 0 : free_AP_REQ(&ap_req);
557 0 : kdc_log(r->context, r->config, 5,
558 : "Armor key does not have secrets at this KDC, "
559 : "need to proxy");
560 0 : goto out;
561 2 : } else if (ret) {
562 0 : free_AP_REQ(&ap_req);
563 0 : ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
564 0 : goto out;
565 : }
566 :
567 2 : ret = hdb_enctype2key(r->context, r->armor_server, NULL,
568 : ap_req.ticket.enc_part.etype,
569 : &r->armor_key);
570 2 : if (ret) {
571 0 : free_AP_REQ(&ap_req);
572 0 : goto out;
573 : }
574 :
575 4 : ret = krb5_verify_ap_req2(r->context, &ac,
576 : &ap_req,
577 : armor_server_principal,
578 2 : &r->armor_key->key,
579 : 0,
580 : &ap_req_options,
581 : &r->armor_ticket,
582 : KRB5_KU_AP_REQ_AUTH);
583 2 : free_AP_REQ(&ap_req);
584 2 : if (ret)
585 0 : goto out;
586 :
587 2 : ret = krb5_unparse_name(r->context, armor_server_principal,
588 : &armor_server_principal_name);
589 2 : if (ret)
590 0 : goto out;
591 :
592 : /* FIXME krb5_verify_ap_req2() also checks this */
593 4 : ret = _kdc_verify_flags(r->context, r->config,
594 2 : &r->armor_ticket->ticket,
595 : armor_server_principal_name);
596 2 : if (ret) {
597 0 : kdc_audit_addreason((kdc_request_t)r,
598 : "Armor TGT expired or invalid");
599 0 : goto out;
600 : }
601 2 : ticket = r->armor_ticket;
602 : } else {
603 32153 : heim_assert(tgs_ticket != NULL, "TGS authentication context without ticket");
604 32153 : ac = tgs_ac;
605 32153 : ticket = tgs_ticket;
606 : }
607 :
608 32155 : krb5_unparse_name(r->context, ticket->client, &armor_client_principal_name);
609 32155 : kdc_audit_addkv((kdc_request_t)r, 0, "armor_client_name", "%s",
610 32155 : armor_client_principal_name ? armor_client_principal_name : "<unknown>");
611 :
612 32155 : if (ac->remote_subkey == NULL) {
613 0 : krb5_auth_con_free(r->context, ac);
614 0 : kdc_log(r->context, r->config, 2,
615 : "FAST AP-REQ remote subkey missing");
616 0 : ret = KRB5KDC_ERR_PREAUTH_FAILED;
617 0 : goto out;
618 : }
619 :
620 32155 : r->fast.flags.kdc_verified =
621 32155 : !_kdc_is_anonymous_pkinit(r->context, ticket->client);
622 :
623 64310 : ret = _krb5_fast_armor_key(r->context,
624 32155 : ac->remote_subkey,
625 32155 : &ticket->ticket.key,
626 : &armorkey,
627 32155 : r->explicit_armor_present ? NULL : &r->armor_crypto);
628 32155 : if (ret)
629 0 : goto out;
630 :
631 32155 : if (r->explicit_armor_present) {
632 0 : ret = _krb5_fast_explicit_armor_key(r->context,
633 : &armorkey,
634 : tgs_ac->remote_subkey,
635 : &explicit_armorkey,
636 : &r->armor_crypto);
637 0 : if (ret)
638 0 : goto out;
639 :
640 0 : krb5_free_keyblock_contents(r->context, &explicit_armorkey);
641 : }
642 :
643 32155 : krb5_free_keyblock_contents(r->context, &armorkey);
644 :
645 32155 : ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto,
646 : KRB5_KU_FAST_ENC,
647 : &fxreq.u.armored_data.enc_fast_req,
648 : &data);
649 32155 : if (ret) {
650 0 : kdc_log(r->context, r->config, 2,
651 : "Failed to decrypt FAST request");
652 0 : goto out;
653 : }
654 :
655 32155 : ret = decode_KrbFastReq(data.data, data.length, &fastreq, NULL);
656 32155 : krb5_data_free(&data);
657 32155 : if (ret)
658 0 : goto out;
659 :
660 : /*
661 : * verify req-checksum of the outer body
662 : */
663 32155 : if (tgs_ac) {
664 : /*
665 : * -- For TGS, contains the checksum performed over the type
666 : * -- AP-REQ in the PA-TGS-REQ padata.
667 : */
668 32153 : i = 0;
669 32153 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ);
670 32153 : if (pa == NULL) {
671 0 : kdc_log(r->context, r->config, 4,
672 : "FAST TGS request missing TGS-REQ padata");
673 0 : ret = KRB5KRB_ERR_GENERIC;
674 0 : goto out;
675 : }
676 :
677 32153 : ret = _kdc_verify_checksum(r->context, r->armor_crypto,
678 : KRB5_KU_FAST_REQ_CHKSUM,
679 32153 : &pa->padata_value,
680 : &fxreq.u.armored_data.req_checksum);
681 32153 : if (ret) {
682 0 : kdc_log(r->context, r->config, 2,
683 : "Bad checksum in FAST TGS request");
684 0 : goto out;
685 : }
686 : } else {
687 : /*
688 : * -- For AS, contains the checksum performed over the type
689 : * -- KDC-REQ-BODY for the req-body field of the KDC-REQ
690 : * -- structure;
691 : */
692 2 : ret = _kdc_verify_checksum(r->context, r->armor_crypto,
693 : KRB5_KU_FAST_REQ_CHKSUM,
694 2 : &r->req.req_body._save,
695 : &fxreq.u.armored_data.req_checksum);
696 2 : if (ret) {
697 0 : kdc_log(r->context, r->config, 2,
698 : "Bad checksum in FAST AS request");
699 0 : goto out;
700 : }
701 : }
702 :
703 : /*
704 : * check for unsupported mandatory options
705 : */
706 32155 : if (FastOptions2int(fastreq.fast_options) & 0xfffc) {
707 0 : kdc_log(r->context, r->config, 2,
708 : "FAST unsupported mandatory option set");
709 0 : ret = KRB5_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS;
710 0 : goto out;
711 : }
712 :
713 32155 : r->fast.flags.requested_hidden_names = fastreq.fast_options.hide_client_names;
714 :
715 : /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */
716 32155 : if (r->req.padata)
717 32155 : free_METHOD_DATA(r->req.padata);
718 : else
719 0 : ALLOC(r->req.padata);
720 :
721 32155 : ret = copy_METHOD_DATA(&fastreq.padata, r->req.padata);
722 32155 : if (ret)
723 0 : goto out;
724 :
725 32155 : free_KDC_REQ_BODY(&r->req.req_body);
726 32155 : ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body);
727 32155 : if (ret)
728 0 : goto out;
729 :
730 32155 : kdc_log(r->context, r->config, 5, "Client selected FAST");
731 :
732 32155 : out:
733 32155 : if (ac && ac != tgs_ac)
734 2 : krb5_auth_con_free(r->context, ac);
735 :
736 32155 : krb5_free_principal(r->context, armor_server_principal);
737 32155 : krb5_xfree(armor_client_principal_name);
738 32155 : krb5_xfree(armor_server_principal_name);
739 :
740 32155 : free_KrbFastReq(&fastreq);
741 32155 : free_PA_FX_FAST_REQUEST(&fxreq);
742 :
743 32155 : return ret;
744 : }
745 :
746 : /*
747 : *
748 : */
749 : krb5_error_code
750 69670 : _kdc_fast_unwrap_request(astgs_request_t r,
751 : krb5_ticket *tgs_ticket,
752 : krb5_auth_context tgs_ac)
753 : {
754 : krb5_error_code ret;
755 : const PA_DATA *pa;
756 69670 : int i = 0;
757 :
758 69670 : if (!r->config->enable_fast)
759 5559 : return 0;
760 :
761 64111 : ret = fast_unwrap_request(r, tgs_ticket, tgs_ac);
762 64111 : if (ret)
763 0 : return ret;
764 :
765 : /*
766 : * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
767 : */
768 64111 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE);
769 64111 : if (pa) {
770 1 : krb5_const_principal ticket_client = NULL;
771 :
772 1 : if (tgs_ticket)
773 0 : ticket_client = tgs_ticket->client;
774 :
775 1 : ret = fast_parse_cookie(r, ticket_client, pa);
776 : }
777 :
778 64111 : return ret;
779 : }
780 :
781 : /*
782 : * Strengthen reply key by mixing with a random key that is
783 : * protected by FAST.
784 : */
785 : krb5_error_code
786 55569 : _kdc_fast_strengthen_reply_key(astgs_request_t r)
787 : {
788 55569 : if (r->armor_crypto) {
789 : krb5_keyblock new_reply_key;
790 : krb5_error_code ret;
791 :
792 32154 : kdc_log(r->context, r->config, 5,
793 : "FAST strengthen reply key with strengthen-key");
794 :
795 32154 : heim_assert(r->reply_key.keytype != KRB5_ENCTYPE_NULL, "NULL reply key enctype");
796 :
797 32154 : ret = krb5_generate_random_keyblock(r->context, r->reply_key.keytype,
798 : &r->strengthen_key);
799 32154 : if (ret)
800 0 : krb5_abortx(r->context, "random generator fail");
801 :
802 32154 : ret = _krb5_fast_cf2(r->context,
803 : &r->strengthen_key, "strengthenkey",
804 : &r->reply_key, "replykey",
805 : &new_reply_key, NULL);
806 32154 : if (ret)
807 0 : return ret;
808 :
809 32154 : krb5_free_keyblock_contents(r->context, &r->reply_key);
810 32154 : r->reply_key = new_reply_key;
811 : }
812 :
813 55569 : return 0;
814 : }
815 :
816 : /*
817 : * Zero and free KDCFastState
818 : */
819 : void
820 71023 : _kdc_free_fast_state(KDCFastState *state)
821 : {
822 : size_t i;
823 :
824 71023 : for (i = 0; i < state->fast_state.len; i++) {
825 0 : PA_DATA *pa = &state->fast_state.val[i];
826 :
827 0 : if (pa->padata_value.data)
828 0 : memset_s(pa->padata_value.data, 0,
829 0 : pa->padata_value.length, pa->padata_value.length);
830 : }
831 71023 : free_KDCFastState(state);
832 71023 : }
833 :
834 : krb5_error_code
835 0 : _kdc_fast_check_armor_pac(astgs_request_t r)
836 : {
837 : krb5_error_code ret;
838 : int flags;
839 0 : krb5_boolean ad_kdc_issued = FALSE;
840 0 : krb5_pac mspac = NULL;
841 0 : krb5_principal armor_client_principal = NULL;
842 : HDB *armor_db;
843 0 : hdb_entry *armor_client = NULL;
844 0 : char *armor_client_principal_name = NULL;
845 :
846 0 : flags = HDB_F_FOR_TGS_REQ;
847 0 : if (_kdc_synthetic_princ_used_p(r->context, r->armor_ticket))
848 0 : flags |= HDB_F_SYNTHETIC_OK;
849 0 : if (r->req.req_body.kdc_options.canonicalize)
850 0 : flags |= HDB_F_CANON;
851 :
852 0 : ret = _krb5_principalname2krb5_principal(r->context,
853 : &armor_client_principal,
854 0 : r->armor_ticket->ticket.cname,
855 0 : r->armor_ticket->ticket.crealm);
856 0 : if (ret)
857 0 : goto out;
858 :
859 0 : ret = krb5_unparse_name(r->context, armor_client_principal,
860 : &armor_client_principal_name);
861 0 : if (ret)
862 0 : goto out;
863 :
864 0 : ret = _kdc_db_fetch_client(r->context, r->config, flags,
865 : armor_client_principal, armor_client_principal_name,
866 0 : r->req.req_body.realm, &armor_db, &armor_client);
867 0 : if (ret)
868 0 : goto out;
869 :
870 0 : ret = kdc_check_flags(r, FALSE, armor_client, NULL);
871 0 : if (ret)
872 0 : goto out;
873 :
874 0 : ret = _kdc_check_pac(r, armor_client_principal, NULL,
875 : armor_client, r->armor_server,
876 : r->armor_server, r->armor_server,
877 0 : &r->armor_key->key, &r->armor_key->key,
878 0 : &r->armor_ticket->ticket, &ad_kdc_issued, &mspac, NULL, NULL);
879 0 : if (ret) {
880 0 : const char *msg = krb5_get_error_message(r->context, ret);
881 :
882 0 : kdc_log(r->context, r->config, 4,
883 : "Verify armor PAC (%s) failed for %s (%s) from %s with %s (%s)",
884 : armor_client_principal_name, r->cname, r->sname,
885 0 : r->from, msg, mspac ? "Ticket unsigned" : "No PAC");
886 :
887 0 : krb5_free_error_message(r->context, msg);
888 :
889 0 : goto out;
890 : }
891 :
892 0 : if (r->explicit_armor_present) {
893 0 : r->explicit_armor_clientdb = armor_db;
894 0 : armor_db = NULL;
895 :
896 0 : r->explicit_armor_client = armor_client;
897 0 : armor_client = NULL;
898 :
899 0 : r->explicit_armor_pac = mspac;
900 0 : mspac = NULL;
901 : }
902 :
903 0 : out:
904 0 : krb5_xfree(armor_client_principal_name);
905 0 : if (armor_client)
906 0 : _kdc_free_ent(r->context, armor_db, armor_client);
907 0 : krb5_free_principal(r->context, armor_client_principal);
908 0 : krb5_pac_free(r->context, mspac);
909 :
910 0 : return ret;
911 : }
|