/** @file keyMgntAP.c
|
*
|
* @brief This file defined the eapol paket process and key management for authenticator
|
*
|
* Copyright (C) 2014-2017, Marvell International Ltd.
|
*
|
* This software file (the "File") is distributed by Marvell International
|
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
* (the "License"). You may use, redistribute and/or modify this File in
|
* accordance with the terms and conditions of the License, a copy of which
|
* is available by writing to the Free Software Foundation, Inc.,
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
*
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
* this warranty disclaimer.
|
*/
|
|
/******************************************************
|
Change log:
|
03/07/2014: Initial version
|
******************************************************/
|
//Authenticator related function definitions
|
#include "wltypes.h"
|
#include "IEEE_types.h"
|
|
#include "hostsa_ext_def.h"
|
#include "authenticator.h"
|
|
#include "wl_macros.h"
|
#include "wlpd.h"
|
#include "pass_phrase.h"
|
#include "sha1.h"
|
#include "crypt_new.h"
|
#include "parser.h"
|
#include "keyCommonDef.h"
|
#include "keyMgmtStaTypes.h"
|
#include "AssocAp_srv_rom.h"
|
#include "pmkCache.h"
|
#include "keyMgmtApTypes.h"
|
#include "keyMgmtAp.h"
|
#include "rc4.h"
|
#include "authenticator_api.h"
|
|
//////////////////////
|
// STATIC FUNCTIONS
|
//////////////////////
|
|
//#ifdef AUTHENTICATOR
|
////////////////////////
|
// FORWARD DECLARATIONS
|
////////////////////////
|
Status_e GeneratePWKMsg3(hostsa_private *priv, cm_Connection *connPtr);
|
Status_e GenerateGrpMsg1(hostsa_private *priv, cm_Connection *connPtr);
|
Status_e GenerateApEapolMsg(hostsa_private *priv,
|
t_void *pconnPtr, keyMgmtState_e msgState);
|
|
static void
|
handleFailedHSK(t_void *priv, t_void *pconnPtr, IEEEtypes_ReasonCode_t reason)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
hostsa_mlan_fns *pm_fns = &psapriv->mlan_fns;
|
cm_Connection *connPtr = (cm_Connection *)pconnPtr;
|
|
KeyMgmtStopHskTimer(connPtr);
|
pm_fns->hostsa_SendDeauth(pm_fns->pmlan_private, connPtr->mac_addr,
|
(t_u16)reason);
|
}
|
|
static void
|
incrementReplayCounter(apKeyMgmtInfoSta_t *pKeyMgmtInfo)
|
{
|
if (++pKeyMgmtInfo->counterLo == 0) {
|
pKeyMgmtInfo->counterHi++;
|
}
|
}
|
|
int
|
isValidReplayCount(t_void *priv, apKeyMgmtInfoSta_t *pKeyMgmtInfo,
|
UINT8 *pRxReplayCount)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
hostsa_util_fns *util_fns = &psapriv->util_fns;
|
UINT32 rxCounterHi;
|
UINT32 rxCounterLo;
|
|
memcpy(util_fns, &rxCounterHi, pRxReplayCount, 4);
|
memcpy(util_fns, &rxCounterLo, pRxReplayCount + 4, 4);
|
|
if ((pKeyMgmtInfo->counterHi == WORD_SWAP(rxCounterHi)) &&
|
(pKeyMgmtInfo->counterLo == WORD_SWAP(rxCounterLo))) {
|
return 1;
|
}
|
return 0;
|
}
|
|
void
|
KeyMgmtSendGrpKeyMsgToAllSta(hostsa_private *priv)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
cm_Connection *connPtr = MNULL;
|
t_void *sta_node = MNULL;
|
|
ENTER();
|
|
pm_fns->Hostsa_find_connection(priv->pmlan_private, (t_void *)&connPtr,
|
&sta_node);
|
|
while (connPtr != MNULL) {
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
|
if (pKeyMgmtInfo->rom.keyMgmtState == HSK_END) {
|
GenerateApEapolMsg(priv, connPtr,
|
GRP_REKEY_MSG1_PENDING);
|
} else if ((pKeyMgmtInfo->rom.keyMgmtState == WAITING_4_GRPMSG2)
|
|| (pKeyMgmtInfo->rom.staSecType.wpa2 &&
|
(pKeyMgmtInfo->rom.keyMgmtState ==
|
WAITING_4_MSG4)) ||
|
(pKeyMgmtInfo->rom.keyMgmtState ==
|
WAITING_4_GRP_REKEY_MSG2)) {
|
// TODO:How to handle group rekey if either Groupwise handshake
|
// Group rekey is already in progress for this STA?
|
}
|
|
pm_fns->Hostsa_find_next_connection(priv->pmlan_private,
|
(t_void *)&connPtr,
|
&sta_node);
|
}
|
|
LEAVE();
|
}
|
|
UINT32
|
keyApi_ApUpdateKeyMaterial(void *priv, cm_Connection *connPtr,
|
BOOLEAN updateGrpKey)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
hostsa_util_fns *util_fns = &psapriv->util_fns;
|
hostsa_mlan_fns *pm_fns = &psapriv->mlan_fns;
|
BssConfig_t *pBssConfig = MNULL;
|
KeyData_t *pKeyData = MNULL;
|
//cipher_key_buf_t *pCipherKeyBuf;
|
Cipher_t *pCipher = MNULL;
|
//KeyData_t pwsKeyData;
|
mlan_ds_encrypt_key encrypt_key;
|
t_u8 bcast_addr[MAC_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
apInfo_t *pApInfo = &psapriv->apinfo;
|
|
pBssConfig = &pApInfo->bssConfig;
|
|
if (pBssConfig->SecType.wpa || pBssConfig->SecType.wpa2) {
|
memset(util_fns, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
|
|
//connPtr->cmFlags.RSNEnabled = TRUE;
|
if (updateGrpKey == TRUE) {
|
pKeyData = &pApInfo->bssData.grpKeyData;
|
pCipher = &pBssConfig->RsnConfig.mcstCipher;
|
} else if (connPtr) {
|
/* pCipherKeyBuf = connPtr->pwTxRxCipherKeyBuf;
|
memcpy((void*)&pwsKeyData,
|
(void*)&pCipherKeyBuf->cipher_key.ckd.hskData.pwsKeyData,
|
sizeof(KeyData_t)); */
|
pKeyData = &connPtr->hskData.pwsKeyData;
|
pCipher =
|
&connPtr->staData.keyMgmtInfo.rom.staUcstCipher;
|
}
|
|
if (updateGrpKey == TRUE) {
|
memcpy(util_fns, encrypt_key.mac_addr, bcast_addr,
|
MAC_ADDR_SIZE);
|
encrypt_key.key_flags |= KEY_FLAG_GROUP_KEY;
|
} else if (connPtr) {
|
memcpy(util_fns, encrypt_key.mac_addr,
|
connPtr->mac_addr, MAC_ADDR_SIZE);
|
encrypt_key.key_flags |= KEY_FLAG_SET_TX_KEY;
|
}
|
|
if (!pKeyData || !pCipher) {
|
PRINTM(MERROR, "Invalid KeyData or Cipher pointer!\n");
|
return 1;
|
}
|
|
if (pCipher->ccmp) {
|
/**AES*/
|
encrypt_key.key_len = TK_SIZE;
|
memcpy(util_fns, encrypt_key.key_material,
|
pKeyData->Key, TK_SIZE);
|
} else if (pCipher->tkip) {
|
/**TKIP*/
|
encrypt_key.key_len =
|
TK_SIZE + MIC_KEY_SIZE + MIC_KEY_SIZE;
|
memcpy(util_fns, encrypt_key.key_material,
|
pKeyData->Key, TK_SIZE);
|
memcpy(util_fns, &encrypt_key.key_material[TK_SIZE],
|
pKeyData->TxMICKey, MIC_KEY_SIZE);
|
memcpy(util_fns,
|
&encrypt_key.key_material[TK_SIZE +
|
MIC_KEY_SIZE],
|
pKeyData->RxMICKey, MIC_KEY_SIZE);
|
}
|
/**set pn 0*/
|
memset(util_fns, encrypt_key.pn, 0, PN_SIZE);
|
|
/**key flag*/
|
encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;
|
/**key index*/
|
encrypt_key.key_index = pKeyData->KeyIndex;
|
/**set command to fw update key*/
|
pm_fns->hostsa_set_encrypt_key(psapriv->pmlan_private,
|
&encrypt_key);
|
|
}
|
|
return 0;
|
}
|
|
void
|
GenerateGTK(void *priv)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
apInfo_t *pApInfo = &psapriv->apinfo;
|
BssData_t *pBssData = MNULL;
|
|
pBssData = &pApInfo->bssData;
|
|
GenerateGTK_internal(psapriv, &pBssData->grpKeyData,
|
pBssData->GNonce, psapriv->curr_addr);
|
}
|
|
void
|
ReInitGTK(t_void *priv)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
apInfo_t *pApInfo = &psapriv->apinfo;
|
BssData_t *pBssData;
|
|
pBssData = &pApInfo->bssData;
|
|
/*
|
Disabled for interop
|
Not all clients like this
|
pBssData->grpKeyData.KeyIndex = (pBssData->grpKeyData.KeyIndex & 3) + 1;
|
*/
|
|
ROM_InitGTK(psapriv, &pBssData->grpKeyData,
|
pBssData->GNonce, psapriv->curr_addr);
|
|
keyApi_ApUpdateKeyMaterial(priv, MNULL, MTRUE);
|
}
|
|
void
|
KeyMgmtGrpRekeyCountUpdate(t_void *context)
|
{
|
phostsa_private psapriv = (phostsa_private)context;
|
apInfo_t *pApInfo = &psapriv->apinfo;
|
hostsa_util_fns *putil_fns = &psapriv->util_fns;
|
|
ENTER();
|
|
if (psapriv->GrpRekeyTimerIsSet &&
|
pApInfo->bssData.grpRekeyCntRemaining) {
|
//Periodic group rekey is configured.
|
pApInfo->bssData.grpRekeyCntRemaining--;
|
if (!pApInfo->bssData.grpRekeyCntRemaining) {
|
//Group rekey timeout hit.
|
pApInfo->bssData.grpRekeyCntRemaining
|
= pApInfo->bssData.grpRekeyCntConfigured;
|
|
ReInitGTK((t_void *)psapriv);
|
|
KeyMgmtSendGrpKeyMsgToAllSta(psapriv);
|
}
|
|
/**start Group rekey timer*/
|
putil_fns->moal_start_timer(putil_fns->pmoal_handle,
|
psapriv->GrpRekeytimer,
|
MFALSE, MRVDRV_TIMER_60S);
|
}
|
|
LEAVE();
|
}
|
|
void
|
KeyMgmtInit(void *priv)
|
{
|
phostsa_private psapriv = (phostsa_private)priv;
|
apInfo_t *pApInfo = &psapriv->apinfo;
|
UINT8 *pPassPhrase;
|
UINT8 *pPskValue;
|
UINT8 passPhraseLen;
|
|
pPassPhrase = pApInfo->bssConfig.RsnConfig.PSKPassPhrase;
|
pPskValue = pApInfo->bssConfig.RsnConfig.PSKValue;
|
passPhraseLen = pApInfo->bssConfig.RsnConfig.PSKPassPhraseLen;
|
|
ROM_InitGTK(psapriv, &pApInfo->bssData.grpKeyData,
|
pApInfo->bssData.GNonce, psapriv->curr_addr);
|
|
if (pApInfo->bssData.updatePassPhrase == MTRUE) {
|
pmkCacheGeneratePSK(priv, pApInfo->bssConfig.SsId,
|
pApInfo->bssConfig.SsIdLen,
|
(char *)pPassPhrase, pPskValue);
|
|
pApInfo->bssData.updatePassPhrase = MFALSE;
|
}
|
}
|
|
void
|
KeyMgmtHskTimeout(t_void *context)
|
{
|
cm_Connection *connPtr = (cm_Connection *)context;
|
phostsa_private priv = (phostsa_private)connPtr->priv;
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
apRsnConfig_t *pRsnConfig;
|
IEEEtypes_ReasonCode_t reason;
|
BOOLEAN maxRetriesDone = MFALSE;
|
apInfo_t *pApInfo = &priv->apinfo;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
pRsnConfig = &pApInfo->bssConfig.RsnConfig;
|
|
connPtr->timer_is_set = 0;
|
/* Assume when this function gets called pKeyMgmtInfo->keyMgmtState
|
** will not be in HSK_NOT_STARTED or HSK_END
|
*/
|
if (pKeyMgmtInfo->rom.keyMgmtState <= WAITING_4_MSG4) {
|
if (pKeyMgmtInfo->numHskTries >= pRsnConfig->MaxPwsHskRetries) {
|
maxRetriesDone = MTRUE;
|
reason = IEEEtypes_REASON_4WAY_HANDSHK_TIMEOUT;
|
}
|
} else {
|
if (pKeyMgmtInfo->numHskTries >= pRsnConfig->MaxGrpHskRetries) {
|
maxRetriesDone = MTRUE;
|
reason = IEEEtypes_REASON_GRP_KEY_UPD_TIMEOUT;
|
}
|
}
|
|
if (maxRetriesDone) {
|
// Some STAs do not respond to PWK Msg1 if the EAPOL Proto Version is 1
|
// in 802.1X header, hence switch to v2 after all attempts with v1 fail
|
// for PWK Msg1. Set the HskTimeoutCtn to 1 to get the same "retries"
|
// as with v1.
|
if (((WAITING_4_MSG2 == pKeyMgmtInfo->rom.keyMgmtState)
|
|| (MSG1_PENDING == pKeyMgmtInfo->rom.keyMgmtState))
|
&& (EAPOL_PROTOCOL_V1 == pKeyMgmtInfo->EAPOLProtoVersion)) {
|
pKeyMgmtInfo->numHskTries = 1;
|
pKeyMgmtInfo->EAPOLProtoVersion = EAPOL_PROTOCOL_V2;
|
GenerateApEapolMsg(priv, connPtr,
|
pKeyMgmtInfo->rom.keyMgmtState);
|
} else {
|
pm_fns->hostsa_SendDeauth(priv->pmlan_private,
|
connPtr->mac_addr,
|
(t_u16)reason);
|
pKeyMgmtInfo->rom.keyMgmtState = HSK_END;
|
}
|
} else {
|
GenerateApEapolMsg(priv, connPtr,
|
pKeyMgmtInfo->rom.keyMgmtState);
|
}
|
|
return;
|
}
|
|
void
|
KeyMgmtStartHskTimer(void *context)
|
{
|
cm_Connection *connPtr = (cm_Connection *)context;
|
phostsa_private psapriv = (phostsa_private)(connPtr->priv);
|
hostsa_util_fns *util_fns = &psapriv->util_fns;
|
apInfo_t *pApInfo = MNULL;
|
UINT32 timeoutInms;
|
apRsnConfig_t *pRsnConfig;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
pApInfo = &psapriv->apinfo;
|
pRsnConfig = &pApInfo->bssConfig.RsnConfig;
|
if ((connPtr->staData.keyMgmtInfo.rom.keyMgmtState >= MSG1_PENDING)
|
&& (connPtr->staData.keyMgmtInfo.rom.keyMgmtState <=
|
WAITING_4_MSG4)) {
|
timeoutInms = pRsnConfig->PwsHskTimeOut;
|
} else if ((connPtr->staData.keyMgmtInfo.rom.keyMgmtState >=
|
GRPMSG1_PENDING)
|
&& (connPtr->staData.keyMgmtInfo.rom.keyMgmtState <=
|
WAITING_4_GRP_REKEY_MSG2)) {
|
timeoutInms = pRsnConfig->GrpHskTimeOut;
|
} else {
|
//EAPOL HSK is not in progress. No need to start HSK timer
|
return;
|
}
|
|
// Retry happen, increase timeout to at least 1 sec
|
if (connPtr->staData.keyMgmtInfo.numHskTries > 0) {
|
timeoutInms = MAX(AP_RETRY_EAPOL_HSK_TIMEOUT, timeoutInms);
|
}
|
|
/* if STA is in PS1 then we are using max(STA_PS_EAPOL_HSK_TIMEOUT,
|
* HSKtimeout)for timeout instead of configured timeout value
|
*/
|
/* if(PWR_MODE_PWR_SAVE == connPtr->staData.pwrSaveInfo.mode)
|
{
|
timeoutInms = MAX(STA_PS_EAPOL_HSK_TIMEOUT, timeoutInms);
|
}
|
*/
|
util_fns->moal_start_timer(util_fns->pmoal_handle,
|
connPtr->HskTimer, MFALSE, timeoutInms);
|
connPtr->timer_is_set = 1;
|
}
|
|
void
|
KeyMgmtStopHskTimer(t_void *pconnPtr)
|
{
|
cm_Connection *connPtr = (cm_Connection *)pconnPtr;
|
phostsa_private priv = (phostsa_private)connPtr->priv;
|
hostsa_util_fns *util_fns = &priv->util_fns;
|
|
util_fns->moal_stop_timer(util_fns->pmoal_handle, connPtr->HskTimer);
|
|
connPtr->timer_is_set = 0;
|
}
|
|
void
|
PrepDefaultEapolMsg(phostsa_private priv, cm_Connection *connPtr,
|
EAPOL_KeyMsg_Tx_t **pTxEapolPtr, pmlan_buffer pmbuf)
|
{
|
hostsa_util_fns *util_fns = &priv->util_fns;
|
apInfo_t *pApInfo = &priv->apinfo;
|
EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
UINT8 intf_hr_len =
|
pm_fns->Hostsa_get_intf_hr_len(pm_fns->pmlan_private);
|
#define UAP_EAPOL_PRIORITY 7 /* Voice */
|
|
ENTER();
|
|
pmbuf->priority = UAP_EAPOL_PRIORITY;
|
pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
|
pmbuf->data_offset = (sizeof(UapTxPD) + intf_hr_len + DMA_ALIGNMENT);
|
tx_eapol_ptr =
|
(EAPOL_KeyMsg_Tx_t *)((UINT8 *)pmbuf->pbuf +
|
pmbuf->data_offset);
|
memset(util_fns, (UINT8 *)tx_eapol_ptr, 0x00,
|
sizeof(EAPOL_KeyMsg_Tx_t));
|
|
formEAPOLEthHdr(priv, tx_eapol_ptr, connPtr->mac_addr, priv->curr_addr);
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
|
SetEAPOLKeyDescTypeVersion(tx_eapol_ptr,
|
pKeyMgmtInfo->rom.staSecType.wpa2,
|
MFALSE,
|
(pKeyMgmtInfo->rom.staUcstCipher.ccmp ||
|
pApInfo->bssConfig.RsnConfig.mcstCipher.
|
ccmp));
|
|
*pTxEapolPtr = tx_eapol_ptr;
|
|
LEAVE();
|
}
|
|
Status_e
|
GeneratePWKMsg1(hostsa_private *priv, cm_Connection *connPtr)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
|
UINT16 frameLen = 0, packet_len = 0;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
UINT32 replay_cnt[2];
|
eapolHskData_t *pHskData;
|
pmlan_buffer pmbuf = MNULL;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
|
MLAN_TX_DATA_BUF_SIZE_2K, 0,
|
MOAL_MALLOC_BUFFER);
|
if (pmbuf == NULL) {
|
PRINTM(MERROR, "allocate buffer fail for eapol \n");
|
return FAIL;
|
}
|
|
PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
pHskData = &connPtr->hskData;
|
|
incrementReplayCounter(pKeyMgmtInfo);
|
replay_cnt[0] = pKeyMgmtInfo->counterHi;
|
replay_cnt[1] = pKeyMgmtInfo->counterLo;
|
|
supplicantGenerateRand(priv, pHskData->ANonce, NONCE_SIZE);
|
|
PopulateKeyMsg(priv, tx_eapol_ptr,
|
&pKeyMgmtInfo->rom.staUcstCipher,
|
PAIRWISE_KEY_MSG, replay_cnt, pHskData->ANonce);
|
|
frameLen = EAPOL_KeyMsg_Len - sizeof(Hdr_8021x_t)
|
- sizeof(tx_eapol_ptr->keyMsg.key_data)
|
+ tx_eapol_ptr->keyMsg.key_material_len; //key_mtr_len is 0 here
|
|
packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
|
|
tx_eapol_ptr->keyMsg.hdr_8021x.protocol_ver
|
= pKeyMgmtInfo->EAPOLProtoVersion;
|
tx_eapol_ptr->keyMsg.hdr_8021x.pckt_type
|
= IEEE_8021X_PACKET_TYPE_EAPOL_KEY;
|
tx_eapol_ptr->keyMsg.hdr_8021x.pckt_body_len = htons(frameLen);
|
|
UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
|
return SUCCESS;
|
}
|
|
// returns 0 on success, or error code
|
Status_e
|
ProcessPWKMsg2(hostsa_private *priv,
|
cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
|
{
|
EAPOL_KeyMsg_t *rx_eapol_ptr;
|
UINT8 *PMK;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
BssConfig_t *pBssConfig = NULL;
|
IEPointers_t iePointers;
|
UINT32 ieLen;
|
UINT8 *pIe = NULL;
|
apInfo_t *pApInfo = &priv->apinfo;
|
Cipher_t wpaUcastCipher;
|
Cipher_t wpa2UcastCipher;
|
eapolHskData_t *pHskData = &connPtr->hskData;
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);
|
|
pBssConfig = &pApInfo->bssConfig;
|
// compare the RSN IE from assoc req to current
|
pIe = (UINT8 *)rx_eapol_ptr->key_data;
|
ieLen = pIe[1] + sizeof(IEEEtypes_InfoElementHdr_t);
|
GetIEPointers((void *)priv, pIe, ieLen, &iePointers);
|
wpaUcastCipher = pBssConfig->RsnConfig.wpaUcstCipher;
|
wpa2UcastCipher = pBssConfig->RsnConfig.wpa2UcstCipher;
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
if (assocSrvAp_checkRsnWpa(connPtr, &pKeyMgmtInfo->rom,
|
wpaUcastCipher,
|
wpa2UcastCipher,
|
pBssConfig->RsnConfig.mcstCipher,
|
pBssConfig->RsnConfig.AuthKey,
|
&pKeyMgmtInfo->rom.staSecType,
|
iePointers.pRsn,
|
iePointers.pWpa, TRUE) == FAIL) {
|
handleFailedHSK(priv, connPtr, IEEEtypes_REASON_IE_4WAY_DIFF);
|
return FAIL;
|
}
|
|
PMK = pApInfo->bssConfig.RsnConfig.PSKValue;
|
|
KeyMgmtAp_DerivePTK(priv, PMK,
|
connPtr->mac_addr,
|
priv->curr_addr,
|
pHskData->ANonce,
|
rx_eapol_ptr->key_nonce,
|
pKeyMgmtInfo->EAPOL_MIC_Key,
|
pKeyMgmtInfo->EAPOL_Encr_Key,
|
&pHskData->pwsKeyData, MFALSE);
|
|
if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
|
return FAIL;
|
}
|
|
KeyMgmtStopHskTimer(connPtr);
|
connPtr->staData.keyMgmtInfo.numHskTries = 0;
|
|
return GenerateApEapolMsg(priv, connPtr, MSG3_PENDING);
|
}
|
|
Status_e
|
GeneratePWKMsg3(hostsa_private *priv, cm_Connection *connPtr)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
|
UINT16 frameLen = 0, packet_len = 0;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
apInfo_t *pApInfo = &priv->apinfo;
|
BssConfig_t *pBssConfig = MNULL;
|
UINT32 replay_cnt[2];
|
eapolHskData_t *pHskData;
|
pmlan_buffer pmbuf = MNULL;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
|
MLAN_TX_DATA_BUF_SIZE_2K, 0,
|
MOAL_MALLOC_BUFFER);
|
if (pmbuf == NULL) {
|
PRINTM(MERROR, "allocate buffer fail for eapol \n");
|
return FAIL;
|
}
|
|
PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);
|
|
pBssConfig = &pApInfo->bssConfig;
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
pHskData = &connPtr->hskData;
|
|
incrementReplayCounter(pKeyMgmtInfo);
|
|
replay_cnt[0] = pKeyMgmtInfo->counterHi;
|
replay_cnt[1] = pKeyMgmtInfo->counterLo;
|
|
PopulateKeyMsg(priv, tx_eapol_ptr,
|
&pKeyMgmtInfo->rom.staUcstCipher,
|
((PAIRWISE_KEY_MSG | SECURE_HANDSHAKE_FLAG) |
|
((pKeyMgmtInfo->rom.staSecType.
|
wpa2) ? WPA2_HANDSHAKE : 0)), replay_cnt,
|
pHskData->ANonce);
|
|
/*if (pKeyMgmtInfo->staSecType.wpa2)
|
{
|
// Netgear WAG511 and USB55 cards don't like this field set to
|
// anything other than zero. Hence hard code this value to zero
|
// in all outbound EAPOL frames...
|
// The client is now vulnerable to replay attacks from the point
|
// it receives EAP-message3 till reception of first management
|
// frame from uAP.
|
|
tx_eapol_ptr->keyMsg.key_RSC[0] =
|
pApInfo->bssConfig.grpKeyData.TxIV16 & 0x00FF;
|
tx_eapol_ptr->keyMsg.key_RSC[1] =
|
(pApInfo->bssConfig.grpKeyData.TxIV16 >> 8) & 0x00FF;
|
memcpy((void*)(tx_eapol_ptr->keyMsg.key_RSC + 2),
|
&pApInfo->bssData.grpKeyData.TxIV32, 4);
|
} */
|
/*
|
pBcnFrame = (dot11MgtFrame_t *)BML_DATA_PTR(connPtr->pBcnBufferDesc);
|
if (pKeyMgmtInfo->rom.staSecType.wpa)
|
{
|
pWpaIE = syncSrv_ParseAttrib(pBcnFrame,
|
ELEM_ID_VENDOR_SPECIFIC,
|
IEEE_MSG_BEACON,
|
(UINT8 *)wpa_oui01,
|
sizeof(wpa_oui01));
|
}
|
else if (pKeyMgmtInfo->rom.staSecType.wpa2)
|
{
|
pWpa2IE = syncSrv_ParseAttrib(pBcnFrame,
|
ELEM_ID_RSN,
|
IEEE_MSG_BEACON,
|
NULL,
|
0);
|
}*/
|
if (!KeyData_UpdateKeyMaterial(priv, tx_eapol_ptr,
|
&pKeyMgmtInfo->rom.staSecType,
|
pBssConfig->wpa_ie,
|
pBssConfig->rsn_ie)) {
|
/* We have WPA/WPA2 enabled but no corresponding IE */
|
pm_fns->hostsa_free_mlan_buffer(pm_fns->pmlan_adapter, pmbuf);
|
return FAIL;
|
}
|
|
if (pKeyMgmtInfo->rom.staSecType.wpa2) { // WPA2
|
prepareKDE(priv, tx_eapol_ptr,
|
&pApInfo->bssData.grpKeyData,
|
&pApInfo->bssConfig.RsnConfig.mcstCipher);
|
|
if (!Encrypt_keyData((t_void *)priv, tx_eapol_ptr,
|
pKeyMgmtInfo->EAPOL_Encr_Key,
|
&pKeyMgmtInfo->rom.staUcstCipher))
|
{
|
pm_fns->hostsa_free_mlan_buffer(pm_fns->pmlan_adapter,
|
pmbuf);
|
return FAIL;
|
}
|
}
|
|
frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv,
|
tx_eapol_ptr,
|
pKeyMgmtInfo->
|
EAPOL_MIC_Key,
|
pKeyMgmtInfo->
|
EAPOLProtoVersion,
|
tx_eapol_ptr->keyMsg.
|
key_info.
|
KeyDescriptorVersion);
|
|
packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
|
UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
|
return SUCCESS;
|
}
|
|
Status_e
|
ProcessPWKMsg4(hostsa_private *priv,
|
cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
EAPOL_KeyMsg_t *rx_eapol_ptr;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
eapolHskData_t *pHskData = &connPtr->hskData;
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
|
return FAIL;
|
}
|
pHskData->pwsKeyData.TxIV16 = 0x0001;
|
pHskData->pwsKeyData.TxIV32 = 0;
|
|
if (keyApi_ApUpdateKeyMaterial(priv, connPtr, FALSE)) {
|
handleFailedHSK(priv, connPtr, IEEEtypes_REASON_UNSPEC);
|
return FAIL;
|
}
|
|
KeyMgmtStopHskTimer(connPtr);
|
connPtr->staData.keyMgmtInfo.numHskTries = 0;
|
if (pKeyMgmtInfo->rom.staSecType.wpa2) {
|
pm_fns->Hostsa_sendEventRsnConnect(priv->pmlan_private,
|
connPtr->mac_addr);
|
pKeyMgmtInfo->rom.keyMgmtState = HSK_END;
|
} else {
|
return GenerateApEapolMsg(priv, connPtr, GRPMSG1_PENDING);
|
}
|
|
return SUCCESS;
|
}
|
|
Status_e
|
GenerateGrpMsg1(hostsa_private *priv, cm_Connection *connPtr)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
|
UINT16 frameLen = 0, packet_len = 0;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
apInfo_t *pApInfo = &priv->apinfo;
|
UINT32 replay_cnt[2];
|
pmlan_buffer pmbuf = MNULL;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
|
MLAN_TX_DATA_BUF_SIZE_2K, 0,
|
MOAL_MALLOC_BUFFER);
|
if (pmbuf == NULL) {
|
PRINTM(MERROR, "allocate buffer fail for eapol \n");
|
return FAIL;
|
}
|
|
PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
|
incrementReplayCounter(pKeyMgmtInfo);
|
|
replay_cnt[0] = pKeyMgmtInfo->counterHi;
|
replay_cnt[1] = pKeyMgmtInfo->counterLo;
|
|
PopulateKeyMsg(priv, tx_eapol_ptr,
|
&pApInfo->bssConfig.RsnConfig.mcstCipher,
|
(SECURE_HANDSHAKE_FLAG |
|
((pKeyMgmtInfo->rom.staSecType.
|
wpa2) ? WPA2_HANDSHAKE : 0)), replay_cnt,
|
pApInfo->bssData.GNonce);
|
|
KeyData_AddKey(priv,
|
tx_eapol_ptr,
|
&pKeyMgmtInfo->rom.staSecType,
|
&pApInfo->bssData.grpKeyData,
|
&pApInfo->bssConfig.RsnConfig.mcstCipher);
|
if (!Encrypt_keyData(priv, tx_eapol_ptr,
|
pKeyMgmtInfo->EAPOL_Encr_Key,
|
&pKeyMgmtInfo->rom.staUcstCipher))
|
{
|
// nothing here.
|
}
|
|
frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv,
|
tx_eapol_ptr,
|
pKeyMgmtInfo->
|
EAPOL_MIC_Key,
|
pKeyMgmtInfo->
|
EAPOLProtoVersion,
|
tx_eapol_ptr->keyMsg.
|
key_info.
|
KeyDescriptorVersion);
|
|
packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
|
|
UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
|
return SUCCESS;
|
}
|
|
Status_e
|
ProcessGrpMsg2(hostsa_private *priv,
|
cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
|
{
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
EAPOL_KeyMsg_t *rx_eapol_ptr;
|
apKeyMgmtInfoSta_t *pKeyMgmtInfo;
|
|
PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);
|
|
rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);
|
|
pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
|
|
if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
|
handleFailedHSK(priv, connPtr, IEEEtypes_REASON_IE_4WAY_DIFF);
|
return FAIL;
|
}
|
KeyMgmtStopHskTimer(connPtr);
|
connPtr->staData.keyMgmtInfo.numHskTries = 0;
|
|
if (WAITING_4_GRPMSG2 == pKeyMgmtInfo->rom.keyMgmtState) {
|
/* sendEventRsnConnect(connPtr, pKeyMgmtInfo); */
|
pm_fns->Hostsa_sendEventRsnConnect(priv->pmlan_private,
|
connPtr->mac_addr);
|
}
|
|
pKeyMgmtInfo->rom.keyMgmtState = HSK_END;
|
|
return SUCCESS;
|
}
|
|
Status_e
|
GenerateApEapolMsg(hostsa_private *priv,
|
t_void *pconnPtr, keyMgmtState_e msgState)
|
{
|
cm_Connection *connPtr = (cm_Connection *)pconnPtr;
|
Status_e status;
|
// OSASysContext prevContext;
|
|
if (connPtr->timer_is_set) {
|
KeyMgmtStopHskTimer((t_void *)connPtr);
|
}
|
/* If msgState is any waiting_** state,
|
** it will decrease to corresponding **_pending state.
|
*/
|
/* Note: it will reduce the if checks
|
*/
|
if ((msgState & 0x1) == 0) {
|
msgState--;
|
}
|
connPtr->staData.keyMgmtInfo.rom.keyMgmtState = msgState;
|
|
if (msgState == MSG1_PENDING) {
|
status = GeneratePWKMsg1(priv, connPtr);
|
} else if (msgState == MSG3_PENDING) {
|
status = GeneratePWKMsg3(priv, connPtr);
|
} else if ((msgState == GRPMSG1_PENDING)
|
|| (msgState == GRP_REKEY_MSG1_PENDING)) {
|
status = GenerateGrpMsg1(priv, connPtr);
|
} else {
|
//This should not happen
|
return FAIL;
|
}
|
if (SUCCESS == status) {
|
connPtr->staData.keyMgmtInfo.rom.keyMgmtState++;
|
}
|
|
if (SUCCESS == status) {
|
connPtr->staData.keyMgmtInfo.numHskTries++;
|
/* we are starting the timer irrespective of whether the msg generation is
|
sucessful or not. This is because, if the msg generation fails because
|
of buffer unavailabilty then we can re-try the msg after the timeout
|
period. */
|
if (!connPtr->timer_is_set)
|
KeyMgmtStartHskTimer(connPtr);
|
}
|
|
return status;
|
}
|
|
//#endif // AUTHENTICATOR
|
|
void
|
ApMicErrTimerExpCb(t_void *context)
|
{
|
cm_Connection *connPtr = (cm_Connection *)context;
|
phostsa_private priv;
|
// UINT32 int_save;
|
apInfo_t *pApInfo;
|
|
if (connPtr == NULL) {
|
//no AP connection. Do nothing, just return
|
return;
|
}
|
priv = (phostsa_private)connPtr->priv;
|
if (!priv)
|
return;
|
pApInfo = &priv->apinfo;
|
|
switch (connPtr->staData.apMicError.status) {
|
case FIRST_MIC_FAIL_IN_60_SEC:
|
connPtr->staData.apMicError.status = NO_MIC_FAILURE;
|
break;
|
case SECOND_MIC_FAIL_IN_60_SEC:
|
if ((pApInfo->bssConfig.RsnConfig.mcstCipher.tkip) &&
|
IsAuthenticatorEnabled(priv)) {
|
// re-enable the group re-key timer
|
pApInfo->bssData.grpRekeyCntRemaining
|
= pApInfo->bssData.grpRekeyCntConfigured;
|
}
|
connPtr->staData.apMicError.status = NO_MIC_FAILURE;
|
connPtr->staData.apMicError.disableStaAsso = 0;
|
|
break;
|
default:
|
break;
|
}
|
}
|
|
void
|
ApMicCounterMeasureInvoke(t_void *pconnPtr)
|
{
|
cm_Connection *connPtr = (cm_Connection *)pconnPtr;
|
phostsa_private priv = (phostsa_private)connPtr->priv;
|
hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
|
hostsa_util_fns *util_fns = &priv->util_fns;
|
apInfo_t *pApInfo = &priv->apinfo;
|
|
if (connPtr->staData.apMicError.MICCounterMeasureEnabled) {
|
switch (connPtr->staData.apMicError.status) {
|
case NO_MIC_FAILURE:
|
util_fns->moal_start_timer(util_fns->pmoal_handle,
|
connPtr->staData.apMicTimer,
|
MFALSE, MRVDRV_TIMER_60S);
|
connPtr->staData.apMicError.status =
|
FIRST_MIC_FAIL_IN_60_SEC;
|
break;
|
|
case FIRST_MIC_FAIL_IN_60_SEC:
|
connPtr->staData.apMicError.disableStaAsso = 1;
|
connPtr->staData.apMicError.status =
|
SECOND_MIC_FAIL_IN_60_SEC;
|
//start timer for 60 seconds
|
util_fns->moal_stop_timer(util_fns->pmoal_handle,
|
connPtr->staData.apMicTimer);
|
util_fns->moal_start_timer(util_fns->pmoal_handle,
|
connPtr->staData.apMicTimer,
|
MFALSE, MRVDRV_TIMER_60S);
|
|
/* smeAPStateMgr_sendSmeMsg(connPtr, MlmeApBcastDisassoc); */
|
pm_fns->Hostsa_DisAssocAllSta(priv->pmlan_private,
|
IEEEtypes_REASON_MIC_FAILURE);
|
// if current GTK is tkip
|
if ((pApInfo->bssConfig.RsnConfig.mcstCipher.tkip) &&
|
IsAuthenticatorEnabled(priv)) {
|
//Disable periodic group rekey and re-init GTK.
|
priv->GrpRekeyTimerIsSet = MFALSE;
|
pApInfo->bssData.grpRekeyCntRemaining = 0;
|
ReInitGTK(priv);
|
}
|
break;
|
|
default:
|
break;
|
}
|
}
|
return;
|
}
|