1*159d09a2SMark Phalan /*
2*159d09a2SMark Phalan  * Copyright 1995 by the Massachusetts Institute of Technology.  All
3*159d09a2SMark Phalan  * Rights Reserved.
4*159d09a2SMark Phalan  *
5*159d09a2SMark Phalan  * Export of this software from the United States of America may
6*159d09a2SMark Phalan  *   require a specific license from the United States Government.
7*159d09a2SMark Phalan  *   It is the responsibility of any person or organization contemplating
8*159d09a2SMark Phalan  *   export to obtain such a license before exporting.
9*159d09a2SMark Phalan  *
10*159d09a2SMark Phalan  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11*159d09a2SMark Phalan  * distribute this software and its documentation for any purpose and
12*159d09a2SMark Phalan  * without fee is hereby granted, provided that the above copyright
13*159d09a2SMark Phalan  * notice appear in all copies and that both that copyright notice and
14*159d09a2SMark Phalan  * this permission notice appear in supporting documentation, and that
15*159d09a2SMark Phalan  * the name of M.I.T. not be used in advertising or publicity pertaining
16*159d09a2SMark Phalan  * to distribution of the software without specific, written prior
17*159d09a2SMark Phalan  * permission.  Furthermore if you modify this software you must label
18*159d09a2SMark Phalan  * your software as modified software and not distribute it in such a
19*159d09a2SMark Phalan  * fashion that it might be confused with the original M.I.T. software.
20*159d09a2SMark Phalan  * M.I.T. makes no representations about the suitability of
21*159d09a2SMark Phalan  * this software for any purpose.  It is provided "as is" without express
22*159d09a2SMark Phalan  * or implied warranty.
23*159d09a2SMark Phalan  *
24*159d09a2SMark Phalan  */
25*159d09a2SMark Phalan 
26*159d09a2SMark Phalan /*
27*159d09a2SMark Phalan  * This file contains routines for establishing, verifying, and any other
28*159d09a2SMark Phalan  * necessary functions, for utilizing the pre-authentication field of the
29*159d09a2SMark Phalan  * kerberos kdc request, with various hardware/software verification devices.
30*159d09a2SMark Phalan  */
31*159d09a2SMark Phalan 
32*159d09a2SMark Phalan #include "k5-int.h"
33*159d09a2SMark Phalan #include <stdio.h>
34*159d09a2SMark Phalan #include <time.h>
35*159d09a2SMark Phalan 
36*159d09a2SMark Phalan static krb5_error_code obtain_enc_ts_padata
37*159d09a2SMark Phalan 	(krb5_context,
38*159d09a2SMark Phalan 	 krb5_pa_data *,
39*159d09a2SMark Phalan 	 krb5_etype_info,
40*159d09a2SMark Phalan 	 krb5_keyblock *,
41*159d09a2SMark Phalan 	 krb5_error_code ( * )(krb5_context,
42*159d09a2SMark Phalan 			       const krb5_enctype,
43*159d09a2SMark Phalan 			       krb5_data *,
44*159d09a2SMark Phalan 			       krb5_const_pointer,
45*159d09a2SMark Phalan 			       krb5_keyblock **),
46*159d09a2SMark Phalan 	 krb5_const_pointer,
47*159d09a2SMark Phalan 	 krb5_creds *,
48*159d09a2SMark Phalan 	 krb5_kdc_req *,
49*159d09a2SMark Phalan 	 krb5_pa_data **);
50*159d09a2SMark Phalan 
51*159d09a2SMark Phalan static krb5_error_code process_pw_salt
52*159d09a2SMark Phalan 	(krb5_context,
53*159d09a2SMark Phalan 	 krb5_pa_data *,
54*159d09a2SMark Phalan 	 krb5_kdc_req *,
55*159d09a2SMark Phalan 	 krb5_kdc_rep *,
56*159d09a2SMark Phalan 	 krb5_error_code ( * )(krb5_context,
57*159d09a2SMark Phalan 			       const krb5_enctype,
58*159d09a2SMark Phalan 			       krb5_data *,
59*159d09a2SMark Phalan 			       krb5_const_pointer,
60*159d09a2SMark Phalan 			       krb5_keyblock **),
61*159d09a2SMark Phalan 	 krb5_const_pointer,
62*159d09a2SMark Phalan 	 krb5_error_code ( * )(krb5_context,
63*159d09a2SMark Phalan 			       const krb5_keyblock *,
64*159d09a2SMark Phalan 			       krb5_const_pointer,
65*159d09a2SMark Phalan 			       krb5_kdc_rep * ),
66*159d09a2SMark Phalan 	 krb5_keyblock **,
67*159d09a2SMark Phalan 	 krb5_creds *,
68*159d09a2SMark Phalan 	 krb5_int32 *,
69*159d09a2SMark Phalan 	 krb5_int32 *);
70*159d09a2SMark Phalan 
71*159d09a2SMark Phalan static krb5_error_code obtain_sam_padata
72*159d09a2SMark Phalan 	(krb5_context,
73*159d09a2SMark Phalan 	 krb5_pa_data *,
74*159d09a2SMark Phalan 	 krb5_etype_info,
75*159d09a2SMark Phalan 	 krb5_keyblock *,
76*159d09a2SMark Phalan 	 krb5_error_code ( * )(krb5_context,
77*159d09a2SMark Phalan 			       const krb5_enctype,
78*159d09a2SMark Phalan 			       krb5_data *,
79*159d09a2SMark Phalan 			       krb5_const_pointer,
80*159d09a2SMark Phalan 			       krb5_keyblock **),
81*159d09a2SMark Phalan 	 krb5_const_pointer,
82*159d09a2SMark Phalan 	 krb5_creds *,
83*159d09a2SMark Phalan 	 krb5_kdc_req *,
84*159d09a2SMark Phalan 	 krb5_pa_data **);
85*159d09a2SMark Phalan 
86*159d09a2SMark Phalan static const krb5_preauth_ops preauth_systems[] = {
87*159d09a2SMark Phalan     {
88*159d09a2SMark Phalan 	KV5M_PREAUTH_OPS,
89*159d09a2SMark Phalan 	KRB5_PADATA_ENC_TIMESTAMP,
90*159d09a2SMark Phalan         0,
91*159d09a2SMark Phalan         obtain_enc_ts_padata,
92*159d09a2SMark Phalan         0,
93*159d09a2SMark Phalan     },
94*159d09a2SMark Phalan     {
95*159d09a2SMark Phalan 	KV5M_PREAUTH_OPS,
96*159d09a2SMark Phalan 	KRB5_PADATA_PW_SALT,
97*159d09a2SMark Phalan         0,
98*159d09a2SMark Phalan         0,
99*159d09a2SMark Phalan         process_pw_salt,
100*159d09a2SMark Phalan     },
101*159d09a2SMark Phalan     {
102*159d09a2SMark Phalan 	KV5M_PREAUTH_OPS,
103*159d09a2SMark Phalan 	KRB5_PADATA_AFS3_SALT,
104*159d09a2SMark Phalan         0,
105*159d09a2SMark Phalan         0,
106*159d09a2SMark Phalan         process_pw_salt,
107*159d09a2SMark Phalan     },
108*159d09a2SMark Phalan     {
109*159d09a2SMark Phalan 	KV5M_PREAUTH_OPS,
110*159d09a2SMark Phalan 	KRB5_PADATA_SAM_CHALLENGE,
111*159d09a2SMark Phalan         0,
112*159d09a2SMark Phalan         obtain_sam_padata,
113*159d09a2SMark Phalan         0,
114*159d09a2SMark Phalan     },
115*159d09a2SMark Phalan     { KV5M_PREAUTH_OPS, -1 }
116*159d09a2SMark Phalan };
117*159d09a2SMark Phalan 
118*159d09a2SMark Phalan static krb5_error_code find_pa_system
119*159d09a2SMark Phalan     (krb5_preauthtype type, const krb5_preauth_ops **Preauth_proc);
120*159d09a2SMark Phalan 
121*159d09a2SMark Phalan /* some typedef's for the function args to make things look a bit cleaner */
122*159d09a2SMark Phalan 
123*159d09a2SMark Phalan typedef krb5_error_code (*git_key_proc) (krb5_context,
124*159d09a2SMark Phalan 					 const krb5_enctype,
125*159d09a2SMark Phalan 					 krb5_data *,
126*159d09a2SMark Phalan 					 krb5_const_pointer,
127*159d09a2SMark Phalan 					 krb5_keyblock **);
128*159d09a2SMark Phalan 
129*159d09a2SMark Phalan typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
130*159d09a2SMark Phalan 					     const krb5_keyblock *,
131*159d09a2SMark Phalan 					     krb5_const_pointer,
132*159d09a2SMark Phalan 					     krb5_kdc_rep *);
133*159d09a2SMark Phalan 
krb5_obtain_padata(krb5_context context,krb5_pa_data ** preauth_to_use,git_key_proc key_proc,krb5_const_pointer key_seed,krb5_creds * creds,krb5_kdc_req * request)134*159d09a2SMark Phalan krb5_error_code krb5_obtain_padata(krb5_context context, krb5_pa_data **preauth_to_use, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request)
135*159d09a2SMark Phalan {
136*159d09a2SMark Phalan     krb5_error_code		retval;
137*159d09a2SMark Phalan     krb5_etype_info	    	etype_info = 0;
138*159d09a2SMark Phalan     krb5_pa_data **		pa;
139*159d09a2SMark Phalan     krb5_pa_data **		send_pa_list;
140*159d09a2SMark Phalan     krb5_pa_data **		send_pa;
141*159d09a2SMark Phalan     const krb5_preauth_ops	*ops;
142*159d09a2SMark Phalan     krb5_keyblock *		def_enc_key = 0;
143*159d09a2SMark Phalan     krb5_enctype 		enctype;
144*159d09a2SMark Phalan     krb5_data 			salt;
145*159d09a2SMark Phalan     krb5_data			scratch;
146*159d09a2SMark Phalan     int				size;
147*159d09a2SMark Phalan     int				f_salt = 0;
148*159d09a2SMark Phalan 
149*159d09a2SMark Phalan     if (preauth_to_use == NULL)
150*159d09a2SMark Phalan 	return 0;
151*159d09a2SMark Phalan 
152*159d09a2SMark Phalan     for (pa = preauth_to_use, size=0; *pa; pa++, size++) {
153*159d09a2SMark Phalan 	if ((*pa)->pa_type == KRB5_PADATA_ETYPE_INFO) {
154*159d09a2SMark Phalan 	    /* XXX use the first one.  Is there another way to disambiguate? */
155*159d09a2SMark Phalan 	    if (etype_info)
156*159d09a2SMark Phalan 		continue;
157*159d09a2SMark Phalan 
158*159d09a2SMark Phalan 	    scratch.length = (*pa)->length;
159*159d09a2SMark Phalan 	    scratch.data = (char *) (*pa)->contents;
160*159d09a2SMark Phalan 	    retval = decode_krb5_etype_info(&scratch, &etype_info);
161*159d09a2SMark Phalan 	    if (retval)
162*159d09a2SMark Phalan 		return retval;
163*159d09a2SMark Phalan 	    if (etype_info[0] == NULL) {
164*159d09a2SMark Phalan 		krb5_free_etype_info(context, etype_info);
165*159d09a2SMark Phalan 		etype_info = NULL;
166*159d09a2SMark Phalan 	    }
167*159d09a2SMark Phalan 	}
168*159d09a2SMark Phalan     }
169*159d09a2SMark Phalan 
170*159d09a2SMark Phalan     if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
171*159d09a2SMark Phalan 	return ENOMEM;
172*159d09a2SMark Phalan 
173*159d09a2SMark Phalan     send_pa = send_pa_list;
174*159d09a2SMark Phalan     *send_pa = 0;
175*159d09a2SMark Phalan 
176*159d09a2SMark Phalan     enctype = request->ktype[0];
177*159d09a2SMark Phalan     salt.data = 0;
178*159d09a2SMark Phalan     salt.length = SALT_TYPE_NO_LENGTH;
179*159d09a2SMark Phalan     if (etype_info) {
180*159d09a2SMark Phalan 	enctype = etype_info[0]->etype;
181*159d09a2SMark Phalan 	salt.data = (char *) etype_info[0]->salt;
182*159d09a2SMark Phalan 	if(etype_info[0]->length == KRB5_ETYPE_NO_SALT)
183*159d09a2SMark Phalan 	  salt.length = SALT_TYPE_NO_LENGTH; /* XXX */
184*159d09a2SMark Phalan 	else
185*159d09a2SMark Phalan 	  salt.length = etype_info[0]->length;
186*159d09a2SMark Phalan     }
187*159d09a2SMark Phalan     if (salt.length == SALT_TYPE_NO_LENGTH) {
188*159d09a2SMark Phalan         /*
189*159d09a2SMark Phalan 	 * This will set the salt length
190*159d09a2SMark Phalan 	 */
191*159d09a2SMark Phalan 	if ((retval = krb5_principal2salt(context, request->client, &salt)))
192*159d09a2SMark Phalan 	    return(retval);
193*159d09a2SMark Phalan 	f_salt = 1;
194*159d09a2SMark Phalan     }
195*159d09a2SMark Phalan 
196*159d09a2SMark Phalan     if ((retval = (*key_proc)(context, enctype, &salt, key_seed,
197*159d09a2SMark Phalan 			      &def_enc_key)))
198*159d09a2SMark Phalan 	goto cleanup;
199*159d09a2SMark Phalan 
200*159d09a2SMark Phalan 
201*159d09a2SMark Phalan     for (pa = preauth_to_use; *pa; pa++) {
202*159d09a2SMark Phalan 	if (find_pa_system((*pa)->pa_type, &ops))
203*159d09a2SMark Phalan 	    continue;
204*159d09a2SMark Phalan 
205*159d09a2SMark Phalan 	if (ops->obtain == 0)
206*159d09a2SMark Phalan 	    continue;
207*159d09a2SMark Phalan 
208*159d09a2SMark Phalan 	retval = ((ops)->obtain)(context, *pa, etype_info, def_enc_key,
209*159d09a2SMark Phalan 				 key_proc, key_seed, creds,
210*159d09a2SMark Phalan 				 request, send_pa);
211*159d09a2SMark Phalan 	if (retval)
212*159d09a2SMark Phalan 	    goto cleanup;
213*159d09a2SMark Phalan 
214*159d09a2SMark Phalan 	if (*send_pa)
215*159d09a2SMark Phalan 	    send_pa++;
216*159d09a2SMark Phalan 	*send_pa = 0;
217*159d09a2SMark Phalan     }
218*159d09a2SMark Phalan 
219*159d09a2SMark Phalan     retval = 0;
220*159d09a2SMark Phalan 
221*159d09a2SMark Phalan     if (send_pa_list[0]) {
222*159d09a2SMark Phalan 	request->padata = send_pa_list;
223*159d09a2SMark Phalan 	send_pa_list = 0;
224*159d09a2SMark Phalan     }
225*159d09a2SMark Phalan 
226*159d09a2SMark Phalan cleanup:
227*159d09a2SMark Phalan     if (etype_info)
228*159d09a2SMark Phalan 	krb5_free_etype_info(context, etype_info);
229*159d09a2SMark Phalan     if (f_salt)
230*159d09a2SMark Phalan 	krb5_xfree(salt.data);
231*159d09a2SMark Phalan     if (send_pa_list)
232*159d09a2SMark Phalan 	krb5_free_pa_data(context, send_pa_list);
233*159d09a2SMark Phalan     if (def_enc_key)
234*159d09a2SMark Phalan 	krb5_free_keyblock(context, def_enc_key);
235*159d09a2SMark Phalan     return retval;
236*159d09a2SMark Phalan 
237*159d09a2SMark Phalan }
238*159d09a2SMark Phalan 
239*159d09a2SMark Phalan krb5_error_code
krb5_process_padata(krb5_context context,krb5_kdc_req * request,krb5_kdc_rep * as_reply,git_key_proc key_proc,krb5_const_pointer keyseed,git_decrypt_proc decrypt_proc,krb5_keyblock ** decrypt_key,krb5_creds * creds,krb5_int32 * do_more)240*159d09a2SMark Phalan krb5_process_padata(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *as_reply, git_key_proc key_proc, krb5_const_pointer keyseed, git_decrypt_proc decrypt_proc, krb5_keyblock **decrypt_key, krb5_creds *creds, krb5_int32 *do_more)
241*159d09a2SMark Phalan {
242*159d09a2SMark Phalan     krb5_error_code		retval = 0;
243*159d09a2SMark Phalan     const krb5_preauth_ops * 	ops;
244*159d09a2SMark Phalan     krb5_pa_data **		pa;
245*159d09a2SMark Phalan     krb5_int32			done = 0;
246*159d09a2SMark Phalan 
247*159d09a2SMark Phalan     *do_more = 0;		/* By default, we don't need to repeat... */
248*159d09a2SMark Phalan     if (as_reply->padata == 0)
249*159d09a2SMark Phalan 	return 0;
250*159d09a2SMark Phalan 
251*159d09a2SMark Phalan     for (pa = as_reply->padata; *pa; pa++) {
252*159d09a2SMark Phalan 	if (find_pa_system((*pa)->pa_type, &ops))
253*159d09a2SMark Phalan 	    continue;
254*159d09a2SMark Phalan 
255*159d09a2SMark Phalan 	if (ops->process == 0)
256*159d09a2SMark Phalan 	    continue;
257*159d09a2SMark Phalan 
258*159d09a2SMark Phalan 	retval = ((ops)->process)(context, *pa, request, as_reply,
259*159d09a2SMark Phalan 				  key_proc, keyseed, decrypt_proc,
260*159d09a2SMark Phalan 				  decrypt_key, creds, do_more, &done);
261*159d09a2SMark Phalan 	if (retval)
262*159d09a2SMark Phalan 	    goto cleanup;
263*159d09a2SMark Phalan 	if (done)
264*159d09a2SMark Phalan 	    break;
265*159d09a2SMark Phalan     }
266*159d09a2SMark Phalan 
267*159d09a2SMark Phalan cleanup:
268*159d09a2SMark Phalan     return retval;
269*159d09a2SMark Phalan }
270*159d09a2SMark Phalan 
271*159d09a2SMark Phalan /*
272*159d09a2SMark Phalan  * This routine is the "obtain" function for the ENC_TIMESTAMP
273*159d09a2SMark Phalan  * preauthentication type.  It take the current time and encrypts it
274*159d09a2SMark Phalan  * in the user's key.
275*159d09a2SMark Phalan  */
276*159d09a2SMark Phalan static krb5_error_code
obtain_enc_ts_padata(krb5_context context,krb5_pa_data * in_padata,krb5_etype_info etype_info,krb5_keyblock * def_enc_key,git_key_proc key_proc,krb5_const_pointer key_seed,krb5_creds * creds,krb5_kdc_req * request,krb5_pa_data ** out_padata)277*159d09a2SMark Phalan obtain_enc_ts_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata)
278*159d09a2SMark Phalan {
279*159d09a2SMark Phalan     krb5_pa_enc_ts		pa_enc;
280*159d09a2SMark Phalan     krb5_error_code		retval;
281*159d09a2SMark Phalan     krb5_data *			scratch;
282*159d09a2SMark Phalan     krb5_enc_data 		enc_data;
283*159d09a2SMark Phalan     krb5_pa_data *		pa;
284*159d09a2SMark Phalan 
285*159d09a2SMark Phalan     retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
286*159d09a2SMark Phalan     if (retval)
287*159d09a2SMark Phalan 	return retval;
288*159d09a2SMark Phalan 
289*159d09a2SMark Phalan     if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0)
290*159d09a2SMark Phalan 	return retval;
291*159d09a2SMark Phalan 
292*159d09a2SMark Phalan     enc_data.ciphertext.data = 0;
293*159d09a2SMark Phalan 
294*159d09a2SMark Phalan     if ((retval = krb5_encrypt_helper(context, def_enc_key,
295*159d09a2SMark Phalan 				      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
296*159d09a2SMark Phalan 				      scratch, &enc_data)))
297*159d09a2SMark Phalan 	goto cleanup;
298*159d09a2SMark Phalan 
299*159d09a2SMark Phalan     krb5_free_data(context, scratch);
300*159d09a2SMark Phalan     scratch = 0;
301*159d09a2SMark Phalan 
302*159d09a2SMark Phalan     if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0)
303*159d09a2SMark Phalan 	goto cleanup;
304*159d09a2SMark Phalan 
305*159d09a2SMark Phalan     if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
306*159d09a2SMark Phalan 	retval = ENOMEM;
307*159d09a2SMark Phalan 	goto cleanup;
308*159d09a2SMark Phalan     }
309*159d09a2SMark Phalan 
310*159d09a2SMark Phalan     pa->magic = KV5M_PA_DATA;
311*159d09a2SMark Phalan     pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
312*159d09a2SMark Phalan     pa->length = scratch->length;
313*159d09a2SMark Phalan     pa->contents = (krb5_octet *) scratch->data;
314*159d09a2SMark Phalan 
315*159d09a2SMark Phalan     *out_padata = pa;
316*159d09a2SMark Phalan 
317*159d09a2SMark Phalan     krb5_xfree(scratch);
318*159d09a2SMark Phalan     scratch = 0;
319*159d09a2SMark Phalan 
320*159d09a2SMark Phalan     retval = 0;
321*159d09a2SMark Phalan 
322*159d09a2SMark Phalan cleanup:
323*159d09a2SMark Phalan     if (scratch)
324*159d09a2SMark Phalan 	krb5_free_data(context, scratch);
325*159d09a2SMark Phalan     if (enc_data.ciphertext.data)
326*159d09a2SMark Phalan 	krb5_xfree(enc_data.ciphertext.data);
327*159d09a2SMark Phalan     return retval;
328*159d09a2SMark Phalan }
329*159d09a2SMark Phalan 
330*159d09a2SMark Phalan static krb5_error_code
process_pw_salt(krb5_context context,krb5_pa_data * padata,krb5_kdc_req * request,krb5_kdc_rep * as_reply,git_key_proc key_proc,krb5_const_pointer keyseed,git_decrypt_proc decrypt_proc,krb5_keyblock ** decrypt_key,krb5_creds * creds,krb5_int32 * do_more,krb5_int32 * done)331*159d09a2SMark Phalan process_pw_salt(krb5_context context, krb5_pa_data *padata, krb5_kdc_req *request, krb5_kdc_rep *as_reply, git_key_proc key_proc, krb5_const_pointer keyseed, git_decrypt_proc decrypt_proc, krb5_keyblock **decrypt_key, krb5_creds *creds, krb5_int32 *do_more, krb5_int32 *done)
332*159d09a2SMark Phalan {
333*159d09a2SMark Phalan     krb5_error_code	retval;
334*159d09a2SMark Phalan     krb5_data		salt;
335*159d09a2SMark Phalan 
336*159d09a2SMark Phalan     if (*decrypt_key != 0)
337*159d09a2SMark Phalan 	return 0;
338*159d09a2SMark Phalan 
339*159d09a2SMark Phalan     salt.data = (char *) padata->contents;
340*159d09a2SMark Phalan     salt.length =
341*159d09a2SMark Phalan       (padata->pa_type == KRB5_PADATA_AFS3_SALT)?(SALT_TYPE_AFS_LENGTH):(padata->length);
342*159d09a2SMark Phalan 
343*159d09a2SMark Phalan     if ((retval = (*key_proc)(context, as_reply->enc_part.enctype,
344*159d09a2SMark Phalan 			      &salt, keyseed, decrypt_key))) {
345*159d09a2SMark Phalan 	*decrypt_key = 0;
346*159d09a2SMark Phalan 	return retval;
347*159d09a2SMark Phalan     }
348*159d09a2SMark Phalan 
349*159d09a2SMark Phalan     return 0;
350*159d09a2SMark Phalan }
351*159d09a2SMark Phalan 
352*159d09a2SMark Phalan static krb5_error_code
find_pa_system(krb5_preauthtype type,const krb5_preauth_ops ** preauth)353*159d09a2SMark Phalan find_pa_system(krb5_preauthtype type, const krb5_preauth_ops **preauth)
354*159d09a2SMark Phalan {
355*159d09a2SMark Phalan     const krb5_preauth_ops *ap = preauth_systems;
356*159d09a2SMark Phalan 
357*159d09a2SMark Phalan     while ((ap->type != -1) && (ap->type != type))
358*159d09a2SMark Phalan 	ap++;
359*159d09a2SMark Phalan     if (ap->type == -1)
360*159d09a2SMark Phalan 	return(KRB5_PREAUTH_BAD_TYPE);
361*159d09a2SMark Phalan     *preauth = ap;
362*159d09a2SMark Phalan     return 0;
363*159d09a2SMark Phalan }
364*159d09a2SMark Phalan 
365*159d09a2SMark Phalan 
366*159d09a2SMark Phalan extern const char *krb5_default_pwd_prompt1;
367*159d09a2SMark Phalan 
368*159d09a2SMark Phalan static krb5_error_code
sam_get_pass_from_user(krb5_context context,krb5_etype_info etype_info,git_key_proc key_proc,krb5_const_pointer key_seed,krb5_kdc_req * request,krb5_keyblock ** new_enc_key,const char * prompt)369*159d09a2SMark Phalan sam_get_pass_from_user(krb5_context context, krb5_etype_info etype_info, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_kdc_req *request, krb5_keyblock **new_enc_key, const char *prompt)
370*159d09a2SMark Phalan {
371*159d09a2SMark Phalan     krb5_enctype 		enctype;
372*159d09a2SMark Phalan     krb5_error_code		retval;
373*159d09a2SMark Phalan     const char *oldprompt;
374*159d09a2SMark Phalan 
375*159d09a2SMark Phalan     /* enctype = request->ktype[0]; */
376*159d09a2SMark Phalan     enctype = ENCTYPE_DES_CBC_MD5;
377*159d09a2SMark Phalan /* hack with this first! */
378*159d09a2SMark Phalan     oldprompt = krb5_default_pwd_prompt1;
379*159d09a2SMark Phalan     krb5_default_pwd_prompt1 = prompt;
380*159d09a2SMark Phalan     {
381*159d09a2SMark Phalan       krb5_data newpw;
382*159d09a2SMark Phalan       newpw.data = 0; newpw.length = 0;
383*159d09a2SMark Phalan       /* we don't keep the new password, just the key... */
384*159d09a2SMark Phalan       retval = (*key_proc)(context, enctype, 0,
385*159d09a2SMark Phalan 			   (krb5_const_pointer)&newpw, new_enc_key);
386*159d09a2SMark Phalan       krb5_xfree(newpw.data);
387*159d09a2SMark Phalan     }
388*159d09a2SMark Phalan     krb5_default_pwd_prompt1 = oldprompt;
389*159d09a2SMark Phalan     return retval;
390*159d09a2SMark Phalan }
391*159d09a2SMark Phalan static
handle_sam_labels(krb5_sam_challenge * sc)392*159d09a2SMark Phalan char *handle_sam_labels(krb5_sam_challenge *sc)
393*159d09a2SMark Phalan {
394*159d09a2SMark Phalan     char *label = sc->sam_challenge_label.data;
395*159d09a2SMark Phalan     unsigned int label_len = sc->sam_challenge_label.length;
396*159d09a2SMark Phalan     char *prompt = sc->sam_response_prompt.data;
397*159d09a2SMark Phalan     unsigned int prompt_len = sc->sam_response_prompt.length;
398*159d09a2SMark Phalan     char *challenge = sc->sam_challenge.data;
399*159d09a2SMark Phalan     unsigned int challenge_len = sc->sam_challenge.length;
400*159d09a2SMark Phalan     char *prompt1, *p;
401*159d09a2SMark Phalan     char *sep1 = ": [";
402*159d09a2SMark Phalan     char *sep2 = "]\n";
403*159d09a2SMark Phalan     char *sep3 = ": ";
404*159d09a2SMark Phalan 
405*159d09a2SMark Phalan     if (sc->sam_cksum.length == 0) {
406*159d09a2SMark Phalan       /* or invalid -- but lets just handle presence now XXX */
407*159d09a2SMark Phalan       switch (sc->sam_type) {
408*159d09a2SMark Phalan       case PA_SAM_TYPE_ENIGMA:	/* Enigma Logic */
409*159d09a2SMark Phalan 	label = "Challenge for Enigma Logic mechanism";
410*159d09a2SMark Phalan 	break;
411*159d09a2SMark Phalan       case PA_SAM_TYPE_DIGI_PATH: /*  Digital Pathways */
412*159d09a2SMark Phalan       case PA_SAM_TYPE_DIGI_PATH_HEX: /*  Digital Pathways */
413*159d09a2SMark Phalan 	label = "Challenge for Digital Pathways mechanism";
414*159d09a2SMark Phalan 	break;
415*159d09a2SMark Phalan       case PA_SAM_TYPE_ACTIVCARD_DEC: /*  Digital Pathways */
416*159d09a2SMark Phalan       case PA_SAM_TYPE_ACTIVCARD_HEX: /*  Digital Pathways */
417*159d09a2SMark Phalan 	label = "Challenge for Activcard mechanism";
418*159d09a2SMark Phalan 	break;
419*159d09a2SMark Phalan       case PA_SAM_TYPE_SKEY_K0:	/*  S/key where  KDC has key 0 */
420*159d09a2SMark Phalan 	label = "Challenge for Enhanced S/Key mechanism";
421*159d09a2SMark Phalan 	break;
422*159d09a2SMark Phalan       case PA_SAM_TYPE_SKEY:	/*  Traditional S/Key */
423*159d09a2SMark Phalan 	label = "Challenge for Traditional S/Key mechanism";
424*159d09a2SMark Phalan 	break;
425*159d09a2SMark Phalan       case PA_SAM_TYPE_SECURID:	/*  Security Dynamics */
426*159d09a2SMark Phalan 	label = "Challenge for Security Dynamics mechanism";
427*159d09a2SMark Phalan 	break;
428*159d09a2SMark Phalan       case PA_SAM_TYPE_SECURID_PREDICT:	/* predictive Security Dynamics */
429*159d09a2SMark Phalan 	label = "Challenge for Security Dynamics mechanism";
430*159d09a2SMark Phalan 	break;
431*159d09a2SMark Phalan       }
432*159d09a2SMark Phalan       prompt = "Passcode";
433*159d09a2SMark Phalan       label_len = strlen(label);
434*159d09a2SMark Phalan       prompt_len = strlen(prompt);
435*159d09a2SMark Phalan     }
436*159d09a2SMark Phalan 
437*159d09a2SMark Phalan     /* example:
438*159d09a2SMark Phalan        Challenge for Digital Pathways mechanism: [134591]
439*159d09a2SMark Phalan        Passcode:
440*159d09a2SMark Phalan      */
441*159d09a2SMark Phalan     p = prompt1 = malloc(label_len + strlen(sep1) +
442*159d09a2SMark Phalan 			 challenge_len + strlen(sep2) +
443*159d09a2SMark Phalan 			 prompt_len+ strlen(sep3) + 1);
444*159d09a2SMark Phalan     if (p == NULL)
445*159d09a2SMark Phalan 	return NULL;
446*159d09a2SMark Phalan     if (challenge_len) {
447*159d09a2SMark Phalan 	strncpy(p, label, label_len); p += label_len;
448*159d09a2SMark Phalan 	strcpy(p, sep1); p += strlen(sep1);
449*159d09a2SMark Phalan 	strncpy(p, challenge, challenge_len); p += challenge_len;
450*159d09a2SMark Phalan 	strcpy(p, sep2); p += strlen(sep2);
451*159d09a2SMark Phalan     }
452*159d09a2SMark Phalan     strncpy(p, prompt, prompt_len); p += prompt_len;
453*159d09a2SMark Phalan     strcpy(p, sep3); /* p += strlen(sep3); */
454*159d09a2SMark Phalan     return prompt1;
455*159d09a2SMark Phalan }
456*159d09a2SMark Phalan 
457*159d09a2SMark Phalan /*
458*159d09a2SMark Phalan  * This routine is the "obtain" function for the SAM_CHALLENGE
459*159d09a2SMark Phalan  * preauthentication type.  It presents the challenge...
460*159d09a2SMark Phalan  */
461*159d09a2SMark Phalan static krb5_error_code
obtain_sam_padata(krb5_context context,krb5_pa_data * in_padata,krb5_etype_info etype_info,krb5_keyblock * def_enc_key,git_key_proc key_proc,krb5_const_pointer key_seed,krb5_creds * creds,krb5_kdc_req * request,krb5_pa_data ** out_padata)462*159d09a2SMark Phalan obtain_sam_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata)
463*159d09a2SMark Phalan {
464*159d09a2SMark Phalan     krb5_error_code		retval;
465*159d09a2SMark Phalan     krb5_data *			scratch;
466*159d09a2SMark Phalan     krb5_data			tmpsam;
467*159d09a2SMark Phalan     krb5_pa_data *		pa;
468*159d09a2SMark Phalan     krb5_sam_challenge		*sam_challenge = 0;
469*159d09a2SMark Phalan     krb5_sam_response		sam_response;
470*159d09a2SMark Phalan     /* these two get encrypted and stuffed in to sam_response */
471*159d09a2SMark Phalan     krb5_enc_sam_response_enc	enc_sam_response_enc;
472*159d09a2SMark Phalan     krb5_keyblock *		sam_use_key = 0;
473*159d09a2SMark Phalan     char * prompt;
474*159d09a2SMark Phalan 
475*159d09a2SMark Phalan     tmpsam.length = in_padata->length;
476*159d09a2SMark Phalan     tmpsam.data = (char *) in_padata->contents;
477*159d09a2SMark Phalan     retval = decode_krb5_sam_challenge(&tmpsam, &sam_challenge);
478*159d09a2SMark Phalan     if (retval)
479*159d09a2SMark Phalan       return retval;
480*159d09a2SMark Phalan 
481*159d09a2SMark Phalan     if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
482*159d09a2SMark Phalan       return KRB5_SAM_UNSUPPORTED;
483*159d09a2SMark Phalan     }
484*159d09a2SMark Phalan 
485*159d09a2SMark Phalan     enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
486*159d09a2SMark Phalan     if (!sam_challenge->sam_nonce) {
487*159d09a2SMark Phalan       retval = krb5_us_timeofday(context,
488*159d09a2SMark Phalan                                  &enc_sam_response_enc.sam_timestamp,
489*159d09a2SMark Phalan                                  &enc_sam_response_enc.sam_usec);
490*159d09a2SMark Phalan       sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
491*159d09a2SMark Phalan     }
492*159d09a2SMark Phalan     if (retval)
493*159d09a2SMark Phalan       return retval;
494*159d09a2SMark Phalan     if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
495*159d09a2SMark Phalan       /* encrypt passcode in key by stuffing it here */
496*159d09a2SMark Phalan       unsigned int pcsize = 256;
497*159d09a2SMark Phalan       char *passcode = malloc(pcsize+1);
498*159d09a2SMark Phalan       if (passcode == NULL)
499*159d09a2SMark Phalan 	return ENOMEM;
500*159d09a2SMark Phalan       prompt = handle_sam_labels(sam_challenge);
501*159d09a2SMark Phalan       if (prompt == NULL) {
502*159d09a2SMark Phalan 	free(passcode);
503*159d09a2SMark Phalan 	return ENOMEM;
504*159d09a2SMark Phalan       }
505*159d09a2SMark Phalan       retval = krb5_read_password(context, prompt, 0, passcode, &pcsize);
506*159d09a2SMark Phalan       free(prompt);
507*159d09a2SMark Phalan 
508*159d09a2SMark Phalan       if (retval) {
509*159d09a2SMark Phalan 	free(passcode);
510*159d09a2SMark Phalan 	return retval;
511*159d09a2SMark Phalan       }
512*159d09a2SMark Phalan       enc_sam_response_enc.sam_sad.data = passcode;
513*159d09a2SMark Phalan       enc_sam_response_enc.sam_sad.length = pcsize;
514*159d09a2SMark Phalan     } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
515*159d09a2SMark Phalan       prompt = handle_sam_labels(sam_challenge);
516*159d09a2SMark Phalan       if (prompt == NULL)
517*159d09a2SMark Phalan 	return ENOMEM;
518*159d09a2SMark Phalan       retval = sam_get_pass_from_user(context, etype_info, key_proc,
519*159d09a2SMark Phalan 				      key_seed, request, &sam_use_key,
520*159d09a2SMark Phalan 				      prompt);
521*159d09a2SMark Phalan       free(prompt);
522*159d09a2SMark Phalan       if (retval)
523*159d09a2SMark Phalan 	return retval;
524*159d09a2SMark Phalan       enc_sam_response_enc.sam_sad.length = 0;
525*159d09a2SMark Phalan     } else {
526*159d09a2SMark Phalan       /* what *was* it? */
527*159d09a2SMark Phalan       return KRB5_SAM_UNSUPPORTED;
528*159d09a2SMark Phalan     }
529*159d09a2SMark Phalan 
530*159d09a2SMark Phalan     /* so at this point, either sam_use_key is generated from the passcode
531*159d09a2SMark Phalan      * or enc_sam_response_enc.sam_sad is set to it, and we use
532*159d09a2SMark Phalan      * def_enc_key instead. */
533*159d09a2SMark Phalan     /* encode the encoded part of the response */
534*159d09a2SMark Phalan     if ((retval = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
535*159d09a2SMark Phalan 						   &scratch)) != 0)
536*159d09a2SMark Phalan       return retval;
537*159d09a2SMark Phalan 
538*159d09a2SMark Phalan     if ((retval = krb5_encrypt_data(context,
539*159d09a2SMark Phalan 				    sam_use_key?sam_use_key:def_enc_key,
540*159d09a2SMark Phalan 				    0, scratch,
541*159d09a2SMark Phalan 				    &sam_response.sam_enc_nonce_or_ts)))
542*159d09a2SMark Phalan       goto cleanup;
543*159d09a2SMark Phalan 
544*159d09a2SMark Phalan     krb5_free_data(context, scratch);
545*159d09a2SMark Phalan     scratch = 0;
546*159d09a2SMark Phalan 
547*159d09a2SMark Phalan     /* sam_enc_key is reserved for future use */
548*159d09a2SMark Phalan     sam_response.sam_enc_key.ciphertext.length = 0;
549*159d09a2SMark Phalan 
550*159d09a2SMark Phalan     /* copy things from the challenge */
551*159d09a2SMark Phalan     sam_response.sam_nonce = sam_challenge->sam_nonce;
552*159d09a2SMark Phalan     sam_response.sam_flags = sam_challenge->sam_flags;
553*159d09a2SMark Phalan     sam_response.sam_track_id = sam_challenge->sam_track_id;
554*159d09a2SMark Phalan     sam_response.sam_type = sam_challenge->sam_type;
555*159d09a2SMark Phalan     sam_response.magic = KV5M_SAM_RESPONSE;
556*159d09a2SMark Phalan 
557*159d09a2SMark Phalan     if ((retval = encode_krb5_sam_response(&sam_response, &scratch)) != 0)
558*159d09a2SMark Phalan 	return retval;
559*159d09a2SMark Phalan 
560*159d09a2SMark Phalan     if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
561*159d09a2SMark Phalan 	retval = ENOMEM;
562*159d09a2SMark Phalan 	goto cleanup;
563*159d09a2SMark Phalan     }
564*159d09a2SMark Phalan 
565*159d09a2SMark Phalan     pa->magic = KV5M_PA_DATA;
566*159d09a2SMark Phalan     pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
567*159d09a2SMark Phalan     pa->length = scratch->length;
568*159d09a2SMark Phalan     pa->contents = (krb5_octet *) scratch->data;
569*159d09a2SMark Phalan     scratch = 0;		/* so we don't free it! */
570*159d09a2SMark Phalan 
571*159d09a2SMark Phalan     *out_padata = pa;
572*159d09a2SMark Phalan 
573*159d09a2SMark Phalan     retval = 0;
574*159d09a2SMark Phalan 
575*159d09a2SMark Phalan cleanup:
576*159d09a2SMark Phalan     if (scratch)
577*159d09a2SMark Phalan 	krb5_free_data(context, scratch);
578*159d09a2SMark Phalan     if (sam_challenge)
579*159d09a2SMark Phalan         krb5_xfree(sam_challenge);
580*159d09a2SMark Phalan     return retval;
581*159d09a2SMark Phalan }
582