blob: 2a939b9d327441e4f148fe000aea1daa22b65f16 [file] [log] [blame]
/** @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;
}