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