1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * kdc/kdc_preauth.c 10 * 11 * Copyright 1995 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * Preauthentication routines for the KDC. 34 */ 35 36 /* 37 * Copyright (C) 1998 by the FundsXpress, INC. 38 * 39 * All rights reserved. 40 * 41 * Export of this software from the United States of America may require 42 * a specific license from the United States Government. It is the 43 * responsibility of any person or organization contemplating export to 44 * obtain such a license before exporting. 45 * 46 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 47 * distribute this software and its documentation for any purpose and 48 * without fee is hereby granted, provided that the above copyright 49 * notice appear in all copies and that both that copyright notice and 50 * this permission notice appear in supporting documentation, and that 51 * the name of FundsXpress. not be used in advertising or publicity pertaining 52 * to distribution of the software without specific, written prior 53 * permission. FundsXpress makes no representations about the suitability of 54 * this software for any purpose. It is provided "as is" without express 55 * or implied warranty. 56 * 57 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 58 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 59 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 60 */ 61 62 #include "k5-int.h" 63 #include "kdc_util.h" 64 #include "extern.h" 65 #include "com_err.h" 66 #include <assert.h> 67 #include <stdio.h> 68 #include <libintl.h> 69 #include <syslog.h> 70 71 typedef krb5_error_code (*verify_proc) 72 (krb5_context, krb5_db_entry *client, 73 krb5_kdc_req *request, 74 krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data); 75 76 typedef krb5_error_code (*edata_proc) 77 (krb5_context, krb5_kdc_req *request, 78 krb5_db_entry *client, krb5_db_entry *server, 79 krb5_pa_data *data); 80 81 typedef krb5_error_code (*return_proc) 82 (krb5_context, krb5_pa_data * padata, 83 krb5_db_entry *client, 84 krb5_kdc_req *request, krb5_kdc_rep *reply, 85 krb5_key_data *client_key, 86 krb5_keyblock *encrypting_key, 87 krb5_pa_data **send_pa); 88 89 typedef struct _krb5_preauth_systems { 90 char * name; 91 int type; 92 int flags; 93 edata_proc get_edata; 94 verify_proc verify_padata; 95 return_proc return_padata; 96 } krb5_preauth_systems; 97 98 static krb5_error_code verify_enc_timestamp 99 (krb5_context, krb5_db_entry *client, 100 krb5_kdc_req *request, 101 krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data); 102 103 static krb5_error_code get_etype_info 104 (krb5_context, krb5_kdc_req *request, 105 krb5_db_entry *client, krb5_db_entry *server, 106 krb5_pa_data *data); 107 108 static krb5_error_code 109 get_etype_info2(krb5_context context, krb5_kdc_req *request, 110 krb5_db_entry *client, krb5_db_entry *server, 111 krb5_pa_data *pa_data); 112 113 static krb5_error_code 114 return_etype_info2(krb5_context, krb5_pa_data * padata, 115 krb5_db_entry *client, 116 krb5_kdc_req *request, krb5_kdc_rep *reply, 117 krb5_key_data *client_key, 118 krb5_keyblock *encrypting_key, 119 krb5_pa_data **send_pa); 120 121 122 static krb5_error_code return_pw_salt 123 (krb5_context, krb5_pa_data * padata, 124 krb5_db_entry *client, 125 krb5_kdc_req *request, krb5_kdc_rep *reply, 126 krb5_key_data *client_key, 127 krb5_keyblock *encrypting_key, 128 krb5_pa_data **send_pa); 129 130 /* SAM preauth support */ 131 static krb5_error_code verify_sam_response 132 (krb5_context, krb5_db_entry *client, 133 krb5_kdc_req *request, 134 krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data); 135 136 static krb5_error_code get_sam_edata 137 (krb5_context, krb5_kdc_req *request, 138 krb5_db_entry *client, krb5_db_entry *server, 139 krb5_pa_data *data); 140 141 static krb5_error_code return_sam_data 142 (krb5_context, krb5_pa_data * padata, 143 krb5_db_entry *client, 144 krb5_kdc_req *request, krb5_kdc_rep *reply, 145 krb5_key_data *client_key, 146 krb5_keyblock *encrypting_key, 147 krb5_pa_data **send_pa); 148 /* 149 * Preauth property flags 150 */ 151 #define PA_HARDWARE 0x00000001 152 #define PA_REQUIRED 0x00000002 153 #define PA_SUFFICIENT 0x00000004 154 /* Not really a padata, so don't include it in the etype list*/ 155 #define PA_PSEUDO 0x00000008 156 157 static krb5_preauth_systems preauth_systems[] = { 158 { 159 "timestamp", 160 KRB5_PADATA_ENC_TIMESTAMP, 161 0, 162 0, 163 verify_enc_timestamp, 164 0 165 }, 166 { 167 "etype-info", 168 KRB5_PADATA_ETYPE_INFO, 169 0, 170 get_etype_info, 171 0, 172 0 173 }, 174 { 175 "etype-info2", 176 KRB5_PADATA_ETYPE_INFO2, 177 0, 178 get_etype_info2, 179 0, 180 return_etype_info2 181 }, 182 { 183 "pw-salt", 184 KRB5_PADATA_PW_SALT, 185 PA_PSEUDO, /* Don't include this in the error list */ 186 0, 187 0, 188 return_pw_salt 189 }, 190 { 191 "sam-response", 192 KRB5_PADATA_SAM_RESPONSE, 193 0, 194 0, 195 verify_sam_response, 196 return_sam_data 197 }, 198 { 199 "sam-challenge", 200 KRB5_PADATA_SAM_CHALLENGE, 201 PA_HARDWARE, /* causes get_preauth_hint_list to use this */ 202 get_sam_edata, 203 0, 204 0 205 }, 206 { "[end]", -1,} 207 }; 208 209 #define MAX_PREAUTH_SYSTEMS (sizeof(preauth_systems)/sizeof(preauth_systems[0])) 210 211 static krb5_error_code 212 find_pa_system(int type, krb5_preauth_systems **preauth) 213 { 214 krb5_preauth_systems *ap = preauth_systems; 215 216 while ((ap->type != -1) && (ap->type != type)) 217 ap++; 218 if (ap->type == -1) 219 return(KRB5_PREAUTH_BAD_TYPE); 220 *preauth = ap; 221 return 0; 222 } 223 224 const char *missing_required_preauth(client, server, enc_tkt_reply) 225 krb5_db_entry *client, *server; 226 krb5_enc_tkt_part *enc_tkt_reply; 227 { 228 #if 0 229 /* 230 * If this is the pwchange service, and the pre-auth bit is set, 231 * allow it even if the HW preauth would normally be required. 232 * 233 * Sandia national labs wanted this for some strange reason... we 234 * leave it disabled normally. 235 */ 236 if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) && 237 isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH)) 238 return 0; 239 #endif 240 241 #ifdef DEBUG 242 krb5_klog_syslog (LOG_DEBUG, 243 "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth", 244 isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ", 245 isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ", 246 isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ", 247 isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no "); 248 #endif 249 250 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 251 !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH)) 252 return "NEEDED_PREAUTH"; 253 254 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) && 255 !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH)) 256 return "NEEDED_HW_PREAUTH"; 257 258 return 0; 259 } 260 261 void get_preauth_hint_list( 262 krb5_kdc_req *request, 263 krb5_db_entry *client, 264 krb5_db_entry *server, 265 krb5_data *e_data) 266 { 267 int hw_only; 268 krb5_preauth_systems *ap; 269 krb5_pa_data **pa_data, **pa; 270 krb5_data *edat; 271 krb5_error_code retval; 272 273 /* Zero these out in case we need to abort */ 274 e_data->length = 0; 275 e_data->data = 0; 276 277 hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH); 278 pa_data = malloc(sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1)); 279 if (pa_data == 0) 280 return; 281 memset(pa_data, 0, sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1)); 282 pa = pa_data; 283 284 for (ap = preauth_systems; ap->type != -1; ap++) { 285 if (hw_only && !(ap->flags & PA_HARDWARE)) 286 continue; 287 if (ap->flags & PA_PSEUDO) 288 continue; 289 *pa = malloc(sizeof(krb5_pa_data)); 290 if (*pa == 0) 291 goto errout; 292 memset(*pa, 0, sizeof(krb5_pa_data)); 293 (*pa)->magic = KV5M_PA_DATA; 294 (*pa)->pa_type = ap->type; 295 if (ap->get_edata) { 296 retval = (ap->get_edata)(kdc_context, request, client, server, *pa); 297 if (retval) { 298 /* just failed on this type, continue */ 299 free(*pa); 300 *pa = 0; 301 continue; 302 } 303 } 304 pa++; 305 } 306 if (pa_data[0] == 0) { 307 krb5_klog_syslog (LOG_INFO, 308 "%spreauth required but hint list is empty", 309 hw_only ? "hw" : ""); 310 } 311 retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data, 312 &edat); 313 if (retval) 314 goto errout; 315 *e_data = *edat; 316 free(edat); 317 318 errout: 319 krb5_free_pa_data(kdc_context, pa_data); 320 return; 321 } 322 323 /* 324 * This routine is called to verify the preauthentication information 325 * for a V5 request. 326 * 327 * Returns 0 if the pre-authentication is valid, non-zero to indicate 328 * an error code of some sort. 329 */ 330 331 krb5_error_code 332 check_padata ( 333 krb5_context context, 334 krb5_db_entry * client, 335 krb5_kdc_req * request, 336 krb5_enc_tkt_part * enc_tkt_reply) 337 { 338 krb5_error_code retval = 0; 339 krb5_pa_data **padata; 340 krb5_preauth_systems *pa_sys; 341 int pa_ok = 0, pa_found = 0; 342 343 if (request->padata == 0) 344 return 0; 345 346 #ifdef DEBUG 347 krb5_klog_syslog (LOG_DEBUG, "checking padata"); 348 #endif 349 for (padata = request->padata; *padata; padata++) { 350 #ifdef DEBUG 351 krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type); 352 #endif 353 if (find_pa_system((*padata)->pa_type, &pa_sys)) 354 continue; 355 #ifdef DEBUG 356 krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name); 357 #endif 358 if (pa_sys->verify_padata == 0) 359 continue; 360 pa_found++; 361 retval = pa_sys->verify_padata(context, client, request, 362 enc_tkt_reply, *padata); 363 if (retval) { 364 krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s", 365 pa_sys->name, error_message (retval)); 366 if (pa_sys->flags & PA_REQUIRED) { 367 pa_ok = 0; 368 break; 369 } 370 } else { 371 #ifdef DEBUG 372 krb5_klog_syslog (LOG_DEBUG, ".. .. ok"); 373 #endif 374 pa_ok = 1; 375 if (pa_sys->flags & PA_SUFFICIENT) 376 break; 377 } 378 } 379 if (pa_ok) 380 return 0; 381 382 /* pa system was not found, but principal doesn't require preauth */ 383 if (!pa_found && 384 !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 385 !isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH)) 386 return 0; 387 388 if (!pa_found) 389 krb5_klog_syslog (LOG_INFO, "no valid preauth type found: %s", 390 error_message (retval)); 391 392 /* The following switch statement allows us 393 * to return some preauth system errors back to the client. 394 */ 395 switch(retval) { 396 case KRB5KRB_AP_ERR_BAD_INTEGRITY: 397 case KRB5KRB_AP_ERR_SKEW: 398 return retval; 399 default: 400 return KRB5KDC_ERR_PREAUTH_FAILED; 401 } 402 } 403 404 /* 405 * return_padata creates any necessary preauthentication 406 * structures which should be returned by the KDC to the client 407 */ 408 krb5_error_code 409 return_padata( 410 krb5_context context, 411 krb5_db_entry * client, 412 krb5_kdc_req * request, 413 krb5_kdc_rep * reply, 414 krb5_key_data * client_key, 415 krb5_keyblock * encrypting_key) 416 { 417 krb5_error_code retval; 418 krb5_pa_data ** padata; 419 krb5_pa_data ** send_pa_list; 420 krb5_pa_data ** send_pa; 421 krb5_pa_data * pa = 0; 422 krb5_preauth_systems * ap; 423 int size = 0; 424 425 for (ap = preauth_systems; ap->type != -1; ap++) { 426 if (ap->return_padata) 427 size++; 428 } 429 430 if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL) 431 return ENOMEM; 432 433 send_pa = send_pa_list; 434 *send_pa = 0; 435 436 for (ap = preauth_systems; ap->type != -1; ap++) { 437 if (ap->return_padata == 0) 438 continue; 439 pa = 0; 440 if (request->padata) { 441 for (padata = request->padata; *padata; padata++) { 442 if ((*padata)->pa_type == ap->type) { 443 pa = *padata; 444 break; 445 } 446 } 447 } 448 if ((retval = ap->return_padata(context, pa, client, request, reply, 449 client_key, encrypting_key, send_pa))) 450 goto cleanup; 451 452 if (*send_pa) 453 send_pa++; 454 *send_pa = 0; 455 } 456 457 retval = 0; 458 459 if (send_pa_list[0]) { 460 reply->padata = send_pa_list; 461 send_pa_list = 0; 462 } 463 464 cleanup: 465 if (send_pa_list) 466 krb5_free_pa_data(context, send_pa_list); 467 return (retval); 468 } 469 static krb5_boolean 470 enctype_requires_etype_info_2(krb5_enctype enctype) 471 { 472 switch(enctype) { 473 case ENCTYPE_DES_CBC_CRC: 474 case ENCTYPE_DES_CBC_MD4: 475 case ENCTYPE_DES_CBC_MD5: 476 case ENCTYPE_DES3_CBC_SHA1: 477 case ENCTYPE_DES3_CBC_RAW: 478 case ENCTYPE_ARCFOUR_HMAC: 479 case ENCTYPE_ARCFOUR_HMAC_EXP : 480 return 0; 481 default: 482 if (krb5_c_valid_enctype(enctype)) 483 return 1; 484 else return 0; 485 } 486 } 487 488 static krb5_boolean 489 request_contains_enctype (krb5_context context, const krb5_kdc_req *request, 490 krb5_enctype enctype) 491 { 492 int i; 493 for (i =0; i < request->nktypes; i++) 494 if (request->ktype[i] == enctype) 495 return 1; 496 return 0; 497 } 498 499 static krb5_error_code 500 verify_enc_timestamp( 501 krb5_context context, 502 krb5_db_entry * client, 503 krb5_kdc_req * request, 504 krb5_enc_tkt_part * enc_tkt_reply, 505 krb5_pa_data * pa) 506 { 507 krb5_pa_enc_ts * pa_enc = 0; 508 krb5_error_code retval; 509 krb5_data scratch; 510 krb5_data enc_ts_data; 511 krb5_enc_data *enc_data = 0; 512 krb5_keyblock key; 513 krb5_key_data * client_key; 514 krb5_int32 start; 515 krb5_timestamp timenow; 516 krb5_error_code decrypt_err; 517 518 (void) memset(&key, 0, sizeof(krb5_keyblock)); 519 scratch.data = (char *) pa->contents; 520 scratch.length = pa->length; 521 522 enc_ts_data.data = 0; 523 524 if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0) 525 goto cleanup; 526 527 enc_ts_data.length = enc_data->ciphertext.length; 528 if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL) 529 goto cleanup; 530 531 start = 0; 532 decrypt_err = 0; 533 while (1) { 534 if ((retval = krb5_dbe_search_enctype(context, client, 535 &start, enc_data->enctype, 536 -1, 0, &client_key))) 537 goto cleanup; 538 539 if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, 540 client_key, &key, NULL))) 541 goto cleanup; 542 543 key.enctype = enc_data->enctype; 544 545 retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, 546 0, enc_data, &enc_ts_data); 547 krb5_free_keyblock_contents(context, &key); 548 if (retval == 0) 549 break; 550 else 551 decrypt_err = retval; 552 } 553 554 if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0) 555 goto cleanup; 556 557 if ((retval = krb5_timeofday(context, &timenow)) != 0) 558 goto cleanup; 559 560 if (labs(timenow - pa_enc->patimestamp) > context->clockskew) { 561 retval = KRB5KRB_AP_ERR_SKEW; 562 goto cleanup; 563 } 564 565 setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH); 566 567 retval = 0; 568 569 cleanup: 570 if (enc_data) { 571 krb5_free_data_contents(context, &enc_data->ciphertext); 572 free(enc_data); 573 } 574 krb5_free_data_contents(context, &enc_ts_data); 575 if (pa_enc) 576 free(pa_enc); 577 578 /* 579 * If we get NO_MATCHING_KEY and decryption previously failed, and 580 * we failed to find any other keys of the correct enctype after 581 * that failed decryption, it probably means that the password was 582 * incorrect. 583 */ 584 if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0) 585 retval = decrypt_err; 586 587 return retval; 588 } 589 590 static krb5_error_code 591 _make_etype_info_entry(krb5_context context, 592 krb5_kdc_req *request, krb5_key_data *client_key, 593 krb5_enctype etype, krb5_etype_info_entry **entry, 594 int etype_info2) 595 { 596 krb5_data salt; 597 krb5_etype_info_entry * tmp_entry; 598 krb5_error_code retval; 599 600 if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL) 601 return ENOMEM; 602 603 salt.data = 0; 604 605 tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY; 606 tmp_entry->etype = etype; 607 tmp_entry->length = KRB5_ETYPE_NO_SALT; 608 tmp_entry->salt = 0; 609 tmp_entry->s2kparams.data = NULL; 610 tmp_entry->s2kparams.length = 0; 611 retval = get_salt_from_key(context, request->client, 612 client_key, &salt); 613 if (retval) 614 goto fail; 615 if (etype_info2 && client_key->key_data_ver > 1 && 616 client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) { 617 switch (etype) { 618 case ENCTYPE_DES_CBC_CRC: 619 case ENCTYPE_DES_CBC_MD4: 620 case ENCTYPE_DES_CBC_MD5: 621 tmp_entry->s2kparams.data = malloc(1); 622 if (tmp_entry->s2kparams.data == NULL) { 623 retval = ENOMEM; 624 goto fail; 625 } 626 tmp_entry->s2kparams.length = 1; 627 tmp_entry->s2kparams.data[0] = 1; 628 break; 629 default: 630 break; 631 } 632 } 633 634 if (salt.length >= 0) { 635 tmp_entry->length = salt.length; 636 tmp_entry->salt = (unsigned char *) salt.data; 637 salt.data = 0; 638 } 639 *entry = tmp_entry; 640 return 0; 641 642 fail: 643 if (tmp_entry) { 644 if (tmp_entry->s2kparams.data) 645 free(tmp_entry->s2kparams.data); 646 free(tmp_entry); 647 } 648 if (salt.data) 649 free(salt.data); 650 return retval; 651 } 652 /* 653 * This function returns the etype information for a particular 654 * client, to be passed back in the preauth list in the KRB_ERROR 655 * message. It supports generating both etype_info and etype_info2 656 * as most of the work is the same. 657 */ 658 static krb5_error_code 659 etype_info_helper(krb5_context context, krb5_kdc_req *request, 660 krb5_db_entry *client, krb5_db_entry *server, 661 krb5_pa_data *pa_data, int etype_info2) 662 { 663 krb5_etype_info_entry ** entry = 0; 664 krb5_key_data *client_key; 665 krb5_error_code retval; 666 krb5_data * scratch; 667 krb5_enctype db_etype; 668 int i = 0; 669 int start = 0; 670 int seen_des = 0; 671 672 entry = malloc((client->n_key_data * 2 + 1) * 673 sizeof(krb5_etype_info_entry *)); 674 if (entry == NULL) 675 return ENOMEM; 676 entry[0] = NULL; 677 678 while (1) { 679 retval = krb5_dbe_search_enctype(context, client, &start, -1, 680 -1, 0, &client_key); 681 if (retval == KRB5_KDB_NO_MATCHING_KEY) 682 break; 683 if (retval) 684 goto cleanup; 685 db_etype = client_key->key_data_type[0]; 686 if (db_etype == ENCTYPE_DES_CBC_MD4) 687 db_etype = ENCTYPE_DES_CBC_MD5; 688 if (request_contains_enctype(context, request, db_etype)) { 689 assert(etype_info2 || 690 !enctype_requires_etype_info_2(db_etype)); 691 if ((retval = _make_etype_info_entry(context, request, client_key, 692 db_etype, &entry[i], etype_info2)) != 0) { 693 goto cleanup; 694 } 695 entry[i+1] = 0; 696 i++; 697 } 698 699 /* 700 * If there is a des key in the kdb, try the "similar" enctypes, 701 * avoid duplicate entries. 702 */ 703 if (!seen_des) { 704 switch (db_etype) { 705 case ENCTYPE_DES_CBC_MD5: 706 db_etype = ENCTYPE_DES_CBC_CRC; 707 break; 708 case ENCTYPE_DES_CBC_CRC: 709 db_etype = ENCTYPE_DES_CBC_MD5; 710 break; 711 default: 712 continue; 713 714 } 715 if (request_contains_enctype(context, request, db_etype)) { 716 if ((retval = _make_etype_info_entry(context, request, 717 client_key, db_etype, &entry[i], etype_info2)) != 0) { 718 goto cleanup; 719 } 720 entry[i+1] = 0; 721 i++; 722 } 723 seen_des++; 724 } 725 } 726 if (etype_info2) 727 retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, 728 &scratch); 729 else 730 retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, &scratch); 731 if (retval) 732 goto cleanup; 733 pa_data->contents = (unsigned char *)scratch->data; 734 pa_data->length = scratch->length; 735 /* 736 * note, don't free scratch->data as it is in use (don't use 737 * krb5_free_data() either). 738 */ 739 free(scratch); 740 741 retval = 0; 742 743 cleanup: 744 if (entry) 745 krb5_free_etype_info(context, entry); 746 return retval; 747 } 748 749 static krb5_error_code 750 get_etype_info(krb5_context context, krb5_kdc_req *request, 751 krb5_db_entry *client, krb5_db_entry *server, 752 krb5_pa_data *pa_data) 753 { 754 int i; 755 for (i=0; i < request->nktypes; i++) { 756 if (enctype_requires_etype_info_2(request->ktype[i])) 757 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will 758 * skip this 759 * type*/ 760 } 761 return etype_info_helper(context, request, client, server, pa_data, 0); 762 } 763 764 static krb5_error_code 765 get_etype_info2(krb5_context context, krb5_kdc_req *request, 766 krb5_db_entry *client, krb5_db_entry *server, 767 krb5_pa_data *pa_data) 768 { 769 return etype_info_helper( context, request, client, server, pa_data, 1); 770 } 771 772 static krb5_error_code 773 return_etype_info2(krb5_context context, krb5_pa_data * padata, 774 krb5_db_entry *client, 775 krb5_kdc_req *request, krb5_kdc_rep *reply, 776 krb5_key_data *client_key, 777 krb5_keyblock *encrypting_key, 778 krb5_pa_data **send_pa) 779 { 780 krb5_error_code retval; 781 krb5_pa_data *tmp_padata; 782 krb5_etype_info_entry **entry = NULL; 783 krb5_data *scratch = NULL; 784 785 tmp_padata = malloc( sizeof(krb5_pa_data)); 786 if (tmp_padata == NULL) 787 return ENOMEM; 788 tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2; 789 entry = malloc(2 * sizeof(krb5_etype_info_entry *)); 790 if (entry == NULL) { 791 retval = ENOMEM; 792 goto cleanup; 793 } 794 entry[0] = NULL; 795 entry[1] = NULL; 796 retval = _make_etype_info_entry(context, request, 797 client_key, client_key->key_data_type[0], 798 entry, 1); 799 if (retval) 800 goto cleanup; 801 802 retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, 803 &scratch); 804 if (retval) 805 goto cleanup; 806 tmp_padata->contents = (uchar_t *)scratch->data; 807 tmp_padata->length = scratch->length; 808 *send_pa = tmp_padata; 809 810 /* For cleanup - we no longer own the contents of the krb5_data 811 * only to pointer to the krb5_data 812 */ 813 scratch->data = 0; 814 815 cleanup: 816 if (entry) 817 krb5_free_etype_info(context, entry); 818 if (retval) { 819 if (tmp_padata) 820 free(tmp_padata); 821 } 822 if (scratch) 823 krb5_free_data(context, scratch); 824 return retval; 825 } 826 827 828 static krb5_error_code 829 return_pw_salt(context, in_padata, client, request, reply, client_key, 830 encrypting_key, send_pa) 831 krb5_context context; 832 krb5_pa_data * in_padata; 833 krb5_db_entry * client; 834 krb5_kdc_req * request; 835 krb5_kdc_rep * reply; 836 krb5_key_data * client_key; 837 krb5_keyblock * encrypting_key; 838 krb5_pa_data ** send_pa; 839 { 840 krb5_error_code retval; 841 krb5_pa_data * padata; 842 krb5_data * scratch; 843 krb5_data salt_data; 844 int i; 845 846 for (i = 0; i < request->nktypes; i++) { 847 if (enctype_requires_etype_info_2(request->ktype[i])) 848 return 0; 849 } 850 851 if (client_key->key_data_ver == 1 || 852 client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL) 853 return 0; 854 855 if ((padata = malloc(sizeof(krb5_pa_data))) == NULL) 856 return ENOMEM; 857 padata->magic = KV5M_PA_DATA; 858 padata->pa_type = KRB5_PADATA_PW_SALT; 859 860 switch (client_key->key_data_type[1]) { 861 case KRB5_KDB_SALTTYPE_V4: 862 /* send an empty (V4) salt */ 863 padata->contents = 0; 864 padata->length = 0; 865 break; 866 case KRB5_KDB_SALTTYPE_NOREALM: 867 if ((retval = krb5_principal2salt_norealm(kdc_context, 868 request->client, 869 &salt_data))) 870 goto cleanup; 871 padata->contents = (krb5_octet *)salt_data.data; 872 padata->length = salt_data.length; 873 break; 874 case KRB5_KDB_SALTTYPE_AFS3: 875 /* send an AFS style realm-based salt */ 876 /* for now, just pass the realm back and let the client 877 do the work. In the future, add a kdc configuration 878 variable that specifies the old cell name. */ 879 padata->pa_type = KRB5_PADATA_AFS3_SALT; 880 /* it would be just like ONLYREALM, but we need to pass the 0 */ 881 scratch = krb5_princ_realm(kdc_context, request->client); 882 if ((padata->contents = malloc(scratch->length+1)) == NULL) { 883 retval = ENOMEM; 884 goto cleanup; 885 } 886 memcpy(padata->contents, scratch->data, scratch->length); 887 padata->length = scratch->length+1; 888 padata->contents[scratch->length] = 0; 889 break; 890 case KRB5_KDB_SALTTYPE_ONLYREALM: 891 scratch = krb5_princ_realm(kdc_context, request->client); 892 if ((padata->contents = malloc(scratch->length)) == NULL) { 893 retval = ENOMEM; 894 goto cleanup; 895 } 896 memcpy(padata->contents, scratch->data, scratch->length); 897 padata->length = scratch->length; 898 break; 899 case KRB5_KDB_SALTTYPE_SPECIAL: 900 if ((padata->contents = malloc(client_key->key_data_length[1])) 901 == NULL) { 902 retval = ENOMEM; 903 goto cleanup; 904 } 905 memcpy(padata->contents, client_key->key_data_contents[1], 906 client_key->key_data_length[1]); 907 padata->length = client_key->key_data_length[1]; 908 break; 909 default: 910 free(padata); 911 return 0; 912 } 913 914 *send_pa = padata; 915 return 0; 916 917 cleanup: 918 free(padata); 919 return retval; 920 } 921 922 static krb5_error_code 923 return_sam_data(context, in_padata, client, request, reply, client_key, 924 encrypting_key, send_pa) 925 krb5_context context; 926 krb5_pa_data * in_padata; 927 krb5_db_entry * client; 928 krb5_kdc_req * request; 929 krb5_kdc_rep * reply; 930 krb5_key_data * client_key; 931 krb5_keyblock * encrypting_key; 932 krb5_pa_data ** send_pa; 933 { 934 krb5_error_code retval; 935 krb5_data scratch; 936 int i; 937 938 krb5_sam_response *sr = 0; 939 krb5_predicted_sam_response *psr = 0; 940 941 if (in_padata == 0) 942 return 0; 943 944 /* 945 * We start by doing the same thing verify_sam_response() does: 946 * extract the psr from the padata (which is an sr). Nothing 947 * here should generate errors! We've already successfully done 948 * all this once. 949 */ 950 951 scratch.data = (char *) in_padata->contents; /* SUNWresync121 XXX */ 952 scratch.length = in_padata->length; 953 954 if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 955 com_err("krb5kdc", retval, 956 gettext("return_sam_data(): decode_krb5_sam_response failed")); 957 goto cleanup; 958 } 959 960 { 961 krb5_enc_data tmpdata; 962 963 tmpdata.enctype = ENCTYPE_UNKNOWN; 964 tmpdata.ciphertext = sr->sam_track_id; 965 966 scratch.length = tmpdata.ciphertext.length; 967 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 968 retval = ENOMEM; 969 goto cleanup; 970 } 971 972 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 973 &tmpdata, &scratch))) { 974 com_err("krb5kdc", retval, 975 gettext("return_sam_data(): decrypt track_id failed")); 976 free(scratch.data); 977 goto cleanup; 978 } 979 } 980 981 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 982 com_err("krb5kdc", retval, 983 gettext( 984 "return_sam_data(): decode_krb5_predicted_sam_response failed")); 985 free(scratch.data); 986 goto cleanup; 987 } 988 989 /* We could use sr->sam_flags, but it may be absent or altered. */ 990 if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) { 991 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 992 gettext("Unsupported SAM flag must-pk-encrypt-sad")); 993 goto cleanup; 994 } 995 if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) { 996 /* No key munging */ 997 goto cleanup; 998 } 999 if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) { 1000 /* Use sam_key instead of client key */ 1001 krb5_free_keyblock_contents(context, encrypting_key); 1002 krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key); 1003 /* XXX Attach a useful pa_data */ 1004 goto cleanup; 1005 } 1006 1007 /* Otherwise (no flags set), we XOR the keys */ 1008 /* XXX The passwords-04 draft is underspecified here wrt different 1009 key types. We will do what I hope to get into the -05 draft. */ 1010 { 1011 krb5_octet *p = encrypting_key->contents; 1012 krb5_octet *q = psr->sam_key.contents; 1013 int length = ((encrypting_key->length < psr->sam_key.length) 1014 ? encrypting_key->length 1015 : psr->sam_key.length); 1016 1017 for (i = 0; i < length; i++) 1018 p[i] ^= q[i]; 1019 } 1020 1021 /* Post-mixing key correction */ 1022 switch (encrypting_key->enctype) { 1023 case ENCTYPE_DES_CBC_CRC: 1024 case ENCTYPE_DES_CBC_MD4: 1025 case ENCTYPE_DES_CBC_MD5: 1026 case ENCTYPE_DES_CBC_RAW: 1027 mit_des_fixup_key_parity(encrypting_key->contents); 1028 if (mit_des_is_weak_key(encrypting_key->contents)) 1029 ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0; 1030 break; 1031 1032 /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */ 1033 case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */ 1034 case ENCTYPE_DES3_CBC_RAW: 1035 case ENCTYPE_DES3_CBC_SHA1: 1036 for (i = 0; i < 3; i++) { 1037 mit_des_fixup_key_parity(encrypting_key->contents + i * 8); 1038 if (mit_des_is_weak_key(encrypting_key->contents + i * 8)) 1039 ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0; 1040 } 1041 break; 1042 1043 default: 1044 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1045 gettext("Unimplemented keytype for SAM key mixing")); 1046 goto cleanup; 1047 } 1048 1049 /* XXX Attach a useful pa_data */ 1050 cleanup: 1051 if (sr) 1052 krb5_free_sam_response(context, sr); 1053 if (psr) 1054 krb5_free_predicted_sam_response(context, psr); 1055 1056 return retval; 1057 } 1058 1059 static struct { 1060 char* name; 1061 int sam_type; 1062 } *sam_ptr, sam_inst_map[] = { 1063 #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */ 1064 { "SNK4", PA_SAM_TYPE_DIGI_PATH, }, 1065 { "SECURID", PA_SAM_TYPE_SECURID, }, 1066 { "GRAIL", PA_SAM_TYPE_GRAIL, }, 1067 #endif 1068 { 0, 0 }, 1069 }; 1070 1071 static krb5_error_code 1072 get_sam_edata(context, request, client, server, pa_data) 1073 krb5_context context; 1074 krb5_kdc_req * request; 1075 krb5_db_entry * client; 1076 krb5_db_entry * server; 1077 krb5_pa_data * pa_data; 1078 { 1079 krb5_error_code retval; 1080 krb5_sam_challenge sc; 1081 krb5_predicted_sam_response psr; 1082 krb5_data * scratch; 1083 krb5_keyblock encrypting_key; 1084 char response[9]; 1085 char inputblock[8]; 1086 krb5_data predict_response; 1087 1088 (void) memset(&encrypting_key, 0, sizeof(krb5_keyblock)); 1089 (void) memset(&sc, 0, sizeof(sc)); 1090 (void) memset(&psr, 0, sizeof(psr)); 1091 1092 /* Given the client name we can figure out what type of preauth 1093 they need. The spec is currently for querying the database for 1094 names that match the types of preauth used. Later we should 1095 make this mapping show up in kdc.conf. In the meantime, we 1096 hardcode the following: 1097 /SNK4 -- Digital Pathways SNK/4 preauth. 1098 /GRAIL -- experimental preauth 1099 The first one found is used. See sam_inst_map above. 1100 1101 For SNK4 in particular, the key in the database is the key for 1102 the device; kadmin needs a special interface for it. 1103 */ 1104 1105 { 1106 int npr = 1, more; 1107 krb5_db_entry assoc; 1108 krb5_key_data *assoc_key; 1109 krb5_principal newp; 1110 int probeslot; 1111 1112 sc.sam_type = 0; 1113 1114 retval = krb5_copy_principal(kdc_context, request->client, &newp); 1115 if (retval) { 1116 com_err(gettext("krb5kdc"), 1117 retval, 1118 gettext("copying client name for preauth probe")); 1119 return retval; 1120 } 1121 1122 probeslot = krb5_princ_size(context, newp)++; 1123 krb5_princ_name(kdc_context, newp) = 1124 realloc(krb5_princ_name(kdc_context, newp), 1125 krb5_princ_size(context, newp) * sizeof(krb5_data)); 1126 1127 for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) { 1128 krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name; 1129 krb5_princ_component(kdc_context,newp,probeslot)->length = 1130 strlen(sam_ptr->name); 1131 npr = 1; 1132 retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, (uint *)&more); 1133 if(!retval) { 1134 sc.sam_type = sam_ptr->sam_type; 1135 break; 1136 } 1137 } 1138 1139 krb5_princ_component(kdc_context,newp,probeslot)->data = 0; 1140 krb5_princ_component(kdc_context,newp,probeslot)->length = 0; 1141 krb5_princ_size(context, newp)--; 1142 1143 krb5_free_principal(kdc_context, newp); 1144 1145 /* if sc.sam_type is set, it worked */ 1146 if (sc.sam_type) { 1147 /* so use assoc to get the key out! */ 1148 { 1149 /* here's what do_tgs_req does */ 1150 retval = krb5_dbe_find_enctype(kdc_context, &assoc, 1151 ENCTYPE_DES_CBC_RAW, 1152 KRB5_KDB_SALTTYPE_NORMAL, 1153 0, /* Get highest kvno */ 1154 &assoc_key); 1155 if (retval) { 1156 char *sname; 1157 krb5_unparse_name(kdc_context, request->client, &sname); 1158 com_err(gettext("krb5kdc"), 1159 retval, 1160 gettext("snk4 finding the enctype and key <%s>"), 1161 sname); 1162 free(sname); 1163 return retval; 1164 } 1165 /* convert server.key into a real key */ 1166 retval = krb5_dbekd_decrypt_key_data(kdc_context, 1167 &master_keyblock, 1168 assoc_key, &encrypting_key, 1169 NULL); 1170 if (retval) { 1171 com_err(gettext("krb5kdc"), 1172 retval, 1173 gettext("snk4 pulling out key entry")); 1174 return retval; 1175 } 1176 /* now we can use encrypting_key... */ 1177 } 1178 } else { 1179 /* SAM is not an option - so don't return as hint */ 1180 return KRB5_PREAUTH_BAD_TYPE; 1181 } 1182 } 1183 sc.magic = KV5M_SAM_CHALLENGE; 1184 psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY; 1185 1186 /* Replay prevention */ 1187 if ((retval = krb5_copy_principal(context, request->client, &psr.client))) 1188 return retval; 1189 #ifdef USE_RCACHE 1190 if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))) 1191 return retval; 1192 #endif /* USE_RCACHE */ 1193 1194 switch (sc.sam_type) { 1195 case PA_SAM_TYPE_GRAIL: 1196 sc.sam_type_name.data = "Experimental System"; 1197 sc.sam_type_name.length = strlen(sc.sam_type_name.data); 1198 sc.sam_challenge_label.data = "experimental challenge label"; 1199 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1200 sc.sam_challenge.data = "12345"; 1201 sc.sam_challenge.length = strlen(sc.sam_challenge.data); 1202 1203 #if 0 /* Enable this to test "normal" (no flags set) mode. */ 1204 psr.sam_flags = sc.sam_flags = 0; 1205 #endif 1206 1207 psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 1208 /* string2key on sc.sam_challenge goes in here */ 1209 /* eblock is just to set the enctype */ 1210 { 1211 const krb5_enctype type = ENCTYPE_DES_CBC_MD5; 1212 1213 if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge, 1214 0 /* salt */, &psr.sam_key))) 1215 goto cleanup; 1216 1217 if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch))) 1218 goto cleanup; 1219 1220 { 1221 size_t enclen; 1222 krb5_enc_data tmpdata; 1223 1224 if ((retval = krb5_c_encrypt_length(context, 1225 psr_key.enctype, 1226 scratch->length, &enclen))) 1227 goto cleanup; 1228 1229 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 1230 retval = ENOMEM; 1231 goto cleanup; 1232 } 1233 tmpdata.ciphertext.length = enclen; 1234 1235 if ((retval = krb5_c_encrypt(context, &psr_key, 1236 /* XXX */ 0, 0, scratch, &tmpdata))) 1237 goto cleanup; 1238 1239 sc.sam_track_id = tmpdata.ciphertext; 1240 } 1241 } 1242 1243 sc.sam_response_prompt.data = "response prompt"; 1244 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 1245 sc.sam_pk_for_sad.length = 0; 1246 sc.sam_nonce = 0; 1247 /* Generate checksum */ 1248 /*krb5_checksum_size(context, ctype)*/ 1249 /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 1250 seed_length,outcksum) */ 1251 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 1252 seed_length) */ 1253 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 1254 sc.sam_cksum.contents = (krb5_octet *) 1255 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 1256 if (sc.sam_cksum.contents == NULL) return(ENOMEM); 1257 1258 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 1259 sc.sam_challenge.data, 1260 sc.sam_challenge.length, 1261 psr.sam_key.contents, /* key */ 1262 psr.sam_key.length, /* key length */ 1263 &sc.sam_cksum); 1264 if (retval) { free(sc.sam_cksum.contents); return(retval); } 1265 #endif /* 0 */ 1266 1267 retval = encode_krb5_sam_challenge(&sc, &scratch); 1268 if (retval) goto cleanup; 1269 pa_data->magic = KV5M_PA_DATA; 1270 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 1271 pa_data->contents = (unsigned char *) scratch->data; 1272 pa_data->length = scratch->length; 1273 1274 retval = 0; 1275 break; 1276 case PA_SAM_TYPE_DIGI_PATH: 1277 sc.sam_type_name.data = "Digital Pathways"; 1278 sc.sam_type_name.length = strlen(sc.sam_type_name.data); 1279 #if 1 1280 sc.sam_challenge_label.data = "Enter the following on your keypad"; 1281 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1282 #endif 1283 /* generate digit string, take it mod 1000000 (six digits.) */ 1284 { 1285 int j; 1286 krb5_keyblock session_key; 1287 char outputblock[8]; 1288 int i; 1289 1290 (void) memset(&session_key, 0, sizeof(krb5_keyblock)); 1291 (void) memset(inputblock, 0, 8); 1292 1293 retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC, 1294 &session_key); 1295 1296 if (retval) { 1297 /* random key failed */ 1298 com_err(gettext("krb5kdc"), 1299 retval, 1300 gettext("generating random challenge for preauth")); 1301 return retval; 1302 } 1303 /* now session_key has a key which we can pick bits out of */ 1304 /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */ 1305 if (session_key.length != 8) { 1306 retval = KRB5KDC_ERR_ETYPE_NOSUPP, 1307 com_err(gettext("krb5kdc"), 1308 retval = KRB5KDC_ERR_ETYPE_NOSUPP, 1309 gettext("keytype didn't match code expectations")); 1310 return retval; 1311 } 1312 for(i = 0; i<6; i++) { 1313 inputblock[i] = '0' + ((session_key.contents[i]/2) % 10); 1314 } 1315 if (session_key.contents) 1316 krb5_free_keyblock_contents(kdc_context, &session_key); 1317 1318 /* retval = krb5_finish_key(kdc_context, &eblock); */ 1319 /* now we have inputblock containing the 8 byte input to DES... */ 1320 sc.sam_challenge.data = inputblock; 1321 sc.sam_challenge.length = 6; 1322 1323 encrypting_key.enctype = ENCTYPE_DES_CBC_RAW; 1324 1325 if (retval) { 1326 com_err(gettext("krb5kdc"), 1327 retval, 1328 gettext("snk4 processing key")); 1329 } 1330 1331 { 1332 krb5_data plain; 1333 krb5_enc_data cipher; 1334 1335 plain.length = 8; 1336 plain.data = inputblock; 1337 1338 /* XXX I know this is enough because of the fixed raw enctype. 1339 if it's not, the underlying code will return a reasonable 1340 error, which should never happen */ 1341 cipher.ciphertext.length = 8; 1342 cipher.ciphertext.data = outputblock; 1343 1344 if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key, 1345 /* XXX */ 0, 0, &plain, &cipher))) { 1346 com_err(gettext("krb5kdc"), 1347 retval, 1348 gettext("snk4 response generation failed")); 1349 return retval; 1350 } 1351 } 1352 1353 /* now output block is the raw bits of the response; convert it 1354 to display form */ 1355 for (j=0; j<4; j++) { 1356 char n[2]; 1357 int k; 1358 n[0] = outputblock[j] & 0xf; 1359 n[1] = (outputblock[j]>>4) & 0xf; 1360 for (k=0; k<2; k++) { 1361 if(n[k] > 9) n[k] = ((n[k]-1)>>2); 1362 /* This is equivalent to: 1363 if(n[k]>=0xa && n[k]<=0xc) n[k] = 2; 1364 if(n[k]>=0xd && n[k]<=0xf) n[k] = 3; 1365 */ 1366 } 1367 /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */ 1368 /* for v5, we just generate a string */ 1369 response[2*j+0] = '0' + n[1]; 1370 response[2*j+1] = '0' + n[0]; 1371 /* and now, response has what we work with. */ 1372 } 1373 response[8] = 0; 1374 predict_response.data = response; 1375 predict_response.length = 8; 1376 #if 0 /* for debugging, hack the output too! */ 1377 sc.sam_challenge_label.data = response; 1378 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1379 #endif 1380 } 1381 1382 psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 1383 /* string2key on sc.sam_challenge goes in here */ 1384 /* eblock is just to set the enctype */ 1385 { 1386 retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5, 1387 &predict_response, 0 /* salt */, 1388 &psr.sam_key); 1389 if (retval) goto cleanup; 1390 1391 retval = encode_krb5_predicted_sam_response(&psr, &scratch); 1392 if (retval) goto cleanup; 1393 1394 { 1395 size_t enclen; 1396 krb5_enc_data tmpdata; 1397 1398 if ((retval = krb5_c_encrypt_length(context, 1399 psr_key.enctype, 1400 scratch->length, &enclen))) 1401 goto cleanup; 1402 1403 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 1404 retval = ENOMEM; 1405 goto cleanup; 1406 } 1407 tmpdata.ciphertext.length = enclen; 1408 1409 if ((retval = krb5_c_encrypt(context, &psr_key, 1410 /* XXX */ 0, 0, scratch, &tmpdata))) 1411 goto cleanup; 1412 1413 sc.sam_track_id = tmpdata.ciphertext; 1414 } 1415 if (retval) goto cleanup; 1416 } 1417 1418 sc.sam_response_prompt.data = "Enter the displayed response"; 1419 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 1420 sc.sam_pk_for_sad.length = 0; 1421 sc.sam_nonce = 0; 1422 /* Generate checksum */ 1423 /*krb5_checksum_size(context, ctype)*/ 1424 /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 1425 seed_length,outcksum) */ 1426 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 1427 seed_length) */ 1428 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 1429 sc.sam_cksum.contents = (krb5_octet *) 1430 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 1431 if (sc.sam_cksum.contents == NULL) return(ENOMEM); 1432 1433 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 1434 sc.sam_challenge.data, 1435 sc.sam_challenge.length, 1436 psr.sam_key.contents, /* key */ 1437 psr.sam_key.length, /* key length */ 1438 &sc.sam_cksum); 1439 if (retval) { free(sc.sam_cksum.contents); return(retval); } 1440 #endif /* 0 */ 1441 1442 retval = encode_krb5_sam_challenge(&sc, &scratch); 1443 if (retval) goto cleanup; 1444 pa_data->magic = KV5M_PA_DATA; 1445 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 1446 pa_data->contents = (unsigned char *) scratch->data; 1447 pa_data->length = scratch->length; 1448 1449 retval = 0; 1450 break; 1451 } 1452 1453 cleanup: 1454 krb5_free_keyblock_contents(context, &encrypting_key); 1455 return retval; 1456 } 1457 1458 static krb5_error_code 1459 verify_sam_response(context, client, request, enc_tkt_reply, pa) 1460 krb5_context context; 1461 krb5_db_entry * client; 1462 krb5_kdc_req * request; 1463 krb5_enc_tkt_part * enc_tkt_reply; 1464 krb5_pa_data * pa; 1465 { 1466 krb5_error_code retval; 1467 krb5_data scratch; 1468 krb5_sam_response *sr = 0; 1469 krb5_predicted_sam_response *psr = 0; 1470 krb5_enc_sam_response_enc *esre = 0; 1471 krb5_timestamp timenow; 1472 char *princ_req = 0, *princ_psr = 0; 1473 1474 scratch.data = (char *) pa->contents; 1475 scratch.length = pa->length; 1476 1477 if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 1478 scratch.data = 0; 1479 com_err("krb5kdc", retval, gettext("decode_krb5_sam_response failed")); 1480 goto cleanup; 1481 } 1482 1483 /* XXX We can only handle the challenge/response model of SAM. 1484 See passwords-04, par 4.1, 4.2 */ 1485 { 1486 krb5_enc_data tmpdata; 1487 1488 tmpdata.enctype = ENCTYPE_UNKNOWN; 1489 tmpdata.ciphertext = sr->sam_track_id; 1490 1491 scratch.length = tmpdata.ciphertext.length; 1492 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 1493 retval = ENOMEM; 1494 goto cleanup; 1495 } 1496 1497 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 1498 &tmpdata, &scratch))) { 1499 com_err(gettext("krb5kdc"), 1500 retval, 1501 gettext("decrypt track_id failed")); 1502 goto cleanup; 1503 } 1504 } 1505 1506 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 1507 com_err(gettext("krb5kdc"), retval, 1508 gettext("decode_krb5_predicted_sam_response failed -- replay attack?")); 1509 goto cleanup; 1510 } 1511 1512 /* Replay detection */ 1513 if ((retval = krb5_unparse_name(context, request->client, &princ_req))) 1514 goto cleanup; 1515 if ((retval = krb5_unparse_name(context, psr->client, &princ_psr))) 1516 goto cleanup; 1517 if (strcmp(princ_req, princ_psr) != 0) { 1518 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1519 gettext("Principal mismatch in SAM psr! -- replay attack?")); 1520 goto cleanup; 1521 } 1522 1523 if ((retval = krb5_timeofday(context, &timenow))) 1524 goto cleanup; 1525 1526 #ifdef USE_RCACHE 1527 { 1528 krb5_donot_replay rep; 1529 extern krb5_deltat rc_lifetime; 1530 /* 1531 * Verify this response came back in a timely manner. 1532 * We do this b/c otherwise very old (expunged from the rcache) 1533 * psr's would be able to be replayed. 1534 */ 1535 if (timenow - psr->stime > rc_lifetime) { 1536 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1537 gettext("SAM psr came back too late! -- replay attack?")); 1538 goto cleanup; 1539 } 1540 1541 /* Now check the replay cache. */ 1542 rep.client = princ_psr; 1543 rep.server = "SAM/rc"; /* Should not match any principal name. */ 1544 rep.ctime = psr->stime; 1545 rep.cusec = psr->susec; 1546 if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) { 1547 com_err("krb5kdc", retval, gettext("SAM psr replay attack!")); 1548 goto cleanup; 1549 } 1550 } 1551 #endif /* USE_RCACHE */ 1552 1553 1554 { 1555 free(scratch.data); 1556 scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length; 1557 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 1558 retval = ENOMEM; 1559 goto cleanup; 1560 } 1561 1562 if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0, 1563 0, &sr->sam_enc_nonce_or_ts, &scratch))) { 1564 com_err("krb5kdc", retval, gettext("decrypt nonce_or_ts failed")); 1565 goto cleanup; 1566 } 1567 } 1568 1569 if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) { 1570 com_err("krb5kdc", retval, gettext("decode_krb5_enc_sam_response_enc failed")); 1571 goto cleanup; 1572 } 1573 1574 if (esre->sam_timestamp != sr->sam_patimestamp) { 1575 retval = KRB5KDC_ERR_PREAUTH_FAILED; 1576 goto cleanup; 1577 } 1578 1579 if (labs(timenow - sr->sam_patimestamp) > context->clockskew) { 1580 retval = KRB5KRB_AP_ERR_SKEW; 1581 goto cleanup; 1582 } 1583 1584 setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH); 1585 1586 cleanup: 1587 if (retval) com_err(gettext("krb5kdc"), 1588 retval, 1589 gettext("sam verify failure")); 1590 if (scratch.data) free(scratch.data); 1591 if (sr) free(sr); 1592 if (psr) free(psr); 1593 if (esre) free(esre); 1594 1595 return retval; 1596 } 1597