| /** @file keyMgntAP.c |
| * |
| * @brief This file defined the eapol paket process and key management for authenticator |
| * |
| * 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 |
| ******************************************************/ |
| //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 (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; |
| #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_HEADER_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 = (phostsa_private)connPtr->priv; |
| // UINT32 int_save; |
| apInfo_t *pApInfo = &priv->apinfo; |
| |
| if (connPtr == NULL) { |
| // no AP connection. Do nothing, just return |
| return; |
| } |
| |
| 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; |
| } |