uint8_t validate_generic_tlv(struct lldp_tlv *tlv) { debug_printf(DEBUG_TLV, "Generic TLV Validation for TLV type: %d.\n", tlv->type); debug_printf(DEBUG_TLV, "TLV Info String Length: %d\n", tlv->length); debug_printf(DEBUG_TLV, "TLV Info String: "); debug_hex_dump(DEBUG_TLV, tlv->info_string, tlv->length); // Length will never fall below 0 because it's an unsigned variable if(tlv->length > 511) { debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 0 and 511 inclusive!\n", tlv->length); return XEINVALIDTLV; } return XVALIDTLV; }
void peap_do_phase2(struct generic_eap_data *thisint, u_char *in, int in_size, u_char *out, int *out_size) { struct tls_vars *mytls_vars; struct phase2_data *p2d; u_char *decr_data, *encr_data; int encrsize, decrsize; struct config_eap_peap *peapconf; struct generic_eap_data *eapdata; if ((!thisint) || (!in) || (!out)) { debug_printf(DEBUG_NORMAL, "Invalid parameters passed in to peap_do_phase2()!\n"); return; } *out_size = 0; mytls_vars = (struct tls_vars *)thisint->eap_data; if (mytls_vars == NULL) { debug_printf(DEBUG_NORMAL, "mytls_vars (thisint->eap_data) == NULL!\n"); return; } peapconf = (struct config_eap_peap *)thisint->eap_conf_data; if (peapconf == NULL) { debug_printf(DEBUG_NORMAL, "peapconf == NULL!\n"); return; } p2d = (struct phase2_data *)mytls_vars->phase2data; if (p2d->eapdata == NULL) { p2d->eapdata = (struct generic_eap_data *)malloc(sizeof(struct generic_eap_data)); if (p2d->eapdata == NULL) { *out_size = 0; return; } memset(p2d->eapdata, 0, sizeof(struct generic_eap_data)); p2d->eapdata->eap_data = NULL; } p2d->eapdata->eap_conf_data = peapconf->phase2->method_data; p2d->eapdata->identity = thisint->identity; decr_data = (char *)malloc(1550); if (decr_data == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for decryption buffer!\n"); return; } encr_data = (char *)malloc(1550); if (encr_data == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for encryption buffer!\n"); free(decr_data); return; } if (in_size > 0) { tls_crypt_decrypt(thisint, in, in_size, decr_data, &decrsize); } else { free(decr_data); decr_data = NULL; } // We need to check this. I don't think it is needed anymore. if (decrsize <=0) { debug_printf(DEBUG_AUTHTYPES, "Sending ACK!\n"); bzero(out,10); *out_size = 1; free(decr_data); free(encr_data); return; } debug_printf(DEBUG_AUTHTYPES, "Decrypted packet returned %d byte(s)\n", decrsize); if (thisint->tempPwd != NULL) { eapdata = p2d->eapdata; if (eapdata != NULL) { eapdata->tempPwd = thisint->tempPwd; } } bzero(out, 100); switch (p2d->peap_version) { case 0: debug_printf(DEBUG_AUTHTYPES, "Doing PEAP v0!\n"); do_peap_version0(p2d->eapdata, decr_data, decrsize, encr_data, &encrsize); break; case 1: debug_printf(DEBUG_AUTHTYPES, "Doing PEAP v1!\n"); do_peap_version1(p2d->eapdata, decr_data, decrsize, encr_data, &encrsize); break; default: debug_printf(DEBUG_NORMAL, "Unknown PEAP version! (%d)\n",p2d->peap_version); break; } eapdata = p2d->eapdata; if (eapdata->need_password == 1) { thisint->need_password = 1; thisint->eaptype = eapdata->eaptype; thisint->eapchallenge = eapdata->eapchallenge; *out_size = 0; } if (encrsize > 0) { debug_printf(DEBUG_AUTHTYPES, "Unencrypted return frame : \n"); debug_hex_dump(DEBUG_AUTHTYPES, encr_data, encrsize); tls_crypt_encrypt_nolen(thisint, encr_data, encrsize, out, out_size); debug_printf(DEBUG_AUTHTYPES, "Encrypted return frame : \n"); debug_hex_dump(DEBUG_AUTHTYPES, out, *out_size); } free(encr_data); free(decr_data); }
void do_peap_version1(struct generic_eap_data *thisint, u_char *in, int in_size, u_char *out, int *out_size) { char *new_frame = NULL, *username = NULL; int eapvalue, new_frame_size; uint16_t i; struct tls_vars *mytls_vars; struct config_eap_peap *userdata; if ((!thisint) || (!out) || (!out_size)) { debug_printf(DEBUG_NORMAL, "Invalid data passed in to do_peap_version1()!\n"); if (out_size) *out_size = 0; return; } if (in_size > 1520) { debug_printf(DEBUG_NORMAL, "Invalid frame passed in to do_peap_version1()!\n"); return; } *out_size = 0; /// XXXXXXXXX Reconsider how this is done! (Phase 2 for PEAP in general.) userdata = (struct config_eap_peap *)thisint->eap_conf_data; if (!userdata) { debug_printf(DEBUG_NORMAL, "Invalid user configuration in do_peap_version1()!\n"); return; } mytls_vars = (struct tls_vars *)thisint->eap_data; // mytls_vars may be NULL here! This is okay, as long as we aren't in the // middle of an inner authentication. eapvalue = in[4]; debug_printf(DEBUG_AUTHTYPES, "Inner packet : \n"); if (in_size < 1522) { debug_hex_dump(DEBUG_AUTHTYPES, in, in_size); } else { debug_printf(DEBUG_AUTHTYPES, "INVALID PACKET SIZE!\n"); } new_frame = (char *)malloc(1024); if (new_frame == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for new_frame in do_peap_version1()!\n"); return; } bzero(new_frame, 1024); switch ((uint8_t)eapvalue) { case EAP_REQUEST: // In version 1, we answer with an EAP header. debug_printf(DEBUG_AUTHTYPES, "Got a Phase 2 EAP_REQUEST!\n"); out[0] = EAP_RESPONSE; out[1] = in[1]; // Use the same ID # username = thisint->identity; i = htons(strlen(username)+5); memcpy((char *)&out[2], (uint16_t *)&i, 2); // The length of the username + header. out[4] = EAP_TYPE_IDENTITY; memcpy(&out[5], username, strlen(username)+1); thisint->need_password = 0; *out_size = strlen(username)+5; break; case EAP_SUCCESS: printf("Got a phase 2 success!\n"); break; case EAP_FAILURE: printf("Got a phase 2 failure!\n"); break; default: case EAP_TYPE_PEAP: // Is this a PEAP inner request? debug_printf(DEBUG_AUTHTYPES, "Got a phase 2 request for PEAP, NAKing!\n"); out[0] = EAP_RESPONSE; out[1] = in[1]; out[2] = 0; out[3] = 6; out[4]=EAP_TYPE_NAK; // NAK out[5]=EAP_TYPE_MSCHAPV2; // MS-CHAPv2 *out_size = 6; break; /* case EAP_TYPE_GTC: debug_printf(DEBUG_AUTHTYPES, "Got a phase 2 request for GTC!\n"); if (thisint->eap_data == NULL) { eapotp_setup(thisint); thisint->eapid = EAP_TYPE_GTC; debug_printf(DEBUG_AUTHTYPES, "(PEAP - Phase 2) Initialized GTC!\n"); } if (!thisint->eap_data) { debug_printf(DEBUG_NORMAL, "Invalid EAP state data in GTC section of do_peap_version1()!\n"); return; } eapotp_process(thisint, (u_char *)&in[5], (in_size-5), new_frame, &new_frame_size); if (thisint->need_password == 0) { out[0] = EAP_RESPONSE; out[1] = in[1]; i = ntohs(6+new_frame_size); // 6 bytes header, plus out answer memcpy(&out[2], (uint16_t *)&i, 2); out[4] = EAP_TYPE_GTC; // We have a GTC answer memcpy(&out[5], new_frame, new_frame_size); *out_size = new_frame_size+5; } else { *out_size = 0; } break; */ case EAP_TYPE_MSCHAPV2: debug_printf(DEBUG_AUTHTYPES, "Got a phase 2 request for MS-CHAPv2!\n"); if (thisint->eap_data == NULL) { eapmschapv2_setup(thisint); thisint->eapid = EAP_TYPE_MSCHAPV2; debug_printf(DEBUG_AUTHTYPES, "(PEAP - Phase 2) Initalized MS-CHAPv2..\n"); } /* if (thisint->tempPwd != NULL) { debug_printf(DEBUG_AUTHTYPES, "Temp Password : %s\n", thisint->tempPwd); }*/ if (!thisint->eap_data) { debug_printf(DEBUG_NORMAL, "Invalid EAP state data in MS-CHAPv2 part of do_peap_version1()!\n"); return; } eapmschapv2_process(thisint, (u_char *)&in[5], (in_size-5), new_frame, &new_frame_size); if ((thisint->need_password == 0) && ((new_frame_size > 0) && (new_frame_size < 1522))) { out[0] = EAP_RESPONSE; out[1] = in[1]; i = ntohs(6+new_frame_size); // 6 bytes header, plus out answer memcpy(&out[2], (uint16_t *)&i, 2); out[4] = EAP_TYPE_MSCHAPV2; // We have an MSCHAPv2 answer memcpy(&out[5], new_frame, new_frame_size); *out_size = new_frame_size+5; } else { *out_size = 0; } break; case PEAP_EAP_EXTENSION: // EAP Extension debug_printf(DEBUG_AUTHTYPES, "Got an EAP extension frame!\n"); out[0] = EAP_RESPONSE; memcpy(&out[1], &in[1], in_size-1); *out_size = in_size; break; /* default: debug_printf(DEBUG_NORMAL, "Not sure how to handle this request! (%02X)\n", eapvalue); *out_size = 0; break; */ } free(new_frame); }
int do_v1_at_mac(struct generic_eap_data *thisint, char *K_int, char *indata, int in_size, int inoffset, char *noncemt, char *vlist, int vlistlen, uint16_t selver, char *resultmac) { char *framecpy, *mac_calc; int saved_offset, i; uint16_t value16; if ((!thisint) || (!K_int) || (!indata) || (!noncemt) || (!vlist) || (!resultmac)) { debug_printf(DEBUG_NORMAL, "Invalid data passed to do_v1_at_mac()!\n"); return XEMALLOC; } if (indata[inoffset] != AT_MAC) { debug_printf(DEBUG_NORMAL, "Error! The offset passed in is not of type AT_MAC!\n"); return -1; } inoffset++; if (indata[inoffset] != 5) printf("AT_MAC length isn't 5!\n"); inoffset+=2; // Skip the reserved bytes. saved_offset = inoffset; framecpy = (char *)malloc(in_size+50); // We need extra to // reconstruct the eap // piece. if (framecpy == NULL) { printf("Couldn't allocate memory for framecpy!\n"); return -1; } // Now, reconstruct the header for the EAP piece, so we can // calculate the MAC across all of it. framecpy[0] = 1; // It was a request. framecpy[1] = thisint->eapid; value16 = in_size + 5; value16 = htons(value16); memcpy((char *)&framecpy[2], &value16, 2); framecpy[4] = 18; // EAP-SIM memcpy((char *)&framecpy[5], (char *)&indata[0], in_size); // Now, zero out the MAC value. for (i=(saved_offset+5);i<=(in_size+5);i++) { framecpy[i] = 0x00; } memcpy(&framecpy[(in_size+5)], noncemt, 16); // We should now be ready to calculate the AT_MAC for // ourselves. debug_printf(DEBUG_AUTHTYPES, "Hashing this frame to get AT_MAC: \n"); debug_hex_dump(DEBUG_AUTHTYPES, framecpy, (in_size+5+16)); mac_calc = (char *)malloc(100); if (mac_calc == NULL) return -1; HMAC(EVP_sha1(), &K_int[0], 16, framecpy, (in_size+5+16), mac_calc, &i); memcpy(resultmac, mac_calc, 16); // We get 20 back, but we only want 16. debug_printf(DEBUG_AUTHTYPES, "Result MAC = "); debug_hex_printf(DEBUG_AUTHTYPES, resultmac, 16); free(framecpy); framecpy = NULL; free(mac_calc); mac_calc = NULL; return 0; }
/************************************************ * * Process an authentication request. Based on the information in the packet, * we call the correct EAP type. We return an error if it is an EAP type * that we don't know. * ************************************************/ int eap_request_auth(struct interface_data *thisint, char *inframe, int insize, char *outframe, int *payloadsize, int *eapsize) { struct eap_header *myouteap, *myineap; int eapmethod, done, valideap, working_eap_type, eapinsize = 0; struct config_eap_method *start=NULL, *cur=NULL, *newmethod = NULL; char *tosendframe; if (!thisint) { debug_printf(DEBUG_NORMAL, "There is no interface data available in eap_request_auth()!\n"); return XEMALLOC; } if ((!outframe) || (!payloadsize) || (!eapsize)) { debug_printf(DEBUG_NORMAL, "Invalid parameter passed in to eap_request_auth()!\n"); return XEMALLOC; } eapmethod = 0; done = FALSE; valideap = FALSE; if (inframe != NULL) { myineap = (struct eap_header *)&inframe[OFFSET_TO_EAP]; tosendframe = (char *)&inframe[OFFSET_TO_DATA]; working_eap_type = myineap->eap_type; } else { myineap = NULL; working_eap_type = thisint->eapType; tosendframe = NULL; } myouteap = (struct eap_header *)&outframe[OFFSET_TO_EAP]; // Make sure we have valid method data. if (thisint->userdata == NULL) { debug_printf(DEBUG_NORMAL, "No user data available in eap_request_auth()!\n"); return XEMALLOC; } if (thisint->userdata->methods == NULL) { debug_printf(DEBUG_NORMAL, "No EAP methods available in eap_request_auth()!\n"); return XEMALLOC; } // Check to make sure that the type requested is in our list of valid // types. start = thisint->userdata->methods; cur = start; while ((cur != NULL) && (cur->method_num != working_eap_type)) { cur = cur->next; } // If we have a type that matches, then go ahead... if (cur != NULL) { valideap = TRUE; newmethod = cur; } else { valideap = FALSE; } // If the requested EAP type isn't valid, then send a NAK. if ((valideap == FALSE) && (inframe != NULL) && (ntohs(myineap->eap_length)>4)) { debug_printf(DEBUG_STATE, "Unsupported EAP type requested. (%d) Sending NAK!\n",myineap->eap_type); myouteap->eap_code = EAP_RESPONSE; myouteap->eap_identifier = thisint->statemachine->receivedId; myouteap->eap_length = htons(6); myouteap->eap_type = EAP_TYPE_NAK; if (thisint->userdata == NULL) { debug_printf(DEBUG_NORMAL, "Userdata is NULL when trying to return a NAK! Check your configuration to see if it is correct.\n"); return XEBADCONFIG; } if (thisint->userdata->methods == NULL) { debug_printf(DEBUG_NORMAL, "There are no authentication methods defined for this interface! Make sure you have at least one EAP type defined in your configuration.\n"); return XEBADCONFIG; } outframe[OFFSET_TO_DATA] = thisint->userdata->methods->method_num; *eapsize = 6; *payloadsize = (6 + sizeof(struct eapol_header)); return *payloadsize; } // Now, determine which authenticator in our array is the right one. eapmethod = 0; while ((eaphandlers[eapmethod].eap_auth_type != NO_EAP_AUTH) && (eaphandlers[eapmethod].eap_auth_type != working_eap_type)) { eapmethod++; } if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH) { if (inframe != NULL) { debug_printf(DEBUG_NORMAL, "No EAP Type Handler found for EAP Type %d!\n", myineap->eap_type); } return -1; } // If we had an EAP type before, and we have changed this time through, // make sure we call the cleanup methods. if ((thisint->eapType > 0) && (thisint->eapType != eaphandlers[eapmethod].eap_auth_type)) { debug_printf(DEBUG_AUTHTYPES, "EAP Type Changed! Cleaning up old type!\n"); eap_clear_active_method(thisint); } // If this is a new EAP type, call the setup method. if ((thisint->eapType == 0) || (thisint->userdata->activemethod == NULL)) { if (thisint->userdata->activemethod != NULL) { debug_printf(DEBUG_NORMAL, "For some reason thisint->userdata->activemethod != NULL! We will attempt to clean it up.\n"); // If, by some strange alignment of the planets, we managed to get // here, there is a good chance that we will leak memory! free(thisint->userdata->activemethod); thisint->userdata->activemethod = NULL; } thisint->userdata->activemethod = (struct generic_eap_data *)malloc(sizeof(struct generic_eap_data)); if (thisint->userdata->activemethod == NULL) return -1; memset(thisint->userdata->activemethod, 0, sizeof(struct generic_eap_data)); thisint->userdata->activemethod->eap_conf_data = newmethod->method_data; thisint->userdata->activemethod->eap_data = NULL; thisint->userdata->activemethod->staleFrame = NULL; thisint->userdata->activemethod->staleSize = 0; thisint->userdata->activemethod->identity = (char *)malloc(strlen(thisint->userdata->identity)+1); if (thisint->userdata->activemethod->identity == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to copy identity!\n"); } else { strcpy(thisint->userdata->activemethod->identity, thisint->userdata->identity); } (*eaphandlers[eapmethod].eap_auth_setup)(thisint->userdata->activemethod); thisint->eapType = eaphandlers[eapmethod].eap_auth_type; if (thisint->userdata->activemethod->eap_data == NULL) { debug_printf(DEBUG_AUTHTYPES, "This EAP type didn't set up any state information!?\n"); } } // If we were passed a frame, then record the ID, otherwise leave it the // same as it was before. (Assume we are still working on processing the // last frame.) if (myineap != NULL) { if (thisint->userdata->activemethod == NULL) { debug_printf(DEBUG_NORMAL, "Memory allocation failure! Activemethod is NULL!\n"); return XEMALLOC; } thisint->userdata->activemethod->eapid = myineap->eap_identifier; } // If we have had a password given to us from a GUI client, we need to // send it up to our EAP type, so it can be handled. if (thisint->userdata->activemethod != NULL) { if (thisint->tempPassword != NULL) { thisint->userdata->activemethod->tempPwd = thisint->tempPassword; } } if (inframe != NULL) { eapinsize = ntohs(myineap->eap_length)-5; } if (thisint->userdata->activemethod != NULL) { if ((thisint->userdata->activemethod->staleFrame != NULL) && (inframe == NULL)) { debug_printf(DEBUG_AUTHTYPES, "Attempting to repost stale buffer.\n"); tosendframe = (char *)malloc(thisint->userdata->activemethod->staleSize); if (tosendframe == NULL) { debug_printf(DEBUG_NORMAL, "Failed to malloc memory for temporary frame buffer!\n"); return XEMALLOC; } memcpy(tosendframe, thisint->userdata->activemethod->staleFrame, thisint->userdata->activemethod->staleSize); } } if (tosendframe == NULL) { debug_printf(DEBUG_AUTHTYPES, "No data in frame, returning.\n"); *payloadsize = 0; return XENONE; } (*eaphandlers[eapmethod].eap_auth_handlers)(thisint->userdata->activemethod, tosendframe, eapinsize, &outframe[OFFSET_TO_DATA], eapsize); // See if an EAP type requested a password. if (thisint->userdata->activemethod->need_password == 1) { debug_printf(DEBUG_AUTHTYPES, "Saving current frame!\n"); debug_printf(DEBUG_AUTHTYPES, "To save frame :\n"); debug_hex_dump(DEBUG_AUTHTYPES, tosendframe, eapinsize); interactive_store_frame(tosendframe, eapinsize, thisint->userdata->activemethod); debug_printf(DEBUG_AUTHTYPES, "Requesting password from GUI!\n"); interactive_gui_prompt(thisint, thisint->userdata->activemethod->tempPwd, thisint->userdata->activemethod->eaptype, thisint->userdata->activemethod->eapchallenge); *eapsize = 0; free(thisint->userdata->activemethod->eaptype); thisint->userdata->activemethod->eaptype = NULL; free(thisint->userdata->activemethod->eapchallenge); thisint->userdata->activemethod->eapchallenge = NULL; thisint->userdata->activemethod->need_password = 0; return XENONE; } else { // We have used this packet, so remove it from the stale frame buffer. if (thisint->userdata->activemethod->staleFrame != NULL) { debug_printf(DEBUG_AUTHTYPES, "Clearing out stale buffer!\n"); free(thisint->userdata->activemethod->staleFrame); thisint->userdata->activemethod->staleFrame = NULL; thisint->userdata->activemethod->staleSize = 0; } } if ((tosendframe != NULL) && (inframe == NULL)) { if (tosendframe != NULL) { debug_printf(DEBUG_AUTHTYPES, "tosendframe isn't the same as inframe! Purging!\n"); free(tosendframe); tosendframe = NULL; } } // If we are using LEAP, we need to make some extra calls here. if (eaphandlers[eapmethod].eap_auth_type == EAP_TYPE_LEAP) { thisint->statemachine->eapSuccess = eapleap_done(thisint->userdata->activemethod); if (thisint->statemachine->eapSuccess == 1) { eapleap_get_keys(thisint); } } if (*eapsize > 0) { *eapsize = *eapsize + (sizeof(struct eap_header)-1); myouteap->eap_length = htons(*eapsize); if (eaphandlers[eapmethod].eap_auth_type == EAP_TYPE_LEAP && myineap->eap_code == EAP_SUCCESS) { myouteap->eap_code = EAP_REQUEST; myouteap->eap_identifier = myineap->eap_identifier; } else { myouteap->eap_code = EAP_RESPONSE; myouteap->eap_identifier = thisint->statemachine->receivedId; } myouteap->eap_type = thisint->eapType; *payloadsize = (*eapsize + sizeof(struct eapol_header)); } else { *payloadsize = 0; } return *payloadsize; }
int eapsim_process(struct generic_eap_data *thisint, u_char *dataoffs, int insize, u_char *out, int *outsize) { int packet_offset, outptr, numVers, i, value16, maxver, saved_offset; int tlen; struct typelength *typelen; struct typelengthres *typelenres; struct eaptypedata *mydata; char *hash, *at_mac_sres, *nsres=NULL, *framecpy, *username; char sha1resp[20], K_sres[16], K_encr[16], K_recv[32], K_send[32]; char mac_val[16], mac_calc[16], K_int[16]; struct config_eap_sim *userdata; if ((!thisint) || (!thisint->eap_data)) { debug_printf(DEBUG_NORMAL, "Invalid interface struct passed in to eapsim_process()!\n"); return XEMALLOC; } mydata = (struct eaptypedata *)thisint->eap_data; userdata = (struct config_eap_sim *)thisint->eap_conf_data; if (!userdata) { debug_printf(DEBUG_NORMAL, "Invalid user data struct in eapsim_process()!\n"); return XEMALLOC; } if ((thisint->tempPwd == NULL) && (userdata->password == NULL)) { thisint->need_password = 1; thisint->eaptype = strdup("EAP-SIM"); thisint->eapchallenge = NULL; *outsize = 0; return XENONE; } // Make sure we have something to process... if (dataoffs == NULL) return XENONE; if (sc_need_init()==1) { init_smartcard(thisint); } if (userdata->username == NULL) { username = thisint->identity; } else { username = userdata->username; } if ((userdata->password == NULL) && (thisint->tempPwd != NULL)) { userdata->password = thisint->tempPwd; thisint->tempPwd = NULL; } *outsize = 0; bzero(&mac_calc[0], 16); bzero(&mac_val[0], 16); switch (dataoffs[0]) { case SIM_START: debug_printf(DEBUG_AUTHTYPES, "Got SIM_START!\n"); bzero(out, 100); packet_offset = 3; typelen = (struct typelength *)&out[0]; typelen->type = SIM_START; typelen->length = 0; typelenres = (struct typelengthres *)&out[3]; typelenres->type = AT_NONCE_MT; typelenres->length = 5; typelenres->reserved = 0; // Generate a few random bytes for our NONCE MT. mydata->nonce_mt = (char *)malloc(16); if (mydata->nonce_mt == NULL) return XEMALLOC; RAND_bytes(mydata->nonce_mt,16); debug_printf(DEBUG_AUTHTYPES, "NONCE MT = "); debug_hex_printf(DEBUG_AUTHTYPES, mydata->nonce_mt, 16); outptr = 7; memcpy(&out[outptr], mydata->nonce_mt, 16); outptr += 16; // Process SIM value fields. while (packet_offset < insize) { switch (dataoffs[packet_offset]) { case AT_MAC: debug_printf(DEBUG_NORMAL, "You cannot have an AT_MAC in a Start packet!\n"); return XESIMNOATMAC; case AT_ANY_ID_REQ: case AT_FULLAUTH_ID_REQ: case AT_PERMANENT_ID_REQ: debug_printf(DEBUG_AUTHTYPES, "Got AT_FULLAUTH_ID_REQ or AT_PERMANENT_ID_REQ!\n"); typelenres = (struct typelengthres *)&dataoffs[packet_offset]; if ((typelenres->length != 5) && (typelenres->length != 1)) { debug_printf(DEBUG_NORMAL, "Invalid AT_FULLAUTH_ID_REQ length!\n"); return XESIMBADLEN; } packet_offset+=4; // Skip the reserved and length bytes. // Build an AT_IDENTITY response. typelenres = (struct typelengthres *)&out[outptr]; typelenres->type = AT_IDENTITY; typelenres->length = (strlen(username)/4)+1; typelenres->reserved = htons(strlen(username)); outptr+=sizeof(struct typelengthres); memcpy(&out[outptr], username, strlen(username)); outptr += strlen(username); break; case AT_VERSION_LIST: debug_printf(DEBUG_AUTHTYPES, "Got an AT_VERSION_LIST request!\n"); typelenres = (struct typelengthres *)&dataoffs[packet_offset]; debug_printf(DEBUG_AUTHTYPES, "Version List Length (# versions) : %d\n", typelenres->length); numVers = typelenres->length; mydata->verlistlen = ntohs(typelenres->reserved); debug_printf(DEBUG_AUTHTYPES, "Version List Length (bytes) : %d\n", mydata->verlistlen); packet_offset+=sizeof(struct typelengthres); maxver = 0; // Set the starting value to be 0. mydata->verlist = (char *)malloc(mydata->verlistlen); if (mydata->verlist == NULL) return XEMALLOC; memcpy(mydata->verlist, &dataoffs[packet_offset], mydata->verlistlen); for (i=0;i<numVers;i++) { memcpy(&value16, &dataoffs[packet_offset], 2); value16 = ntohs(value16); debug_printf(DEBUG_AUTHTYPES, "AT_VERSION_LIST Value : %d\n", value16); if (value16 > maxver) maxver = value16; packet_offset += 2; } if (maxver > EAPSIM_MAX_SUPPORTED_VER) maxver = EAPSIM_MAX_SUPPORTED_VER; debug_printf(DEBUG_AUTHTYPES, "Setting version to %d\n",maxver); typelenres = (struct typelengthres *)&out[outptr]; typelenres->type = AT_SELECTED_VERSION; typelenres->length = 1; typelenres->reserved = htons(maxver); outptr += sizeof(struct typelengthres); mydata->workingversion = maxver; break; default: debug_printf(DEBUG_NORMAL, "Unknown SIM type!\n"); return XESIMBADTYPE; } } // Write the length in the response header. value16 = htons(outptr); memcpy((char *)&out[1], &value16, 2); *outsize = (outptr); break; case SIM_CHALLENGE: debug_printf(DEBUG_AUTHTYPES, "Got SIM_CHALLENGE!\n"); packet_offset = 3; typelen = (struct typelength *)&out[0]; typelen->type = SIM_CHALLENGE; outptr = 3; while (packet_offset < insize) { switch (dataoffs[packet_offset]) { case AT_RAND: debug_printf(DEBUG_AUTHTYPES, "Got an AT_RAND.\n"); typelenres = (struct typelengthres *)&dataoffs[packet_offset]; packet_offset+=4; memcpy(mydata->triplet[0].random, &dataoffs[packet_offset], 16); debug_printf(DEBUG_AUTHTYPES, "Random1 = "); debug_hex_printf(DEBUG_AUTHTYPES, mydata->triplet[0].random, 16); do_gsm(mydata->triplet[0].random, mydata->triplet[0].response, mydata->triplet[0].ckey); packet_offset+=16; memcpy(mydata->triplet[1].random, &dataoffs[packet_offset], 16); debug_printf(DEBUG_AUTHTYPES, "Random2 = "); debug_hex_printf(DEBUG_AUTHTYPES, mydata->triplet[1].random, 16); do_gsm(mydata->triplet[1].random, mydata->triplet[1].response, mydata->triplet[1].ckey); packet_offset+=16; memcpy(mydata->triplet[2].random, &dataoffs[packet_offset], 16); debug_printf(DEBUG_AUTHTYPES, "Random3 = "); debug_hex_printf(DEBUG_AUTHTYPES, mydata->triplet[2].random, 16); do_gsm(mydata->triplet[2].random, mydata->triplet[2].response, mydata->triplet[2].ckey); packet_offset+=16; if (mydata->workingversion == 0) { hash = (char *)malloc((8*3)+16); // 3 keys + 16 nonce. if (hash == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to build hash!\n"); return XEMALLOC; } bzero(hash, ((8*3)+16)); memcpy(&hash[0], mydata->triplet[0].ckey, 8); memcpy(&hash[8], mydata->triplet[1].ckey, 8); memcpy(&hash[16], mydata->triplet[2].ckey, 8); memcpy(&hash[24], mydata->nonce_mt, 16); SHA1(hash, 40, &sha1resp[0]); } else { tlen = strlen(username)+(8*3)+16+ mydata->verlistlen+2; hash = (char *)malloc(tlen); if (hash == NULL) return XEMALLOC; nsres = (char *)malloc(4*3); if (nsres == NULL) return XEMALLOC; bzero(nsres, 12); memcpy(&nsres[0], mydata->triplet[0].response, 4); memcpy(&nsres[4], mydata->triplet[1].response, 4); memcpy(&nsres[8], mydata->triplet[2].response, 4); bzero(hash, tlen); memcpy(&hash[0], username, strlen(username)); memcpy(&hash[strlen(username)], mydata->triplet[0].ckey, 8); memcpy(&hash[strlen(username)+8], mydata->triplet[1].ckey, 8); memcpy(&hash[strlen(username)+16], mydata->triplet[2].ckey, 8); memcpy(&hash[strlen(username)+24], mydata->nonce_mt, 16); memcpy(&hash[strlen(username)+24+16], mydata->verlist, mydata->verlistlen); value16 = htons(mydata->workingversion); memcpy(&hash[strlen(username)+24+16+ mydata->verlistlen], &value16, 2); SHA1(hash, (strlen(username)+24+16+ mydata->verlistlen+2), sha1resp); free(hash); hash = NULL; } debug_printf(DEBUG_AUTHTYPES, "MK = "); debug_hex_printf(DEBUG_AUTHTYPES, &sha1resp[0], 20); at_mac_sres = (char *)malloc(120); if (at_mac_sres == NULL) { debug_printf(DEBUG_NORMAL, "Couldn't malloc at_mac_sres!\n"); return XEMALLOC; } fips186_2_prng(sha1resp, 20, NULL, 0, at_mac_sres, 120); if (mydata->workingversion == 0) { memcpy(&K_sres[0], &at_mac_sres[0], 16); memcpy(&K_encr[0], &at_mac_sres[16], 16); memcpy(&K_int[0], &at_mac_sres[32], 16); bzero(&K_recv[0], 32); bzero(&K_send[0], 32); memcpy(&K_recv[0], &at_mac_sres[48], 20); memcpy(&K_send[0], &at_mac_sres[68], 20); } else { // K_int is the same as K_aut in Version 1. memcpy(&K_int[0], &at_mac_sres[16], 16); memcpy(&K_recv[0], &at_mac_sres[32], 32); memcpy(&K_send[0], &at_mac_sres[64], 32); } // We should be done with at_mac_sres, so free it. free(at_mac_sres); at_mac_sres = NULL; if (mydata->keyingMaterial != NULL) { free(mydata->keyingMaterial); mydata->keyingMaterial = NULL; } mydata->keyingMaterial = (char *)malloc(64); if (mydata->keyingMaterial == NULL) return XEMALLOC; bzero(mydata->keyingMaterial, 64); memcpy(mydata->keyingMaterial, &K_recv[0], 32); memcpy(&mydata->keyingMaterial[32], &K_send[0], 32); if (mydata->workingversion == 0) { hash = (char *)malloc((4*3)+16); if (hash == NULL) return XEMALLOC; memcpy(&hash[0], mydata->triplet[0].response, 4); memcpy(&hash[4], mydata->triplet[1].response, 4); memcpy(&hash[8], mydata->triplet[2].response, 4); hash[12] = 11; HMAC(EVP_sha1(), &K_sres[0], 16, &hash[0], 13, (char *)&sha1resp[0], &i); debug_printf(DEBUG_AUTHTYPES, "Final return value : "); debug_hex_printf(DEBUG_AUTHTYPES, &sha1resp[0], i); typelenres = (struct typelengthres *)&out[outptr]; typelenres->type = AT_MAC_SRES; typelenres->length = 5; typelenres->reserved = 0; outptr += sizeof(struct typelengthres); memcpy(&out[outptr], &sha1resp, i); outptr += i; } break; case AT_IV: debug_printf(DEBUG_AUTHTYPES, "Got an IV (Not supported)\n"); packet_offset+=5; break; case AT_ENCR_DATA: debug_printf(DEBUG_AUTHTYPES, "Got an AT_ENCR_DATA (Not supported)\n"); packet_offset+=5; break; case AT_MAC: debug_printf(DEBUG_AUTHTYPES, "Got an AT_MAC\n"); saved_offset = packet_offset; memcpy(&mac_val[0], &dataoffs[packet_offset+4], 16); packet_offset+=20; if (mydata->workingversion == 0) { if (do_v0_at_mac(thisint, &K_int[0], dataoffs, insize, saved_offset, &mac_calc[0]) == -1) { debug_printf(DEBUG_NORMAL, "Error calculating AT_MAC for Version 0!\n"); return XESIMBADMAC; } } else { debug_printf(DEBUG_AUTHTYPES, "K_int[0] = "); debug_hex_printf(DEBUG_AUTHTYPES, &K_int[0], 16); if (do_v1_at_mac(thisint, &K_int[0], dataoffs, insize, saved_offset, mydata->nonce_mt, mydata->verlist, mydata->verlistlen, mydata->workingversion, &mac_calc[0]) == -1) { debug_printf(DEBUG_NORMAL, "Error calculating AT_MAC for Version 1!\n"); return XESIMBADMAC; } } if (memcmp(&mac_calc[0], &mac_val[0], 16) != 0) { debug_printf(DEBUG_NORMAL, "ERROR : AT_MAC failed MAC check!\n"); debug_printf(DEBUG_AUTHTYPES, "mac_calc = "); debug_hex_printf(DEBUG_AUTHTYPES, &mac_calc[0], 16); debug_printf(DEBUG_AUTHTYPES, "mac_val = "); debug_hex_printf(DEBUG_AUTHTYPES, &mac_val[0], 16); //return XESIMBADMAC; } } } if (mydata->workingversion == 1) { framecpy = (char *)malloc(outptr+8+20+(8*3)); if (framecpy == NULL) return XEMALLOC; bzero(framecpy, (outptr+5+20+(4*3))); framecpy[0] = 2; framecpy[1] = thisint->eapid; value16 = htons(outptr+5+20); memcpy(&framecpy[2], &value16, 2); framecpy[4] = EAP_TYPE_SIM; memcpy(&framecpy[5], &out[0], outptr); framecpy[5+outptr] = AT_MAC; framecpy[5+outptr+1] = 5; memcpy(&framecpy[5+outptr+20], nsres, (4*3)); debug_printf(DEBUG_AUTHTYPES, "Hashing against :\n"); debug_hex_dump(DEBUG_AUTHTYPES, &framecpy[0], outptr+25+12); HMAC(EVP_sha1(), &K_int[0], 16, framecpy, (outptr+5+20+12), &mac_calc[0], &i); memcpy(&out[outptr], &framecpy[5+outptr], 20); memcpy(&out[outptr+4], &mac_calc[0], 16); outptr += 20; free(framecpy); framecpy = NULL; } if (nsres != NULL) { free(nsres); nsres = NULL; } value16 = htons(outptr); memcpy((char *)&out[1], &value16, 2); *outsize = outptr; break; case SIM_NOTIFICATION: debug_printf(DEBUG_NORMAL, "Got SIM_NOTIFICATION! (Unsupported)\n"); break; case SIM_REAUTHENTICATION: debug_printf(DEBUG_NORMAL, "Got SIM_REAUTHENTICATION! (Unsupported)\n"); break; default: debug_printf(DEBUG_NORMAL, "Unknown SubType value! (%d)\n", dataoffs[0]); break; } out[2] = 0; return XENONE; }