/** @file AssocAp_src_rom.c
|
*
|
* @brief This file defines the function for checking security type and ie
|
*
|
* 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 "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 AKM_1X:
|
matchedAkms = (allowedAkms & UAP_HOSTCMD_KEYMGMT_EAP);
|
break;
|
|
case AKM_PSK:
|
matchedAkms = (allowedAkms & UAP_HOSTCMD_KEYMGMT_PSK);
|
break;
|
case AKM_SHA256_PSK:
|
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));
|
memset(util_fns, &pwCipher, 0x00, sizeof(pwCipher));
|
memset(util_fns, &grpCipher, 0x00, sizeof(grpCipher));
|
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;
|
}
|