diff options
author | Theodore Tso <tytso@mit.edu> | 1992-09-30 13:24:49 +0000 |
---|---|---|
committer | Theodore Tso <tytso@mit.edu> | 1992-09-30 13:24:49 +0000 |
commit | c15373cde8cf9cd0aefb9eb591401faa32a06166 (patch) | |
tree | 1606e04be4cfd412e50f44f956d3859849d4c702 /src/lib/krb5/krb/preauth.c | |
parent | 8d6cbed053acbd046975c48a252924630ea6669d (diff) | |
download | krb5-c15373cde8cf9cd0aefb9eb591401faa32a06166.tar.gz krb5-c15373cde8cf9cd0aefb9eb591401faa32a06166.tar.xz krb5-c15373cde8cf9cd0aefb9eb591401faa32a06166.zip |
*** empty log message ***
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2449 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/krb5/krb/preauth.c')
-rw-r--r-- | src/lib/krb5/krb/preauth.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/lib/krb5/krb/preauth.c b/src/lib/krb5/krb/preauth.c new file mode 100644 index 0000000000..fba6a9d442 --- /dev/null +++ b/src/lib/krb5/krb/preauth.c @@ -0,0 +1,460 @@ +/* + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Note: The internal interfaces to this routine are subject to change + * and/or cleanup. You should only expect the interfaces to + * krb5_obtain_padata and krb5_verify_padata to have some chance of + * staying stable. [tytso:19920903.1544EDT] + */ + +/* + * This file contains routines for establishing, verifying, and any other + * necessary functions, for utilizing the pre-authentication field of the + * kerberos kdc request, with various hardware/software verification devices. + * + * Note: At some point these functions may very well be split apart + * into different files.... [tytso:19920903.1618EDT] + */ + +#include <stdio.h> +#include <time.h> +#include <krb5/krb5.h> +#include <krb5/ext-proto.h> +#include <krb5/preauth.h> +#include <krb5/mit-des.h> + +#include <syslog.h> + +static krb5_preauth_ops preauth_systems[] = { +#if 0 + { + KRB5_PADATA_ENC_RANDOM, + KRB5_PREAUTH_FLAGS_ENCRYPT, + get_random_padata, + verify_random_padata, + }, +#endif + { + KRB5_PADATA_ENC_TIMESTAMP, + KRB5_PREAUTH_FLAGS_ENCRYPT, + get_timestamp_padata, + verify_timestamp_padata, + }, +#ifdef KRBCONF_SECUREID + { + KRB5_PADATA_ENC_SECURID, + KRB5_PREAUTH_FLAGS_ENCRYPT | KRB5_PREAUTH_FLAGS_HARDWARE, + get_securid_padata, + verify_securid_padata, + }, +#endif + { -1,} +}; + +/* + * krb5_obtain_padata is a glue routine which when passed in + * a preauthentication type, client principal, and src_addr, returns + * preauthentication data contained in data to be passed onto the KDC. + * + * If problems occur then a non zero value is returned... + * + * Note: This is a first crack at what any preauthentication will need... + */ +krb5_error_code +krb5_obtain_padata(type, client, src_addr, encrypt_key, ret_data) + int type; /*IN: Preauth type */ + krb5_principal client; /*IN: requestor */ + krb5_address **src_addr; /*IN: array of ptrs to addresses */ + krb5_keyblock *encrypt_key; /*IN: encryption key */ + krb5_pa_data **ret_data; /*OUT: Returned padata */ +{ + krb5_error_code retval; + krb5_preauth_ops *p_system; + krb5_encrypt_block eblock; + krb5_data scratch; + krb5_pa_data *data; + + if (!ret_data) + return EINVAL; + *ret_data = 0; + + if (type == KRB5_PADATA_NONE ) + return(0); + + data = (krb5_pa_data *) malloc(sizeof(krb5_pa_data)); + if (!data) + return ENOMEM; + + data->length = 0; + data->contents = 0; + data->pa_type = type; + + /* Find appropriate preauthenticator */ + retval = find_preauthenticator(type, &p_system); + if (retval) + goto error_out; + + retval = (*p_system->obtain)( client, src_addr, data ); + if (retval) + goto error_out; + + /* Check to see if we need to encrypt padata */ + if (p_system->flags & KRB5_PREAUTH_FLAGS_ENCRYPT) { + /* If we dont have a encryption key we are out of luck */ + if (!encrypt_key) { + retval = KRB5_PREAUTH_NO_KEY; + goto error_out; + } + krb5_use_keytype(&eblock, encrypt_key->keytype); + + /* do any necessay key pre-processing */ + retval = krb5_process_key(&eblock, encrypt_key); + if (retval) + goto error_out; + + /* + * Set up scratch data and length for encryption + * Must allocate more space for checksum and confounder + * We also leave space for an uncrypted size field. + */ + scratch.length = krb5_encrypt_size(data->length, + eblock.crypto_entry) + 4; + + if(!(scratch.data = malloc(scratch.length))){ + (void) krb5_finish_key(&eblock); + retval = ENOMEM; + goto error_out; + } + + scratch.data[0] = data->length >> 24; + scratch.data[1] = data->length >> 16; + scratch.data[2] = data->length >> 8; + scratch.data[3] = data->length; + + /* Encrypt preauth data in encryption key */ + if (retval = krb5_encrypt((krb5_pointer) data->contents, + (char *) scratch.data + 4, + data->length, &eblock, 0)) { + (void) krb5_finish_key(&eblock); + free(scratch.data); + goto error_out; + } + (void) krb5_finish_key(&eblock); + + free(data->contents); + data->length = scratch.length; + data->contents = (unsigned char *) scratch.data; + } + + *ret_data = data; + return 0; + +error_out: + free(data); + return retval; +} + +/* + * krb5_verify_padata is a glue routine which when passed in + * the client, src_addr and padata verifies it with the appropriate + * verify function. + * + * If problems occur then a non zero value is returned... + * else returns zero if padata verifies, and returns a "unique" id. + * + * Note: This is a first crack at what any preauthentication will need... + */ + +krb5_error_code +krb5_verify_padata(data,client,src_addr, decrypt_key, req_id, flags) + krb5_pa_data *data; /*IN: padata */ + krb5_principal client; /*IN: requestor */ + krb5_address **src_addr; /*IN: array of ptrs to addresses */ + krb5_keyblock *decrypt_key; /*IN: decryption key */ + int * req_id; /*OUT: identifier */ + int * flags; /*OUT: flags */ +{ + krb5_preauth_ops *p_system; + krb5_encrypt_block eblock; + krb5_data scratch; + int free_scratch = 0; + krb5_checksum cksum; + krb5_error_code retval; + + if (!data) + return(EINVAL); + + /* Find appropriate preauthenticator */ + retval = find_preauthenticator((int) data->pa_type, &p_system); + if (retval) + return retval; + + /* Check to see if we need to decrypt padata */ + if (p_system->flags & KRB5_PREAUTH_FLAGS_ENCRYPT) { + + /* If we dont have a decryption key we are out of luck */ + if (!decrypt_key) + return(EINVAL); + + krb5_use_keytype(&eblock, decrypt_key->keytype); + + scratch.length = data->length; + if (!(scratch.data = (char *)malloc(scratch.length))) { + return(ENOMEM); + } + + /* do any necessay key pre-processing */ + retval = krb5_process_key(&eblock,decrypt_key); + if (retval) { + free(scratch.data); + return(retval); + } + + /* Decrypt data */ + retval = krb5_decrypt((char *) data->contents + 4, + (krb5_pointer) scratch.data, + scratch.length - 4, &eblock, 0); + if (retval) { + (void) krb5_finish_key(&eblock); + free(scratch.data); + return(retval); + } + + scratch.length = (((int) ((unsigned char *)data->contents)[0] << 24) + + ((int) ((unsigned char *)data->contents)[1] << 16) + + ((int) ((unsigned char *)data->contents)[2] << 8) + + (int) ((unsigned char *)data->contents)[3]); + free_scratch++; + } else { + scratch.data = (char *) data->contents; + scratch.length = data->length; + } + + retval = (*p_system->verify)(client, src_addr, &scratch); + if (free_scratch) + free(scratch.data); + if (retval) + return retval; + if (flags) + *flags = p_system->flags; + + /* Generate a request id by crc32ing the (encrypted) preauth data. */ + /* Note: The idea behind req_id is that it is dependant upon + the information in data. This could then be used for + replay detection. */ + /* MUST malloc cksum.contents */ + cksum.contents = (krb5_octet *)calloc(1, + krb5_checksum_size(CKSUMTYPE_CRC32)); + if (!cksum.contents) return(1); + + if (krb5_calculate_checksum(CKSUMTYPE_CRC32, + data->contents, + data->length, + 0, /* seed is ignored */ + 0, /* seed length is ignored */ + &cksum )) { + *req_id = 0; + } else { + /* Checksum length should be 32 bits, so truncation should never + take place */ + if ( cksum.length > sizeof(*req_id)) cksum.length = sizeof(*req_id); + + /* Offset req_id for 64 bit systems */ + memcpy((char *)req_id + (sizeof(*req_id) - cksum.length), + cksum.contents,cksum.length); + } + free(cksum.contents); + return(0); +} + +static krb5_error_code +find_preauthenticator(type, preauth) + int type; + krb5_preauth_ops **preauth; +{ + krb5_preauth_ops *ap = preauth_systems; + + while ((ap->type != -1) && (ap->type != type)) + ap++; + if (ap->type == -1) + return(KRB5_PREAUTH_BAD_TYPE); + *preauth = ap; + return 0; +} + +/* + * Format is: 8 bytes of random confounder, + * 1 byte version number (currently 0), + * 4 bytes: number of seconds since Jan 1, 1970, in MSB order. + */ +krb5_error_code +get_timestamp_padata(client, src_addr, pa_data) + krb5_principal client; + krb5_address **src_addr; + krb5_pa_data *pa_data; +{ + unsigned char *tmp; + krb5_error_code retval; + krb5_timestamp kdc_time; + int i; + + pa_data->length = 13; + tmp = pa_data->contents = (unsigned char *) malloc(pa_data->length); + if (!tmp) + return(ENOMEM); + + retval = krb5_timeofday(&kdc_time); + if (retval) + return retval; + srand(kdc_time); /* XXX NOT GOOD ENOUGH!!!! */ + + for (i=0; i < 8; i++) + *tmp++ = rand() & 255; + + *tmp++ = 0; + *tmp++ = (kdc_time >> 24) & 255; + *tmp++ = (kdc_time >> 16) & 255; + *tmp++ = (kdc_time >> 8) & 255; + *tmp++ = kdc_time & 255; + + return(0); +} + +krb5_error_code +verify_timestamp_padata(client, src_addr, data) + krb5_principal client; + krb5_address **src_addr; + krb5_data *data; +{ + unsigned char *tmp; + krb5_error_code retval; + krb5_timestamp currenttime, patime; + extern krb5_deltat krb5_clockskew; +#define in_clock_skew(date) (abs((date)-currenttime) < krb5_clockskew) + + tmp = (unsigned char *) data->data; + if (tmp[8] != 0) + return KRB5_PREAUTH_FAILED; + patime = tmp[9] << 24; + patime += tmp[10] << 16; + patime += tmp[11] << 8; + patime += tmp[12]; + + retval = krb5_timeofday(¤ttime); + if (retval) + return retval; + + if (!in_clock_skew(patime)) + return KRB5_PREAUTH_FAILED; + + return 0; +} + +#if 0 +krb5_error_code +get_random_padata(client, src_addr, pa_data) + krb5_principal client; + krb5_address **src_addr; + krb5_pa_data *pa_data; +{ + char temp[MAX_PREAUTH_SIZE]; + + srand(time(0)); + sprintf(temp, "%1u", rand() & 0x7fffffff); + pa_data->length = strlen(temp) + 1; + pa_data->contents = (unsigned char *) malloc(pa_data->length); + if (!pa_data->contents) + return(ENOMEM); + memcpy(pa_data->contents, temp, pa_data->length); + return(0); +} + +krb5_error_code +verify_random_padata(client, src_addr, data) + krb5_principal client; + krb5_address **src_addr; + krb5_data *data; +{ + if (atof(data->data) > 2147483637.0) + return KRB5_PREAUTH_FAILED; + + return 0; +} +#endif + +#ifdef SECUREID +#include "sdcli.h" +#include "sdconf.c" + +int verify_securid_padata(preauth_data) +PreAuthenticator *preauth_data; +{ + char username[255]; + struct SD_CLIENT sd; + + memset((char *)&sd,0, sizeof (sd)); + memset((char *) username, 0, sizeof(username)); + memcpy((char *) username, (char *) preauth_data->client[1]->data, + preauth_data->client[1]->length); + /* If Instance then Append */ + if (preauth_data->client[2] != '\0') { + memcpy((char *) username + preauth_data->client[1]->length, + (char *) "/", 1); + memcpy((char *) username + preauth_data->client[1]->length + 1, + (char *) preauth_data->client[2]->data, + preauth_data->client[2]->length); + } + if (sd_check( preauth_data->data,username,&sd) != ACM_OK) return(1); + return(0); +} + +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: "; + +int get_securid_padata(preauth_data) +PreAuthenticator *preauth_data; +{ + + char temp[MAX_PREAUTH_SIZE]; + int tempsize; + int retval = 0; + + tempsize = sizeof(temp) - 1; + if (krb5_read_password(krb5_SecureId_prompt, 0, temp, &tempsize)) + return(1); + temp[tempsize] = '\0'; + + if (temp[0] == '\0') return(1); + preauth_data->datalen = strlen(temp) + 1; + preauth_data->data = (char *) calloc(1,preauth_data->datalen); + if (preauth_data->data) { + memcpy(preauth_data->data,temp,preauth_data->datalen); + retval = 0; + } + else retval = 1; + memset(temp,0,preauth_data->datalen); + return(retval); +} +#endif |