eapfast_phase2.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 1,907 行 · 第 1/4 页

C
1,907
字号
  debug_hex_dump(DEBUG_AUTHTYPES, phase2->sm->eapKeyData, 32);

  if (phase2->simckj == NULL)
    {
      debug_printf(DEBUG_AUTHTYPES, "Generating a new S-IMCK[0].\n");
      phase2->simckj = Malloc(40);
      if (phase2->simckj == NULL) 
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store "
		       "S-IMCK[0]!\n");
	  return NULL;
	}

      memcpy(phase2->simckj, phase2->pkeys->session_key_seed, 40);
    }

  key = Malloc(32);
  if (key == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store "
		   "temporary key data!\n");
      return NULL;
    }

  memset(key, 0x00, 32);

  if (phase2->sm->eapKeyData != NULL)
    {
      memcpy(key, phase2->sm->eapKeyData, 32);
    }

  keyblock = eapfast_phase2_t_prf(phase2->simckj, 40,
				  FAST_IMCK_LABEL, key, 32, 60);

  cmkj = Malloc(20);
  if (cmkj == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store CMK[j]!\n");
      return NULL;
    }

  // Store the new S-IMCK[j]
  memcpy(phase2->simckj, keyblock, 40);
  
  memcpy(cmkj, keyblock+40, 20);

  return cmkj;
}

/****************************************************************
 *
 *  Process a crypto binding TLV, and verify that it is valid.  If it
 *  isn't valid, then wipe out the result packet that we have been 
 *  building, and replace it with a Result-Failure TLV, and an Error TLV
 *  that indicates the problem was with the crypto-binding.
 *
 ****************************************************************/
