From b4c573c77362bc04a0ff9984ca35682e0ee79a8d Mon Sep 17 00:00:00 2001 From: Ashok Ponnaiah Date: Fri, 18 May 2018 12:48:44 +0530 Subject: [PATCH] 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 --- .../crypto/src/wlan_crypto_def_i.h | 28 ++-- .../crypto/src/wlan_crypto_global_api.c | 134 ++++++++++++++---- 2 files changed, 118 insertions(+), 44 deletions(-) diff --git a/umac/cmn_services/crypto/src/wlan_crypto_def_i.h b/umac/cmn_services/crypto/src/wlan_crypto_def_i.h index e4735deec1..7579533b22 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_def_i.h +++ b/umac/cmn_services/crypto/src/wlan_crypto_def_i.h @@ -273,14 +273,14 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val) #define RSN_CIPHER_SUITE_BIP_CMAC_256 WLAN_RSN_SEL(WLAN_CSE_BIP_CMAC_256) #define RESET_PARAM(__param) ((__param) = 0) -#define SET_PARAM(__param, __val) ((__param) |= (1<<(__val))) -#define HAS_PARAM(__param, __val) ((__param) & (1<<(__val))) +#define SET_PARAM(__param, __val) ((__param) |= (1 << (__val))) +#define HAS_PARAM(__param, __val) ((__param) & (1 << (__val))) #define CLEAR_PARAM(__param, __val) ((__param) &= ((~1) << (__val))) #define RESET_AUTHMODE(_param) ((_param)->authmodeset = 0) -#define SET_AUTHMODE(_param, _mode) ((_param)->authmodeset |= (1<<(_mode))) -#define HAS_AUTHMODE(_param, _mode) ((_param)->authmodeset & (1<<(_mode))) +#define SET_AUTHMODE(_param, _mode) ((_param)->authmodeset |= (1 << (_mode))) +#define HAS_AUTHMODE(_param, _mode) ((_param)->authmodeset & (1 << (_mode))) #define AUTH_IS_OPEN(_param) HAS_AUTHMODE((_param), WLAN_CRYPTO_AUTH_OPEN) #define AUTH_IS_SHARED_KEY(_param) \ @@ -297,8 +297,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val) #define RESET_UCAST_CIPHERS(_param) ((_param)->ucastcipherset = 0) -#define SET_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset |= (1<<(_c))) -#define HAS_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset & (1<<(_c))) +#define SET_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset |= (1 << (_c))) +#define HAS_UCAST_CIPHER(_param, _c) ((_param)->ucastcipherset & (1 << (_c))) #define UCIPHER_IS_CLEAR(_param) \ HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_NONE) @@ -318,8 +318,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val) HAS_UCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI_SMS4) #define RESET_MCAST_CIPHERS(_param) ((_param)->mcastcipherset = 0) -#define SET_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset |= (1<<(_c))) -#define HAS_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset & (1<<(_c))) +#define SET_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset |= (1 << (_c))) +#define HAS_MCAST_CIPHER(_param, _c) ((_param)->mcastcipherset & (1 << (_c))) #define HAS_ANY_MCAST_CIPHER(_param) ((_param)->mcastcipherset) #define CLEAR_MCAST_CIPHER(_param, _c) \ ((_param)->mcastcipherset &= (~(1)<<(_c))) @@ -342,8 +342,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val) HAS_MCAST_CIPHER((_param), WLAN_CRYPTO_CIPHER_WAPI_SMS4) #define RESET_MGMT_CIPHERS(_param) ((_param)->mgmtcipherset = 0) -#define SET_MGMT_CIPHER(_param, _c) ((_param)->mgmtcipherset = (1<<(_c))) -#define HAS_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 IS_MGMT_CIPHER(_c) ((_c == WLAN_CRYPTO_CIPHER_AES_CMAC) || \ (_c == WLAN_CRYPTO_CIPHER_AES_CMAC_256) || \ (_c == WLAN_CRYPTO_CIPHER_AES_GMAC) || \ @@ -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) #define RESET_KEY_MGMT(_param) ((_param)->key_mgmt = 0) -#define SET_KEY_MGMT(_param, _c) ((_param)->key_mgmt |= (1<<(_c))) -#define HAS_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 + 1))) #define UCAST_CIPHER_MATCH(_param1, _param2) \ (((_param1)->ucastcipherset & (_param2)->ucastcipherset) != 0) @@ -378,8 +378,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val) (!(_param1)->key_mgmt && !(_param2)->key_mgmt)) #define RESET_CIPHER_CAP(_param) ((_param)->cipher_caps = 0) -#define SET_CIPHER_CAP(_param, _c) ((_param)->cipher_caps |= (1<<(_c))) -#define HAS_CIPHER_CAP(_param, _c) ((_param)->cipher_caps & (1<<(_c))) +#define SET_CIPHER_CAP(_param, _c) ((_param)->cipher_caps |= (1 << (_c))) +#define HAS_CIPHER_CAP(_param, _c) ((_param)->cipher_caps & (1 << (_c))) #define HAS_ANY_CIPHER_CAP(_param) ((_param)->cipher_caps) /** diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c index 9b8bea8f9f..63642101e4 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c +++ b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c @@ -2109,17 +2109,15 @@ QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params, int32_t w; int n; - /* - * Check the length once for fixed parts: OUI, type, - * 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) + /* Check the length once for fixed parts: OUI, type & version */ + if (len < 2) 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; /* NB: iswapoui already validated the OUI and type */ w = LE_READ_2(frm); @@ -2128,52 +2126,128 @@ QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params, 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 */ - RESET_MCAST_CIPHERS(crypto_params); w = wlan_crypto_rsn_suite_to_cipher(frm); if (w < 0) return QDF_STATUS_E_INVAL; - SET_MCAST_CIPHER(crypto_params, w); - frm += 4, len -= 4; + else { + SET_MCAST_CIPHER(crypto_params, w); + 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 */ n = LE_READ_2(frm); frm += 2, len -= 2; - if (len < n*4+2) - return QDF_STATUS_E_INVAL; - - RESET_UCAST_CIPHERS(crypto_params); - for (; n > 0; n--) { - w = wlan_crypto_rsn_suite_to_cipher(frm); - if (w < 0) + if (n) { + if (len < n * 4) return QDF_STATUS_E_INVAL; - SET_UCAST_CIPHER(crypto_params, w); - frm += 4, len -= 4; + + for (; n > 0; n--) { + w = wlan_crypto_rsn_suite_to_cipher(frm); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_UCAST_CIPHER(crypto_params, w); + 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) 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 */ n = LE_READ_2(frm); frm += 2, len -= 2; - if (len < n*4) - return QDF_STATUS_E_INVAL; - w = 0; - RESET_KEY_MGMT(crypto_params); - for (; n > 0; n--) { - w = wlan_crypto_rsn_suite_to_keymgmt(frm); - if (w < 0) + if (n) { + if (len < n * 4) return QDF_STATUS_E_INVAL; - SET_KEY_MGMT(crypto_params, (1 << w)); - frm += 4, len -= 4; + + for (; n > 0; n--) { + w = wlan_crypto_rsn_suite_to_keymgmt(frm); + if (w < 0) + return QDF_STATUS_E_INVAL; + SET_KEY_MGMT(crypto_params, w); + 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 */ if (len >= 2) { crypto_params->rsn_caps = LE_READ_2(frm); 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;