2 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5 * Export of this software from the United States of America may
6 * require a specific license from the United States Government.
7 * It is the responsibility of any person or organization contemplating
8 * export to obtain such a license before exporting.
10 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11 * distribute this software and its documentation for any purpose and
12 * without fee is hereby granted, provided that the above copyright
13 * notice appear in all copies and that both that copyright notice and
14 * this permission notice appear in supporting documentation, and that
15 * the name of M.I.T. not be used in advertising or publicity pertaining
16 * to distribution of the software without specific, written prior
17 * permission. M.I.T. makes no representations about the suitability of
18 * this software for any purpose. It is provided "as is" without express
19 * or implied warranty.
21 * Sandia National Laboratories also makes no representations about the
22 * suitability of the modifications, or additions to this software for
23 * any purpose. It is provided "as is" without express or implied warranty.
25 * Note: The internal interfaces to this routine are subject to change
26 * and/or cleanup. You should only expect the interfaces to
27 * krb5_obtain_padata and krb5_verify_padata to have some chance of
28 * staying stable. [tytso:19920903.1544EDT]
32 * This file contains routines for establishing, verifying, and any other
33 * necessary functions, for utilizing the pre-authentication field of the
34 * kerberos kdc request, with various hardware/software verification devices.
36 * Note: At some point these functions may very well be split apart
37 * into different files.... [tytso:19920903.1618EDT]
45 #define getpid _getpid
49 static krb5_preauth_ops preauth_systems[] = {
52 KRB5_PADATA_ENC_UNIX_TIME,
53 KRB5_PREAUTH_FLAGS_ENCRYPT,
55 verify_unixtime_padata,
59 KRB5_PADATA_ENC_SANDIA_SECURID,
60 KRB5_PREAUTH_FLAGS_ENCRYPT | KRB5_PREAUTH_FLAGS_HARDWARE,
62 verify_securid_padata,
67 static krb5_error_code find_preauthenticator
68 PROTOTYPE((int type, krb5_preauth_ops **Preauth_proc));
71 * krb5_obtain_padata is a glue routine which when passed in
72 * a preauthentication type, client principal, and src_addr, returns
73 * preauthentication data contained in data to be passed onto the KDC.
75 * If problems occur then a non zero value is returned...
77 * Note: This is a first crack at what any preauthentication will need...
80 krb5_obtain_padata(context, type, client, src_addr, encrypt_key, ret_data)
82 int type; /*IN: Preauth type */
83 krb5_principal client; /*IN: requestor */
84 krb5_address **src_addr; /*IN: array of ptrs to addresses */
85 krb5_keyblock *encrypt_key; /*IN: encryption key */
86 krb5_pa_data **ret_data; /*OUT: Returned padata */
88 krb5_error_code retval;
89 krb5_preauth_ops *p_system;
90 krb5_encrypt_block eblock;
98 if (type == KRB5_PADATA_NONE )
101 data = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
107 data->pa_type = type;
109 /* Find appropriate preauthenticator */
110 retval = find_preauthenticator(type, &p_system);
114 retval = (*p_system->obtain)(context, client, src_addr, data );
118 /* Check to see if we need to encrypt padata */
119 if (p_system->flags & KRB5_PREAUTH_FLAGS_ENCRYPT) {
120 /* If we dont have a encryption key we are out of luck */
122 retval = KRB5_PREAUTH_NO_KEY;
125 krb5_use_keytype(context, &eblock, encrypt_key->keytype);
127 /* do any necessay key pre-processing */
128 retval = krb5_process_key(context, &eblock, encrypt_key);
133 * Set up scratch data and length for encryption
134 * Must allocate more space for checksum and confounder
135 * We also leave space for an uncrypted size field.
137 scratch.length = krb5_encrypt_size(data->length,
138 eblock.crypto_entry) + 4;
140 if(!(scratch.data = malloc(scratch.length))){
141 (void) krb5_finish_key(context, &eblock);
146 scratch.data[0] = data->length >> 24;
147 scratch.data[1] = data->length >> 16;
148 scratch.data[2] = data->length >> 8;
149 scratch.data[3] = data->length;
151 /* Encrypt preauth data in encryption key */
152 if (retval = krb5_encrypt(context, (krb5_pointer) data->contents,
153 (char *) scratch.data + 4,
154 data->length, &eblock, 0)) {
155 (void) krb5_finish_key(context, &eblock);
159 (void) krb5_finish_key(context, &eblock);
161 free(data->contents);
162 data->length = scratch.length;
163 data->contents = (unsigned char *) scratch.data;
175 * krb5_verify_padata is a glue routine which when passed in
176 * the client, src_addr and padata verifies it with the appropriate
179 * If problems occur then a non zero value is returned...
180 * else returns zero if padata verifies, and returns a "unique" id.
182 * Note: This is a first crack at what any preauthentication will need...
186 krb5_verify_padata(context, data,client,src_addr, decrypt_key, req_id, flags)
187 krb5_context context;
188 krb5_pa_data *data; /*IN: padata */
189 krb5_principal client; /*IN: requestor */
190 krb5_address **src_addr; /*IN: array of ptrs to addresses */
191 krb5_keyblock *decrypt_key; /*IN: decryption key */
192 int * req_id; /*OUT: identifier */
193 int * flags; /*OUT: flags */
195 krb5_preauth_ops *p_system;
196 krb5_encrypt_block eblock;
198 int free_scratch = 0;
200 krb5_error_code retval;
205 /* Find appropriate preauthenticator */
206 retval = find_preauthenticator((int) data->pa_type, &p_system);
210 /* Check to see if we need to decrypt padata */
211 if (p_system->flags & KRB5_PREAUTH_FLAGS_ENCRYPT) {
213 /* If we dont have a decryption key we are out of luck */
217 krb5_use_keytype(context, &eblock, decrypt_key->keytype);
219 scratch.length = data->length;
220 if (!(scratch.data = (char *)malloc(scratch.length))) {
224 /* do any necessay key pre-processing */
225 retval = krb5_process_key(context, &eblock,decrypt_key);
232 retval = krb5_decrypt(context, (char *) data->contents + 4,
233 (krb5_pointer) scratch.data,
234 scratch.length - 4, &eblock, 0);
236 (void) krb5_finish_key(context, &eblock);
241 scratch.length = (((int) ((unsigned char *)data->contents)[0] << 24)
242 + ((int) ((unsigned char *)data->contents)[1] << 16)
243 + ((int) ((unsigned char *)data->contents)[2] << 8)
244 + (int) ((unsigned char *)data->contents)[3]);
247 scratch.data = (char *) data->contents;
248 scratch.length = data->length;
251 retval = (*p_system->verify)(context, client, src_addr, &scratch);
257 *flags = p_system->flags;
259 /* Generate a request id by crc32ing the (encrypted) preauth data. */
260 /* Note: The idea behind req_id is that it is dependant upon
261 the information in data. This could then be used for
263 /* MUST malloc cksum.contents */
264 cksum.contents = (krb5_octet *)calloc(1,
265 krb5_checksum_size(context, CKSUMTYPE_CRC32));
266 if (!cksum.contents) return(1);
268 if (krb5_calculate_checksum(context, CKSUMTYPE_CRC32,
271 0, /* seed is ignored */
272 0, /* seed length is ignored */
276 /* Checksum length should be 32 bits, so truncation should never
278 if ( cksum.length > sizeof(*req_id)) cksum.length = sizeof(*req_id);
280 /* Offset req_id for 64 bit systems */
281 memcpy((char *)req_id + (sizeof(*req_id) - cksum.length),
282 cksum.contents,cksum.length);
284 free(cksum.contents);
288 static krb5_error_code
289 find_preauthenticator(type, preauth)
291 krb5_preauth_ops **preauth;
293 krb5_preauth_ops *ap = preauth_systems;
295 while ((ap->type != -1) && (ap->type != type))
298 return(KRB5_PREAUTH_BAD_TYPE);
304 * Format is: 8 bytes of random confounder,
305 * 1 byte version number (currently 0),
306 * 4 bytes: number of seconds since Jan 1, 1970, in MSB order.
308 int seeded = 0 ; /* Used by srand below */
311 get_unixtime_padata(context, client, src_addr, pa_data)
312 krb5_context context;
313 krb5_principal client;
314 krb5_address **src_addr;
315 krb5_pa_data *pa_data;
318 krb5_error_code retval;
319 krb5_timestamp kdc_time;
322 pa_data->length = 13;
323 tmp = pa_data->contents = (unsigned char *) malloc(pa_data->length);
327 retval = krb5_timeofday(context, &kdc_time);
331 seeded = (int) kdc_time + getpid();
335 for (i=0; i < 8; i++)
336 *tmp++ = rand() & 255;
338 *tmp++ = (unsigned char) 0;
339 *tmp++ = (unsigned char) ((kdc_time >> 24) & 255);
340 *tmp++ = (unsigned char) ((kdc_time >> 16) & 255);
341 *tmp++ = (unsigned char) ((kdc_time >> 8) & 255);
342 *tmp++ = (unsigned char) (kdc_time & 255);
348 verify_unixtime_padata(context, client, src_addr, data)
349 krb5_context context;
350 krb5_principal client;
351 krb5_address **src_addr;
355 krb5_error_code retval;
356 krb5_timestamp currenttime, patime;
357 extern krb5_deltat krb5_clockskew;
358 #define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew)
360 tmp = (unsigned char *) data->data;
362 return KRB5_PREAUTH_FAILED;
363 patime = (int) tmp[9] << 24;
364 patime += (int) tmp[10] << 16;
365 patime += (int) tmp[11] << 8;
368 retval = krb5_timeofday(context, ¤ttime);
372 if (!in_clock_skew(patime))
373 return KRB5_PREAUTH_FAILED;
378 #ifdef KRBCONF_SECUREID
383 verify_securid_padata(client, src_addr, data)
384 krb5_principal client;
385 krb5_address **src_addr;
391 krb5_error_code retval;
395 memset((char *)&sd,0, sizeof (sd));
396 memset((char *) username, 0, sizeof(username));
397 memcpy((char *) username, krb5_princ_component(context, client,0)->data,
398 krb5_princ_component(context, client,0)->length);
399 /* If Instance then Append */
400 if (krb5_princ_size(context, client) > 1 ) {
401 if (strncmp(krb5_princ_realm(context, client)->data,
402 krb5_princ_component(context, client,1)->data,
403 krb5_princ_component(context, client,1)->length) ||
404 krb5_princ_realm(context, client)->length !=
405 krb5_princ_component(context, client,1)->length) {
406 strncat(username,"/",1);
407 strncat(username,krb5_princ_component(context, client,1)->data,
408 krb5_princ_component(context, client,1)->length);
411 if (retval = sd_check(data->data,username,&sd) != ACM_OK) {
413 "%s - Invalid Securid Authentication Data sd_check Code %d",
415 return(KRB5_PREAUTH_FAILED);
421 krb5_unparse_name(context, client,&username);
423 "%s Provided Securid but this KDC does not support Securid",
426 return(KRB5_PREAUTH_FAILED);
431 verify_securid_padata(context, client, src_addr, data)
432 krb5_context context;
433 krb5_principal client;
434 krb5_address **src_addr;
438 krb5_unparse_name(context, client,&username);
440 "%s Provided Securid but this KDC does not support Securid",
443 return(KRB5_PREAUTH_FAILED);
450 static char *krb5_SecureId_prompt = "\nEnter Your SecurId Access Code Prepended with Your PIN\n (or a \'#\'if Your PIN is entered on the card keypad)\n or Type return <CR> if You Do NOT Use a SecurId Card: ";
452 static char *krb5_SecureId_prompt = "\nEnter Your SecurId Access Code Prepended with Your PIN\n (or a \'#\'if Your PIN is entered on the card keypad): ";
455 get_securid_padata(context, client,src_addr,pa_data)
456 krb5_context context;
457 krb5_principal client;
458 krb5_address **src_addr;
459 krb5_pa_data *pa_data;
462 char temp[MAX_PREAUTH_SIZE];
466 tempsize = sizeof(temp) - 1;
467 if (krb5_read_password(context, krb5_SecureId_prompt, 0, temp, &tempsize))
468 return(KRB5_PARSE_ILLCHAR);
469 temp[tempsize] = '\0';
472 return(KRB5_PARSE_ILLCHAR);
473 pa_data->length = strlen(temp) + 1;
474 pa_data->contents = (krb5_octet *) calloc(1,pa_data->length);
475 if (pa_data->contents) {
476 memcpy(pa_data->contents,temp,pa_data->length);
479 else retval = ENOMEM;
480 memset(temp,0,pa_data->length);