1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kdc/kdc_preauth.c - Preauthentication routines for the KDC */ 3 /* 4 * Copyright 1995, 2003, 2007, 2009 by the Massachusetts Institute of 5 * Technology. All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 /* 27 * Copyright (C) 1998 by the FundsXpress, INC. 28 * 29 * All rights reserved. 30 * 31 * Export of this software from the United States of America may require 32 * a specific license from the United States Government. It is the 33 * responsibility of any person or organization contemplating export to 34 * obtain such a license before exporting. 35 * 36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 37 * distribute this software and its documentation for any purpose and 38 * without fee is hereby granted, provided that the above copyright 39 * notice appear in all copies and that both that copyright notice and 40 * this permission notice appear in supporting documentation, and that 41 * the name of FundsXpress. not be used in advertising or publicity pertaining 42 * to distribution of the software without specific, written prior 43 * permission. FundsXpress makes no representations about the suitability of 44 * this software for any purpose. It is provided "as is" without express 45 * or implied warranty. 46 * 47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 50 */ 51 /* 52 * Copyright (c) 2006-2008, Novell, Inc. 53 * All rights reserved. 54 * 55 * Redistribution and use in source and binary forms, with or without 56 * modification, are permitted provided that the following conditions are met: 57 * 58 * * Redistributions of source code must retain the above copyright notice, 59 * this list of conditions and the following disclaimer. 60 * * Redistributions in binary form must reproduce the above copyright 61 * notice, this list of conditions and the following disclaimer in the 62 * documentation and/or other materials provided with the distribution. 63 * * The copyright holder's name is not used to endorse or promote products 64 * derived from this software without specific prior written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 67 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 70 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 71 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 72 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 74 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 76 * POSSIBILITY OF SUCH DAMAGE. 77 */ 78 79 #include "k5-int.h" 80 #include "kdc_util.h" 81 #include "extern.h" 82 #include <stdio.h> 83 #include "adm_proto.h" 84 85 #include <syslog.h> 86 87 #include <assert.h> 88 #include <krb5/kdcpreauth_plugin.h> 89 90 /* Let freshness tokens be valid for ten minutes. */ 91 #define FRESHNESS_LIFETIME 600 92 93 typedef struct preauth_system_st { 94 const char *name; 95 int type; 96 int flags; 97 krb5_kdcpreauth_moddata moddata; 98 krb5_kdcpreauth_init_fn init; 99 krb5_kdcpreauth_fini_fn fini; 100 krb5_kdcpreauth_edata_fn get_edata; 101 krb5_kdcpreauth_verify_fn verify_padata; 102 krb5_kdcpreauth_return_fn return_padata; 103 krb5_kdcpreauth_free_modreq_fn free_modreq; 104 krb5_kdcpreauth_loop_fn loop; 105 } preauth_system; 106 107 static preauth_system *preauth_systems; 108 static size_t n_preauth_systems; 109 110 static krb5_error_code 111 make_etype_info(krb5_context context, krb5_boolean etype_info2, 112 krb5_principal client, krb5_key_data *client_key, 113 krb5_enctype enctype, krb5_data **der_out); 114 115 /* Get all available kdcpreauth vtables and a count of preauth types they 116 * support. Return an empty list on failure. */ 117 static void 118 get_plugin_vtables(krb5_context context, 119 struct krb5_kdcpreauth_vtable_st **vtables_out, 120 size_t *n_tables_out, size_t *n_systems_out) 121 { 122 krb5_plugin_initvt_fn *plugins = NULL, *pl; 123 struct krb5_kdcpreauth_vtable_st *vtables; 124 size_t count, n_tables, n_systems, i; 125 126 *vtables_out = NULL; 127 *n_tables_out = *n_systems_out = 0; 128 129 /* Auto-register encrypted challenge and (if possible) pkinit. */ 130 k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit", 131 "preauth"); 132 k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "otp", 133 "preauth"); 134 k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "spake", 135 "preauth"); 136 k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, 137 "encrypted_challenge", 138 kdcpreauth_encrypted_challenge_initvt); 139 k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, 140 "encrypted_timestamp", 141 kdcpreauth_encrypted_timestamp_initvt); 142 143 if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins)) 144 return; 145 for (count = 0; plugins[count]; count++); 146 vtables = calloc(count + 1, sizeof(*vtables)); 147 if (vtables == NULL) 148 goto cleanup; 149 for (pl = plugins, n_tables = 0; *pl != NULL; pl++) { 150 if ((*pl)(context, 1, 2, (krb5_plugin_vtable)&vtables[n_tables]) == 0) 151 n_tables++; 152 } 153 for (i = 0, n_systems = 0; i < n_tables; i++) { 154 for (count = 0; vtables[i].pa_type_list[count] != 0; count++); 155 n_systems += count; 156 } 157 *vtables_out = vtables; 158 *n_tables_out = n_tables; 159 *n_systems_out = n_systems; 160 161 cleanup: 162 k5_plugin_free_modules(context, plugins); 163 } 164 165 /* Make a list of realm names. The caller should free the list container but 166 * not the list elements (which are aliases into kdc_realmlist). */ 167 static krb5_error_code 168 get_realm_names(struct server_handle *handle, const char ***list_out) 169 { 170 const char **list; 171 int i; 172 173 list = calloc(handle->kdc_numrealms + 1, sizeof(*list)); 174 if (list == NULL) 175 return ENOMEM; 176 for (i = 0; i < handle->kdc_numrealms; i++) 177 list[i] = handle->kdc_realmlist[i]->realm_name; 178 list[i] = NULL; 179 *list_out = list; 180 return 0; 181 } 182 183 void 184 load_preauth_plugins(struct server_handle *handle, krb5_context context, 185 verto_ctx *ctx) 186 { 187 krb5_error_code ret; 188 struct krb5_kdcpreauth_vtable_st *vtables = NULL, *vt; 189 size_t n_systems, n_tables, i, j; 190 krb5_kdcpreauth_moddata moddata; 191 const char **realm_names = NULL, *emsg; 192 preauth_system *sys; 193 194 /* Get all available kdcpreauth vtables. */ 195 get_plugin_vtables(context, &vtables, &n_tables, &n_systems); 196 197 /* Allocate the list of static and plugin preauth systems. */ 198 preauth_systems = calloc(n_systems + 1, sizeof(preauth_system)); 199 if (preauth_systems == NULL) 200 goto cleanup; 201 202 if (get_realm_names(handle, &realm_names)) 203 goto cleanup; 204 205 /* Add the dynamically-loaded mechanisms to the list. */ 206 n_systems = 0; 207 for (i = 0; i < n_tables; i++) { 208 /* Try to initialize this module. */ 209 vt = &vtables[i]; 210 moddata = NULL; 211 if (vt->init) { 212 ret = vt->init(context, &moddata, realm_names); 213 if (ret) { 214 emsg = krb5_get_error_message(context, ret); 215 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to " 216 "initialize: %s"), vt->name, emsg); 217 krb5_free_error_message(context, emsg); 218 continue; 219 } 220 } 221 222 if (vt->loop) { 223 ret = vt->loop(context, moddata, ctx); 224 if (ret) { 225 emsg = krb5_get_error_message(context, ret); 226 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to setup " 227 "loop: %s"), vt->name, emsg); 228 krb5_free_error_message(context, emsg); 229 if (vt->fini) 230 vt->fini(context, moddata); 231 continue; 232 } 233 } 234 235 /* Add this module to the systems list once for each pa type. */ 236 for (j = 0; vt->pa_type_list[j] != 0; j++) { 237 sys = &preauth_systems[n_systems]; 238 sys->name = vt->name; 239 sys->type = vt->pa_type_list[j]; 240 sys->flags = (vt->flags) ? vt->flags(context, sys->type) : 0; 241 sys->moddata = moddata; 242 sys->init = vt->init; 243 /* Only call fini once for each plugin. */ 244 sys->fini = (j == 0) ? vt->fini : NULL; 245 sys->get_edata = vt->edata; 246 sys->verify_padata = vt->verify; 247 sys->return_padata = vt->return_padata; 248 sys->free_modreq = vt->free_modreq; 249 sys->loop = vt->loop; 250 n_systems++; 251 } 252 } 253 n_preauth_systems = n_systems; 254 /* Add the end-of-list marker. */ 255 preauth_systems[n_systems].name = "[end]"; 256 preauth_systems[n_systems].type = -1; 257 258 cleanup: 259 free(vtables); 260 free(realm_names); 261 } 262 263 void 264 unload_preauth_plugins(krb5_context context) 265 { 266 size_t i; 267 268 for (i = 0; i < n_preauth_systems; i++) { 269 if (preauth_systems[i].fini) 270 preauth_systems[i].fini(context, preauth_systems[i].moddata); 271 } 272 free(preauth_systems); 273 preauth_systems = NULL; 274 n_preauth_systems = 0; 275 } 276 277 /* 278 * The make_padata_context() function creates a space for storing any 279 * request-specific module data which will be needed by return_padata() later. 280 * Each preauth type gets a storage location of its own. 281 */ 282 struct request_pa_context { 283 int n_contexts; 284 struct { 285 preauth_system *pa_system; 286 krb5_kdcpreauth_modreq modreq; 287 } *contexts; 288 }; 289 290 static krb5_error_code 291 make_padata_context(krb5_context context, void **padata_context) 292 { 293 int i; 294 struct request_pa_context *ret; 295 296 ret = malloc(sizeof(*ret)); 297 if (ret == NULL) { 298 return ENOMEM; 299 } 300 301 ret->n_contexts = n_preauth_systems; 302 ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts); 303 if (ret->contexts == NULL) { 304 free(ret); 305 return ENOMEM; 306 } 307 308 memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts); 309 310 for (i = 0; i < ret->n_contexts; i++) { 311 ret->contexts[i].pa_system = &preauth_systems[i]; 312 ret->contexts[i].modreq = NULL; 313 } 314 315 *padata_context = ret; 316 317 return 0; 318 } 319 320 /* 321 * The free_padata_context function frees any context information pointers 322 * which the check_padata() function created but which weren't already cleaned 323 * up by return_padata(). 324 */ 325 void 326 free_padata_context(krb5_context kcontext, void *padata_context) 327 { 328 struct request_pa_context *context = padata_context; 329 preauth_system *sys; 330 int i; 331 332 if (context == NULL) 333 return; 334 for (i = 0; i < context->n_contexts; i++) { 335 sys = context->contexts[i].pa_system; 336 if (!sys->free_modreq || !context->contexts[i].modreq) 337 continue; 338 sys->free_modreq(kcontext, sys->moddata, context->contexts[i].modreq); 339 context->contexts[i].modreq = NULL; 340 } 341 342 free(context->contexts); 343 free(context); 344 } 345 346 static krb5_deltat 347 max_time_skew(krb5_context context, krb5_kdcpreauth_rock rock) 348 { 349 return context->clockskew; 350 } 351 352 static krb5_error_code 353 client_keys(krb5_context context, krb5_kdcpreauth_rock rock, 354 krb5_keyblock **keys_out) 355 { 356 krb5_kdc_req *request = rock->request; 357 krb5_db_entry *client = rock->client; 358 krb5_keyblock *keys, key; 359 krb5_key_data *entry_key; 360 int i, k; 361 362 keys = calloc(request->nktypes + 1, sizeof(krb5_keyblock)); 363 if (keys == NULL) 364 return ENOMEM; 365 366 k = 0; 367 for (i = 0; i < request->nktypes; i++) { 368 entry_key = NULL; 369 if (krb5_dbe_find_enctype(context, client, request->ktype[i], 370 -1, 0, &entry_key) != 0) 371 continue; 372 if (krb5_dbe_decrypt_key_data(context, NULL, entry_key, 373 &key, NULL) != 0) 374 continue; 375 keys[k++] = key; 376 } 377 if (k == 0) { 378 free(keys); 379 return ENOENT; 380 } 381 *keys_out = keys; 382 return 0; 383 } 384 385 static void free_keys(krb5_context context, krb5_kdcpreauth_rock rock, 386 krb5_keyblock *keys) 387 { 388 krb5_keyblock *k; 389 390 if (keys == NULL) 391 return; 392 for (k = keys; k->enctype != 0; k++) 393 krb5_free_keyblock_contents(context, k); 394 free(keys); 395 } 396 397 static krb5_data * 398 request_body(krb5_context context, krb5_kdcpreauth_rock rock) 399 { 400 return rock->inner_body; 401 } 402 403 static krb5_keyblock * 404 fast_armor(krb5_context context, krb5_kdcpreauth_rock rock) 405 { 406 return rock->rstate->armor_key; 407 } 408 409 static krb5_error_code 410 get_string(krb5_context context, krb5_kdcpreauth_rock rock, const char *key, 411 char **value_out) 412 { 413 return krb5_dbe_get_string(context, rock->client, key, value_out); 414 } 415 416 static void 417 free_string(krb5_context context, krb5_kdcpreauth_rock rock, char *string) 418 { 419 krb5_dbe_free_string(context, string); 420 } 421 422 static void * 423 client_entry(krb5_context context, krb5_kdcpreauth_rock rock) 424 { 425 return rock->client; 426 } 427 428 static verto_ctx * 429 event_context(krb5_context context, krb5_kdcpreauth_rock rock) 430 { 431 return rock->vctx; 432 } 433 434 static krb5_boolean 435 have_client_keys(krb5_context context, krb5_kdcpreauth_rock rock) 436 { 437 krb5_kdc_req *request = rock->request; 438 krb5_key_data *kd; 439 int i; 440 441 for (i = 0; i < request->nktypes; i++) { 442 if (krb5_dbe_find_enctype(context, rock->client, request->ktype[i], 443 -1, 0, &kd) == 0) 444 return TRUE; 445 } 446 return FALSE; 447 } 448 449 static const krb5_keyblock * 450 client_keyblock(krb5_context context, krb5_kdcpreauth_rock rock) 451 { 452 if (rock->client_keyblock->enctype == ENCTYPE_NULL) 453 return NULL; 454 return rock->client_keyblock; 455 } 456 457 static krb5_error_code 458 add_auth_indicator(krb5_context context, krb5_kdcpreauth_rock rock, 459 const char *indicator) 460 { 461 return authind_add(context, indicator, rock->auth_indicators); 462 } 463 464 static krb5_boolean 465 get_cookie(krb5_context context, krb5_kdcpreauth_rock rock, 466 krb5_preauthtype pa_type, krb5_data *out) 467 { 468 return kdc_fast_search_cookie(rock->rstate, pa_type, out); 469 } 470 471 static krb5_error_code 472 set_cookie(krb5_context context, krb5_kdcpreauth_rock rock, 473 krb5_preauthtype pa_type, const krb5_data *data) 474 { 475 return kdc_fast_set_cookie(rock->rstate, pa_type, data); 476 } 477 478 static krb5_boolean 479 match_client(krb5_context context, krb5_kdcpreauth_rock rock, 480 krb5_principal princ) 481 { 482 krb5_db_entry *ent; 483 krb5_boolean match = FALSE; 484 krb5_principal req_client = rock->request->client; 485 krb5_principal client = rock->client->princ; 486 487 /* Check for a direct match against the request principal or 488 * the post-canon client principal. */ 489 if (krb5_principal_compare_flags(context, princ, req_client, 490 KRB5_PRINCIPAL_COMPARE_ENTERPRISE) || 491 krb5_principal_compare(context, princ, client)) 492 return TRUE; 493 494 if (krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_CLIENT, &ent)) 495 return FALSE; 496 match = krb5_principal_compare(context, ent->princ, client); 497 krb5_db_free_principal(context, ent); 498 return match; 499 } 500 501 static krb5_principal 502 client_name(krb5_context context, krb5_kdcpreauth_rock rock) 503 { 504 return rock->client->princ; 505 } 506 507 static void 508 send_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock) 509 { 510 rock->send_freshness_token = TRUE; 511 } 512 513 static krb5_error_code 514 check_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock, 515 const krb5_data *token) 516 { 517 krb5_timestamp token_ts, now; 518 krb5_key_data *kd; 519 krb5_keyblock kb; 520 krb5_kvno token_kvno; 521 krb5_checksum cksum; 522 krb5_data d; 523 uint8_t *token_cksum; 524 size_t token_cksum_len; 525 krb5_boolean valid = FALSE; 526 char ckbuf[4]; 527 528 memset(&kb, 0, sizeof(kb)); 529 530 if (krb5_timeofday(context, &now) != 0) 531 goto cleanup; 532 533 if (token->length <= 8) 534 goto cleanup; 535 token_ts = load_32_be(token->data); 536 token_kvno = load_32_be(token->data + 4); 537 token_cksum = (uint8_t *)token->data + 8; 538 token_cksum_len = token->length - 8; 539 540 /* Check if the token timestamp is too old. */ 541 if (ts_after(now, ts_incr(token_ts, FRESHNESS_LIFETIME))) 542 goto cleanup; 543 544 /* Fetch and decrypt the local krbtgt key of the token's kvno. */ 545 if (krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, token_kvno, 546 &kd) != 0) 547 goto cleanup; 548 if (krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL) != 0) 549 goto cleanup; 550 551 /* Verify the token checksum against the current KDC time. The checksum 552 * must use the mandatory checksum type of the krbtgt key's enctype. */ 553 store_32_be(token_ts, ckbuf); 554 d = make_data(ckbuf, sizeof(ckbuf)); 555 cksum.magic = KV5M_CHECKSUM; 556 cksum.checksum_type = 0; 557 cksum.length = token_cksum_len; 558 cksum.contents = token_cksum; 559 (void)krb5_c_verify_checksum(context, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS, 560 &d, &cksum, &valid); 561 562 cleanup: 563 krb5_free_keyblock_contents(context, &kb); 564 return valid ? 0 : KRB5KDC_ERR_PREAUTH_EXPIRED; 565 } 566 567 static krb5_error_code 568 replace_reply_key(krb5_context context, krb5_kdcpreauth_rock rock, 569 const krb5_keyblock *key, krb5_boolean is_strengthen) 570 { 571 krb5_keyblock copy; 572 573 if (krb5_copy_keyblock_contents(context, key, ©) != 0) 574 return ENOMEM; 575 krb5_free_keyblock_contents(context, rock->client_keyblock); 576 *rock->client_keyblock = copy; 577 if (!is_strengthen) 578 rock->replaced_reply_key = TRUE; 579 return 0; 580 } 581 582 static struct krb5_kdcpreauth_callbacks_st callbacks = { 583 6, 584 max_time_skew, 585 client_keys, 586 free_keys, 587 request_body, 588 fast_armor, 589 get_string, 590 free_string, 591 client_entry, 592 event_context, 593 have_client_keys, 594 client_keyblock, 595 add_auth_indicator, 596 get_cookie, 597 set_cookie, 598 match_client, 599 client_name, 600 send_freshness_token, 601 check_freshness_token, 602 replace_reply_key 603 }; 604 605 static krb5_error_code 606 find_pa_system(int type, preauth_system **preauth) 607 { 608 preauth_system *ap; 609 610 if (preauth_systems == NULL) 611 return KRB5_PREAUTH_BAD_TYPE; 612 ap = preauth_systems; 613 while ((ap->type != -1) && (ap->type != type)) 614 ap++; 615 if (ap->type == -1) 616 return(KRB5_PREAUTH_BAD_TYPE); 617 *preauth = ap; 618 return 0; 619 } 620 621 /* Find a pointer to the request-specific module data for pa_sys. */ 622 static krb5_error_code 623 find_modreq(preauth_system *pa_sys, struct request_pa_context *context, 624 krb5_kdcpreauth_modreq **modreq_out) 625 { 626 int i; 627 628 *modreq_out = NULL; 629 if (context == NULL) 630 return KRB5KRB_ERR_GENERIC; 631 632 for (i = 0; i < context->n_contexts; i++) { 633 if (context->contexts[i].pa_system == pa_sys) { 634 *modreq_out = &context->contexts[i].modreq; 635 return 0; 636 } 637 } 638 639 return KRB5KRB_ERR_GENERIC; 640 } 641 642 /* 643 * Create a list of indices into the preauth_systems array, sorted by order of 644 * preference. 645 */ 646 static krb5_boolean 647 pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type) 648 { 649 while (*pa_data != NULL) { 650 if ((*pa_data)->pa_type == pa_type) 651 return TRUE; 652 pa_data++; 653 } 654 return FALSE; 655 } 656 static void 657 sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order) 658 { 659 size_t i, j, k, n_repliers, n_key_replacers; 660 661 /* First, set up the default order. */ 662 i = 0; 663 for (j = 0; j < n_preauth_systems; j++) { 664 if (preauth_systems[j].return_padata != NULL) 665 pa_order[i++] = j; 666 } 667 n_repliers = i; 668 pa_order[n_repliers] = -1; 669 670 /* Reorder so that PA_REPLACES_KEY modules are listed first. */ 671 for (i = 0; i < n_repliers; i++) { 672 /* If this module replaces the key, then it's okay to leave it where it 673 * is in the order. */ 674 if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY) 675 continue; 676 /* If not, search for a module which does, and swap in the first one we 677 * find. */ 678 for (j = i + 1; j < n_repliers; j++) { 679 if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) { 680 k = pa_order[j]; 681 pa_order[j] = pa_order[i]; 682 pa_order[i] = k; 683 break; 684 } 685 } 686 /* If we didn't find one, we have moved all of the key-replacing 687 * modules, and i is the count of those modules. */ 688 if (j == n_repliers) 689 break; 690 } 691 n_key_replacers = i; 692 693 if (request->padata != NULL) { 694 /* Now reorder the subset of modules which replace the key, 695 * bubbling those which handle pa_data types provided by the 696 * client ahead of the others. 697 */ 698 for (i = 0; i < n_key_replacers; i++) { 699 if (pa_list_includes(request->padata, 700 preauth_systems[pa_order[i]].type)) 701 continue; 702 for (j = i + 1; j < n_key_replacers; j++) { 703 if (pa_list_includes(request->padata, 704 preauth_systems[pa_order[j]].type)) { 705 k = pa_order[j]; 706 pa_order[j] = pa_order[i]; 707 pa_order[i] = k; 708 break; 709 } 710 } 711 } 712 } 713 #ifdef DEBUG 714 krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:"); 715 for (i = 0; i < n_preauth_systems; i++) { 716 if (preauth_systems[i].return_padata != NULL) 717 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name, 718 preauth_systems[i].type); 719 } 720 krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:"); 721 for (i = 0; pa_order[i] != -1; i++) { 722 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", 723 preauth_systems[pa_order[i]].name, 724 preauth_systems[pa_order[i]].type); 725 } 726 #endif 727 } 728 729 const char *missing_required_preauth(krb5_db_entry *client, 730 krb5_db_entry *server, 731 krb5_enc_tkt_part *enc_tkt_reply) 732 { 733 #ifdef DEBUG 734 krb5_klog_syslog ( 735 LOG_DEBUG, 736 "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth", 737 isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ", 738 isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ", 739 isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ", 740 isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no "); 741 #endif 742 743 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 744 !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH)) 745 return "NEEDED_PREAUTH"; 746 747 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) && 748 !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH)) 749 return "NEEDED_HW_PREAUTH"; 750 751 return 0; 752 } 753 754 /* Return true if request's enctypes indicate support for etype-info2. */ 755 static krb5_boolean 756 requires_info2(const krb5_kdc_req *request) 757 { 758 int i; 759 760 for (i = 0; i < request->nktypes; i++) { 761 if (enctype_requires_etype_info_2(request->ktype[i])) 762 return TRUE; 763 } 764 return FALSE; 765 } 766 767 /* Add PA-ETYPE-INFO2 and possibly PA-ETYPE-INFO entries to pa_list as 768 * appropriate for the request and client principal. */ 769 static krb5_error_code 770 add_etype_info(krb5_context context, krb5_kdcpreauth_rock rock, 771 krb5_pa_data ***pa_list) 772 { 773 krb5_error_code ret; 774 krb5_data *der; 775 776 if (rock->client_key == NULL) 777 return 0; 778 779 if (!requires_info2(rock->request)) { 780 /* Include PA-ETYPE-INFO only for old clients. */ 781 ret = make_etype_info(context, FALSE, rock->client->princ, 782 rock->client_key, rock->client_keyblock->enctype, 783 &der); 784 if (ret) 785 return ret; 786 ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_ETYPE_INFO, der); 787 krb5_free_data(context, der); 788 if (ret) 789 return ret; 790 } 791 792 /* Always include PA-ETYPE-INFO2. */ 793 ret = make_etype_info(context, TRUE, rock->client->princ, rock->client_key, 794 rock->client_keyblock->enctype, &der); 795 if (ret) 796 return ret; 797 ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_ETYPE_INFO2, der); 798 krb5_free_data(context, der); 799 return ret; 800 } 801 802 /* Add PW-SALT entries to pa_list as appropriate for the request and client 803 * principal. */ 804 static krb5_error_code 805 add_pw_salt(krb5_context context, krb5_kdcpreauth_rock rock, 806 krb5_pa_data ***pa_list) 807 { 808 krb5_error_code ret; 809 krb5_data *salt = NULL; 810 krb5_int16 salttype; 811 812 /* Only include this pa-data for old clients. */ 813 if (rock->client_key == NULL || requires_info2(rock->request)) 814 return 0; 815 816 ret = krb5_dbe_compute_salt(context, rock->client_key, 817 rock->request->client, &salttype, &salt); 818 if (ret) 819 return 0; 820 821 ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_PW_SALT, salt); 822 krb5_free_data(context, salt); 823 return ret; 824 } 825 826 static krb5_error_code 827 add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock, 828 krb5_pa_data ***pa_list) 829 { 830 krb5_error_code ret; 831 krb5_timestamp now; 832 krb5_keyblock kb; 833 krb5_checksum cksum; 834 krb5_data d; 835 krb5_pa_data *pa = NULL; 836 char ckbuf[4]; 837 838 memset(&cksum, 0, sizeof(cksum)); 839 memset(&kb, 0, sizeof(kb)); 840 841 if (!rock->send_freshness_token) 842 return 0; 843 if (krb5int_find_pa_data(context, rock->request->padata, 844 KRB5_PADATA_AS_FRESHNESS) == NULL) 845 return 0; 846 847 /* Compute a checksum over the current KDC time. */ 848 ret = krb5_timeofday(context, &now); 849 if (ret) 850 goto cleanup; 851 store_32_be(now, ckbuf); 852 d = make_data(ckbuf, sizeof(ckbuf)); 853 ret = krb5_c_make_checksum(context, 0, rock->local_tgt_key, 854 KRB5_KEYUSAGE_PA_AS_FRESHNESS, &d, &cksum); 855 856 /* Compose a freshness token from the time, krbtgt kvno, and checksum. */ 857 ret = k5_alloc_pa_data(KRB5_PADATA_AS_FRESHNESS, 8 + cksum.length, &pa); 858 if (ret) 859 goto cleanup; 860 store_32_be(now, pa->contents); 861 store_32_be(current_kvno(rock->local_tgt), pa->contents + 4); 862 memcpy(pa->contents + 8, cksum.contents, cksum.length); 863 864 ret = k5_add_pa_data_element(pa_list, &pa); 865 866 cleanup: 867 krb5_free_keyblock_contents(context, &kb); 868 krb5_free_checksum_contents(context, &cksum); 869 k5_free_pa_data_element(pa); 870 return ret; 871 } 872 873 struct hint_state { 874 kdc_hint_respond_fn respond; 875 void *arg; 876 krb5_context context; 877 878 krb5_kdcpreauth_rock rock; 879 krb5_kdc_req *request; 880 krb5_pa_data ***e_data_out; 881 882 int hw_only; 883 preauth_system *ap; 884 krb5_pa_data **pa_data; 885 krb5_preauthtype pa_type; 886 }; 887 888 static void 889 hint_list_finish(struct hint_state *state, krb5_error_code code) 890 { 891 krb5_context context = state->context; 892 kdc_hint_respond_fn oldrespond = state->respond; 893 void *oldarg = state->arg; 894 895 /* Add a freshness token if a preauth module requested it and the client 896 * request indicates support for it. */ 897 if (!code) 898 code = add_freshness_token(context, state->rock, &state->pa_data); 899 900 if (!code) { 901 if (state->pa_data == NULL) { 902 krb5_klog_syslog(LOG_INFO, 903 _("%spreauth required but hint list is empty"), 904 state->hw_only ? "hw" : ""); 905 } 906 907 *state->e_data_out = state->pa_data; 908 state->pa_data = NULL; 909 } 910 911 krb5_free_pa_data(context, state->pa_data); 912 free(state); 913 (*oldrespond)(oldarg); 914 } 915 916 static void 917 hint_list_next(struct hint_state *arg); 918 919 static void 920 finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa) 921 { 922 krb5_error_code ret; 923 struct hint_state *state = arg; 924 925 if (code == 0) { 926 if (pa == NULL) { 927 ret = k5_alloc_pa_data(state->pa_type, 0, &pa); 928 if (ret) 929 goto error; 930 } 931 ret = k5_add_pa_data_element(&state->pa_data, &pa); 932 k5_free_pa_data_element(pa); 933 if (ret) 934 goto error; 935 } 936 937 state->ap++; 938 hint_list_next(state); 939 return; 940 941 error: 942 hint_list_finish(state, ret); 943 } 944 945 static void 946 hint_list_next(struct hint_state *state) 947 { 948 krb5_context context = state->context; 949 preauth_system *ap = state->ap; 950 951 if (ap->type == -1) { 952 hint_list_finish(state, 0); 953 return; 954 } 955 956 if (state->hw_only && !(ap->flags & PA_HARDWARE)) 957 goto next; 958 if (ap->flags & PA_PSEUDO) 959 goto next; 960 961 state->pa_type = ap->type; 962 if (ap->get_edata) { 963 ap->get_edata(context, state->request, &callbacks, state->rock, 964 ap->moddata, ap->type, finish_get_edata, state); 965 } else 966 finish_get_edata(state, 0, NULL); 967 return; 968 969 next: 970 state->ap++; 971 hint_list_next(state); 972 } 973 974 void 975 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock, 976 krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond, 977 void *arg) 978 { 979 krb5_context context = rock->rstate->realm_data->realm_context; 980 struct hint_state *state; 981 982 *e_data_out = NULL; 983 984 /* Allocate our state. */ 985 state = calloc(1, sizeof(*state)); 986 if (state == NULL) 987 goto error; 988 state->hw_only = isflagset(rock->client->attributes, 989 KRB5_KDB_REQUIRES_HW_AUTH); 990 state->respond = respond; 991 state->arg = arg; 992 state->request = request; 993 state->rock = rock; 994 state->context = context; 995 state->e_data_out = e_data_out; 996 state->pa_data = NULL; 997 state->ap = preauth_systems; 998 999 /* Add an empty PA-FX-FAST element to advertise FAST support. */ 1000 if (k5_add_empty_pa_data(&state->pa_data, KRB5_PADATA_FX_FAST) != 0) 1001 goto error; 1002 1003 if (add_etype_info(context, rock, &state->pa_data) != 0) 1004 goto error; 1005 1006 hint_list_next(state); 1007 return; 1008 1009 error: 1010 if (state != NULL) 1011 krb5_free_pa_data(context, state->pa_data); 1012 free(state); 1013 (*respond)(arg); 1014 } 1015 1016 /* 1017 * Add authorization data returned from preauth modules to the ticket 1018 * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs 1019 */ 1020 static krb5_error_code 1021 add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad) 1022 { 1023 krb5_authdata **newad; 1024 int oldones, newones; 1025 int i; 1026 1027 if (enc_tkt_part == NULL || ad == NULL) 1028 return EINVAL; 1029 1030 for (newones = 0; ad[newones] != NULL; newones++); 1031 if (newones == 0) 1032 return 0; /* nothing to add */ 1033 1034 if (enc_tkt_part->authorization_data == NULL) 1035 oldones = 0; 1036 else 1037 for (oldones = 0; 1038 enc_tkt_part->authorization_data[oldones] != NULL; oldones++); 1039 1040 newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *)); 1041 if (newad == NULL) 1042 return ENOMEM; 1043 1044 /* Copy any existing pointers */ 1045 for (i = 0; i < oldones; i++) 1046 newad[i] = enc_tkt_part->authorization_data[i]; 1047 1048 /* Add the new ones */ 1049 for (i = 0; i < newones; i++) 1050 newad[oldones+i] = ad[i]; 1051 1052 /* Terminate the new list */ 1053 newad[oldones+i] = NULL; 1054 1055 /* Free any existing list */ 1056 if (enc_tkt_part->authorization_data != NULL) 1057 free(enc_tkt_part->authorization_data); 1058 1059 /* Install our new list */ 1060 enc_tkt_part->authorization_data = newad; 1061 1062 return 0; 1063 } 1064 1065 struct padata_state { 1066 kdc_preauth_respond_fn respond; 1067 void *arg; 1068 kdc_realm_t *realm; 1069 1070 krb5_kdcpreauth_modreq *modreq_ptr; 1071 krb5_pa_data **padata; 1072 int pa_found; 1073 krb5_context context; 1074 krb5_kdcpreauth_rock rock; 1075 krb5_data *req_pkt; 1076 krb5_kdc_req *request; 1077 krb5_enc_tkt_part *enc_tkt_reply; 1078 void **padata_context; 1079 1080 preauth_system *pa_sys; 1081 krb5_pa_data **pa_e_data; 1082 krb5_boolean typed_e_data_flag; 1083 int pa_ok; 1084 krb5_error_code saved_code; 1085 1086 krb5_pa_data ***e_data_out; 1087 krb5_boolean *typed_e_data_out; 1088 }; 1089 1090 /* Return code if it is 0 or one of the codes we pass through to the client. 1091 * Otherwise return KRB5KDC_ERR_PREAUTH_FAILED. */ 1092 static krb5_error_code 1093 filter_preauth_error(krb5_error_code code) 1094 { 1095 /* The following switch statement allows us 1096 * to return some preauth system errors back to the client. 1097 */ 1098 switch(code) { 1099 case 0: 1100 case KRB5KRB_AP_ERR_BAD_INTEGRITY: 1101 case KRB5KRB_AP_ERR_SKEW: 1102 case KRB5KDC_ERR_PREAUTH_REQUIRED: 1103 case KRB5KDC_ERR_ETYPE_NOSUPP: 1104 /* rfc 4556 */ 1105 case KRB5KDC_ERR_CLIENT_NOT_TRUSTED: 1106 case KRB5KDC_ERR_INVALID_SIG: 1107 case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED: 1108 case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE: 1109 case KRB5KDC_ERR_INVALID_CERTIFICATE: 1110 case KRB5KDC_ERR_REVOKED_CERTIFICATE: 1111 case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN: 1112 case KRB5KDC_ERR_CLIENT_NAME_MISMATCH: 1113 case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE: 1114 case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED: 1115 case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED: 1116 case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED: 1117 case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED: 1118 /* earlier drafts of what became rfc 4556 */ 1119 case KRB5KDC_ERR_CERTIFICATE_MISMATCH: 1120 case KRB5KDC_ERR_KDC_NOT_TRUSTED: 1121 case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE: 1122 /* This value is shared with 1123 * KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */ 1124 /* case KRB5KDC_ERR_KEY_TOO_WEAK: */ 1125 case KRB5KDC_ERR_DISCARD: 1126 /* pkinit alg-agility */ 1127 case KRB5KDC_ERR_NO_ACCEPTABLE_KDF: 1128 /* rfc 6113 */ 1129 case KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED: 1130 return code; 1131 default: 1132 return KRB5KDC_ERR_PREAUTH_FAILED; 1133 } 1134 } 1135 1136 /* 1137 * If the client performed optimistic pre-authentication for a multi-round-trip 1138 * mechanism, it may need key information to complete the exchange, so send it 1139 * a PA-ETYPE-INFO2 element in addition to the pa-data from the module. 1140 */ 1141 static krb5_error_code 1142 maybe_add_etype_info2(struct padata_state *state, krb5_error_code code) 1143 { 1144 krb5_error_code ret; 1145 krb5_context context = state->context; 1146 krb5_kdcpreauth_rock rock = state->rock; 1147 krb5_data *der; 1148 1149 /* Only add key information when requesting another preauth round trip. */ 1150 if (code != KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) 1151 return 0; 1152 1153 /* Don't try to add key information when there is no key. */ 1154 if (rock->client_key == NULL) 1155 return 0; 1156 1157 /* If the client sent a cookie, it has already seen a KDC response with key 1158 * information. */ 1159 if (krb5int_find_pa_data(context, state->request->padata, 1160 KRB5_PADATA_FX_COOKIE) != NULL) 1161 return 0; 1162 1163 ret = make_etype_info(context, TRUE, rock->client->princ, rock->client_key, 1164 rock->client_keyblock->enctype, &der); 1165 if (ret) 1166 return ret; 1167 ret = k5_add_pa_data_from_data(&state->pa_e_data, KRB5_PADATA_ETYPE_INFO2, 1168 der); 1169 krb5_free_data(context, der); 1170 return ret; 1171 } 1172 1173 /* Release state and respond to the AS-REQ processing code with the result of 1174 * checking pre-authentication data. */ 1175 static void 1176 finish_check_padata(struct padata_state *state, krb5_error_code code) 1177 { 1178 kdc_preauth_respond_fn respond; 1179 void *arg; 1180 1181 if (state->pa_ok || !state->pa_found) { 1182 /* Return successfully. If we didn't match a preauth system, we may 1183 * return PREAUTH_REQUIRED later, but we didn't fail to verify. */ 1184 code = 0; 1185 goto cleanup; 1186 } 1187 1188 /* Add key information to the saved error pa-data if required. */ 1189 if (maybe_add_etype_info2(state, code) != 0) { 1190 code = KRB5KDC_ERR_PREAUTH_FAILED; 1191 goto cleanup; 1192 } 1193 1194 /* Return any saved error pa-data, stealing the pointer from state. */ 1195 *state->e_data_out = state->pa_e_data; 1196 *state->typed_e_data_out = state->typed_e_data_flag; 1197 state->pa_e_data = NULL; 1198 1199 cleanup: 1200 /* Discard saved error pa-data if we aren't returning it, free state, and 1201 * respond to the AS-REQ processing code. */ 1202 respond = state->respond; 1203 arg = state->arg; 1204 krb5_free_pa_data(state->context, state->pa_e_data); 1205 free(state); 1206 (*respond)(arg, filter_preauth_error(code)); 1207 } 1208 1209 static void 1210 next_padata(struct padata_state *state); 1211 1212 static void 1213 finish_verify_padata(void *arg, krb5_error_code code, 1214 krb5_kdcpreauth_modreq modreq, krb5_pa_data **e_data, 1215 krb5_authdata **authz_data) 1216 { 1217 struct padata_state *state = arg; 1218 const char *emsg; 1219 krb5_boolean typed_e_data_flag; 1220 1221 assert(state); 1222 *state->modreq_ptr = modreq; 1223 1224 if (code) { 1225 emsg = krb5_get_error_message(state->context, code); 1226 krb5_klog_syslog(LOG_INFO, "preauth (%s) verify failure: %s", 1227 state->pa_sys->name, emsg); 1228 krb5_free_error_message(state->context, emsg); 1229 1230 /* Ignore authorization data returned from modules that fail */ 1231 if (authz_data != NULL) { 1232 krb5_free_authdata(state->context, authz_data); 1233 authz_data = NULL; 1234 } 1235 1236 typed_e_data_flag = ((state->pa_sys->flags & PA_TYPED_E_DATA) != 0); 1237 1238 /* 1239 * We'll return edata from either the first PA_REQUIRED module 1240 * that fails, or the first non-PA_REQUIRED module that fails. 1241 * Hang on to edata from the first non-PA_REQUIRED module. 1242 * If we've already got one saved, simply discard this one. 1243 */ 1244 if (state->pa_sys->flags & PA_REQUIRED) { 1245 /* free up any previous edata we might have been saving */ 1246 if (state->pa_e_data != NULL) 1247 krb5_free_pa_data(state->context, state->pa_e_data); 1248 state->pa_e_data = e_data; 1249 state->typed_e_data_flag = typed_e_data_flag; 1250 1251 /* Make sure we use the current retval */ 1252 state->pa_ok = 0; 1253 finish_check_padata(state, code); 1254 return; 1255 } else if (state->pa_e_data == NULL) { 1256 /* save the first error code and e-data */ 1257 state->pa_e_data = e_data; 1258 state->typed_e_data_flag = typed_e_data_flag; 1259 state->saved_code = code; 1260 } else if (e_data != NULL) { 1261 /* discard this extra e-data from non-PA_REQUIRED module */ 1262 krb5_free_pa_data(state->context, e_data); 1263 } 1264 } else { 1265 #ifdef DEBUG 1266 krb5_klog_syslog (LOG_DEBUG, ".. .. ok"); 1267 #endif 1268 1269 /* Ignore any edata returned on success */ 1270 if (e_data != NULL) 1271 krb5_free_pa_data(state->context, e_data); 1272 1273 /* Add any authorization data to the ticket */ 1274 if (authz_data != NULL) { 1275 add_authorization_data(state->enc_tkt_reply, authz_data); 1276 free(authz_data); 1277 } 1278 1279 state->pa_ok = 1; 1280 if (state->pa_sys->flags & PA_SUFFICIENT) { 1281 finish_check_padata(state, state->saved_code); 1282 return; 1283 } 1284 } 1285 1286 next_padata(state); 1287 } 1288 1289 static void 1290 next_padata(struct padata_state *state) 1291 { 1292 assert(state); 1293 if (!state->padata) 1294 state->padata = state->request->padata; 1295 else 1296 state->padata++; 1297 1298 if (!*state->padata) { 1299 finish_check_padata(state, state->saved_code); 1300 return; 1301 } 1302 1303 #ifdef DEBUG 1304 krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*state->padata)->pa_type); 1305 #endif 1306 if (find_pa_system((*state->padata)->pa_type, &state->pa_sys)) 1307 goto next; 1308 if (find_modreq(state->pa_sys, *state->padata_context, &state->modreq_ptr)) 1309 goto next; 1310 #ifdef DEBUG 1311 krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", state->pa_sys->name); 1312 #endif 1313 if (state->pa_sys->verify_padata == 0) 1314 goto next; 1315 1316 state->pa_found++; 1317 state->pa_sys->verify_padata(state->context, state->req_pkt, 1318 state->request, state->enc_tkt_reply, 1319 *state->padata, &callbacks, state->rock, 1320 state->pa_sys->moddata, finish_verify_padata, 1321 state); 1322 return; 1323 1324 next: 1325 next_padata(state); 1326 } 1327 1328 /* 1329 * This routine is called to verify the preauthentication information 1330 * for a V5 request. 1331 * 1332 * Returns 0 if the pre-authentication is valid, non-zero to indicate 1333 * an error code of some sort. 1334 */ 1335 1336 void 1337 check_padata(krb5_context context, krb5_kdcpreauth_rock rock, 1338 krb5_data *req_pkt, krb5_kdc_req *request, 1339 krb5_enc_tkt_part *enc_tkt_reply, void **padata_context, 1340 krb5_pa_data ***e_data, krb5_boolean *typed_e_data, 1341 kdc_preauth_respond_fn respond, void *arg) 1342 { 1343 struct padata_state *state; 1344 1345 if (request->padata == 0) { 1346 (*respond)(arg, 0); 1347 return; 1348 } 1349 1350 if (make_padata_context(context, padata_context) != 0) { 1351 (*respond)(arg, KRB5KRB_ERR_GENERIC); 1352 return; 1353 } 1354 1355 state = calloc(1, sizeof(*state)); 1356 if (state == NULL) { 1357 (*respond)(arg, ENOMEM); 1358 return; 1359 } 1360 state->respond = respond; 1361 state->arg = arg; 1362 state->context = context; 1363 state->rock = rock; 1364 state->req_pkt = req_pkt; 1365 state->request = request; 1366 state->enc_tkt_reply = enc_tkt_reply; 1367 state->padata_context = padata_context; 1368 state->e_data_out = e_data; 1369 state->typed_e_data_out = typed_e_data; 1370 state->realm = rock->rstate->realm_data; 1371 1372 #ifdef DEBUG 1373 krb5_klog_syslog (LOG_DEBUG, "checking padata"); 1374 #endif 1375 1376 next_padata(state); 1377 } 1378 1379 /* Return true if k1 and k2 have the same type and contents. */ 1380 static krb5_boolean 1381 keyblock_equal(const krb5_keyblock *k1, const krb5_keyblock *k2) 1382 { 1383 if (k1->enctype != k2->enctype) 1384 return FALSE; 1385 if (k1->length != k2->length) 1386 return FALSE; 1387 return memcmp(k1->contents, k2->contents, k1->length) == 0; 1388 } 1389 1390 /* 1391 * return_padata creates any necessary preauthentication 1392 * structures which should be returned by the KDC to the client 1393 */ 1394 krb5_error_code 1395 return_padata(krb5_context context, krb5_kdcpreauth_rock rock, 1396 krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, 1397 krb5_keyblock *encrypting_key, void **padata_context) 1398 { 1399 krb5_error_code retval; 1400 krb5_pa_data ** padata; 1401 krb5_pa_data ** send_pa_list = NULL; 1402 krb5_pa_data * send_pa; 1403 krb5_pa_data * pa = 0; 1404 krb5_pa_data null_item; 1405 preauth_system * ap; 1406 int * pa_order = NULL; 1407 int * pa_type; 1408 int size = 0; 1409 krb5_kdcpreauth_modreq *modreq_ptr; 1410 krb5_boolean key_modified; 1411 krb5_keyblock original_key; 1412 1413 memset(&original_key, 0, sizeof(original_key)); 1414 1415 if ((!*padata_context) && 1416 (make_padata_context(context, padata_context) != 0)) { 1417 return KRB5KRB_ERR_GENERIC; 1418 } 1419 1420 for (ap = preauth_systems; ap->type != -1; ap++) { 1421 if (ap->return_padata) 1422 size++; 1423 } 1424 1425 pa_order = k5calloc(size + 1, sizeof(int), &retval); 1426 if (pa_order == NULL) 1427 goto cleanup; 1428 sort_pa_order(context, request, pa_order); 1429 1430 retval = krb5_copy_keyblock_contents(context, encrypting_key, 1431 &original_key); 1432 if (retval) 1433 goto cleanup; 1434 key_modified = FALSE; 1435 null_item.contents = NULL; 1436 null_item.length = 0; 1437 1438 for (pa_type = pa_order; *pa_type != -1; pa_type++) { 1439 ap = &preauth_systems[*pa_type]; 1440 if (key_modified && (ap->flags & PA_REPLACES_KEY)) 1441 continue; 1442 if (ap->return_padata == 0) 1443 continue; 1444 if (find_modreq(ap, *padata_context, &modreq_ptr)) 1445 continue; 1446 pa = &null_item; 1447 null_item.pa_type = ap->type; 1448 if (request->padata) { 1449 for (padata = request->padata; *padata; padata++) { 1450 if ((*padata)->pa_type == ap->type) { 1451 pa = *padata; 1452 break; 1453 } 1454 } 1455 } 1456 send_pa = NULL; 1457 retval = ap->return_padata(context, pa, req_pkt, request, reply, 1458 encrypting_key, &send_pa, &callbacks, rock, 1459 ap->moddata, *modreq_ptr); 1460 if (retval) 1461 goto cleanup; 1462 1463 if (send_pa != NULL) { 1464 retval = k5_add_pa_data_element(&send_pa_list, &send_pa); 1465 k5_free_pa_data_element(send_pa); 1466 if (retval) 1467 goto cleanup; 1468 } 1469 1470 if (!key_modified && !keyblock_equal(&original_key, encrypting_key)) 1471 key_modified = TRUE; 1472 } 1473 1474 /* 1475 * Add etype-info and pw-salt pa-data as needed. If we replaced the reply 1476 * key, we can't send consistent etype-info; the salt from the client key 1477 * data doesn't correspond to the replaced reply key, and RFC 4120 section 1478 * 5.2.7.5 forbids us from sending etype-info describing the initial reply 1479 * key in an AS-REP if it doesn't have the same enctype as the replaced 1480 * reply key. For all current and foreseeable preauth mechs, we can assume 1481 * the client received etype-info2 in an earlier step and already computed 1482 * the initial reply key if it needed it. The client can determine the 1483 * enctype of the replaced reply key from the etype field of the enc-part 1484 * field of the AS-REP. 1485 */ 1486 if (!key_modified) { 1487 retval = add_etype_info(context, rock, &send_pa_list); 1488 if (retval) 1489 goto cleanup; 1490 retval = add_pw_salt(context, rock, &send_pa_list); 1491 if (retval) 1492 goto cleanup; 1493 } 1494 1495 if (send_pa_list != NULL) { 1496 reply->padata = send_pa_list; 1497 send_pa_list = 0; 1498 } 1499 1500 cleanup: 1501 krb5_free_keyblock_contents(context, &original_key); 1502 free(pa_order); 1503 krb5_free_pa_data(context, send_pa_list); 1504 1505 return (retval); 1506 } 1507 1508 static krb5_error_code 1509 _make_etype_info_entry(krb5_context context, 1510 krb5_principal client_princ, krb5_key_data *client_key, 1511 krb5_enctype etype, krb5_etype_info_entry **entry_out, 1512 int etype_info2) 1513 { 1514 krb5_error_code retval; 1515 krb5_int16 salttype; 1516 krb5_data *salt = NULL; 1517 krb5_etype_info_entry *entry = NULL; 1518 1519 *entry_out = NULL; 1520 entry = malloc(sizeof(*entry)); 1521 if (entry == NULL) 1522 return ENOMEM; 1523 1524 entry->magic = KV5M_ETYPE_INFO_ENTRY; 1525 entry->etype = etype; 1526 entry->length = KRB5_ETYPE_NO_SALT; 1527 entry->salt = NULL; 1528 entry->s2kparams = empty_data(); 1529 retval = krb5_dbe_compute_salt(context, client_key, client_princ, 1530 &salttype, &salt); 1531 if (retval) 1532 goto cleanup; 1533 1534 entry->length = salt->length; 1535 entry->salt = (unsigned char *)salt->data; 1536 salt->data = NULL; 1537 *entry_out = entry; 1538 entry = NULL; 1539 1540 cleanup: 1541 if (entry != NULL) 1542 krb5_free_data_contents(context, &entry->s2kparams); 1543 free(entry); 1544 krb5_free_data(context, salt); 1545 return retval; 1546 } 1547 1548 /* Encode an etype-info or etype-info2 message for client_key with the given 1549 * enctype, using client to compute the salt if necessary. */ 1550 static krb5_error_code 1551 make_etype_info(krb5_context context, krb5_boolean etype_info2, 1552 krb5_principal client, krb5_key_data *client_key, 1553 krb5_enctype enctype, krb5_data **der_out) 1554 { 1555 krb5_error_code retval; 1556 krb5_etype_info_entry **entry = NULL; 1557 1558 *der_out = NULL; 1559 1560 entry = k5calloc(2, sizeof(*entry), &retval); 1561 if (entry == NULL) 1562 goto cleanup; 1563 retval = _make_etype_info_entry(context, client, client_key, enctype, 1564 &entry[0], etype_info2); 1565 if (retval != 0) 1566 goto cleanup; 1567 1568 if (etype_info2) 1569 retval = encode_krb5_etype_info2(entry, der_out); 1570 else 1571 retval = encode_krb5_etype_info(entry, der_out); 1572 1573 cleanup: 1574 krb5_free_etype_info(context, entry); 1575 return retval; 1576 } 1577 1578 /* 1579 * Returns TRUE if the PAC should be included 1580 */ 1581 krb5_boolean 1582 include_pac_p(krb5_context context, krb5_kdc_req *request) 1583 { 1584 krb5_error_code code; 1585 krb5_pa_data **padata; 1586 krb5_boolean retval = TRUE; /* default is to return PAC */ 1587 krb5_data data; 1588 krb5_pa_pac_req *req = NULL; 1589 1590 if (request->padata == NULL) { 1591 return retval; 1592 } 1593 1594 for (padata = request->padata; *padata != NULL; padata++) { 1595 if ((*padata)->pa_type == KRB5_PADATA_PAC_REQUEST) { 1596 data.data = (char *)(*padata)->contents; 1597 data.length = (*padata)->length; 1598 1599 code = decode_krb5_pa_pac_req(&data, &req); 1600 if (code == 0) { 1601 retval = req->include_pac; 1602 krb5_free_pa_pac_req(context, req); 1603 req = NULL; 1604 } 1605 break; 1606 } 1607 } 1608 1609 return retval; 1610 } 1611 1612 static krb5_error_code 1613 return_referral_enc_padata( krb5_context context, 1614 krb5_enc_kdc_rep_part *reply, 1615 krb5_db_entry *server) 1616 { 1617 krb5_error_code code; 1618 krb5_tl_data tl_data; 1619 krb5_pa_data *pa; 1620 1621 tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA; 1622 code = krb5_dbe_lookup_tl_data(context, server, &tl_data); 1623 if (code || tl_data.tl_data_length == 0) 1624 return 0; 1625 1626 code = k5_alloc_pa_data(KRB5_PADATA_SVR_REFERRAL_INFO, 1627 tl_data.tl_data_length, &pa); 1628 if (code) 1629 return code; 1630 memcpy(pa->contents, tl_data.tl_data_contents, tl_data.tl_data_length); 1631 code = k5_add_pa_data_element(&reply->enc_padata, &pa); 1632 k5_free_pa_data_element(pa); 1633 return code; 1634 } 1635 1636 krb5_error_code 1637 return_enc_padata(krb5_context context, krb5_data *req_pkt, 1638 krb5_kdc_req *request, krb5_keyblock *reply_key, 1639 krb5_db_entry *server, krb5_enc_kdc_rep_part *reply_encpart, 1640 krb5_boolean is_referral) 1641 { 1642 krb5_error_code code = 0; 1643 /* This should be initialized and only used for Win2K compat and other 1644 * specific standardized uses such as FAST negotiation. */ 1645 if (is_referral) { 1646 code = return_referral_enc_padata(context, reply_encpart, server); 1647 if (code) 1648 return code; 1649 } 1650 code = kdc_handle_protected_negotiation(context, req_pkt, request, reply_key, 1651 &reply_encpart->enc_padata); 1652 if (code) 1653 goto cleanup; 1654 1655 code = kdc_add_pa_pac_options(context, request, 1656 &reply_encpart->enc_padata); 1657 if (code) 1658 goto cleanup; 1659 1660 /*Add potentially other enc_padata providers*/ 1661 cleanup: 1662 return code; 1663 } 1664