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