/** @file keyMgmtsta_rom.c * * @brief This file defines key management function for sta * * 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 ******************************************************/ #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; KeyData_t GRKey; 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, &GRKey); /* Not install same GTK */ if (!memcmp (util_fns, pKeyMgmtInfoSta->GRKey.Key, GRKey.Key, TK_SIZE)) { priv->gtk_installed = 1; } else { memcpy(util_fns, &pKeyMgmtInfoSta->GRKey, &GRKey, sizeof(KeyData_t)); pKeyMgmtInfoSta->GRKey.TxIV16 = GRKey.TxIV16; pKeyMgmtInfoSta->GRKey.TxIV32 = 0xFFFFFFFF; priv->gtk_installed = 0; } #if 0 if (ramHook_keyMgmtProcessMsgExt(pKeyMgmtInfoSta, pKeyMsg) == FALSE) { return NULL; } #endif } else { /* WPA or Dynamic WEP */ if (!memcmp (util_fns, pKeyMgmtInfoSta->GRKey.Key, pKeyMsg->key_data, pKeyMsg->key_material_len)) { priv->gtk_installed = 1; } else { 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; }