qcacmn: Add support WPA2 security improvements

Add support for WPA security improvements
where if length and data mismatch are present in
the IE's then driver need to gracefully return error
rather than accessing out of bounds data.

Change-Id: Idd56e5b987fed4d7bddad6d5ada927e97f92a1aa
Crs-Fixed: 2243109
This commit is contained in:
Ashok Ponnaiah
2018-05-18 12:48:44 +05:30
committed by nshrivas
parent c6d591092d
commit b4c573c773
2 changed files with 118 additions and 44 deletions

View File

@@ -342,7 +342,7 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val)
HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI_SMS4) HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI_SMS4)
#define RESET_MGMT_CIPHERS(_param) ((_param)->mgmtcipherset = 0) #define RESET_MGMT_CIPHERS(_param) ((_param)->mgmtcipherset = 0)
#define SET_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset = (1<<(_c))) #define SET_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset |= (1 << (_c)))
#define HAS_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset & (1 << (_c))) #define HAS_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset & (1 << (_c)))
#define IS_MGMT_CIPHER(_c) ((_c == WLAN_CRYPTO_CIPHER_AES_CMAC) || \ #define IS_MGMT_CIPHER(_c) ((_c == WLAN_CRYPTO_CIPHER_AES_CMAC) || \
(_c == WLAN_CRYPTO_CIPHER_AES_CMAC_256) || \ (_c == WLAN_CRYPTO_CIPHER_AES_CMAC_256) || \
@@ -361,8 +361,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val)
HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GMAC_256) HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_GMAC_256)
#define RESET_KEY_MGMT(_param) ((_param)->key_mgmt = 0) #define RESET_KEY_MGMT(_param) ((_param)->key_mgmt = 0)
#define SET_KEY_MGMT(_param, _c) ((_param)->key_mgmt |= (1<<(_c))) #define SET_KEY_MGMT(_param, _c) ((_param)->key_mgmt |= (1 << (_c + 1)))
#define HAS_KEY_MGMT(_param, _c) ((_param)->key_mgmt & (1<<(_c))) #define HAS_KEY_MGMT(_param, _c) ((_param)->key_mgmt & (1 << (_c + 1)))
#define UCAST_CIPHER_MATCH(_param1, _param2) \ #define UCAST_CIPHER_MATCH(_param1, _param2) \
(((_param1)->ucastcipherset & (_param2)->ucastcipherset) != 0) (((_param1)->ucastcipherset & (_param2)->ucastcipherset) != 0)

View File

@@ -2109,17 +2109,15 @@ QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params,
int32_t w; int32_t w;
int n; int n;
/* /* Check the length once for fixed parts: OUI, type & version */
* Check the length once for fixed parts: OUI, type, if (len < 2)
* version, mcast cipher, and 2 selector counts.
* Other, variable-length data, must be checked separately.
*/
RESET_AUTHMODE(crypto_params);
SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_RSNA);
if (len < 14)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
/* initialize crypto params */
qdf_mem_zero(crypto_params, sizeof(struct wlan_crypto_params));
SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_RSNA);
frm += 2; frm += 2;
/* NB: iswapoui already validated the OUI and type */ /* NB: iswapoui already validated the OUI and type */
w = LE_READ_2(frm); w = LE_READ_2(frm);
@@ -2128,21 +2126,48 @@ QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params,
frm += 2, len -= 2; frm += 2, len -= 2;
if (!len) {
/* set defaults */
/* default group cipher CCMP-128 */
SET_MCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 4) {
return QDF_STATUS_E_INVAL;
}
/* multicast/group cipher */ /* multicast/group cipher */
RESET_MCAST_CIPHERS(crypto_params);
w = wlan_crypto_rsn_suite_to_cipher(frm); w = wlan_crypto_rsn_suite_to_cipher(frm);
if (w < 0) if (w < 0)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
else {
SET_MCAST_CIPHER(crypto_params, w); SET_MCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4; frm += 4, len -= 4;
}
if (crypto_params->mcastcipherset == 0)
return QDF_STATUS_E_INVAL;
if (!len) {
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 2) {
return QDF_STATUS_E_INVAL;
}
/* unicast ciphers */ /* unicast ciphers */
n = LE_READ_2(frm); n = LE_READ_2(frm);
frm += 2, len -= 2; frm += 2, len -= 2;
if (len < n*4+2) if (n) {
if (len < n * 4)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
RESET_UCAST_CIPHERS(crypto_params);
for (; n > 0; n--) { for (; n > 0; n--) {
w = wlan_crypto_rsn_suite_to_cipher(frm); w = wlan_crypto_rsn_suite_to_cipher(frm);
if (w < 0) if (w < 0)
@@ -2150,30 +2175,79 @@ QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params,
SET_UCAST_CIPHER(crypto_params, w); SET_UCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4; frm += 4, len -= 4;
} }
} else {
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
}
if (crypto_params->ucastcipherset == 0) if (crypto_params->ucastcipherset == 0)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
if (!len) {
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 2) {
return QDF_STATUS_E_INVAL;
}
/* key management algorithms */ /* key management algorithms */
n = LE_READ_2(frm); n = LE_READ_2(frm);
frm += 2, len -= 2; frm += 2, len -= 2;
if (n) {
if (len < n * 4) if (len < n * 4)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
w = 0;
RESET_KEY_MGMT(crypto_params);
for (; n > 0; n--) { for (; n > 0; n--) {
w = wlan_crypto_rsn_suite_to_keymgmt(frm); w = wlan_crypto_rsn_suite_to_keymgmt(frm);
if (w < 0) if (w < 0)
return QDF_STATUS_E_INVAL; return QDF_STATUS_E_INVAL;
SET_KEY_MGMT(crypto_params, (1 << w)); SET_KEY_MGMT(crypto_params, w);
frm += 4, len -= 4; frm += 4, len -= 4;
} }
} else {
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
}
if (crypto_params->key_mgmt == 0)
return QDF_STATUS_E_INVAL;
/* optional capabilities */ /* optional capabilities */
if (len >= 2) { if (len >= 2) {
crypto_params->rsn_caps = LE_READ_2(frm); crypto_params->rsn_caps = LE_READ_2(frm);
frm += 2, len -= 2; frm += 2, len -= 2;
} else if (len && len < 2) {
return QDF_STATUS_E_INVAL;
}
/* PMKID */
if (len >= 2) {
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (n && len) {
if (len >= n * PMKID_LEN)
frm += (n * PMKID_LEN), len -= (n * PMKID_LEN);
else
return QDF_STATUS_E_INVAL;
} else if (n && !len) {
return QDF_STATUS_E_INVAL;
}
/*TODO: Save pmkid in params for further reference */
}
/* BIP */
if (!len &&
(crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
/* when no BIP mentioned and MFP capable use CMAC as default*/
SET_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC);
return QDF_STATUS_SUCCESS;
} else if (len >= 4) {
w = wlan_crypto_rsn_suite_to_cipher(frm);
frm += 4, len -= 4;
SET_MGMT_CIPHER(crypto_params, w);
} }
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;