blob: 4380ca485c214410f4a1f377ceb7a4d1980093c4 [file] [log] [blame]
/** @file keyMgmtsta_rom.c
*
* @brief This file defines key management function for sta
*
* Copyright (C) 2014, 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
******************************************************/
#include "wltypes.h"
#include "IEEE_types.h"
#include "hostsa_ext_def.h"
#include "authenticator.h"
#include "keyMgmtSta_rom.h"
#include "pmkCache_rom.h"
#include "crypt_new_rom.h"
#include "rc4_rom.h"
#include "aes_cmac_rom.h"
#include "sha1.h"
#include "md5.h"
#include "mrvl_sha256_crypto.h"
#include "wl_macros.h"
#define MIC_ERROR_QUIET_TIME_INTERVAL 60000000 /* 60 sec */
#define MIC_ERROR_CHECK_TIME_INTERVAL 60000000
void
supplicantSetAssocRsn_internal(phostsa_private priv, RSNConfig_t *pRsnConfig,
SecurityParams_t *pSecurityParams,
SecurityMode_t wpaType,
Cipher_t *pMcstCipher,
Cipher_t *pUcstCipher,
AkmSuite_t *pAkm,
IEEEtypes_RSNCapability_t *pRsnCap,
Cipher_t *pGrpMgmtCipher)
{
hostsa_util_fns *util_fns = &priv->util_fns;
memset(util_fns, &pRsnConfig->wpaType,
0x00, sizeof(pRsnConfig->wpaType));
memset(util_fns, &pRsnConfig->ucstCipher,
0x00, sizeof(pRsnConfig->ucstCipher));
memset(util_fns, &pRsnConfig->mcstCipher,
0x00, sizeof(pRsnConfig->mcstCipher));
pRsnConfig->pmkidValid = 0;
pRsnConfig->rsnCapValid = 0;
pRsnConfig->grpMgmtCipherValid = 0;
pRsnConfig->rsvd = 0;
if (pSecurityParams->wpaType.wpa2 && wpaType.wpa2) {
/* encryption mode is WPA2 */
memcpy(util_fns, &pRsnConfig->AKM, (UINT8 *)pAkm,
sizeof(pRsnConfig->AKM));
pRsnConfig->wpaType.wpa2 = 1;
if (pRsnCap) {
pRsnConfig->rsnCapValid = 1;
memcpy(util_fns, &pRsnConfig->rsnCap, pRsnCap,
sizeof(pRsnConfig->rsnCap));
}
if (pGrpMgmtCipher) {
pRsnConfig->grpMgmtCipherValid = 1;
memcpy(util_fns, &pRsnConfig->grpMgmtCipher,
pGrpMgmtCipher,
sizeof(pRsnConfig->grpMgmtCipher));
}
} else if (pSecurityParams->wpaType.wpaNone && wpaType.wpaNone) {
memcpy(util_fns, &pRsnConfig->AKM,
wpa_oui_none, sizeof(pRsnConfig->AKM));
/* encryption mode is WPA None */
pRsnConfig->wpaType.wpaNone = 1;
if (pSecurityParams->mcstCipher.ccmp && pMcstCipher->ccmp) {
pRsnConfig->mcstCipher.ccmp = 1;
} else {
pRsnConfig->mcstCipher.tkip = 1;
}
} else if (pSecurityParams->wpaType.wpa && wpaType.wpa) {
/* encryption mode is WPA */
memcpy(util_fns, &pRsnConfig->AKM, (UINT8 *)pAkm,
sizeof(pRsnConfig->AKM));
pRsnConfig->wpaType.wpa = 1;
} else if (pSecurityParams->wpaType.noRsn) {
/* No encryption */
pRsnConfig->wpaType.noRsn = 1;
}
if (pRsnConfig->wpaType.wpa || pRsnConfig->wpaType.wpa2) {
if (pSecurityParams->ucstCipher.ccmp && pUcstCipher->ccmp) {
pRsnConfig->ucstCipher.ccmp = 1;
} else {
pRsnConfig->ucstCipher.tkip = 1;
}
if (pSecurityParams->mcstCipher.ccmp && pMcstCipher->ccmp) {
pRsnConfig->mcstCipher.ccmp = 1;
} else if (pSecurityParams->mcstCipher.tkip &&
pMcstCipher->tkip) {
pRsnConfig->mcstCipher.tkip = 1;
} else if (pSecurityParams->mcstCipher.wep104 &&
pMcstCipher->wep104) {
pRsnConfig->mcstCipher.wep104 = 1;
} else {
pRsnConfig->mcstCipher.wep40 = 1;
}
}
}
UINT16
keyMgmtFormatWpaRsnIe_internal(phostsa_private priv, RSNConfig_t *pRsnConfig,
UINT8 *pos,
IEEEtypes_MacAddr_t *pBssid,
IEEEtypes_MacAddr_t *pStaAddr,
UINT8 *pPmkid, BOOLEAN addPmkid)
{
hostsa_util_fns *util_fns = &priv->util_fns;
IEEEtypes_WPAElement_t *pWpaIe = (IEEEtypes_WPAElement_t *)pos;
IEEEtypes_RSNElement_t *pRsnIe = (IEEEtypes_RSNElement_t *)pos;
UINT32 ieSize = 0;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
UINT16 ptr_val;
if (keyMgmtFormatWpaRsnIe_internal_hook(pRsnConfig,
pos,
pBssid,
pStaAddr,
pPmkid, addPmkid, &ptr_val)) {
return ptr_val;
}
#endif
if (pRsnConfig->wpaType.wpa2) {
/* encryption mode is WPA2 */
pRsnIe->ElementId = ELEM_ID_RSN;
pRsnIe->Len = (sizeof(pRsnIe->Ver)
+ sizeof(pRsnIe->GrpKeyCipher)
+ sizeof(pRsnIe->PwsKeyCnt)
+ sizeof(pRsnIe->PwsKeyCipherList)
+ sizeof(pRsnIe->AuthKeyCnt)
+ sizeof(pRsnIe->AuthKeyList));
memcpy(util_fns, (void *)pRsnIe->AuthKeyList,
&pRsnConfig->AKM, sizeof(pRsnIe->AuthKeyList));
pRsnIe->Ver = 1;
pRsnIe->PwsKeyCnt = 1;
pRsnIe->AuthKeyCnt = 1;
if (pRsnConfig->ucstCipher.ccmp) {
/* unicast cipher is aes */
memcpy(util_fns, (void *)pRsnIe->PwsKeyCipherList,
wpa2_oui04, sizeof(pRsnIe->PwsKeyCipherList));
} else {
/* if not AES the TKIP */
memcpy(util_fns, (void *)pRsnIe->PwsKeyCipherList,
wpa2_oui02, sizeof(pRsnIe->PwsKeyCipherList));
}
if (pRsnConfig->mcstCipher.ccmp) {
/* multicast cipher is aes */
memcpy(util_fns, (void *)pRsnIe->GrpKeyCipher,
wpa2_oui04, sizeof(pRsnIe->GrpKeyCipher));
} else if (pRsnConfig->mcstCipher.tkip) {
/* multicast cipher is tkip */
memcpy(util_fns, (void *)pRsnIe->GrpKeyCipher,
wpa2_oui02, sizeof(pRsnIe->GrpKeyCipher));
} else if (pRsnConfig->mcstCipher.wep104) {
/* multicast cipher is WEP 104 */
memcpy(util_fns, (void *)pRsnIe->GrpKeyCipher,
wpa2_oui05, sizeof(pRsnIe->GrpKeyCipher));
} else {
/* multicast cipher is WEP 40 */
memcpy(util_fns, (void *)pRsnIe->GrpKeyCipher,
wpa2_oui01, sizeof(pRsnIe->GrpKeyCipher));
}
if (addPmkid && ((!pRsnConfig->pmkidValid && pBssid) || pPmkid)) {
if (pPmkid) {
memcpy(util_fns, pRsnConfig->PMKID, pPmkid,
sizeof(pRsnConfig->PMKID));
pRsnConfig->pmkidValid = TRUE;
} else {
pRsnConfig->pmkidValid =
supplicantGetPmkid(priv, pBssid,
pStaAddr,
&pRsnConfig->AKM,
pRsnConfig->PMKID);
}
}
if (pRsnConfig->rsnCapValid
|| pRsnConfig->pmkidValid
|| pRsnConfig->grpMgmtCipherValid) {
memcpy(util_fns, &pRsnIe->RsnCap,
&pRsnConfig->rsnCap, sizeof(pRsnIe->RsnCap));
pRsnIe->Len += sizeof(pRsnIe->RsnCap);
}
if (pRsnConfig->pmkidValid || pRsnConfig->grpMgmtCipherValid) {
pRsnIe->PMKIDCnt = 0;
pRsnIe->Len += sizeof(pRsnIe->PMKIDCnt);
if (pRsnConfig->pmkidValid) {
/* Add PMKID to the RSN if not an EAPOL msg */
pRsnIe->PMKIDCnt = 1;
memcpy(util_fns, (UINT8 *)pRsnIe->PMKIDList,
pRsnConfig->PMKID,
sizeof(pRsnIe->PMKIDList));
pRsnIe->Len += sizeof(pRsnIe->PMKIDList);
}
}
if (pRsnConfig->grpMgmtCipherValid) {
memcpy(util_fns, pRsnIe->GrpMgmtCipher,
&pRsnConfig->grpMgmtCipher,
sizeof(pRsnIe->GrpMgmtCipher));
pRsnIe->Len += sizeof(pRsnIe->GrpMgmtCipher);
}
ieSize = sizeof(pRsnIe->ElementId) + sizeof(pRsnIe->Len);
ieSize += pRsnIe->Len;
} else if (pRsnConfig->wpaType.wpaNone || pRsnConfig->wpaType.wpa) {
/* encryption mode is WPA */
pWpaIe->ElementId = ELEM_ID_VENDOR_SPECIFIC;
pWpaIe->Len = (sizeof(IEEEtypes_WPAElement_t)
- sizeof(pWpaIe->ElementId)
- sizeof(pWpaIe->Len));
memcpy(util_fns, pWpaIe->OuiType, wpa_oui01,
sizeof(pWpaIe->OuiType));
pWpaIe->Ver = 1;
pWpaIe->PwsKeyCnt = 1;
pWpaIe->AuthKeyCnt = 1;
memcpy(util_fns, (void *)pWpaIe->AuthKeyList,
&pRsnConfig->AKM, sizeof(pWpaIe->AuthKeyList));
if (pRsnConfig->wpaType.wpaNone) {
memcpy(util_fns, (void *)pWpaIe->PwsKeyCipherList,
wpa_oui_none, sizeof(pWpaIe->PwsKeyCipherList));
if (pRsnConfig->mcstCipher.tkip) {
/* multicast cipher is tkip */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui02, sizeof(pWpaIe->GrpKeyCipher));
} else if (pRsnConfig->mcstCipher.ccmp) {
/* multicast cipher is aes */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui04, sizeof(pWpaIe->GrpKeyCipher));
}
} else {
if (pRsnConfig->ucstCipher.ccmp) {
/* unicast cipher is aes */
memcpy(util_fns,
(void *)pWpaIe->PwsKeyCipherList,
wpa_oui04,
sizeof(pWpaIe->PwsKeyCipherList));
} else {
/* unicast cipher is tkip */
memcpy(util_fns,
(void *)pWpaIe->PwsKeyCipherList,
wpa_oui02,
sizeof(pWpaIe->PwsKeyCipherList));
}
if (pRsnConfig->mcstCipher.ccmp) {
/* multicast cipher is aes */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui04, sizeof(pWpaIe->GrpKeyCipher));
} else if (pRsnConfig->mcstCipher.tkip) {
/* multicast cipher is tkip */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui02, sizeof(pWpaIe->GrpKeyCipher));
} else if (pRsnConfig->mcstCipher.wep104) {
/* multicast cipher is wep 104 */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui05, sizeof(pWpaIe->GrpKeyCipher));
} else {
/* multicast cipher is wep 40 */
memcpy(util_fns, (void *)pWpaIe->GrpKeyCipher,
wpa_oui01, sizeof(pWpaIe->GrpKeyCipher));
}
}
ieSize = sizeof(pWpaIe->ElementId) + sizeof(pWpaIe->Len);
ieSize += pWpaIe->Len;
}
return ieSize;
}
void
install_wpa_none_keys_internal(phostsa_private priv,
key_MgtMaterial_t *pKeyMgtData, UINT8 *pPMK,
UINT8 type, UINT8 unicast)
{
hostsa_util_fns *util_fns = &priv->util_fns;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
if (install_wpa_none_keys_internal_hook(pKeyMgtData,
pPMK, type, unicast)) {
return;
}
#endif
memset(util_fns, (void *)pKeyMgtData, 0, sizeof(key_MgtMaterial_t));
if (unicast) {
pKeyMgtData->keyInfo = (KEY_INFO_MULTICAST | KEY_INFO_ENABLED);
} else {
pKeyMgtData->keyInfo = (KEY_INFO_UNICAST | KEY_INFO_ENABLED);
}
if (type) {
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.AES.key, pPMK,
16);
pKeyMgtData->keyType = KEY_TYPE_AES;
pKeyMgtData->keyLen = WPA_AES_KEY_LEN;
} else {
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.key, pPMK,
16);
pPMK += 16;
pKeyMgtData->keyType = KEY_TYPE_TKIP;
/* in WPA none the TX & RX MIC key is the same */
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.txMicKey,
pPMK, 8);
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.rxMicKey,
pPMK, 8);
pKeyMgtData->keyLen = WPA_TKIP_KEY_LEN;
}
}
UINT16
keyMgmtGetKeySize_internal(RSNConfig_t *pRsnConfig, UINT8 isPairwise)
{
/* default to TKIP key size */
UINT16 retval = 32;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
if (keyMgmtGetKeySize_internal_hook(pRsnConfig, isPairwise, &retval)) {
return retval;
}
#endif
if (isPairwise) {
if (pRsnConfig->ucstCipher.ccmp) {
retval = 16;
}
} else {
if (pRsnConfig->mcstCipher.ccmp) {
retval = 16;
} else if (pRsnConfig->mcstCipher.wep104) {
retval = 13;
} else if (pRsnConfig->mcstCipher.wep40) {
retval = 5;
}
}
return retval;
}
//#if defined(PSK_SUPPLICANT) || defined (WPA_NONE)
void
supplicantGenerateSha1Pmkid(phostsa_private priv, UINT8 *pPMK,
IEEEtypes_MacAddr_t *pBssid,
IEEEtypes_MacAddr_t *pSta, UINT8 *pPMKID)
{
char pmkidString[] = "PMK Name";
void *pText[3];
int len[3] = { 8, 6, 6 };
pText[0] = pmkidString;
pText[1] = pBssid;
pText[2] = pSta;
Mrvl_hmac_sha1((void *)priv, (UINT8 **)pText, len, 3, pPMK, 32, /* PMK
size
is
always
32
bytes
*/
pPMKID, 16);
}
int
isApReplayCounterFresh(phostsa_private priv, keyMgmtInfoSta_t *pKeyMgmtInfoSta,
UINT8 *pRxReplayCount)
{
hostsa_util_fns *util_fns = &priv->util_fns;
UINT32 tmpHi;
UINT32 tmpLo;
UINT32 rxCountHi;
UINT32 rxCountLo;
/* initialize the value as stale */
int retVal = 0;
memcpy(util_fns, &tmpHi, pRxReplayCount, 4);
memcpy(util_fns, &tmpLo, pRxReplayCount + 4, 4);
rxCountHi = ntohl(tmpHi);
rxCountLo = ntohl(tmpLo);
/* check hi dword first */
if (rxCountHi > pKeyMgmtInfoSta->apCounterHi) {
retVal = 1;
} else if (rxCountHi == pKeyMgmtInfoSta->apCounterHi) {
/* hi dword is equal, check lo dword */
if (rxCountLo > pKeyMgmtInfoSta->apCounterLo) {
retVal = 1;
} else if (rxCountLo == pKeyMgmtInfoSta->apCounterLo) {
/* Counters are equal. Check special case of zero. */
if ((rxCountHi == 0) && (rxCountLo == 0)) {
if (!pKeyMgmtInfoSta->apCounterZeroDone) {
retVal = 1;
}
}
}
}
return retVal;
}
void
updateApReplayCounter(phostsa_private priv, keyMgmtInfoSta_t *pKeyMgmtStaInfo,
UINT8 *pRxReplayCount)
{
hostsa_util_fns *util_fns = &priv->util_fns;
UINT32 tmpHi;
UINT32 tmpLo;
UINT32 rxCountHi;
UINT32 rxCountLo;
memcpy(util_fns, &tmpHi, pRxReplayCount, 4);
memcpy(util_fns, &tmpLo, pRxReplayCount + 4, 4);
rxCountHi = ntohl(tmpHi);
rxCountLo = ntohl(tmpLo);
pKeyMgmtStaInfo->apCounterHi = rxCountHi;
pKeyMgmtStaInfo->apCounterLo = rxCountLo;
if ((rxCountHi == 0) && (rxCountLo == 0)) {
pKeyMgmtStaInfo->apCounterZeroDone = 1;
}
}
void
FillKeyMaterialStruct_internal(phostsa_private priv,
key_MgtMaterial_t *pKeyMgtData, UINT16 key_len,
UINT8 isPairwise, KeyData_t *pKey)
{
hostsa_util_fns *util_fns = &priv->util_fns;
UINT8 keyInfo;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
if (FillKeyMaterialStruct_internal_hook(pKeyMgtData,
key_len, isPairwise, pKey)) {
return;
}
#endif
/* Update key material */
memset(util_fns, (void *)pKeyMgtData, 0x00, sizeof(key_MgtMaterial_t));
/* check the key type is pairwise */
if (isPairwise) {
keyInfo = KEY_INFO_UNICAST;
} else {
keyInfo = KEY_INFO_MULTICAST;
}
if (key_len == (UINT16)WPA_AES_KEY_LEN) {
/* AES */
pKeyMgtData->keyType = KEY_TYPE_AES;
pKeyMgtData->keyInfo = keyInfo | KEY_INFO_ENABLED;
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.AES.key,
pKey->Key, key_len);
} else if (key_len == WPA_TKIP_KEY_LEN) {
pKeyMgtData->keyType = KEY_TYPE_TKIP;
pKeyMgtData->keyInfo = keyInfo | KEY_INFO_ENABLED;
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.key,
pKey->Key, TK_SIZE);
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.txMicKey,
pKey->TxMICKey, 8);
memcpy(util_fns, (UINT8 *)pKeyMgtData->keyEncypt.TKIP.rxMicKey,
pKey->RxMICKey, 8);
} else if (key_len == WPA_WEP104_KEY_LEN ||
key_len == WPA_WEP40_KEY_LEN) {
pKeyMgtData->keyType = KEY_TYPE_WEP;
pKeyMgtData->keyInfo = keyInfo | KEY_INFO_ENABLED;
if (isPairwise) {
pKeyMgtData->keyEncypt.WEP.keyIndex = 0;
pKeyMgtData->keyEncypt.WEP.isDefaultTx = 1;
} else {
/* use the Key index provided */
pKeyMgtData->keyEncypt.WEP.keyIndex = pKey->KeyIndex;
pKeyMgtData->keyEncypt.WEP.isDefaultTx = 0;
}
memcpy(util_fns, (UINT8 *)(pKeyMgtData->keyEncypt.WEP.key),
pKey->Key, key_len);
} else {
/* Key length does not match ** don't send down anything */
return;
}
pKeyMgtData->keyLen = key_len;
}
//#endif
/*
** This function checks if the given element pointer parameter
** is a KDE or not (returns NULL)
*/
KDE_t *
parseKeyKDE(phostsa_private priv, IEEEtypes_InfoElementHdr_t *pIe)
{
hostsa_util_fns *util_fns = &priv->util_fns;
KDE_t *pKde = NULL;
if (pIe->ElementId == ELEM_ID_VENDOR_SPECIFIC) {
pKde = (KDE_t *)pIe;
if (pKde->length > sizeof(KDE_t) &&
!memcmp(util_fns, (void *)pKde->OUI, kde_oui,
sizeof(kde_oui))) {
return pKde;
}
}
return NULL;
}
/* This function searches KDE_DATA_TYPE_XXX in KDE. We can collect all such
** KDE_DATA_TYPE_XXX in one pass, however, there seems not much benefit
** as in general there would not be many KDE_DATA_TYPE_XXX present.
** Returns NULL, when KDE_DATA_TYPE_XXX not found.
*/
KDE_t *
parseKeyKDE_DataType(phostsa_private priv, UINT8 *pData,
SINT32 dataLen, IEEEtypes_KDEDataType_e KDEDataType)
{
IEEEtypes_InfoElementHdr_t *pIe;
KDE_t *pKde;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
UINT32 ptr_val;
if (parseKeyKDE_DataType_hook(pData, dataLen, KDEDataType, &ptr_val)) {
return (KDE_t *)ptr_val;
}
#endif
if (pData == NULL) {
return NULL;
}
while (dataLen > (SINT32)sizeof(IEEEtypes_InfoElementHdr_t)) {
pIe = (IEEEtypes_InfoElementHdr_t *)pData;
if (pIe->ElementId == ELEM_ID_VENDOR_SPECIFIC) {
pKde = parseKeyKDE(priv, pIe);
if ((pKde != NULL) && (pKde->dataType == KDEDataType)) {
return pKde;
} else if (pIe->Len == 0) {
/* the rest is padding, so adjust the length **
to stop the processing loop */
dataLen = sizeof(IEEEtypes_InfoElementHdr_t);
}
}
dataLen -= (pIe->Len + sizeof(IEEEtypes_InfoElementHdr_t));
pData += (pIe->Len + sizeof(IEEEtypes_InfoElementHdr_t));
}
return NULL;
}
KDE_t *
parseKeyDataGTK(phostsa_private priv, UINT8 *pKey, UINT16 len,
KeyData_t *pGRKey)
{
hostsa_util_fns *util_fns = &priv->util_fns;
GTK_KDE_t *pGtk;
KDE_t *pKde;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
UINT32 ptr_val;
if (parseKeyDataGTK_hook(pKey, len, pGRKey, &ptr_val)) {
return (KDE_t *)ptr_val;
}
#endif
/* parse KDE GTK */
pKde = parseKeyKDE_DataType(priv, pKey, len, KDE_DATA_TYPE_GTK);
if (pKde) {
/* GTK KDE */
pGtk = (GTK_KDE_t *)pKde->data;
/* The KDE overhead is 6 bytes */
memcpy(util_fns, pGRKey->Key, (void *)pGtk->GTK,
pKde->length - 6);
/* save the group key index */
pGRKey->KeyIndex = pGtk->KeyID;
}
return pKde;
}
void
KeyMgmtSta_ApplyKEK(phostsa_private priv, EAPOL_KeyMsg_t *pKeyMsg,
KeyData_t *pGRKey, UINT8 *EAPOL_Encr_Key)
{
#if 0
#if !defined(REMOVE_PATCH_HOOKS)
if (KeyMgmtSta_ApplyKEK_hook(pKeyMsg, pGRKey, EAPOL_Encr_Key)) {
return;
}
#endif
#endif
pGRKey->TxIV16 = pKeyMsg->key_RSC[1] << 8;
pGRKey->TxIV16 |= pKeyMsg->key_RSC[0];
pGRKey->TxIV32 = 0xFFFFFFFF;
pKeyMsg->key_material_len = ntohs(pKeyMsg->key_material_len) & 0xFFFF;
switch (pKeyMsg->key_info.KeyDescriptorVersion) {
/*
** Key Descriptor Version 2 or 3: AES key wrap, defined in IETF
** RFC 3394, shall be used to encrypt the Key Data field using
** the KEK field from the derived PTK.
*/
case 3:
case 2:
/* CCMP */
MRVL_AesUnWrap(EAPOL_Encr_Key,
2,
pKeyMsg->key_material_len / 8 - 1,
(UINT8 *)pKeyMsg->key_data,
NULL, (UINT8 *)pKeyMsg->key_data);
/* AES key wrap has 8 extra bytes that come out ** due to the
default IV */
pKeyMsg->key_material_len -= 8;
break;
/*
** Key Descriptor Version 1: ARC4 is used to encrypt the Key Data
** field using the KEK field from the derived PTK
*/
default:
case 1:
/* TKIP or WEP */
/* Skip the first 256 bytes of the RC4 Stream */
RC4_Encrypt((void *)priv, EAPOL_Encr_Key,
(UINT8 *)pKeyMsg->EAPOL_key_IV,
sizeof(pKeyMsg->EAPOL_key_IV),
(UINT8 *)pKeyMsg->key_data,
pKeyMsg->key_material_len, 256);
break;
}
}
/*
** Verifies the received EAPOL frame during 4-way handshake or
** group key handshake
*/
BOOLEAN
KeyMgmtSta_IsRxEAPOLValid(phostsa_private priv,
keyMgmtInfoSta_t *pKeyMgmtInfoSta,
EAPOL_KeyMsg_t *pKeyMsg)
{
hostsa_util_fns *util_fns = &priv->util_fns;
#if 0 // !defined(REMOVE_PATCH_HOOKS)
BOOLEAN ptr_val;
if (KeyMgmtSta_IsRxEAPOLValid_hook(pKeyMgmtInfoSta, pKeyMsg, &ptr_val)) {
return ptr_val;
}
#endif
if (!pKeyMgmtInfoSta || !pKeyMsg) {
PRINTM(MERROR, "KeyMgmtSta_IsRxEAPOLValid input not valid\n");
return FALSE;
}
if (!isApReplayCounterFresh
(priv, pKeyMgmtInfoSta, (UINT8 *)pKeyMsg->replay_cnt)) {
PRINTM(MERROR,
"KeyMgmtSta_IsRxEAPOLValid isApReplayCounterFresh Fail\n");
return FALSE;
}
/* Check if we have to verify MIC */
if (pKeyMsg->key_info.KeyMIC) {
/* We have to verify MIC, if keyType is 1 it's the 3rd message
in 4-way handshake, in that case verify ANonce. */
if ((pKeyMsg->key_info.KeyType == 1) &&
memcmp(util_fns, (UINT8 *)&pKeyMsg->key_nonce,
(UINT8 *)pKeyMgmtInfoSta->ANonce, NONCE_SIZE) != 0) {
/* Dropping the packet, return some error msg. */
PRINTM(MERROR,
"KeyMgmtSta_IsRxEAPOLValid Nonce check Fail\n");
return FALSE;
}
if (!IsEAPOL_MICValid
(priv, pKeyMsg, pKeyMgmtInfoSta->EAPOL_MIC_Key)) {
/* MIC failed */
PRINTM(MERROR,
"KeyMgmtSta_IsRxEAPOLValid MIC check Fail\n");
return FALSE;
}
}
return TRUE;
}
/*
** This function populates EAPOL frame fileds that are common
** to message 2, 4 of 4-way handshake and group key hadshake
** message 2.
** Any of these fields in general should not change, and if needed
** can be overwritten in the caller function.
*/
void
KeyMgmtSta_PrepareEAPOLFrame(phostsa_private priv, EAPOL_KeyMsg_Tx_t *pTxEapol,
EAPOL_KeyMsg_t *pRxEapol,
t_u8 *da, t_u8 *sa, UINT8 *pSNonce)
{
hostsa_util_fns *util_fns = &priv->util_fns;
if (!pTxEapol || !pRxEapol) {
return;
}
memset(util_fns, (UINT8 *)pTxEapol, 0x00, sizeof(EAPOL_KeyMsg_Tx_t));
formEAPOLEthHdr(priv, pTxEapol, da, sa);
pTxEapol->keyMsg.desc_type = pRxEapol->desc_type;
pTxEapol->keyMsg.key_info.KeyType = pRxEapol->key_info.KeyType;
pTxEapol->keyMsg.key_info.KeyMIC = 1;
pTxEapol->keyMsg.key_info.Secure = pRxEapol->key_info.Secure;
pTxEapol->keyMsg.replay_cnt[0] = pRxEapol->replay_cnt[0];
pTxEapol->keyMsg.replay_cnt[1] = pRxEapol->replay_cnt[1];
pTxEapol->keyMsg.key_info.KeyDescriptorVersion
= pRxEapol->key_info.KeyDescriptorVersion;
// Only for 4-w handshake message 2.
if (pSNonce) {
memcpy(util_fns, (UINT8 *)pTxEapol->keyMsg.key_nonce, pSNonce,
NONCE_SIZE);
}
}
void
KeyMgmtSta_PrepareEAPOLMicErrFrame(phostsa_private priv,
EAPOL_KeyMsg_Tx_t *pTxEapol,
BOOLEAN isUnicast, IEEEtypes_MacAddr_t *da,
IEEEtypes_MacAddr_t *sa,
keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
hostsa_util_fns *util_fns = &priv->util_fns;
if (!pTxEapol || !pKeyMgmtInfoSta) {
return;
}
memset(util_fns, (UINT8 *)pTxEapol, 0x00, sizeof(EAPOL_KeyMsg_Tx_t));
formEAPOLEthHdr(priv, pTxEapol, (t_u8 *)da, (t_u8 *)sa);
pTxEapol->keyMsg.key_info.KeyType = isUnicast;
pTxEapol->keyMsg.key_info.KeyMIC = 1;
pTxEapol->keyMsg.key_info.Secure = 1;
pTxEapol->keyMsg.key_info.Error = 1;
pTxEapol->keyMsg.key_info.Request = 1;
pTxEapol->keyMsg.replay_cnt[0] = htonl(pKeyMgmtInfoSta->staCounterHi);
pTxEapol->keyMsg.replay_cnt[1] = htonl(pKeyMgmtInfoSta->staCounterLo);
}
BOOLEAN
supplicantAkmIsWpaWpa2(phostsa_private priv, AkmSuite_t *pAkm)
{
hostsa_util_fns *util_fns = &priv->util_fns;
if (!memcmp(util_fns, pAkm->akmOui, wpa_oui, sizeof(wpa_oui)) ||
!memcmp(util_fns, pAkm->akmOui, kde_oui, sizeof(kde_oui))) {
return TRUE;
}
return FALSE;
}
BOOLEAN
supplicantAkmIsWpa2(phostsa_private priv, AkmSuite_t *pAkm)
{
hostsa_util_fns *util_fns = &priv->util_fns;
if (memcmp(util_fns, pAkm->akmOui, kde_oui, sizeof(kde_oui)) == 0) {
return TRUE;
}
return FALSE;
}
BOOLEAN
supplicantAkmIsWpaWpa2Psk(phostsa_private priv, AkmSuite_t *pAkm)
{
if (supplicantAkmIsWpaWpa2(priv, pAkm)) {
return ((pAkm->akmType == AKM_PSK) ||
(pAkm->akmType == AKM_SHA256_PSK) ||
(pAkm->akmType == AKM_FT_PSK));
}
return FALSE;
}
BOOLEAN
supplicantAkmUsesKdf(phostsa_private priv, AkmSuite_t *pAkm)
{
if (supplicantAkmIsWpa2(priv, pAkm)) {
if ((pAkm->akmType == AKM_SHA256_PSK) ||
(pAkm->akmType == AKM_SHA256_1X) ||
(pAkm->akmType == AKM_FT_PSK) ||
(pAkm->akmType == AKM_FT_1X)) {
return TRUE;
}
}
return FALSE;
}
BOOLEAN
supplicantAkmWpa2Ft(phostsa_private priv, AkmSuite_t *pAkm)
{
if (supplicantAkmIsWpa2(priv, pAkm)) {
if ((pAkm->akmType == AKM_FT_PSK) ||
(pAkm->akmType == AKM_FT_1X)) {
return TRUE;
}
}
return FALSE;
}
BOOLEAN
supplicantAkmUsesSha256Pmkid(phostsa_private priv, AkmSuite_t *pAkm)
{
if (supplicantAkmIsWpa2(priv, pAkm)) {
if ((pAkm->akmType == AKM_SHA256_PSK) ||
(pAkm->akmType == AKM_SHA256_1X)) {
return TRUE;
}
}
return FALSE;
}
void
supplicantGenerateSha256Pmkid(phostsa_private priv, UINT8 *pPMK,
IEEEtypes_MacAddr_t *pBssid,
IEEEtypes_MacAddr_t *pSta, UINT8 *pPMKID)
{
hostsa_util_fns *util_fns = &priv->util_fns;
UINT8 *pOutput;
UINT8 *vectors[3];
size_t vectLen[NELEMENTS(vectors)];
UINT8 buf[500] = { 0 };
pOutput = (UINT8 *)buf;
/*
** PMKID = Truncate-128(SHA-256("PMK Name" || AA || SPA)
*/
vectors[0] = (UINT8 *)"PMK Name";
vectLen[0] = 8; /* strlen("PMK Name") */
vectors[1] = (UINT8 *)pBssid;
vectLen[1] = sizeof(IEEEtypes_MacAddr_t);
vectors[2] = (UINT8 *)pSta;
vectLen[2] = sizeof(IEEEtypes_MacAddr_t);
mrvl_sha256_crypto_vector((void *)priv, NELEMENTS(vectors), vectors,
vectLen, pOutput);
memcpy(util_fns, pPMKID, pOutput, PMKID_LEN);
}
BOOLEAN
supplicantGetPmkid(phostsa_private priv, IEEEtypes_MacAddr_t *pBssid,
IEEEtypes_MacAddr_t *pStaAddr,
AkmSuite_t *pAkm, UINT8 *pPMKID)
{
BOOLEAN retval;
UINT8 *pPMK;
retval = FALSE;
if (!supplicantAkmIsWpaWpa2Psk(priv, pAkm)) {
pPMK = pmkCacheFindPMK((void *)priv, pBssid);
/* found the PMK so generate the PMKID */
if (pPMK) {
if (supplicantAkmUsesSha256Pmkid(priv, pAkm)) {
supplicantGenerateSha256Pmkid(priv, pPMK,
pBssid, pStaAddr,
pPMKID);
} else {
supplicantGenerateSha1Pmkid(priv, pPMK, pBssid,
pStaAddr, pPMKID);
}
retval = TRUE;
}
}
return retval;
}
EAPOL_KeyMsg_t *
GetKeyMsgNonceFromEAPOL(phostsa_private priv, mlan_buffer *pmbuf,
keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
hostsa_util_fns *util_fns = &priv->util_fns;
EAPOL_KeyMsg_t *pKeyMsg =
(EAPOL_KeyMsg_t *)(pmbuf->pbuf + pmbuf->data_offset +
sizeof(ether_hdr_t));;
if (!KeyMgmtSta_IsRxEAPOLValid(priv, pKeyMgmtInfoSta, pKeyMsg)) {
PRINTM(MERROR, "KeyMgmtSta_IsRxEAPOLValid Fail\n");
return NULL;
}
/* Generate Nonce if this is first PWK Message */
if (pKeyMsg->key_info.KeyMIC == 0) {
memcpy(util_fns, pKeyMgmtInfoSta->ANonce,
pKeyMsg->key_nonce, NONCE_SIZE);
supplicantGenerateRand(priv, pKeyMgmtInfoSta->SNonce,
NONCE_SIZE);
}
return pKeyMsg;
}
#ifndef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
EAPOL_KeyMsg_t *
ProcessRxEAPOL_PwkMsg3(phostsa_private priv, mlan_buffer *pmbuf,
keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
hostsa_util_fns *util_fns = &priv->util_fns;
EAPOL_KeyMsg_t *pKeyMsg;
pKeyMsg = GetKeyMsgNonceFromEAPOL(priv, pmbuf, pKeyMgmtInfoSta);
if (!pKeyMsg) {
PRINTM(MERROR, "ProcessRxEAPOL_PwkMsg3 pKeyMsg is NULL\n");
return NULL;
}
pKeyMgmtInfoSta->newPWKey.TxIV16 = 1;
pKeyMgmtInfoSta->newPWKey.TxIV32 = 0;
/* look for group key once the pairwise has been plumbed */
if (pKeyMsg->key_info.EncryptedKeyData) {
/* I think the timer stop should be moved later on in case
ramHook_Process_CCX_MFP_11r returns FALSE */
// microTimerStop(pKeyMgmtInfoSta->rsnTimer);
util_fns->moal_stop_timer(util_fns->pmoal_handle,
pKeyMgmtInfoSta->rsnTimer);
// pKeyMgmtInfoSta->rsnTimer = 0;
KeyMgmtSta_ApplyKEK(priv, pKeyMsg,
&pKeyMgmtInfoSta->GRKey,
pKeyMgmtInfoSta->EAPOL_Encr_Key);
#if 0
if (ramHook_keyMgmtProcessMsgExt(pKeyMgmtInfoSta, pKeyMsg) ==
FALSE) {
return NULL;
}
#endif
parseKeyDataGTK(priv, pKeyMsg->key_data,
pKeyMsg->key_material_len,
&pKeyMgmtInfoSta->GRKey);
}
return pKeyMsg;
}
#endif
#ifndef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
EAPOL_KeyMsg_t *
ProcessRxEAPOL_GrpMsg1(phostsa_private priv, mlan_buffer *pmbuf,
keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
hostsa_util_fns *util_fns = &priv->util_fns;
EAPOL_KeyMsg_t *pKeyMsg;
pKeyMsg = GetKeyMsgNonceFromEAPOL(priv, pmbuf, pKeyMgmtInfoSta);
if (!pKeyMsg) {
return NULL;
}
KeyMgmtSta_ApplyKEK(priv, pKeyMsg,
&pKeyMgmtInfoSta->GRKey,
pKeyMgmtInfoSta->EAPOL_Encr_Key);
pKeyMgmtInfoSta->RSNDataTrafficEnabled = 1;
// microTimerStop(pKeyMgmtInfoSta->rsnTimer);
util_fns->moal_stop_timer(util_fns->pmoal_handle,
pKeyMgmtInfoSta->rsnTimer);
// pKeyMgmtInfoSta->rsnTimer = 0;
/* Decrypt the group key */
if (pKeyMsg->desc_type == 2) {
/* WPA2 */
/* handle it according to 802.11i GTK frame format */
parseKeyDataGTK(priv, pKeyMsg->key_data,
pKeyMsg->key_material_len,
&pKeyMgmtInfoSta->GRKey);
#if 0
if (ramHook_keyMgmtProcessMsgExt(pKeyMgmtInfoSta, pKeyMsg) ==
FALSE) {
return NULL;
}
#endif
} else {
/* WPA or Dynamic WEP */
memcpy(util_fns, pKeyMgmtInfoSta->GRKey.Key,
pKeyMsg->key_data, pKeyMsg->key_material_len);
pKeyMgmtInfoSta->GRKey.KeyIndex = pKeyMsg->key_info.KeyIndex;
}
return pKeyMsg;
}
#endif
void
KeyMgmtResetCounter(keyMgmtInfoSta_t *pKeyMgmtInfo)
{
if (pKeyMgmtInfo) {
pKeyMgmtInfo->staCounterHi = 0;
pKeyMgmtInfo->staCounterLo = 0;
}
}
/*
** This code executes when the MIC failure timer timesout
*/
void
MicErrTimerExp_Sta(t_void *context)
{
phostsa_private psapriv = (phostsa_private)context;
keyMgmtInfoSta_t *pKeyMgmtInfo = &psapriv->suppData->keyMgmtInfoSta;
if (pKeyMgmtInfo) {
// if (pKeyMgmtInfo->micTimer == timerId)
{
if (pKeyMgmtInfo->sta_MIC_Error.status
== SECOND_MIC_FAIL_IN_60_SEC) {
// ramHook_keyMgmtSendTkipQuietOver(data);
}
pKeyMgmtInfo->sta_MIC_Error.status = NO_MIC_FAILURE;
pKeyMgmtInfo->sta_MIC_Error.disableStaAsso = 0;
}
pKeyMgmtInfo->micTimer = 0;
}
}
void
DeauthDelayTimerExp_Sta(t_void *context)
{
phostsa_private psapriv = (phostsa_private)context;
keyMgmtInfoSta_t *pKeyMgmtInfoSta = &psapriv->suppData->keyMgmtInfoSta;
if (pKeyMgmtInfoSta) {
// if (pKeyMgmtInfoSta->deauthDelayTimer == timerId)
{
if (pKeyMgmtInfoSta->sta_MIC_Error.status
== SECOND_MIC_FAIL_IN_60_SEC) {
// ramHook_keyMgmtSendDeauth(psapriv,
// IEEEtypes_REASON_MIC_FAILURE);
keyMgmtSendDeauth2Peer(psapriv,
IEEEtypes_REASON_MIC_FAILURE);
}
}
pKeyMgmtInfoSta->deauthDelayTimer = 0;
}
}
/*
** Key Management timeout handler
*/
void
keyMgmtStaRsnSecuredTimeoutHandler(t_void *context)
{
phostsa_private psapriv = (phostsa_private)context;
keyMgmtInfoSta_t *pKeyMgmtInfoSta = &psapriv->suppData->keyMgmtInfoSta;
if (pKeyMgmtInfoSta) {
// if (pKeyMgmtInfoSta->rsnTimer == timerId)
{
if (pKeyMgmtInfoSta->RSNSecured == FALSE) {
/* Clear timer before calling the timeout so
the rsnTimer ** can't be cancelled during
the sme state clearing. ** (caused timer
re-entrancy failure). */
// pKeyMgmtInfoSta->rsnTimer = 0;
// ramHook_keyMgmtSendDeauth(
// psapriv,
// IEEEtypes_REASON_4WAY_HANDSHK_TIMEOUT);
keyMgmtSendDeauth2Peer(psapriv,
IEEEtypes_REASON_4WAY_HANDSHK_TIMEOUT);
}
}
// pKeyMgmtInfoSta->rsnTimer = 0;
}
}
void
keyMgmtSta_StartSession_internal(phostsa_private priv,
keyMgmtInfoSta_t *pKeyMgmtInfoSta,
// MicroTimerCallback_t callback,
UINT32 expiry, UINT8 flags)
{
hostsa_util_fns *util_fns = &priv->util_fns;
if (!pKeyMgmtInfoSta->sta_MIC_Error.disableStaAsso) {
// microTimerStop(pKeyMgmtInfoSta->rsnTimer);
util_fns->moal_stop_timer(util_fns->pmoal_handle,
pKeyMgmtInfoSta->rsnTimer);
// pKeyMgmtInfoSta->rsnTimer = 0;
// microTimerStart(callback,
// (UINT32)pKeyMgmtInfoSta,
// expiry,
// &pKeyMgmtInfoSta->rsnTimer,
// flags);
util_fns->moal_start_timer(util_fns->pmoal_handle,
pKeyMgmtInfoSta->rsnTimer, MFALSE,
expiry);
}
/* reset the authenticator replay counter */
pKeyMgmtInfoSta->apCounterLo = 0;
pKeyMgmtInfoSta->apCounterHi = 0;
pKeyMgmtInfoSta->apCounterZeroDone = 0;
}
void
KeyMgmtSta_handleMICDeauthTimer(keyMgmtInfoSta_t *pKeyMgmtInfoSta,
MicroTimerCallback_t callback,
UINT32 expiry, UINT8 flags)
{
#if 0
microTimerStop(pKeyMgmtInfoSta->deauthDelayTimer);
microTimerStart(callback,
(UINT32)pKeyMgmtInfoSta,
expiry, &pKeyMgmtInfoSta->deauthDelayTimer, flags);
#endif
}
#ifndef WAR_ROM_BUG57216_QUIET_TIME_INTERVAL
/* This function assumes that argument state would be either
NO_MIC_FAILURE or FIRST_MIC_FAIL_IN_60_SEC
It must not be called with state othe than these two
*/
void
KeyMgmtSta_handleMICErr(MIC_Fail_State_e state,
keyMgmtInfoSta_t *pKeyMgmtInfoSta,
MicroTimerCallback_t callback, UINT8 flags)
{
UINT32 expiry;
// UINT32 int_save = tx_interrupt_control(TX_INT_DISABLE);
if (state == NO_MIC_FAILURE) {
/* First MIC failure */
pKeyMgmtInfoSta->sta_MIC_Error.status =
FIRST_MIC_FAIL_IN_60_SEC;
expiry = MIC_ERROR_CHECK_TIME_INTERVAL;
} else {
/* Received 2 MIC failures within 60 sec. Do deauth from AP */
pKeyMgmtInfoSta->sta_MIC_Error.disableStaAsso = 1;
pKeyMgmtInfoSta->sta_MIC_Error.status =
SECOND_MIC_FAIL_IN_60_SEC;
pKeyMgmtInfoSta->apCounterHi = 0;
pKeyMgmtInfoSta->apCounterLo = 0;
expiry = MIC_ERROR_QUIET_TIME_INTERVAL;
}
// tx_interrupt_control(int_save);
#if 0
microTimerStop(pKeyMgmtInfoSta->micTimer);
microTimerStart(callback,
(UINT32)pKeyMgmtInfoSta,
expiry, &pKeyMgmtInfoSta->micTimer, flags);
#endif
}
#endif
/*
** Initialize the Key Mgmt session
*/
void
KeyMgmtSta_InitSession(phostsa_private priv, keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
hostsa_util_fns *util_fns = &priv->util_fns;
pKeyMgmtInfoSta->RSNDataTrafficEnabled = FALSE;
pKeyMgmtInfoSta->RSNSecured = FALSE;
pKeyMgmtInfoSta->pRxDecryptKey = NULL;
pKeyMgmtInfoSta->pwkHandshakeComplete = FALSE;
if (!pKeyMgmtInfoSta->sta_MIC_Error.disableStaAsso) {
// microTimerStop(pKeyMgmtInfoSta->micTimer);
pKeyMgmtInfoSta->micTimer = 0;
// microTimerStop(pKeyMgmtInfoSta->deauthDelayTimer);
pKeyMgmtInfoSta->deauthDelayTimer = 0;
}
// microTimerStop(pKeyMgmtInfoSta->rsnTimer);
util_fns->moal_stop_timer(util_fns->pmoal_handle,
pKeyMgmtInfoSta->rsnTimer);
// pKeyMgmtInfoSta->rsnTimer = 0;
}