int eapfast_phase2_check_crypto_binding(eap_type_data *eapdata, 
					uint8_t *indata, uint16_t insize)
{
  struct eapfast_crypto_binding_tlv *binding, *maccheck;
  struct tls_vars *mytls_vars;
  struct eapfast_phase2 *phase2;
  uint8_t *temp;
  uint8_t mac[20], nonce[32];
  int len;
  uint8_t *cmkj;

  if (!xsup_assert((eapdata != NULL), "eapdata != NULL", FALSE))
    return 0;

  if (!xsup_assert((indata != NULL), "indata != NULL", FALSE))
    {
      eap_type_common_fail(eapdata);
      return 0;
    }

  if (!xsup_assert((insize >= sizeof(struct eapfast_crypto_binding_tlv)), 
		   "insize is invalid", FALSE))
    {
      eap_type_common_fail(eapdata);
      return 0;
    }

  mytls_vars = (struct tls_vars *)eapdata->eap_data;
  phase2 = (struct eapfast_phase2 *)mytls_vars->phase2data;

  binding = (struct eapfast_crypto_binding_tlv *)indata;
  
  if ((ntohs(binding->length)+4) != sizeof(struct eapfast_crypto_binding_tlv))
    {
      debug_printf(DEBUG_NORMAL, "Crypto-Binding packet is a runt!\n");
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  binding = (struct eapfast_crypto_binding_tlv *)indata;

  if (binding->version != FAST_CRYPTO_BIND_VERSION)
    {
      debug_printf(DEBUG_NORMAL, "Crypto-Binding version is invalid!  "
		   "(Expected %d, got %d.)\n", FAST_CRYPTO_BIND_VERSION,
		   binding->version);
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  debug_printf(DEBUG_AUTHTYPES, "Crypto-Binding version is %d.\n",
	       binding->version);

  if (binding->eap_version != eapfast_get_ver(eapdata))
    {
      debug_printf(DEBUG_NORMAL, "Crypto-Binding EAP version is invalid!  "
		   "(Expected %d, got %d.)\n", eapfast_get_ver(eapdata),
		   binding->eap_version);
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  debug_printf(DEBUG_AUTHTYPES, "EAP Version is %d\n", binding->eap_version);

  if (binding->subtype != FAST_BINDING_REQUEST)
    {
      debug_printf(DEBUG_NORMAL, "Crypto-Binding subtype is invalid!  "
		   "(Expected %d, got %d.)\n", FAST_BINDING_REQUEST,
		   binding->subtype);
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  /*
  if (phase2->sm->eapKeyAvailable != TRUE)
    {
      debug_printf(DEBUG_NORMAL, "No keying material available from phase 2! "
		   "(Unable to generate the Compound MAC.)\n");
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }
  */

  temp = Malloc(ntohs(binding->length)+4);
  if (temp == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store temporary"
		   " Crypto-Binding TLV data.\n");
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  if (!xsup_assert((phase2->sm != NULL), "phase2->sm != NULL", FALSE))
    {
      eapfast_phase2_binding_failed(eapdata);
      FREE(temp);
      return 0;
    }

  memcpy(temp, binding, (ntohs(binding->length)+4));
  maccheck = (struct eapfast_crypto_binding_tlv *)temp;

  // Zero out the MAC section.
  memset(maccheck->compound_mac, 0x00, sizeof(maccheck->compound_mac));

  debug_printf(DEBUG_AUTHTYPES, "Phase 2 Keying material (%d) : ",
	       phase2->sm->eapKeyLen);
  debug_hex_printf(DEBUG_AUTHTYPES, phase2->sm->eapKeyData,
		   phase2->sm->eapKeyLen);

  cmkj = eapfast_phase2_gen_cmkj(eapdata);

  HMAC(EVP_sha1(), cmkj, 20, (unsigned char *)maccheck, 
       sizeof(struct eapfast_crypto_binding_tlv), (unsigned char *)&mac, 
       &len);

  debug_printf(DEBUG_AUTHTYPES, "Calculated Compound MAC (%d)\t: ", len);
  debug_hex_printf(DEBUG_AUTHTYPES, mac, len);

  debug_printf(DEBUG_AUTHTYPES, "Expected Compound MAC \t: ");
  debug_hex_printf(DEBUG_AUTHTYPES, binding->compound_mac, 
		   sizeof(binding->compound_mac));

  if (memcmp(mac, binding->compound_mac, sizeof(binding->compound_mac)) != 0)
    {
      debug_printf(DEBUG_NORMAL, "Compound MAC check failed!\n");
      eapfast_phase2_binding_failed(eapdata);
      FREE(temp);
      return 0;
    }

  memcpy(nonce, binding->nonce, 32);

  FREE(temp);

  // The MAC check was a success.  So, now we need to build the response
  // CMAC, and send it along too.
  temp = Malloc(sizeof(struct eapfast_crypto_binding_tlv));
  if (temp == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to return the "
		   "crypto binding result.\n");
      eapfast_phase2_binding_failed(eapdata);
      return 0;
    }

  memset(temp, 0x00, sizeof(struct eapfast_crypto_binding_tlv));

  binding = (struct eapfast_crypto_binding_tlv *)temp;
  binding->type = htons(MANDATORY_TLV | FAST_CRYPTO_BINDING_TLV);
  binding->length = htons(sizeof(struct eapfast_crypto_binding_tlv)-4);
  binding->reserved = 0;
  binding->version = FAST_CRYPTO_BIND_VERSION;
  binding->eap_version = FAST_VERSION1;
  binding->subtype = FAST_BINDING_RESPONSE;

  memcpy(binding->nonce, nonce, 32);

  binding->nonce[31]++;

  HMAC(EVP_sha1(), cmkj, 20, temp, sizeof(struct eapfast_crypto_binding_tlv),
       (unsigned char *)&mac, &len);

  memcpy(binding->compound_mac, mac, 20);

  memcpy(&phase2->result_data[phase2->result_size], temp, 
	 sizeof(struct eapfast_crypto_binding_tlv));

  phase2->result_size += sizeof(struct eapfast_crypto_binding_tlv);

  return sizeof(struct eapfast_crypto_binding_tlv);
}

/*********************************************************************
 *
 *  Process an ERROR TLV from the server.    This code should validate 
 *  the error from the server, and display some form of an error message
 *  to the user.
 *
 *********************************************************************/
uint16_t eapfast_phase2_process_error_tlv(uint8_t *indata)
{
  struct eapfast_tlv_error *error;

  if (!xsup_assert((indata != NULL), "indata != NULL", FALSE))
    return 0;

  error = (struct eapfast_tlv_error *)indata;

  if (ntohs(error->length) != 4)
    {
      debug_printf(DEBUG_NORMAL, "The TLV length for the ERROR TLV was "
		   "invalid.  Expected 4, got %d.\n", ntohs(error->length));

      return ntohs(error->length)+4;
    }

  switch (ntohl(error->error_code))
    {
    case FAST_TUNNEL_COMPROMISE_ERROR:
      debug_printf(DEBUG_NORMAL, "[EAP-FAST] Tunnel has been compromised!\n");
      break;

    case FAST_UNEXPECTED_TLVS_EXCHANGED:
      debug_printf(DEBUG_NORMAL, "[EAP-FAST] Unexpected TLVs exchanged!\n");
      break;

    default:
      debug_printf(DEBUG_NORMAL, "[EAP-FAST] Unknown error received.  (Error "
		   "was %d.)\n", ntohl(error->error_code));
      break;
    }

  return ntohs(error->length)+4;
}
						   
/***************************************************************
 *
 *  Process a phase 2 packet.
 *
 ***************************************************************/
void eapfast_phase2_process(eap_type_data *eapdata, uint8_t *indata, 
			    uint16_t insize)
{
  struct eapfast_tlv *fastlv;
  uint16_t value16;
  struct tls_vars *mytls_vars;
  struct eapfast_phase2 *phase2;
  uint16_t consumed = 0, result = 0;

  if (!xsup_assert((eapdata != NULL), "eapdata != NULL", FALSE))
    return;

  if (!xsup_assert((indata != NULL), "indata != NULL", FALSE))
    {
      eap_type_common_fail(eapdata);
      return;
    }

  if (!xsup_assert((eapdata->eap_data != NULL), "eapdata->eap_data != NULL",
		   FALSE))
    {
      eap_type_common_fail(eapdata);
      return;
    }

  mytls_vars = (struct tls_vars *)eapdata->eap_data;

  if (!xsup_assert((mytls_vars->phase2data != NULL),
		   "mytls_vars->phase2data != NULL", FALSE))
    {
      eap_type_common_fail(eapdata);
      return;
    }

  phase2 = (struct eapfast_phase2 *)mytls_vars->phase2data;

  // Clear out our storage area, so that we can build the new response.
  FREE(phase2->result_data);

  phase2->result_size = 0;
  phase2->result_data = Malloc(1600);  // Should be plenty of space.
  if (phase2->result_data == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store response "
		   "data.\n");
      eap_type_common_fail(eapdata);
      return;
    }

  // Need to loop through all TLVs included, and make sure we process each one.
  while (consumed < insize)
    {
      fastlv = (struct eapfast_tlv *)&indata[consumed];
      value16 = ntohs(fastlv->type);

      debug_printf(DEBUG_AUTHTYPES, "(Offset %d) PAC id (%d) : ", consumed, 
		   (value16 & MANDATORY_TLV_MASK_OUT));
      eapfast_phase2_PAC_id_to_str(DEBUG_AUTHTYPES,
				   (value16 & MANDATORY_TLV_MASK_OUT));
      debug_printf_nl(DEBUG_AUTHTYPES, "\n");

      switch (value16 & MANDATORY_TLV_MASK_OUT)
	{
	case FAST_RESULT_TLV:
	  result = eapfast_phase2_process_result_tlv(eapdata, 
						     &indata[consumed], 
						     (insize - consumed));
	  break;
	  
	case FAST_NAK_TLV:
	  // It is possible that the supplicant *COULD* get a NAK TLV, but
	  // that should require that we are attempting to use a TLV that
	  // may not be supported by the server.  Since this implementation
	  // doesn't support anything like that, we should never get a
	  // NAK!  If such code is ever added, we need to implement something
	  // here.
	  debug_printf(DEBUG_NORMAL, "Got a TLV NAK.  This shouldn't happen!"
		       "\n");
	  result = 0;
	  break;
	  
	case FAST_ERROR_TLV:
	  debug_printf(DEBUG_NORMAL, "Got an ERROR TLV.\n");
	  result = eapfast_phase2_process_error_tlv(&indata[consumed]);
	  break;
	  
	case FAST_VENDOR_SPECIFIC_TLV:
	  debug_printf(DEBUG_NORMAL, "Vendor specific TLV found, but not "
		       "supported.  NAKing.\n");
	  result = eapfast_phase2_vendor_tlv_nak(eapdata, &indata[consumed]);
	  break;
	  
	case FAST_EAP_PAYLOAD_TLV:
	  result = eapfast_phase2_eap_process(eapdata, &indata[consumed], 
					      (insize - consumed));
	  break;
	  
	case FAST_INTERMEDIATE_RESULT_TLV:
	  result = eapfast_phase2_intermediate_result_process(eapdata, 
							      &indata[consumed],
							      (insize - consumed));
	  break;

	case FAST_PAC_TLV:
	  result = eapfast_phase2_pac_process(eapdata, &indata[consumed], 
					      (insize - consumed));
	  break;
	  
	case FAST_CRYPTO_BINDING_TLV:
	  result = eapfast_phase2_check_crypto_binding(eapdata, 
						       &indata[consumed],
						       (insize - consumed));
	  break;
	  
	case FAST_SERVER_TRUSTED_ROOT_TLV:
	  debug_printf(DEBUG_NORMAL, "Got a 'Server trusted root' TLV, but "
		       "this is not implemented, and should not happen!\n");
	  result = eapfast_phase2_tlv_nak(eapdata, &indata[consumed],
					  0x00000000, 
					  FAST_SERVER_TRUSTED_ROOT_TLV);
	  break;
	  
	case FAST_REQUEST_ACTION_TLV:
	  debug_printf(DEBUG_NORMAL, "The server sent us a request for "
		       "action TLV.  But, we should NEVER get one!  NAKing"
		       "!\n");
	  result = eapfast_phase2_tlv_nak(eapdata, &indata[consumed],
					  0x00000000, FAST_REQUEST_ACTION_TLV);
	  break;
	  
	case FAST_PKCS7_TLV:
	  debug_printf(DEBUG_NORMAL, "Use of a PKCS#7 certificate is not "
		       "currently supported!\n");
	  result = eapfast_phase2_tlv_nak(eapdata, &indata[consumed],
					  0x00000000, FAST_PKCS7_TLV);
	  break;
	  
	default:
	  debug_printf(DEBUG_NORMAL, "Unknown TLV type %d.\n", 
		       ntohs(fastlv->type));
	  result = eapfast_phase2_tlv_nak(eapdata, &indata[consumed],
					  0x00000000, ntohs(fastlv->type));
	  break;
	}

      if (result == 0)
	{
	  // ACK!  We couldn't process something for some reason.  (The reason
	  // should have been displayed by the called function.)
	  return;
	}

      consumed += result;
    }
}

/**********************************************************************
 *
 *  Build an EAP-FAST response.
 *
 **********************************************************************/
void eapfast_phase2_buildResp(eap_type_data *eapdata, uint8_t *result,
			      uint16_t *result_size)
{
  struct tls_vars *mytls_vars;
  struct eapfast_phase2 *phase2;

  if (!xsup_assert((eapdata != NULL), "eapdata != NULL", FALSE))
    {
      *result_size = 0;
      return;
    }

  if (!xsup_assert((eapdata->eap_data != NULL), "eapdata->eap_data != NULL",
		   FALSE))
    {
      eap_type_common_fail(eapdata);
      *result_size = 0;
      return;
    }

  mytls_vars = (struct tls_vars *)eapdata->eap_data;
  phase2 = (struct eapfast_phase2 *)mytls_vars->phase2data;
      
  if (!xsup_assert((phase2->result_data != NULL), 
		   "phase2->result_data != NULL", FALSE))
    {
      eap_type_common_fail(eapdata);
      *result_size = 0;
      return;
    }

  memcpy(result, phase2->result_data, phase2->result_size);
  *result_size = phase2->result_size;
}

#endif // EAP_FAST

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?