diff options
author | Padma, Santhosh Kumar <skpadma@codeaurora.org> | 2018-02-14 16:07:21 +0530 |
---|---|---|
committer | Sunil Ravi <sunilravi@google.com> | 2018-12-21 23:51:37 +0000 |
commit | d31c055f0dc15b261c4e82c4276089258c7a01c1 (patch) | |
tree | a6ba65c344efcc5db01fc5172f995b2be5acad8b /core/cds | |
parent | f1d91c12845504f59dd84df895fd4155efc5334d (diff) | |
download | qcacld-d31c055f0dc15b261c4e82c4276089258c7a01c1.tar.gz |
qcacld-3.0: Add support for GMAC MIC validation
Add changes to validate MIC for the received protected
MC/BC frames with GMAC group management cipher suite.
Change-Id: Ie5f60674a452d2d930acc9ff9eb55de37645097a
CRs-Fixed: 2164828
Diffstat (limited to 'core/cds')
-rw-r--r-- | core/cds/inc/cds_utils.h | 21 | ||||
-rw-r--r-- | core/cds/src/cds_utils.c | 138 |
2 files changed, 158 insertions, 1 deletions
diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h index 46e24b5fcf..d5d15f324e 100644 --- a/core/cds/inc/cds_utils.h +++ b/core/cds/inc/cds_utils.h @@ -168,6 +168,27 @@ bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn, bool cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, uint8_t *frm, uint8_t *efrm, uint16_t frmLen); uint8_t cds_get_mmie_size(void); + +/** + * cds_is_gmac_mmie_valid: Validates GMAC MIC + * @igtk: integrity group temporal key + * @ipn: IGTK packet number + * @frm: IEEE 802.11 frame + * @efrm: End of frame + * @key_length: Length of IGTK + * + * Return: True if MIC validation is successful, false otherwise + */ +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length); + +/** + * cds_get_gmac_mmie_size: Gives length of GMAC MMIE size + * + * Return: Size of MMIE for GMAC + */ +uint8_t cds_get_gmac_mmie_size(void); + #endif /* WLAN_FEATURE_11W */ QDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal pMac); static inline void cds_host_diag_log_work(qdf_wake_lock_t *lock, uint32_t msec, diff --git a/core/cds/src/cds_utils.c b/core/cds/src/cds_utils.c index bf207f3cbb..cde0bb46c6 100644 --- a/core/cds/src/cds_utils.c +++ b/core/cds/src/cds_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -61,6 +61,8 @@ #include <crypto/aes.h> #include "cds_ieee80211_common.h" +#include <qdf_crypto.h> + /*---------------------------------------------------------------------------- * Preprocessor Definitions and Constants * -------------------------------------------------------------------------*/ @@ -68,6 +70,7 @@ #define IV_SIZE_AES_128 16 #define CMAC_IPN_LEN 6 #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ +#define GMAC_NONCE_LEN 12 /*---------------------------------------------------------------------------- * Type Declarations @@ -565,6 +568,139 @@ err_tfm: return !ret ? true : false; } +#if defined(WLAN_FEATURE_GMAC) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +uint8_t cds_get_gmac_mmie_size(void) +{ + return sizeof(struct ieee80211_mmie_16); +} +#else +uint8_t cds_get_gmac_mmie_size(void) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_GMAC +/** + * ipn_swap: Swaps ipn + * @d: destination pointer + * @s: source pointer + * + * Return: None + */ +static inline void ipn_swap(u8 *d, const u8 *s) +{ + *d++ = s[5]; + *d++ = s[4]; + *d++ = s[3]; + *d++ = s[2]; + *d++ = s[1]; + *d = s[0]; +} +#endif + +#if defined(WLAN_FEATURE_GMAC) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length) +{ + struct ieee80211_mmie_16 *mmie; + struct ieee80211_frame *wh; + uint8_t rx_ipn[6], aad[AAD_LEN], mic[IEEE80211_MMIE_GMAC_MICLEN]; + uint16_t data_len; + uint8_t gmac_nonce[GMAC_NONCE_LEN]; + uint8_t iv[AES_BLOCK_SIZE] = {0}; + int ret; + + /* Check if frame is invalid length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Invalid frame length"); + return false; + } + + mmie = (struct ieee80211_mmie_16 *)(efrm - sizeof(*mmie)); + + /* Check Element ID */ + if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || + (mmie->length != (sizeof(*mmie) - 2))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "IE is not Mgmt MIC IE or Invalid length"); + /* IE is not Mgmt MIC IE or invalid length */ + return false; + } + + /* Validate IPN */ + ipn_swap(rx_ipn, mmie->sequence_number); + if (qdf_mem_cmp(rx_ipn, ipn, IEEE80211_MMIE_IPNLEN) <= 0) { + /* Replay error */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "Replay error mmie ipn %02X %02X %02X %02X %02X %02X" + " drvr ipn %02X %02X %02X %02X %02X %02X", + rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], + rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], + ipn[5]); + return false; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate AAD: FC(masked) || A1 || A2 || A3 */ + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + data_len = efrm - (uint8_t *) (wh + 1) - IEEE80211_MMIE_GMAC_MICLEN; + + /* IV */ + qdf_mem_copy(gmac_nonce, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(gmac_nonce + IEEE80211_ADDR_LEN, rx_ipn, + IEEE80211_MMIE_IPNLEN); + qdf_mem_copy(iv, gmac_nonce, GMAC_NONCE_LEN); + iv[AES_BLOCK_SIZE - 1] = 0x01; + + ret = qdf_crypto_aes_gmac(igtk, key_length, iv, aad, + (uint8_t *) (wh + 1), data_len, mic); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "qdf_crypto_aes_gmac failed %d", ret); + return false; + } + + if (qdf_mem_cmp(mic, mmie->mic, IEEE80211_MMIE_GMAC_MICLEN) != 0) { + /* MMIE MIC mismatch */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "BC/MC MGMT frame MMIE MIC check Failed" + " rmic %02X %02X %02X %02X %02X %02X %02X %02X" + " %02X %02X %02X %02X %02X %02X %02X %02X", + mmie->mic[0], mmie->mic[1], mmie->mic[2], + mmie->mic[3], mmie->mic[4], mmie->mic[5], + mmie->mic[6], mmie->mic[7], mmie->mic[8], + mmie->mic[9], mmie->mic[10], mmie->mic[11], + mmie->mic[12], mmie->mic[13], mmie->mic[14], + mmie->mic[15]); + return false; + } + + /* Update IPN */ + qdf_mem_copy(ipn, rx_ipn, IEEE80211_MMIE_IPNLEN); + + return true; +} +#else +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length) +{ + return false; +} +#endif + #endif /* WLAN_FEATURE_11W */ uint32_t cds_chan_to_freq(uint8_t chan) |