cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

key.c (7619B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Key management related functions.
      4 *
      5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
      6 * Copyright (c) 2010, ST-Ericsson
      7 */
      8#include <linux/etherdevice.h>
      9#include <net/mac80211.h>
     10
     11#include "key.h"
     12#include "wfx.h"
     13#include "hif_tx_mib.h"
     14
     15static int wfx_alloc_key(struct wfx_dev *wdev)
     16{
     17	int idx;
     18
     19	idx = ffs(~wdev->key_map) - 1;
     20	if (idx < 0 || idx >= MAX_KEY_ENTRIES)
     21		return -1;
     22
     23	wdev->key_map |= BIT(idx);
     24	return idx;
     25}
     26
     27static void wfx_free_key(struct wfx_dev *wdev, int idx)
     28{
     29	WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
     30	wdev->key_map &= ~BIT(idx);
     31}
     32
     33static u8 fill_wep_pair(struct wfx_hif_wep_pairwise_key *msg,
     34			struct ieee80211_key_conf *key, u8 *peer_addr)
     35{
     36	WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
     37	msg->key_length = key->keylen;
     38	memcpy(msg->key_data, key->key, key->keylen);
     39	ether_addr_copy(msg->peer_address, peer_addr);
     40	return HIF_KEY_TYPE_WEP_PAIRWISE;
     41}
     42
     43static u8 fill_wep_group(struct wfx_hif_wep_group_key *msg,
     44			 struct ieee80211_key_conf *key)
     45{
     46	WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
     47	msg->key_id = key->keyidx;
     48	msg->key_length = key->keylen;
     49	memcpy(msg->key_data, key->key, key->keylen);
     50	return HIF_KEY_TYPE_WEP_DEFAULT;
     51}
     52
     53static u8 fill_tkip_pair(struct wfx_hif_tkip_pairwise_key *msg,
     54			 struct ieee80211_key_conf *key, u8 *peer_addr)
     55{
     56	u8 *keybuf = key->key;
     57
     58	WARN(key->keylen != sizeof(msg->tkip_key_data) + sizeof(msg->tx_mic_key) +
     59			    sizeof(msg->rx_mic_key), "inconsistent data");
     60	memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
     61	keybuf += sizeof(msg->tkip_key_data);
     62	memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key));
     63	keybuf += sizeof(msg->tx_mic_key);
     64	memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key));
     65	ether_addr_copy(msg->peer_address, peer_addr);
     66	return HIF_KEY_TYPE_TKIP_PAIRWISE;
     67}
     68
     69static u8 fill_tkip_group(struct wfx_hif_tkip_group_key *msg, struct ieee80211_key_conf *key,
     70			  struct ieee80211_key_seq *seq, enum nl80211_iftype iftype)
     71{
     72	u8 *keybuf = key->key;
     73
     74	WARN(key->keylen != sizeof(msg->tkip_key_data) + 2 * sizeof(msg->rx_mic_key),
     75	     "inconsistent data");
     76	msg->key_id = key->keyidx;
     77	memcpy(msg->rx_sequence_counter, &seq->tkip.iv16, sizeof(seq->tkip.iv16));
     78	memcpy(msg->rx_sequence_counter + sizeof(u16), &seq->tkip.iv32, sizeof(seq->tkip.iv32));
     79	memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
     80	keybuf += sizeof(msg->tkip_key_data);
     81	if (iftype == NL80211_IFTYPE_AP)
     82		/* Use Tx MIC Key */
     83		memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key));
     84	else
     85		/* Use Rx MIC Key */
     86		memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key));
     87	return HIF_KEY_TYPE_TKIP_GROUP;
     88}
     89
     90static u8 fill_ccmp_pair(struct wfx_hif_aes_pairwise_key *msg,
     91			 struct ieee80211_key_conf *key, u8 *peer_addr)
     92{
     93	WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
     94	ether_addr_copy(msg->peer_address, peer_addr);
     95	memcpy(msg->aes_key_data, key->key, key->keylen);
     96	return HIF_KEY_TYPE_AES_PAIRWISE;
     97}
     98
     99static u8 fill_ccmp_group(struct wfx_hif_aes_group_key *msg,
    100			  struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq)
    101{
    102	WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
    103	memcpy(msg->aes_key_data, key->key, key->keylen);
    104	memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn));
    105	memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn));
    106	msg->key_id = key->keyidx;
    107	return HIF_KEY_TYPE_AES_GROUP;
    108}
    109
    110static u8 fill_sms4_pair(struct wfx_hif_wapi_pairwise_key *msg,
    111			 struct ieee80211_key_conf *key, u8 *peer_addr)
    112{
    113	u8 *keybuf = key->key;
    114
    115	WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data),
    116	     "inconsistent data");
    117	ether_addr_copy(msg->peer_address, peer_addr);
    118	memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
    119	keybuf += sizeof(msg->wapi_key_data);
    120	memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
    121	msg->key_id = key->keyidx;
    122	return HIF_KEY_TYPE_WAPI_PAIRWISE;
    123}
    124
    125static u8 fill_sms4_group(struct wfx_hif_wapi_group_key *msg,
    126			  struct ieee80211_key_conf *key)
    127{
    128	u8 *keybuf = key->key;
    129
    130	WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data),
    131	     "inconsistent data");
    132	memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
    133	keybuf += sizeof(msg->wapi_key_data);
    134	memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
    135	msg->key_id = key->keyidx;
    136	return HIF_KEY_TYPE_WAPI_GROUP;
    137}
    138
    139static u8 fill_aes_cmac_group(struct wfx_hif_igtk_group_key *msg,
    140			      struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq)
    141{
    142	WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data");
    143	memcpy(msg->igtk_key_data, key->key, key->keylen);
    144	memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn));
    145	memreverse(msg->ipn, sizeof(seq->aes_cmac.pn));
    146	msg->key_id = key->keyidx;
    147	return HIF_KEY_TYPE_IGTK_GROUP;
    148}
    149
    150static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta,
    151		       struct ieee80211_key_conf *key)
    152{
    153	int ret;
    154	struct wfx_hif_req_add_key k = { };
    155	struct ieee80211_key_seq seq;
    156	struct wfx_dev *wdev = wvif->wdev;
    157	int idx = wfx_alloc_key(wvif->wdev);
    158	bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
    159	struct ieee80211_vif *vif = wvif_to_vif(wvif);
    160
    161	WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data");
    162	ieee80211_get_key_rx_seq(key, 0, &seq);
    163	if (idx < 0)
    164		return -EINVAL;
    165	k.int_id = wvif->id;
    166	k.entry_index = idx;
    167	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
    168	    key->cipher == WLAN_CIPHER_SUITE_WEP104) {
    169		if (pairwise)
    170			k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, sta->addr);
    171		else
    172			k.type = fill_wep_group(&k.key.wep_group_key, key);
    173	} else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
    174		if (pairwise)
    175			k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, sta->addr);
    176		else
    177			k.type = fill_tkip_group(&k.key.tkip_group_key, key, &seq,
    178						 vif->type);
    179	} else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
    180		if (pairwise)
    181			k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, sta->addr);
    182		else
    183			k.type = fill_ccmp_group(&k.key.aes_group_key, key, &seq);
    184	} else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) {
    185		if (pairwise)
    186			k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, sta->addr);
    187		else
    188			k.type = fill_sms4_group(&k.key.wapi_group_key, key);
    189	} else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
    190		k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq);
    191		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
    192	} else {
    193		dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher);
    194		wfx_free_key(wdev, idx);
    195		return -EOPNOTSUPP;
    196	}
    197	ret = wfx_hif_add_key(wdev, &k);
    198	if (ret) {
    199		wfx_free_key(wdev, idx);
    200		return -EOPNOTSUPP;
    201	}
    202	key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
    203	key->hw_key_idx = idx;
    204	return 0;
    205}
    206
    207static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key)
    208{
    209	WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx");
    210	wfx_free_key(wvif->wdev, key->hw_key_idx);
    211	return wfx_hif_remove_key(wvif->wdev, key->hw_key_idx);
    212}
    213
    214int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif,
    215		struct ieee80211_sta *sta, struct ieee80211_key_conf *key)
    216{
    217	int ret = -EOPNOTSUPP;
    218	struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
    219
    220	mutex_lock(&wvif->wdev->conf_mutex);
    221	if (cmd == SET_KEY)
    222		ret = wfx_add_key(wvif, sta, key);
    223	if (cmd == DISABLE_KEY)
    224		ret = wfx_remove_key(wvif, key);
    225	mutex_unlock(&wvif->wdev->conf_mutex);
    226	return ret;
    227}