| /** @file AssocAp_src_rom.c |
| * |
| * @brief This file defines the function for checking security type and ie |
| * |
| * 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 "hostsa_ext_def.h" |
| #include "IEEE_types.h" |
| |
| #include "authenticator.h" |
| #include "AssocAp_srv_rom.h" |
| #include "parser.h" |
| #include "keyMgmtAp.h" |
| |
| BOOLEAN |
| AssocSrvAp_checkCipherSupport(Cipher_t cipher, Cipher_t allowedCiphers) |
| { |
| BOOLEAN match = FALSE; |
| |
| if (cipher.ccmp && (allowedCiphers.ccmp)) { |
| match = TRUE; |
| } else if (cipher.tkip && (allowedCiphers.tkip)) { |
| match = TRUE; |
| } else if (cipher.wep40 && (allowedCiphers.wep40)) { |
| match = TRUE; |
| } else if (cipher.wep104 && (allowedCiphers.wep104)) { |
| match = TRUE; |
| } |
| |
| return match; |
| } |
| |
| UINT16 |
| AssocSrvAp_checkAkm(phostsa_private priv, AkmSuite_t *pAkm, UINT16 allowedAkms) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| UINT16 matchedAkms; |
| |
| matchedAkms = 0; |
| |
| if ((memcmp(util_fns, pAkm->akmOui, wpa_oui, sizeof(wpa_oui)) != 0) && |
| ((memcmp(util_fns, pAkm->akmOui, kde_oui, sizeof(kde_oui)) != 0))) { |
| return matchedAkms; |
| } |
| |
| switch (pAkm->akmType) { |
| case IEEEtypes_RSN_AUTH_KEY_SUITE_8021X: |
| matchedAkms = (allowedAkms & UAP_HOSTCMD_KEYMGMT_EAP); |
| break; |
| |
| case IEEEtypes_RSN_AUTH_KEY_SUITE_PSK: |
| matchedAkms = (allowedAkms & UAP_HOSTCMD_KEYMGMT_PSK); |
| break; |
| case IEEEtypes_AKM_SUITE_PSK_SHA256: |
| matchedAkms = (allowedAkms & UAP_HOSTCMD_KEYMGMT_PSK_SHA256); |
| break; |
| default: |
| break; |
| } |
| |
| return matchedAkms; |
| } |
| |
| WL_STATUS |
| assocSrvAp_validate4WayHandshakeIe(phostsa_private priv, |
| SecurityMode_t secType, |
| Cipher_t pwCipher, |
| Cipher_t grpCipher, |
| apKeyMgmtInfoStaRom_t *pKeyMgmtInfo, |
| UINT8 akmType, |
| UINT16 rsnCap, Cipher_t config_mcstCipher) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| |
| if (memcmp |
| (util_fns, (void *)&secType, (void *)&pKeyMgmtInfo->staSecType, |
| sizeof(secType)) != 0) { |
| return FAIL; |
| } |
| |
| if (memcmp(util_fns, (void *)&grpCipher, |
| (void *)&config_mcstCipher, sizeof(grpCipher)) != 0) { |
| return FAIL; |
| } |
| |
| if (memcmp |
| (util_fns, (void *)&pwCipher, (void *)&pKeyMgmtInfo->staUcstCipher, |
| sizeof(pwCipher)) != 0) { |
| return FAIL; |
| } |
| |
| if (akmType != pKeyMgmtInfo->staAkmType) { |
| |
| return FAIL; |
| } |
| |
| return SUCCESS; |
| } |
| |
| void |
| AssocSrvAp_InitKeyMgmtInfo(phostsa_private priv, |
| apKeyMgmtInfoStaRom_t *pKeyMgmtInfo, |
| SecurityMode_t *secType, Cipher_t *pwCipher, |
| UINT16 staRsnCap, UINT8 akmType) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| pKeyMgmtInfo->keyMgmtState = HSK_NOT_STARTED; |
| memcpy(util_fns, (void *)&pKeyMgmtInfo->staSecType, (void *)secType, |
| sizeof(SecurityMode_t)); |
| memcpy(util_fns, (void *)&pKeyMgmtInfo->staUcstCipher, (void *)pwCipher, |
| sizeof(Cipher_t)); |
| pKeyMgmtInfo->staAkmType = akmType; |
| if (secType->wpa2) { |
| pKeyMgmtInfo->staRsnCap = staRsnCap; |
| } |
| } |
| |
| void |
| AssocSrvAp_InitStaKeyInfo(cm_Connection *connPtr, |
| SecurityMode_t *secType, |
| Cipher_t *pwCipher, UINT16 staRsnCap, UINT8 akmType) |
| { |
| apKeyMgmtInfoSta_t *pKeyMgmtInfo; |
| |
| phostsa_private priv = (phostsa_private)connPtr->priv; |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| |
| KeyMgmtStopHskTimer(connPtr); |
| |
| pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo; |
| memset(util_fns, (void *)pKeyMgmtInfo, 0x00, |
| sizeof(apKeyMgmtInfoSta_t)); |
| AssocSrvAp_InitKeyMgmtInfo(priv, &pKeyMgmtInfo->rom, secType, pwCipher, |
| staRsnCap, akmType); |
| pKeyMgmtInfo->EAPOLProtoVersion = EAPOL_PROTOCOL_V1; |
| } |
| |
| WL_STATUS |
| assocSrvAp_checkRsnWpa(cm_Connection *connPtr, |
| apKeyMgmtInfoStaRom_t *pKeyMgmtInfo, |
| Cipher_t apWpaCipher, |
| Cipher_t apWpa2Cipher, |
| Cipher_t apMcstCipher, |
| UINT16 apAuthKey, |
| SecurityMode_t *pSecType, |
| IEEEtypes_RSNElement_t *pRsn, |
| IEEEtypes_WPAElement_t *pWpa, |
| BOOLEAN validate4WayHandshakeIE) |
| { |
| phostsa_private priv = (phostsa_private)connPtr->priv; |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| WL_STATUS result = SUCCESS; |
| Cipher_t apCipher; |
| Cipher_t pwCipher; |
| Cipher_t grpCipher; |
| SecurityMode_t wpaType; |
| AkmSuite_t akm[AKM_SUITE_MAX]; |
| UINT8 minimumRsnLen; |
| |
| /* staRsnCap field is only used to compare RsnCap received in |
| AssocRequest with rsnCap received in 4 way handshake PWKMsg2. |
| |
| we use 0xFFFF signature. If rsnCap is not present in pRsn, |
| signature 0xFFFF would be saved in pKeyMgmtInfo->staRsnCap. */ |
| |
| union { |
| UINT16 shortInt; |
| IEEEtypes_RSNCapability_t cfg; |
| } staRsnCap; |
| |
| memset(util_fns, &wpaType, 0x00, sizeof(wpaType)); |
| memset(util_fns, &apCipher, 0x00, sizeof(apCipher)); |
| staRsnCap.shortInt = 0xFFFF; |
| |
| if (pRsn && (pSecType->wpa2 == 1)) { |
| |
| /* |
| In pRsn , All elements after Ver field are optional per the |
| spec. |
| |
| we reject Assoc Request, if GrpKeyCipher, pwsKey and AuthKey |
| is not present. |
| |
| we can rely on minimum length check as we are rejecting |
| Assoc Request having pwsKeyCnt > 1 and AuthKeyCnt > 1 |
| |
| */ |
| |
| minimumRsnLen = (unsigned long)&pRsn->RsnCap - |
| (unsigned long)&pRsn->Ver; |
| |
| if (pRsn->Len < minimumRsnLen) { |
| PRINTM(MERROR, "pRsn->Len %x < minimumRsnLen %x\n", |
| pRsn->Len, minimumRsnLen); |
| return FAIL; |
| } |
| |
| if (pRsn->PwsKeyCnt == 1 && pRsn->AuthKeyCnt == 1) { |
| apCipher = apWpa2Cipher; |
| |
| supplicantParseRsnIe(priv, pRsn, |
| &wpaType, |
| &grpCipher, |
| &pwCipher, |
| akm, |
| NELEMENTS(akm), |
| &staRsnCap.cfg, NULL); |
| } else { |
| PRINTM(MERROR, |
| "pRsn->PwsKeyCnt %x pRsn->AuthKeyCnt %x\n", |
| pRsn->PwsKeyCnt, pRsn->AuthKeyCnt); |
| result = FAIL; |
| } |
| } else if (pWpa && (pSecType->wpa == 1)) { |
| if (pWpa->PwsKeyCnt == 1 && pWpa->AuthKeyCnt == 1) { |
| apCipher = apWpaCipher; |
| supplicantParseWpaIe(priv, pWpa, |
| &wpaType, |
| &grpCipher, |
| &pwCipher, akm, NELEMENTS(akm)); |
| } else { |
| PRINTM(MERROR, |
| "pWpa->PwsKeyCnt %x pWpa->AuthKeyCnt %x\n", |
| pWpa->PwsKeyCnt, pWpa->AuthKeyCnt); |
| result = FAIL; |
| } |
| } else { |
| PRINTM(MERROR, "No wpa or rsn\n"); |
| result = FAIL; |
| } |
| |
| if ((pwCipher.ccmp == 0) && (pwCipher.tkip == 0)) { |
| PRINTM(MERROR, |
| "(pwCipher.ccmp(%x) == 0) && (pwCipher.tkip(%x) == 0)\n", |
| pwCipher.ccmp, pwCipher.tkip); |
| result = FAIL; |
| } |
| |
| if ((grpCipher.ccmp == 0) && (grpCipher.tkip == 0)) { |
| PRINTM(MERROR, |
| "((grpCipher.ccmp(%x) == 0) && (grpCipher.tkip(%x) == 0))\n", |
| grpCipher.ccmp, grpCipher.tkip); |
| result = FAIL; |
| } |
| DBG_HEXDUMP(MCMD_D, " akm", (t_u8 *)&akm[0], sizeof(AkmSuite_t)); |
| if (SUCCESS == result) { |
| #ifdef DOT11W |
| if (staRsnCap.shortInt != 0xFFFF) { |
| /* Save the peer STA PMF capability, which will later |
| used to enable PMF */ |
| connPtr->staData.peerPMFCapable = staRsnCap.cfg.MFPC; |
| } |
| #endif |
| if (validate4WayHandshakeIE == MFALSE) { |
| if ((AssocSrvAp_checkCipherSupport(pwCipher, apCipher) |
| == TRUE) && |
| (AssocSrvAp_checkCipherSupport |
| (grpCipher, apMcstCipher) |
| == TRUE) && |
| (AssocSrvAp_checkAkm(priv, akm, apAuthKey) != 0)) { |
| AssocSrvAp_InitStaKeyInfo(connPtr, &wpaType, |
| &pwCipher, |
| staRsnCap.shortInt, |
| akm[0].akmType); |
| } else { |
| result = FAIL; |
| } |
| } else { |
| result = assocSrvAp_validate4WayHandshakeIe(priv, |
| wpaType, |
| pwCipher, |
| grpCipher, |
| pKeyMgmtInfo, |
| akm[0]. |
| akmType, |
| staRsnCap. |
| shortInt, |
| apMcstCipher); |
| } |
| } |
| return result; |
| } |
| |
| SINT32 |
| assocSrvAp_CheckSecurity(cm_Connection *connPtr, |
| IEEEtypes_WPSElement_t *pWps, |
| IEEEtypes_RSNElement_t *pRsn, |
| IEEEtypes_WPAElement_t *pWpa, |
| IEEEtypes_WAPIElement_t *pWapi, |
| IEEEtypes_StatusCode_t *pResult) |
| { |
| phostsa_private priv = (phostsa_private)connPtr->priv; |
| apInfo_t *pApInfo = &priv->apinfo; |
| BssConfig_t *pBssConfig = NULL; |
| SINT32 retval = MLME_FAILURE; |
| |
| *pResult = IEEEtypes_STATUS_INVALID_RSN_CAPABILITIES; |
| |
| pBssConfig = &pApInfo->bssConfig; |
| |
| PRINTM(MMSG, "assocSrvAp_CheckSecurity Sectyep wpa %x wpa2 %x\n", |
| pBssConfig->SecType.wpa, pBssConfig->SecType.wpa2); |
| if ((pBssConfig->SecType.wpa == 1) || (pBssConfig->SecType.wpa2 == 1)) { |
| apKeyMgmtInfoSta_t *pKeyMgmtInfo = |
| &connPtr->staData.keyMgmtInfo; |
| Cipher_t wpaUcastCipher = pBssConfig->RsnConfig.wpaUcstCipher; |
| Cipher_t wpa2UcastCipher = pBssConfig->RsnConfig.wpa2UcstCipher; |
| DBG_HEXDUMP(MCMD_D, " wpa2UcstCipher", |
| (t_u8 *)&wpa2UcastCipher, sizeof(Cipher_t)); |
| DBG_HEXDUMP(MCMD_D, " wpaUcastCipher", |
| (t_u8 *)&wpaUcastCipher, sizeof(Cipher_t)); |
| connPtr->staData.RSNEnabled = 0; |
| if (assocSrvAp_checkRsnWpa(connPtr, &pKeyMgmtInfo->rom, |
| wpaUcastCipher, |
| wpa2UcastCipher, |
| pBssConfig->RsnConfig.mcstCipher, |
| pBssConfig->RsnConfig.AuthKey, |
| &pBssConfig->SecType, pRsn, pWpa, |
| MFALSE) == SUCCESS) { |
| retval = MLME_SUCCESS; |
| connPtr->staData.RSNEnabled = 1; |
| } |
| } else if (pBssConfig->SecType.wepStatic == 1) { |
| if (!pRsn || !pWpa) { |
| retval = MLME_SUCCESS; |
| } |
| } else if (pBssConfig->SecType.wapi) { |
| /* if (wapi_ie_check(pBssConfig, pWapi, pResult)) { *pResult = |
| 0; retval = MLME_SUCCESS; } */ |
| } |
| |
| return retval; |
| } |