1 /* 2 * Copyright 2005 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 /* using encrypting_key->enctype as this is specified in rfc4120 */ 797 retval = _make_etype_info_entry(context, request, 798 client_key, encrypting_key->enctype, 799 entry, 1); 800 if (retval) 801 goto cleanup; 802 803 retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, 804 &scratch); 805 if (retval) 806 goto cleanup; 807 tmp_padata->contents = (uchar_t *)scratch->data; 808 tmp_padata->length = scratch->length; 809 *send_pa = tmp_padata; 810 811 /* For cleanup - we no longer own the contents of the krb5_data 812 * only to pointer to the krb5_data 813 */ 814 scratch->data = 0; 815 816 cleanup: 817 if (entry) 818 krb5_free_etype_info(context, entry); 819 if (retval) { 820 if (tmp_padata) 821 free(tmp_padata); 822 } 823 if (scratch) 824 krb5_free_data(context, scratch); 825 return retval; 826 } 827 828 829 static krb5_error_code 830 return_pw_salt(context, in_padata, client, request, reply, client_key, 831 encrypting_key, send_pa) 832 krb5_context context; 833 krb5_pa_data * in_padata; 834 krb5_db_entry * client; 835 krb5_kdc_req * request; 836 krb5_kdc_rep * reply; 837 krb5_key_data * client_key; 838 krb5_keyblock * encrypting_key; 839 krb5_pa_data ** send_pa; 840 { 841 krb5_error_code retval; 842 krb5_pa_data * padata; 843 krb5_data * scratch; 844 krb5_data salt_data; 845 int i; 846 847 for (i = 0; i < request->nktypes; i++) { 848 if (enctype_requires_etype_info_2(request->ktype[i])) 849 return 0; 850 } 851 852 if (client_key->key_data_ver == 1 || 853 client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL) 854 return 0; 855 856 if ((padata = malloc(sizeof(krb5_pa_data))) == NULL) 857 return ENOMEM; 858 padata->magic = KV5M_PA_DATA; 859 padata->pa_type = KRB5_PADATA_PW_SALT; 860 861 switch (client_key->key_data_type[1]) { 862 case KRB5_KDB_SALTTYPE_V4: 863 /* send an empty (V4) salt */ 864 padata->contents = 0; 865 padata->length = 0; 866 break; 867 case KRB5_KDB_SALTTYPE_NOREALM: 868 if ((retval = krb5_principal2salt_norealm(kdc_context, 869 request->client, 870 &salt_data))) 871 goto cleanup; 872 padata->contents = (krb5_octet *)salt_data.data; 873 padata->length = salt_data.length; 874 break; 875 case KRB5_KDB_SALTTYPE_AFS3: 876 /* send an AFS style realm-based salt */ 877 /* for now, just pass the realm back and let the client 878 do the work. In the future, add a kdc configuration 879 variable that specifies the old cell name. */ 880 padata->pa_type = KRB5_PADATA_AFS3_SALT; 881 /* it would be just like ONLYREALM, but we need to pass the 0 */ 882 scratch = krb5_princ_realm(kdc_context, request->client); 883 if ((padata->contents = malloc(scratch->length+1)) == NULL) { 884 retval = ENOMEM; 885 goto cleanup; 886 } 887 memcpy(padata->contents, scratch->data, scratch->length); 888 padata->length = scratch->length+1; 889 padata->contents[scratch->length] = 0; 890 break; 891 case KRB5_KDB_SALTTYPE_ONLYREALM: 892 scratch = krb5_princ_realm(kdc_context, request->client); 893 if ((padata->contents = malloc(scratch->length)) == NULL) { 894 retval = ENOMEM; 895 goto cleanup; 896 } 897 memcpy(padata->contents, scratch->data, scratch->length); 898 padata->length = scratch->length; 899 break; 900 case KRB5_KDB_SALTTYPE_SPECIAL: 901 if ((padata->contents = malloc(client_key->key_data_length[1])) 902 == NULL) { 903 retval = ENOMEM; 904 goto cleanup; 905 } 906 memcpy(padata->contents, client_key->key_data_contents[1], 907 client_key->key_data_length[1]); 908 padata->length = client_key->key_data_length[1]; 909 break; 910 default: 911 free(padata); 912 return 0; 913 } 914 915 *send_pa = padata; 916 return 0; 917 918 cleanup: 919 free(padata); 920 return retval; 921 } 922 923 static krb5_error_code 924 return_sam_data(context, in_padata, client, request, reply, client_key, 925 encrypting_key, send_pa) 926 krb5_context context; 927 krb5_pa_data * in_padata; 928 krb5_db_entry * client; 929 krb5_kdc_req * request; 930 krb5_kdc_rep * reply; 931 krb5_key_data * client_key; 932 krb5_keyblock * encrypting_key; 933 krb5_pa_data ** send_pa; 934 { 935 krb5_error_code retval; 936 krb5_data scratch; 937 int i; 938 939 krb5_sam_response *sr = 0; 940 krb5_predicted_sam_response *psr = 0; 941 942 if (in_padata == 0) 943 return 0; 944 945 /* 946 * We start by doing the same thing verify_sam_response() does: 947 * extract the psr from the padata (which is an sr). Nothing 948 * here should generate errors! We've already successfully done 949 * all this once. 950 */ 951 952 scratch.data = (char *) in_padata->contents; /* SUNWresync121 XXX */ 953 scratch.length = in_padata->length; 954 955 if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 956 com_err("krb5kdc", retval, 957 gettext("return_sam_data(): decode_krb5_sam_response failed")); 958 goto cleanup; 959 } 960 961 { 962 krb5_enc_data tmpdata; 963 964 tmpdata.enctype = ENCTYPE_UNKNOWN; 965 tmpdata.ciphertext = sr->sam_track_id; 966 967 scratch.length = tmpdata.ciphertext.length; 968 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 969 retval = ENOMEM; 970 goto cleanup; 971 } 972 973 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 974 &tmpdata, &scratch))) { 975 com_err("krb5kdc", retval, 976 gettext("return_sam_data(): decrypt track_id failed")); 977 free(scratch.data); 978 goto cleanup; 979 } 980 } 981 982 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 983 com_err("krb5kdc", retval, 984 gettext( 985 "return_sam_data(): decode_krb5_predicted_sam_response failed")); 986 free(scratch.data); 987 goto cleanup; 988 } 989 990 /* We could use sr->sam_flags, but it may be absent or altered. */ 991 if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) { 992 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 993 gettext("Unsupported SAM flag must-pk-encrypt-sad")); 994 goto cleanup; 995 } 996 if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) { 997 /* No key munging */ 998 goto cleanup; 999 } 1000 if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) { 1001 /* Use sam_key instead of client key */ 1002 krb5_free_keyblock_contents(context, encrypting_key); 1003 krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key); 1004 /* XXX Attach a useful pa_data */ 1005 goto cleanup; 1006 } 1007 1008 /* Otherwise (no flags set), we XOR the keys */ 1009 /* XXX The passwords-04 draft is underspecified here wrt different 1010 key types. We will do what I hope to get into the -05 draft. */ 1011 { 1012 krb5_octet *p = encrypting_key->contents; 1013 krb5_octet *q = psr->sam_key.contents; 1014 int length = ((encrypting_key->length < psr->sam_key.length) 1015 ? encrypting_key->length 1016 : psr->sam_key.length); 1017 1018 for (i = 0; i < length; i++) 1019 p[i] ^= q[i]; 1020 } 1021 1022 /* Post-mixing key correction */ 1023 switch (encrypting_key->enctype) { 1024 case ENCTYPE_DES_CBC_CRC: 1025 case ENCTYPE_DES_CBC_MD4: 1026 case ENCTYPE_DES_CBC_MD5: 1027 case ENCTYPE_DES_CBC_RAW: 1028 mit_des_fixup_key_parity(encrypting_key->contents); 1029 if (mit_des_is_weak_key(encrypting_key->contents)) 1030 ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0; 1031 break; 1032 1033 /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */ 1034 case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */ 1035 case ENCTYPE_DES3_CBC_RAW: 1036 case ENCTYPE_DES3_CBC_SHA1: 1037 for (i = 0; i < 3; i++) { 1038 mit_des_fixup_key_parity(encrypting_key->contents + i * 8); 1039 if (mit_des_is_weak_key(encrypting_key->contents + i * 8)) 1040 ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0; 1041 } 1042 break; 1043 1044 default: 1045 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1046 gettext("Unimplemented keytype for SAM key mixing")); 1047 goto cleanup; 1048 } 1049 1050 /* XXX Attach a useful pa_data */ 1051 cleanup: 1052 if (sr) 1053 krb5_free_sam_response(context, sr); 1054 if (psr) 1055 krb5_free_predicted_sam_response(context, psr); 1056 1057 return retval; 1058 } 1059 1060 static struct { 1061 char* name; 1062 int sam_type; 1063 } *sam_ptr, sam_inst_map[] = { 1064 #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */ 1065 { "SNK4", PA_SAM_TYPE_DIGI_PATH, }, 1066 { "SECURID", PA_SAM_TYPE_SECURID, }, 1067 { "GRAIL", PA_SAM_TYPE_GRAIL, }, 1068 #endif 1069 { 0, 0 }, 1070 }; 1071 1072 static krb5_error_code 1073 get_sam_edata(context, request, client, server, pa_data) 1074 krb5_context context; 1075 krb5_kdc_req * request; 1076 krb5_db_entry * client; 1077 krb5_db_entry * server; 1078 krb5_pa_data * pa_data; 1079 { 1080 krb5_error_code retval; 1081 krb5_sam_challenge sc; 1082 krb5_predicted_sam_response psr; 1083 krb5_data * scratch; 1084 krb5_keyblock encrypting_key; 1085 char response[9]; 1086 char inputblock[8]; 1087 krb5_data predict_response; 1088 1089 (void) memset(&encrypting_key, 0, sizeof(krb5_keyblock)); 1090 (void) memset(&sc, 0, sizeof(sc)); 1091 (void) memset(&psr, 0, sizeof(psr)); 1092 1093 /* Given the client name we can figure out what type of preauth 1094 they need. The spec is currently for querying the database for 1095 names that match the types of preauth used. Later we should 1096 make this mapping show up in kdc.conf. In the meantime, we 1097 hardcode the following: 1098 /SNK4 -- Digital Pathways SNK/4 preauth. 1099 /GRAIL -- experimental preauth 1100 The first one found is used. See sam_inst_map above. 1101 1102 For SNK4 in particular, the key in the database is the key for 1103 the device; kadmin needs a special interface for it. 1104 */ 1105 1106 { 1107 int npr = 1, more; 1108 krb5_db_entry assoc; 1109 krb5_key_data *assoc_key; 1110 krb5_principal newp; 1111 int probeslot; 1112 1113 sc.sam_type = 0; 1114 1115 retval = krb5_copy_principal(kdc_context, request->client, &newp); 1116 if (retval) { 1117 com_err(gettext("krb5kdc"), 1118 retval, 1119 gettext("copying client name for preauth probe")); 1120 return retval; 1121 } 1122 1123 probeslot = krb5_princ_size(context, newp)++; 1124 krb5_princ_name(kdc_context, newp) = 1125 realloc(krb5_princ_name(kdc_context, newp), 1126 krb5_princ_size(context, newp) * sizeof(krb5_data)); 1127 1128 for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) { 1129 krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name; 1130 krb5_princ_component(kdc_context,newp,probeslot)->length = 1131 strlen(sam_ptr->name); 1132 npr = 1; 1133 retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, (uint *)&more); 1134 if(!retval) { 1135 sc.sam_type = sam_ptr->sam_type; 1136 break; 1137 } 1138 } 1139 1140 krb5_princ_component(kdc_context,newp,probeslot)->data = 0; 1141 krb5_princ_component(kdc_context,newp,probeslot)->length = 0; 1142 krb5_princ_size(context, newp)--; 1143 1144 krb5_free_principal(kdc_context, newp); 1145 1146 /* if sc.sam_type is set, it worked */ 1147 if (sc.sam_type) { 1148 /* so use assoc to get the key out! */ 1149 { 1150 /* here's what do_tgs_req does */ 1151 retval = krb5_dbe_find_enctype(kdc_context, &assoc, 1152 ENCTYPE_DES_CBC_RAW, 1153 KRB5_KDB_SALTTYPE_NORMAL, 1154 0, /* Get highest kvno */ 1155 &assoc_key); 1156 if (retval) { 1157 char *sname; 1158 krb5_unparse_name(kdc_context, request->client, &sname); 1159 com_err(gettext("krb5kdc"), 1160 retval, 1161 gettext("snk4 finding the enctype and key <%s>"), 1162 sname); 1163 free(sname); 1164 return retval; 1165 } 1166 /* convert server.key into a real key */ 1167 retval = krb5_dbekd_decrypt_key_data(kdc_context, 1168 &master_keyblock, 1169 assoc_key, &encrypting_key, 1170 NULL); 1171 if (retval) { 1172 com_err(gettext("krb5kdc"), 1173 retval, 1174 gettext("snk4 pulling out key entry")); 1175 return retval; 1176 } 1177 /* now we can use encrypting_key... */ 1178 } 1179 } else { 1180 /* SAM is not an option - so don't return as hint */ 1181 return KRB5_PREAUTH_BAD_TYPE; 1182 } 1183 } 1184 sc.magic = KV5M_SAM_CHALLENGE; 1185 psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY; 1186 1187 /* Replay prevention */ 1188 if ((retval = krb5_copy_principal(context, request->client, &psr.client))) 1189 return retval; 1190 #ifdef USE_RCACHE 1191 if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))) 1192 return retval; 1193 #endif /* USE_RCACHE */ 1194 1195 switch (sc.sam_type) { 1196 case PA_SAM_TYPE_GRAIL: 1197 sc.sam_type_name.data = "Experimental System"; 1198 sc.sam_type_name.length = strlen(sc.sam_type_name.data); 1199 sc.sam_challenge_label.data = "experimental challenge label"; 1200 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1201 sc.sam_challenge.data = "12345"; 1202 sc.sam_challenge.length = strlen(sc.sam_challenge.data); 1203 1204 #if 0 /* Enable this to test "normal" (no flags set) mode. */ 1205 psr.sam_flags = sc.sam_flags = 0; 1206 #endif 1207 1208 psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 1209 /* string2key on sc.sam_challenge goes in here */ 1210 /* eblock is just to set the enctype */ 1211 { 1212 const krb5_enctype type = ENCTYPE_DES_CBC_MD5; 1213 1214 if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge, 1215 0 /* salt */, &psr.sam_key))) 1216 goto cleanup; 1217 1218 if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch))) 1219 goto cleanup; 1220 1221 { 1222 size_t enclen; 1223 krb5_enc_data tmpdata; 1224 1225 if ((retval = krb5_c_encrypt_length(context, 1226 psr_key.enctype, 1227 scratch->length, &enclen))) 1228 goto cleanup; 1229 1230 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 1231 retval = ENOMEM; 1232 goto cleanup; 1233 } 1234 tmpdata.ciphertext.length = enclen; 1235 1236 if ((retval = krb5_c_encrypt(context, &psr_key, 1237 /* XXX */ 0, 0, scratch, &tmpdata))) 1238 goto cleanup; 1239 1240 sc.sam_track_id = tmpdata.ciphertext; 1241 } 1242 } 1243 1244 sc.sam_response_prompt.data = "response prompt"; 1245 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 1246 sc.sam_pk_for_sad.length = 0; 1247 sc.sam_nonce = 0; 1248 /* Generate checksum */ 1249 /*krb5_checksum_size(context, ctype)*/ 1250 /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 1251 seed_length,outcksum) */ 1252 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 1253 seed_length) */ 1254 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 1255 sc.sam_cksum.contents = (krb5_octet *) 1256 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 1257 if (sc.sam_cksum.contents == NULL) return(ENOMEM); 1258 1259 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 1260 sc.sam_challenge.data, 1261 sc.sam_challenge.length, 1262 psr.sam_key.contents, /* key */ 1263 psr.sam_key.length, /* key length */ 1264 &sc.sam_cksum); 1265 if (retval) { free(sc.sam_cksum.contents); return(retval); } 1266 #endif /* 0 */ 1267 1268 retval = encode_krb5_sam_challenge(&sc, &scratch); 1269 if (retval) goto cleanup; 1270 pa_data->magic = KV5M_PA_DATA; 1271 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 1272 pa_data->contents = (unsigned char *) scratch->data; 1273 pa_data->length = scratch->length; 1274 1275 retval = 0; 1276 break; 1277 case PA_SAM_TYPE_DIGI_PATH: 1278 sc.sam_type_name.data = "Digital Pathways"; 1279 sc.sam_type_name.length = strlen(sc.sam_type_name.data); 1280 #if 1 1281 sc.sam_challenge_label.data = "Enter the following on your keypad"; 1282 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1283 #endif 1284 /* generate digit string, take it mod 1000000 (six digits.) */ 1285 { 1286 int j; 1287 krb5_keyblock session_key; 1288 char outputblock[8]; 1289 int i; 1290 1291 (void) memset(&session_key, 0, sizeof(krb5_keyblock)); 1292 (void) memset(inputblock, 0, 8); 1293 1294 retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC, 1295 &session_key); 1296 1297 if (retval) { 1298 /* random key failed */ 1299 com_err(gettext("krb5kdc"), 1300 retval, 1301 gettext("generating random challenge for preauth")); 1302 return retval; 1303 } 1304 /* now session_key has a key which we can pick bits out of */ 1305 /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */ 1306 if (session_key.length != 8) { 1307 retval = KRB5KDC_ERR_ETYPE_NOSUPP, 1308 com_err(gettext("krb5kdc"), 1309 retval = KRB5KDC_ERR_ETYPE_NOSUPP, 1310 gettext("keytype didn't match code expectations")); 1311 return retval; 1312 } 1313 for(i = 0; i<6; i++) { 1314 inputblock[i] = '0' + ((session_key.contents[i]/2) % 10); 1315 } 1316 if (session_key.contents) 1317 krb5_free_keyblock_contents(kdc_context, &session_key); 1318 1319 /* retval = krb5_finish_key(kdc_context, &eblock); */ 1320 /* now we have inputblock containing the 8 byte input to DES... */ 1321 sc.sam_challenge.data = inputblock; 1322 sc.sam_challenge.length = 6; 1323 1324 encrypting_key.enctype = ENCTYPE_DES_CBC_RAW; 1325 1326 if (retval) { 1327 com_err(gettext("krb5kdc"), 1328 retval, 1329 gettext("snk4 processing key")); 1330 } 1331 1332 { 1333 krb5_data plain; 1334 krb5_enc_data cipher; 1335 1336 plain.length = 8; 1337 plain.data = inputblock; 1338 1339 /* XXX I know this is enough because of the fixed raw enctype. 1340 if it's not, the underlying code will return a reasonable 1341 error, which should never happen */ 1342 cipher.ciphertext.length = 8; 1343 cipher.ciphertext.data = outputblock; 1344 1345 if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key, 1346 /* XXX */ 0, 0, &plain, &cipher))) { 1347 com_err(gettext("krb5kdc"), 1348 retval, 1349 gettext("snk4 response generation failed")); 1350 return retval; 1351 } 1352 } 1353 1354 /* now output block is the raw bits of the response; convert it 1355 to display form */ 1356 for (j=0; j<4; j++) { 1357 char n[2]; 1358 int k; 1359 n[0] = outputblock[j] & 0xf; 1360 n[1] = (outputblock[j]>>4) & 0xf; 1361 for (k=0; k<2; k++) { 1362 if(n[k] > 9) n[k] = ((n[k]-1)>>2); 1363 /* This is equivalent to: 1364 if(n[k]>=0xa && n[k]<=0xc) n[k] = 2; 1365 if(n[k]>=0xd && n[k]<=0xf) n[k] = 3; 1366 */ 1367 } 1368 /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */ 1369 /* for v5, we just generate a string */ 1370 response[2*j+0] = '0' + n[1]; 1371 response[2*j+1] = '0' + n[0]; 1372 /* and now, response has what we work with. */ 1373 } 1374 response[8] = 0; 1375 predict_response.data = response; 1376 predict_response.length = 8; 1377 #if 0 /* for debugging, hack the output too! */ 1378 sc.sam_challenge_label.data = response; 1379 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 1380 #endif 1381 } 1382 1383 psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 1384 /* string2key on sc.sam_challenge goes in here */ 1385 /* eblock is just to set the enctype */ 1386 { 1387 retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5, 1388 &predict_response, 0 /* salt */, 1389 &psr.sam_key); 1390 if (retval) goto cleanup; 1391 1392 retval = encode_krb5_predicted_sam_response(&psr, &scratch); 1393 if (retval) goto cleanup; 1394 1395 { 1396 size_t enclen; 1397 krb5_enc_data tmpdata; 1398 1399 if ((retval = krb5_c_encrypt_length(context, 1400 psr_key.enctype, 1401 scratch->length, &enclen))) 1402 goto cleanup; 1403 1404 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 1405 retval = ENOMEM; 1406 goto cleanup; 1407 } 1408 tmpdata.ciphertext.length = enclen; 1409 1410 if ((retval = krb5_c_encrypt(context, &psr_key, 1411 /* XXX */ 0, 0, scratch, &tmpdata))) 1412 goto cleanup; 1413 1414 sc.sam_track_id = tmpdata.ciphertext; 1415 } 1416 if (retval) goto cleanup; 1417 } 1418 1419 sc.sam_response_prompt.data = "Enter the displayed response"; 1420 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 1421 sc.sam_pk_for_sad.length = 0; 1422 sc.sam_nonce = 0; 1423 /* Generate checksum */ 1424 /*krb5_checksum_size(context, ctype)*/ 1425 /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 1426 seed_length,outcksum) */ 1427 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 1428 seed_length) */ 1429 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 1430 sc.sam_cksum.contents = (krb5_octet *) 1431 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 1432 if (sc.sam_cksum.contents == NULL) return(ENOMEM); 1433 1434 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 1435 sc.sam_challenge.data, 1436 sc.sam_challenge.length, 1437 psr.sam_key.contents, /* key */ 1438 psr.sam_key.length, /* key length */ 1439 &sc.sam_cksum); 1440 if (retval) { free(sc.sam_cksum.contents); return(retval); } 1441 #endif /* 0 */ 1442 1443 retval = encode_krb5_sam_challenge(&sc, &scratch); 1444 if (retval) goto cleanup; 1445 pa_data->magic = KV5M_PA_DATA; 1446 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 1447 pa_data->contents = (unsigned char *) scratch->data; 1448 pa_data->length = scratch->length; 1449 1450 retval = 0; 1451 break; 1452 } 1453 1454 cleanup: 1455 krb5_free_keyblock_contents(context, &encrypting_key); 1456 return retval; 1457 } 1458 1459 static krb5_error_code 1460 verify_sam_response(context, client, request, enc_tkt_reply, pa) 1461 krb5_context context; 1462 krb5_db_entry * client; 1463 krb5_kdc_req * request; 1464 krb5_enc_tkt_part * enc_tkt_reply; 1465 krb5_pa_data * pa; 1466 { 1467 krb5_error_code retval; 1468 krb5_data scratch; 1469 krb5_sam_response *sr = 0; 1470 krb5_predicted_sam_response *psr = 0; 1471 krb5_enc_sam_response_enc *esre = 0; 1472 krb5_timestamp timenow; 1473 char *princ_req = 0, *princ_psr = 0; 1474 1475 scratch.data = (char *) pa->contents; 1476 scratch.length = pa->length; 1477 1478 if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 1479 scratch.data = 0; 1480 com_err("krb5kdc", retval, gettext("decode_krb5_sam_response failed")); 1481 goto cleanup; 1482 } 1483 1484 /* XXX We can only handle the challenge/response model of SAM. 1485 See passwords-04, par 4.1, 4.2 */ 1486 { 1487 krb5_enc_data tmpdata; 1488 1489 tmpdata.enctype = ENCTYPE_UNKNOWN; 1490 tmpdata.ciphertext = sr->sam_track_id; 1491 1492 scratch.length = tmpdata.ciphertext.length; 1493 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 1494 retval = ENOMEM; 1495 goto cleanup; 1496 } 1497 1498 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 1499 &tmpdata, &scratch))) { 1500 com_err(gettext("krb5kdc"), 1501 retval, 1502 gettext("decrypt track_id failed")); 1503 goto cleanup; 1504 } 1505 } 1506 1507 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 1508 com_err(gettext("krb5kdc"), retval, 1509 gettext("decode_krb5_predicted_sam_response failed -- replay attack?")); 1510 goto cleanup; 1511 } 1512 1513 /* Replay detection */ 1514 if ((retval = krb5_unparse_name(context, request->client, &princ_req))) 1515 goto cleanup; 1516 if ((retval = krb5_unparse_name(context, psr->client, &princ_psr))) 1517 goto cleanup; 1518 if (strcmp(princ_req, princ_psr) != 0) { 1519 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1520 gettext("Principal mismatch in SAM psr! -- replay attack?")); 1521 goto cleanup; 1522 } 1523 1524 if ((retval = krb5_timeofday(context, &timenow))) 1525 goto cleanup; 1526 1527 #ifdef USE_RCACHE 1528 { 1529 krb5_donot_replay rep; 1530 extern krb5_deltat rc_lifetime; 1531 /* 1532 * Verify this response came back in a timely manner. 1533 * We do this b/c otherwise very old (expunged from the rcache) 1534 * psr's would be able to be replayed. 1535 */ 1536 if (timenow - psr->stime > rc_lifetime) { 1537 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 1538 gettext("SAM psr came back too late! -- replay attack?")); 1539 goto cleanup; 1540 } 1541 1542 /* Now check the replay cache. */ 1543 rep.client = princ_psr; 1544 rep.server = "SAM/rc"; /* Should not match any principal name. */ 1545 rep.ctime = psr->stime; 1546 rep.cusec = psr->susec; 1547 if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) { 1548 com_err("krb5kdc", retval, gettext("SAM psr replay attack!")); 1549 goto cleanup; 1550 } 1551 } 1552 #endif /* USE_RCACHE */ 1553 1554 1555 { 1556 free(scratch.data); 1557 scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length; 1558 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 1559 retval = ENOMEM; 1560 goto cleanup; 1561 } 1562 1563 if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0, 1564 0, &sr->sam_enc_nonce_or_ts, &scratch))) { 1565 com_err("krb5kdc", retval, gettext("decrypt nonce_or_ts failed")); 1566 goto cleanup; 1567 } 1568 } 1569 1570 if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) { 1571 com_err("krb5kdc", retval, gettext("decode_krb5_enc_sam_response_enc failed")); 1572 goto cleanup; 1573 } 1574 1575 if (esre->sam_timestamp != sr->sam_patimestamp) { 1576 retval = KRB5KDC_ERR_PREAUTH_FAILED; 1577 goto cleanup; 1578 } 1579 1580 if (labs(timenow - sr->sam_patimestamp) > context->clockskew) { 1581 retval = KRB5KRB_AP_ERR_SKEW; 1582 goto cleanup; 1583 } 1584 1585 setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH); 1586 1587 cleanup: 1588 if (retval) com_err(gettext("krb5kdc"), 1589 retval, 1590 gettext("sam verify failure")); 1591 if (scratch.data) free(scratch.data); 1592 if (sr) free(sr); 1593 if (psr) free(psr); 1594 if (esre) free(esre); 1595 1596 return retval; 1597 } 1598