1159d09a2SMark Phalan /*
2159d09a2SMark Phalan * Copyright 1995 by the Massachusetts Institute of Technology. All
3159d09a2SMark Phalan * Rights Reserved.
4159d09a2SMark Phalan *
5159d09a2SMark Phalan * Export of this software from the United States of America may
6159d09a2SMark Phalan * require a specific license from the United States Government.
7159d09a2SMark Phalan * It is the responsibility of any person or organization contemplating
8159d09a2SMark Phalan * export to obtain such a license before exporting.
9159d09a2SMark Phalan *
10159d09a2SMark Phalan * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11159d09a2SMark Phalan * distribute this software and its documentation for any purpose and
12159d09a2SMark Phalan * without fee is hereby granted, provided that the above copyright
13159d09a2SMark Phalan * notice appear in all copies and that both that copyright notice and
14159d09a2SMark Phalan * this permission notice appear in supporting documentation, and that
15159d09a2SMark Phalan * the name of M.I.T. not be used in advertising or publicity pertaining
16159d09a2SMark Phalan * to distribution of the software without specific, written prior
17159d09a2SMark Phalan * permission. Furthermore if you modify this software you must label
18159d09a2SMark Phalan * your software as modified software and not distribute it in such a
19159d09a2SMark Phalan * fashion that it might be confused with the original M.I.T. software.
20159d09a2SMark Phalan * M.I.T. makes no representations about the suitability of
21159d09a2SMark Phalan * this software for any purpose. It is provided "as is" without express
22159d09a2SMark Phalan * or implied warranty.
23159d09a2SMark Phalan *
24159d09a2SMark Phalan */
25159d09a2SMark Phalan
26159d09a2SMark Phalan /*
27159d09a2SMark Phalan * This file contains routines for establishing, verifying, and any other
28*55fea89dSDan Cross * necessary functions, for utilizing the pre-authentication field of the
29159d09a2SMark Phalan * kerberos kdc request, with various hardware/software verification devices.
30159d09a2SMark Phalan */
31159d09a2SMark Phalan
32159d09a2SMark Phalan #include "k5-int.h"
33159d09a2SMark Phalan #include <stdio.h>
34159d09a2SMark Phalan #include <time.h>
35159d09a2SMark Phalan
36159d09a2SMark Phalan static krb5_error_code obtain_enc_ts_padata
37159d09a2SMark Phalan (krb5_context,
38159d09a2SMark Phalan krb5_pa_data *,
39159d09a2SMark Phalan krb5_etype_info,
40159d09a2SMark Phalan krb5_keyblock *,
41159d09a2SMark Phalan krb5_error_code ( * )(krb5_context,
42159d09a2SMark Phalan const krb5_enctype,
43159d09a2SMark Phalan krb5_data *,
44159d09a2SMark Phalan krb5_const_pointer,
45159d09a2SMark Phalan krb5_keyblock **),
46159d09a2SMark Phalan krb5_const_pointer,
47159d09a2SMark Phalan krb5_creds *,
48159d09a2SMark Phalan krb5_kdc_req *,
49159d09a2SMark Phalan krb5_pa_data **);
50159d09a2SMark Phalan
51159d09a2SMark Phalan static krb5_error_code process_pw_salt
52159d09a2SMark Phalan (krb5_context,
53159d09a2SMark Phalan krb5_pa_data *,
54159d09a2SMark Phalan krb5_kdc_req *,
55159d09a2SMark Phalan krb5_kdc_rep *,
56159d09a2SMark Phalan krb5_error_code ( * )(krb5_context,
57159d09a2SMark Phalan const krb5_enctype,
58159d09a2SMark Phalan krb5_data *,
59159d09a2SMark Phalan krb5_const_pointer,
60159d09a2SMark Phalan krb5_keyblock **),
61159d09a2SMark Phalan krb5_const_pointer,
62159d09a2SMark Phalan krb5_error_code ( * )(krb5_context,
63159d09a2SMark Phalan const krb5_keyblock *,
64159d09a2SMark Phalan krb5_const_pointer,
65159d09a2SMark Phalan krb5_kdc_rep * ),
66159d09a2SMark Phalan krb5_keyblock **,
67159d09a2SMark Phalan krb5_creds *,
68159d09a2SMark Phalan krb5_int32 *,
69159d09a2SMark Phalan krb5_int32 *);
70159d09a2SMark Phalan
71159d09a2SMark Phalan static krb5_error_code obtain_sam_padata
72159d09a2SMark Phalan (krb5_context,
73159d09a2SMark Phalan krb5_pa_data *,
74159d09a2SMark Phalan krb5_etype_info,
75*55fea89dSDan Cross krb5_keyblock *,
76159d09a2SMark Phalan krb5_error_code ( * )(krb5_context,
77159d09a2SMark Phalan const krb5_enctype,
78159d09a2SMark Phalan krb5_data *,
79159d09a2SMark Phalan krb5_const_pointer,
80159d09a2SMark Phalan krb5_keyblock **),
81159d09a2SMark Phalan krb5_const_pointer,
82159d09a2SMark Phalan krb5_creds *,
83159d09a2SMark Phalan krb5_kdc_req *,
84159d09a2SMark Phalan krb5_pa_data **);
85159d09a2SMark Phalan
86159d09a2SMark Phalan static const krb5_preauth_ops preauth_systems[] = {
87159d09a2SMark Phalan {
88159d09a2SMark Phalan KV5M_PREAUTH_OPS,
89159d09a2SMark Phalan KRB5_PADATA_ENC_TIMESTAMP,
90159d09a2SMark Phalan 0,
91159d09a2SMark Phalan obtain_enc_ts_padata,
92159d09a2SMark Phalan 0,
93159d09a2SMark Phalan },
94159d09a2SMark Phalan {
95159d09a2SMark Phalan KV5M_PREAUTH_OPS,
96159d09a2SMark Phalan KRB5_PADATA_PW_SALT,
97159d09a2SMark Phalan 0,
98159d09a2SMark Phalan 0,
99159d09a2SMark Phalan process_pw_salt,
100159d09a2SMark Phalan },
101159d09a2SMark Phalan {
102159d09a2SMark Phalan KV5M_PREAUTH_OPS,
103159d09a2SMark Phalan KRB5_PADATA_AFS3_SALT,
104159d09a2SMark Phalan 0,
105159d09a2SMark Phalan 0,
106159d09a2SMark Phalan process_pw_salt,
107159d09a2SMark Phalan },
108159d09a2SMark Phalan {
109159d09a2SMark Phalan KV5M_PREAUTH_OPS,
110159d09a2SMark Phalan KRB5_PADATA_SAM_CHALLENGE,
111159d09a2SMark Phalan 0,
112159d09a2SMark Phalan obtain_sam_padata,
113159d09a2SMark Phalan 0,
114159d09a2SMark Phalan },
115159d09a2SMark Phalan { KV5M_PREAUTH_OPS, -1 }
116159d09a2SMark Phalan };
117159d09a2SMark Phalan
118159d09a2SMark Phalan static krb5_error_code find_pa_system
119159d09a2SMark Phalan (krb5_preauthtype type, const krb5_preauth_ops **Preauth_proc);
120159d09a2SMark Phalan
121159d09a2SMark Phalan /* some typedef's for the function args to make things look a bit cleaner */
122159d09a2SMark Phalan
123159d09a2SMark Phalan typedef krb5_error_code (*git_key_proc) (krb5_context,
124159d09a2SMark Phalan const krb5_enctype,
125159d09a2SMark Phalan krb5_data *,
126159d09a2SMark Phalan krb5_const_pointer,
127159d09a2SMark Phalan krb5_keyblock **);
128159d09a2SMark Phalan
129159d09a2SMark Phalan typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
130159d09a2SMark Phalan const krb5_keyblock *,
131159d09a2SMark Phalan krb5_const_pointer,
132159d09a2SMark Phalan krb5_kdc_rep *);
133159d09a2SMark 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)134159d09a2SMark 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)
135159d09a2SMark Phalan {
136159d09a2SMark Phalan krb5_error_code retval;
137159d09a2SMark Phalan krb5_etype_info etype_info = 0;
138159d09a2SMark Phalan krb5_pa_data ** pa;
139159d09a2SMark Phalan krb5_pa_data ** send_pa_list;
140159d09a2SMark Phalan krb5_pa_data ** send_pa;
141159d09a2SMark Phalan const krb5_preauth_ops *ops;
142159d09a2SMark Phalan krb5_keyblock * def_enc_key = 0;
143159d09a2SMark Phalan krb5_enctype enctype;
144159d09a2SMark Phalan krb5_data salt;
145159d09a2SMark Phalan krb5_data scratch;
146159d09a2SMark Phalan int size;
147159d09a2SMark Phalan int f_salt = 0;
148159d09a2SMark Phalan
149159d09a2SMark Phalan if (preauth_to_use == NULL)
150159d09a2SMark Phalan return 0;
151159d09a2SMark Phalan
152159d09a2SMark Phalan for (pa = preauth_to_use, size=0; *pa; pa++, size++) {
153159d09a2SMark Phalan if ((*pa)->pa_type == KRB5_PADATA_ETYPE_INFO) {
154159d09a2SMark Phalan /* XXX use the first one. Is there another way to disambiguate? */
155159d09a2SMark Phalan if (etype_info)
156159d09a2SMark Phalan continue;
157159d09a2SMark Phalan
158159d09a2SMark Phalan scratch.length = (*pa)->length;
159159d09a2SMark Phalan scratch.data = (char *) (*pa)->contents;
160159d09a2SMark Phalan retval = decode_krb5_etype_info(&scratch, &etype_info);
161159d09a2SMark Phalan if (retval)
162159d09a2SMark Phalan return retval;
163159d09a2SMark Phalan if (etype_info[0] == NULL) {
164159d09a2SMark Phalan krb5_free_etype_info(context, etype_info);
165159d09a2SMark Phalan etype_info = NULL;
166159d09a2SMark Phalan }
167159d09a2SMark Phalan }
168159d09a2SMark Phalan }
169159d09a2SMark Phalan
170159d09a2SMark Phalan if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
171159d09a2SMark Phalan return ENOMEM;
172159d09a2SMark Phalan
173159d09a2SMark Phalan send_pa = send_pa_list;
174159d09a2SMark Phalan *send_pa = 0;
175159d09a2SMark Phalan
176159d09a2SMark Phalan enctype = request->ktype[0];
177159d09a2SMark Phalan salt.data = 0;
178159d09a2SMark Phalan salt.length = SALT_TYPE_NO_LENGTH;
179159d09a2SMark Phalan if (etype_info) {
180159d09a2SMark Phalan enctype = etype_info[0]->etype;
181159d09a2SMark Phalan salt.data = (char *) etype_info[0]->salt;
182*55fea89dSDan Cross if(etype_info[0]->length == KRB5_ETYPE_NO_SALT)
183159d09a2SMark Phalan salt.length = SALT_TYPE_NO_LENGTH; /* XXX */
184*55fea89dSDan Cross else
185159d09a2SMark Phalan salt.length = etype_info[0]->length;
186159d09a2SMark Phalan }
187159d09a2SMark Phalan if (salt.length == SALT_TYPE_NO_LENGTH) {
188159d09a2SMark Phalan /*
189*55fea89dSDan Cross * This will set the salt length
190159d09a2SMark Phalan */
191159d09a2SMark Phalan if ((retval = krb5_principal2salt(context, request->client, &salt)))
192159d09a2SMark Phalan return(retval);
193159d09a2SMark Phalan f_salt = 1;
194159d09a2SMark Phalan }
195*55fea89dSDan Cross
196159d09a2SMark Phalan if ((retval = (*key_proc)(context, enctype, &salt, key_seed,
197159d09a2SMark Phalan &def_enc_key)))
198159d09a2SMark Phalan goto cleanup;
199*55fea89dSDan Cross
200159d09a2SMark Phalan
201159d09a2SMark Phalan for (pa = preauth_to_use; *pa; pa++) {
202159d09a2SMark Phalan if (find_pa_system((*pa)->pa_type, &ops))
203159d09a2SMark Phalan continue;
204159d09a2SMark Phalan
205159d09a2SMark Phalan if (ops->obtain == 0)
206159d09a2SMark Phalan continue;
207*55fea89dSDan Cross
208159d09a2SMark Phalan retval = ((ops)->obtain)(context, *pa, etype_info, def_enc_key,
209159d09a2SMark Phalan key_proc, key_seed, creds,
210159d09a2SMark Phalan request, send_pa);
211159d09a2SMark Phalan if (retval)
212159d09a2SMark Phalan goto cleanup;
213159d09a2SMark Phalan
214159d09a2SMark Phalan if (*send_pa)
215159d09a2SMark Phalan send_pa++;
216159d09a2SMark Phalan *send_pa = 0;
217159d09a2SMark Phalan }
218159d09a2SMark Phalan
219159d09a2SMark Phalan retval = 0;
220159d09a2SMark Phalan
221159d09a2SMark Phalan if (send_pa_list[0]) {
222159d09a2SMark Phalan request->padata = send_pa_list;
223159d09a2SMark Phalan send_pa_list = 0;
224159d09a2SMark Phalan }
225159d09a2SMark Phalan
226159d09a2SMark Phalan cleanup:
227159d09a2SMark Phalan if (etype_info)
228159d09a2SMark Phalan krb5_free_etype_info(context, etype_info);
229159d09a2SMark Phalan if (f_salt)
230159d09a2SMark Phalan krb5_xfree(salt.data);
231159d09a2SMark Phalan if (send_pa_list)
232159d09a2SMark Phalan krb5_free_pa_data(context, send_pa_list);
233159d09a2SMark Phalan if (def_enc_key)
234159d09a2SMark Phalan krb5_free_keyblock(context, def_enc_key);
235159d09a2SMark Phalan return retval;
236*55fea89dSDan Cross
237159d09a2SMark Phalan }
238159d09a2SMark Phalan
239159d09a2SMark 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)240159d09a2SMark 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)
241159d09a2SMark Phalan {
242159d09a2SMark Phalan krb5_error_code retval = 0;
243159d09a2SMark Phalan const krb5_preauth_ops * ops;
244159d09a2SMark Phalan krb5_pa_data ** pa;
245159d09a2SMark Phalan krb5_int32 done = 0;
246*55fea89dSDan Cross
247159d09a2SMark Phalan *do_more = 0; /* By default, we don't need to repeat... */
248159d09a2SMark Phalan if (as_reply->padata == 0)
249159d09a2SMark Phalan return 0;
250159d09a2SMark Phalan
251159d09a2SMark Phalan for (pa = as_reply->padata; *pa; pa++) {
252159d09a2SMark Phalan if (find_pa_system((*pa)->pa_type, &ops))
253159d09a2SMark Phalan continue;
254159d09a2SMark Phalan
255159d09a2SMark Phalan if (ops->process == 0)
256159d09a2SMark Phalan continue;
257*55fea89dSDan Cross
258159d09a2SMark Phalan retval = ((ops)->process)(context, *pa, request, as_reply,
259159d09a2SMark Phalan key_proc, keyseed, decrypt_proc,
260159d09a2SMark Phalan decrypt_key, creds, do_more, &done);
261159d09a2SMark Phalan if (retval)
262159d09a2SMark Phalan goto cleanup;
263159d09a2SMark Phalan if (done)
264159d09a2SMark Phalan break;
265159d09a2SMark Phalan }
266159d09a2SMark Phalan
267159d09a2SMark Phalan cleanup:
268159d09a2SMark Phalan return retval;
269159d09a2SMark Phalan }
270159d09a2SMark Phalan
271159d09a2SMark Phalan /*
272159d09a2SMark Phalan * This routine is the "obtain" function for the ENC_TIMESTAMP
273159d09a2SMark Phalan * preauthentication type. It take the current time and encrypts it
274159d09a2SMark Phalan * in the user's key.
275159d09a2SMark Phalan */
276159d09a2SMark 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)277159d09a2SMark 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)
278159d09a2SMark Phalan {
279159d09a2SMark Phalan krb5_pa_enc_ts pa_enc;
280159d09a2SMark Phalan krb5_error_code retval;
281159d09a2SMark Phalan krb5_data * scratch;
282159d09a2SMark Phalan krb5_enc_data enc_data;
283159d09a2SMark Phalan krb5_pa_data * pa;
284159d09a2SMark Phalan
285159d09a2SMark Phalan retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
286159d09a2SMark Phalan if (retval)
287159d09a2SMark Phalan return retval;
288159d09a2SMark Phalan
289159d09a2SMark Phalan if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0)
290159d09a2SMark Phalan return retval;
291159d09a2SMark Phalan
292159d09a2SMark Phalan enc_data.ciphertext.data = 0;
293159d09a2SMark Phalan
294159d09a2SMark Phalan if ((retval = krb5_encrypt_helper(context, def_enc_key,
295159d09a2SMark Phalan KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
296159d09a2SMark Phalan scratch, &enc_data)))
297159d09a2SMark Phalan goto cleanup;
298159d09a2SMark Phalan
299159d09a2SMark Phalan krb5_free_data(context, scratch);
300159d09a2SMark Phalan scratch = 0;
301*55fea89dSDan Cross
302159d09a2SMark Phalan if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0)
303159d09a2SMark Phalan goto cleanup;
304159d09a2SMark Phalan
305159d09a2SMark Phalan if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
306159d09a2SMark Phalan retval = ENOMEM;
307159d09a2SMark Phalan goto cleanup;
308159d09a2SMark Phalan }
309159d09a2SMark Phalan
310159d09a2SMark Phalan pa->magic = KV5M_PA_DATA;
311159d09a2SMark Phalan pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
312159d09a2SMark Phalan pa->length = scratch->length;
313159d09a2SMark Phalan pa->contents = (krb5_octet *) scratch->data;
314159d09a2SMark Phalan
315159d09a2SMark Phalan *out_padata = pa;
316159d09a2SMark Phalan
317159d09a2SMark Phalan krb5_xfree(scratch);
318159d09a2SMark Phalan scratch = 0;
319159d09a2SMark Phalan
320159d09a2SMark Phalan retval = 0;
321*55fea89dSDan Cross
322159d09a2SMark Phalan cleanup:
323159d09a2SMark Phalan if (scratch)
324159d09a2SMark Phalan krb5_free_data(context, scratch);
325159d09a2SMark Phalan if (enc_data.ciphertext.data)
326159d09a2SMark Phalan krb5_xfree(enc_data.ciphertext.data);
327159d09a2SMark Phalan return retval;
328159d09a2SMark Phalan }
329159d09a2SMark Phalan
330159d09a2SMark 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)331159d09a2SMark 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)
332159d09a2SMark Phalan {
333159d09a2SMark Phalan krb5_error_code retval;
334159d09a2SMark Phalan krb5_data salt;
335*55fea89dSDan Cross
336159d09a2SMark Phalan if (*decrypt_key != 0)
337159d09a2SMark Phalan return 0;
338159d09a2SMark Phalan
339159d09a2SMark Phalan salt.data = (char *) padata->contents;
340*55fea89dSDan Cross salt.length =
341159d09a2SMark Phalan (padata->pa_type == KRB5_PADATA_AFS3_SALT)?(SALT_TYPE_AFS_LENGTH):(padata->length);
342*55fea89dSDan Cross
343159d09a2SMark Phalan if ((retval = (*key_proc)(context, as_reply->enc_part.enctype,
344159d09a2SMark Phalan &salt, keyseed, decrypt_key))) {
345159d09a2SMark Phalan *decrypt_key = 0;
346159d09a2SMark Phalan return retval;
347159d09a2SMark Phalan }
348159d09a2SMark Phalan
349159d09a2SMark Phalan return 0;
350159d09a2SMark Phalan }
351*55fea89dSDan Cross
352159d09a2SMark Phalan static krb5_error_code
find_pa_system(krb5_preauthtype type,const krb5_preauth_ops ** preauth)353159d09a2SMark Phalan find_pa_system(krb5_preauthtype type, const krb5_preauth_ops **preauth)
354159d09a2SMark Phalan {
355159d09a2SMark Phalan const krb5_preauth_ops *ap = preauth_systems;
356*55fea89dSDan Cross
357159d09a2SMark Phalan while ((ap->type != -1) && (ap->type != type))
358159d09a2SMark Phalan ap++;
359159d09a2SMark Phalan if (ap->type == -1)
360159d09a2SMark Phalan return(KRB5_PREAUTH_BAD_TYPE);
361159d09a2SMark Phalan *preauth = ap;
362159d09a2SMark Phalan return 0;
363*55fea89dSDan Cross }
364159d09a2SMark Phalan
365159d09a2SMark Phalan
366159d09a2SMark Phalan extern const char *krb5_default_pwd_prompt1;
367159d09a2SMark Phalan
368159d09a2SMark 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)369159d09a2SMark 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)
370159d09a2SMark Phalan {
371159d09a2SMark Phalan krb5_enctype enctype;
372159d09a2SMark Phalan krb5_error_code retval;
373159d09a2SMark Phalan const char *oldprompt;
374159d09a2SMark Phalan
375159d09a2SMark Phalan /* enctype = request->ktype[0]; */
376159d09a2SMark Phalan enctype = ENCTYPE_DES_CBC_MD5;
377159d09a2SMark Phalan /* hack with this first! */
378159d09a2SMark Phalan oldprompt = krb5_default_pwd_prompt1;
379159d09a2SMark Phalan krb5_default_pwd_prompt1 = prompt;
380159d09a2SMark Phalan {
381159d09a2SMark Phalan krb5_data newpw;
382159d09a2SMark Phalan newpw.data = 0; newpw.length = 0;
383159d09a2SMark Phalan /* we don't keep the new password, just the key... */
384*55fea89dSDan Cross retval = (*key_proc)(context, enctype, 0,
385159d09a2SMark Phalan (krb5_const_pointer)&newpw, new_enc_key);
386159d09a2SMark Phalan krb5_xfree(newpw.data);
387159d09a2SMark Phalan }
388159d09a2SMark Phalan krb5_default_pwd_prompt1 = oldprompt;
389159d09a2SMark Phalan return retval;
390159d09a2SMark Phalan }
391*55fea89dSDan Cross static
handle_sam_labels(krb5_sam_challenge * sc)392159d09a2SMark Phalan char *handle_sam_labels(krb5_sam_challenge *sc)
393159d09a2SMark Phalan {
394159d09a2SMark Phalan char *label = sc->sam_challenge_label.data;
395159d09a2SMark Phalan unsigned int label_len = sc->sam_challenge_label.length;
396159d09a2SMark Phalan char *prompt = sc->sam_response_prompt.data;
397159d09a2SMark Phalan unsigned int prompt_len = sc->sam_response_prompt.length;
398159d09a2SMark Phalan char *challenge = sc->sam_challenge.data;
399159d09a2SMark Phalan unsigned int challenge_len = sc->sam_challenge.length;
400159d09a2SMark Phalan char *prompt1, *p;
401159d09a2SMark Phalan char *sep1 = ": [";
402159d09a2SMark Phalan char *sep2 = "]\n";
403159d09a2SMark Phalan char *sep3 = ": ";
404159d09a2SMark Phalan
405159d09a2SMark Phalan if (sc->sam_cksum.length == 0) {
406159d09a2SMark Phalan /* or invalid -- but lets just handle presence now XXX */
407159d09a2SMark Phalan switch (sc->sam_type) {
408159d09a2SMark Phalan case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
409159d09a2SMark Phalan label = "Challenge for Enigma Logic mechanism";
410159d09a2SMark Phalan break;
411159d09a2SMark Phalan case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */
412159d09a2SMark Phalan case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */
413159d09a2SMark Phalan label = "Challenge for Digital Pathways mechanism";
414159d09a2SMark Phalan break;
415159d09a2SMark Phalan case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */
416159d09a2SMark Phalan case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */
417159d09a2SMark Phalan label = "Challenge for Activcard mechanism";
418159d09a2SMark Phalan break;
419159d09a2SMark Phalan case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */
420159d09a2SMark Phalan label = "Challenge for Enhanced S/Key mechanism";
421159d09a2SMark Phalan break;
422159d09a2SMark Phalan case PA_SAM_TYPE_SKEY: /* Traditional S/Key */
423159d09a2SMark Phalan label = "Challenge for Traditional S/Key mechanism";
424159d09a2SMark Phalan break;
425159d09a2SMark Phalan case PA_SAM_TYPE_SECURID: /* Security Dynamics */
426159d09a2SMark Phalan label = "Challenge for Security Dynamics mechanism";
427159d09a2SMark Phalan break;
428159d09a2SMark Phalan case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */
429159d09a2SMark Phalan label = "Challenge for Security Dynamics mechanism";
430159d09a2SMark Phalan break;
431159d09a2SMark Phalan }
432159d09a2SMark Phalan prompt = "Passcode";
433159d09a2SMark Phalan label_len = strlen(label);
434159d09a2SMark Phalan prompt_len = strlen(prompt);
435159d09a2SMark Phalan }
436159d09a2SMark Phalan
437159d09a2SMark Phalan /* example:
438159d09a2SMark Phalan Challenge for Digital Pathways mechanism: [134591]
439*55fea89dSDan Cross Passcode:
440159d09a2SMark Phalan */
441159d09a2SMark Phalan p = prompt1 = malloc(label_len + strlen(sep1) +
442159d09a2SMark Phalan challenge_len + strlen(sep2) +
443159d09a2SMark Phalan prompt_len+ strlen(sep3) + 1);
444159d09a2SMark Phalan if (p == NULL)
445159d09a2SMark Phalan return NULL;
446159d09a2SMark Phalan if (challenge_len) {
447159d09a2SMark Phalan strncpy(p, label, label_len); p += label_len;
448159d09a2SMark Phalan strcpy(p, sep1); p += strlen(sep1);
449159d09a2SMark Phalan strncpy(p, challenge, challenge_len); p += challenge_len;
450159d09a2SMark Phalan strcpy(p, sep2); p += strlen(sep2);
451159d09a2SMark Phalan }
452159d09a2SMark Phalan strncpy(p, prompt, prompt_len); p += prompt_len;
453159d09a2SMark Phalan strcpy(p, sep3); /* p += strlen(sep3); */
454159d09a2SMark Phalan return prompt1;
455159d09a2SMark Phalan }
456159d09a2SMark Phalan
457159d09a2SMark Phalan /*
458159d09a2SMark Phalan * This routine is the "obtain" function for the SAM_CHALLENGE
459159d09a2SMark Phalan * preauthentication type. It presents the challenge...
460159d09a2SMark Phalan */
461159d09a2SMark 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)462159d09a2SMark 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)
463159d09a2SMark Phalan {
464159d09a2SMark Phalan krb5_error_code retval;
465159d09a2SMark Phalan krb5_data * scratch;
466159d09a2SMark Phalan krb5_data tmpsam;
467159d09a2SMark Phalan krb5_pa_data * pa;
468159d09a2SMark Phalan krb5_sam_challenge *sam_challenge = 0;
469159d09a2SMark Phalan krb5_sam_response sam_response;
470159d09a2SMark Phalan /* these two get encrypted and stuffed in to sam_response */
471159d09a2SMark Phalan krb5_enc_sam_response_enc enc_sam_response_enc;
472159d09a2SMark Phalan krb5_keyblock * sam_use_key = 0;
473159d09a2SMark Phalan char * prompt;
474159d09a2SMark Phalan
475159d09a2SMark Phalan tmpsam.length = in_padata->length;
476159d09a2SMark Phalan tmpsam.data = (char *) in_padata->contents;
477159d09a2SMark Phalan retval = decode_krb5_sam_challenge(&tmpsam, &sam_challenge);
478159d09a2SMark Phalan if (retval)
479159d09a2SMark Phalan return retval;
480159d09a2SMark Phalan
481159d09a2SMark Phalan if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
482159d09a2SMark Phalan return KRB5_SAM_UNSUPPORTED;
483159d09a2SMark Phalan }
484159d09a2SMark Phalan
485159d09a2SMark Phalan enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
486159d09a2SMark Phalan if (!sam_challenge->sam_nonce) {
487159d09a2SMark Phalan retval = krb5_us_timeofday(context,
488159d09a2SMark Phalan &enc_sam_response_enc.sam_timestamp,
489159d09a2SMark Phalan &enc_sam_response_enc.sam_usec);
490159d09a2SMark Phalan sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
491159d09a2SMark Phalan }
492159d09a2SMark Phalan if (retval)
493159d09a2SMark Phalan return retval;
494159d09a2SMark Phalan if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
495159d09a2SMark Phalan /* encrypt passcode in key by stuffing it here */
496159d09a2SMark Phalan unsigned int pcsize = 256;
497159d09a2SMark Phalan char *passcode = malloc(pcsize+1);
498159d09a2SMark Phalan if (passcode == NULL)
499159d09a2SMark Phalan return ENOMEM;
500159d09a2SMark Phalan prompt = handle_sam_labels(sam_challenge);
501159d09a2SMark Phalan if (prompt == NULL) {
502159d09a2SMark Phalan free(passcode);
503159d09a2SMark Phalan return ENOMEM;
504159d09a2SMark Phalan }
505159d09a2SMark Phalan retval = krb5_read_password(context, prompt, 0, passcode, &pcsize);
506159d09a2SMark Phalan free(prompt);
507159d09a2SMark Phalan
508159d09a2SMark Phalan if (retval) {
509159d09a2SMark Phalan free(passcode);
510159d09a2SMark Phalan return retval;
511159d09a2SMark Phalan }
512159d09a2SMark Phalan enc_sam_response_enc.sam_sad.data = passcode;
513159d09a2SMark Phalan enc_sam_response_enc.sam_sad.length = pcsize;
514159d09a2SMark Phalan } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
515159d09a2SMark Phalan prompt = handle_sam_labels(sam_challenge);
516159d09a2SMark Phalan if (prompt == NULL)
517159d09a2SMark Phalan return ENOMEM;
518*55fea89dSDan Cross retval = sam_get_pass_from_user(context, etype_info, key_proc,
519159d09a2SMark Phalan key_seed, request, &sam_use_key,
520159d09a2SMark Phalan prompt);
521159d09a2SMark Phalan free(prompt);
522159d09a2SMark Phalan if (retval)
523*55fea89dSDan Cross return retval;
524159d09a2SMark Phalan enc_sam_response_enc.sam_sad.length = 0;
525159d09a2SMark Phalan } else {
526159d09a2SMark Phalan /* what *was* it? */
527159d09a2SMark Phalan return KRB5_SAM_UNSUPPORTED;
528159d09a2SMark Phalan }
529159d09a2SMark Phalan
530159d09a2SMark Phalan /* so at this point, either sam_use_key is generated from the passcode
531*55fea89dSDan Cross * or enc_sam_response_enc.sam_sad is set to it, and we use
532159d09a2SMark Phalan * def_enc_key instead. */
533159d09a2SMark Phalan /* encode the encoded part of the response */
534159d09a2SMark Phalan if ((retval = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
535159d09a2SMark Phalan &scratch)) != 0)
536159d09a2SMark Phalan return retval;
537159d09a2SMark Phalan
538*55fea89dSDan Cross if ((retval = krb5_encrypt_data(context,
539*55fea89dSDan Cross sam_use_key?sam_use_key:def_enc_key,
540159d09a2SMark Phalan 0, scratch,
541159d09a2SMark Phalan &sam_response.sam_enc_nonce_or_ts)))
542159d09a2SMark Phalan goto cleanup;
543159d09a2SMark Phalan
544159d09a2SMark Phalan krb5_free_data(context, scratch);
545159d09a2SMark Phalan scratch = 0;
546159d09a2SMark Phalan
547159d09a2SMark Phalan /* sam_enc_key is reserved for future use */
548159d09a2SMark Phalan sam_response.sam_enc_key.ciphertext.length = 0;
549159d09a2SMark Phalan
550159d09a2SMark Phalan /* copy things from the challenge */
551159d09a2SMark Phalan sam_response.sam_nonce = sam_challenge->sam_nonce;
552159d09a2SMark Phalan sam_response.sam_flags = sam_challenge->sam_flags;
553159d09a2SMark Phalan sam_response.sam_track_id = sam_challenge->sam_track_id;
554159d09a2SMark Phalan sam_response.sam_type = sam_challenge->sam_type;
555159d09a2SMark Phalan sam_response.magic = KV5M_SAM_RESPONSE;
556159d09a2SMark Phalan
557159d09a2SMark Phalan if ((retval = encode_krb5_sam_response(&sam_response, &scratch)) != 0)
558159d09a2SMark Phalan return retval;
559*55fea89dSDan Cross
560159d09a2SMark Phalan if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
561159d09a2SMark Phalan retval = ENOMEM;
562159d09a2SMark Phalan goto cleanup;
563159d09a2SMark Phalan }
564159d09a2SMark Phalan
565159d09a2SMark Phalan pa->magic = KV5M_PA_DATA;
566159d09a2SMark Phalan pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
567159d09a2SMark Phalan pa->length = scratch->length;
568159d09a2SMark Phalan pa->contents = (krb5_octet *) scratch->data;
569159d09a2SMark Phalan scratch = 0; /* so we don't free it! */
570159d09a2SMark Phalan
571159d09a2SMark Phalan *out_padata = pa;
572159d09a2SMark Phalan
573159d09a2SMark Phalan retval = 0;
574*55fea89dSDan Cross
575159d09a2SMark Phalan cleanup:
576159d09a2SMark Phalan if (scratch)
577159d09a2SMark Phalan krb5_free_data(context, scratch);
578159d09a2SMark Phalan if (sam_challenge)
579159d09a2SMark Phalan krb5_xfree(sam_challenge);
580159d09a2SMark Phalan return retval;
581159d09a2SMark Phalan }
582