Example #1
0
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);
}
Example #4
0
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;
}
Example #5
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;
}
Example #6
0
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;
}