comparison usr/src/cmd/krb5/krb5kdc/kdc_preauth.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
comparison
equal deleted inserted replaced
-1:000000000000 0:c9caec207d52
1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "@(#)kdc_preauth.c 1.11 06/09/27 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 }