Commit 5fdb3735 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Herbert Xu

net/mac80211: move WEP handling to ARC4 library interface

The WEP code in the mac80211 subsystem currently uses the crypto
API to access the arc4 (RC4) cipher, which is overly complicated,
and doesn't really have an upside in this particular case, since
ciphers are always synchronous and therefore always implemented in
software. Given that we have no accelerated software implementations
either, it is much more straightforward to invoke a generic library
interface directly.
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent dc51f257
...@@ -2,7 +2,7 @@ config MAC80211 ...@@ -2,7 +2,7 @@ config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)" tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
depends on CFG80211 depends on CFG80211
select CRYPTO select CRYPTO
select CRYPTO_ARC4 select CRYPTO_LIB_ARC4
select CRYPTO_AES select CRYPTO_AES
select CRYPTO_CCM select CRYPTO_CCM
select CRYPTO_GCM select CRYPTO_GCM
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/fips.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
...@@ -403,9 +404,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -403,9 +404,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
if (IS_ERR(local->wep_tx_tfm)) if (WARN_ON_ONCE(fips_enabled))
return -EINVAL; return -EINVAL;
break;
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_AES_CMAC:
......
...@@ -1258,8 +1258,8 @@ struct ieee80211_local { ...@@ -1258,8 +1258,8 @@ struct ieee80211_local {
struct rate_control_ref *rate_ctrl; struct rate_control_ref *rate_ctrl;
struct crypto_cipher *wep_tx_tfm; struct arc4_ctx wep_tx_ctx;
struct crypto_cipher *wep_rx_tfm; struct arc4_ctx wep_rx_ctx;
u32 wep_iv; u32 wep_iv;
/* see iface.c */ /* see iface.c */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <crypto/arc4.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#define NUM_DEFAULT_KEYS 4 #define NUM_DEFAULT_KEYS 4
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <net/mac80211.h> #include <net/mac80211.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fips.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -733,8 +734,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw_nm); ...@@ -733,8 +734,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
static int ieee80211_init_cipher_suites(struct ieee80211_local *local) static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
{ {
bool have_wep = !(IS_ERR(local->wep_tx_tfm) || bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */
IS_ERR(local->wep_rx_tfm));
bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE); bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE);
int n_suites = 0, r = 0, w = 0; int n_suites = 0, r = 0, w = 0;
u32 *suites; u32 *suites;
...@@ -1301,7 +1301,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1301,7 +1301,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
fail_rate: fail_rate:
rtnl_unlock(); rtnl_unlock();
ieee80211_led_exit(local); ieee80211_led_exit(local);
ieee80211_wep_free(local);
fail_flows: fail_flows:
destroy_workqueue(local->workqueue); destroy_workqueue(local->workqueue);
fail_workqueue: fail_workqueue:
...@@ -1358,7 +1357,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ...@@ -1358,7 +1357,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
destroy_workqueue(local->workqueue); destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy); wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local); ieee80211_led_exit(local);
kfree(local->int_scan_req); kfree(local->int_scan_req);
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fips.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
...@@ -5038,7 +5039,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ...@@ -5038,7 +5039,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
auth_alg = WLAN_AUTH_OPEN; auth_alg = WLAN_AUTH_OPEN;
break; break;
case NL80211_AUTHTYPE_SHARED_KEY: case NL80211_AUTHTYPE_SHARED_KEY:
if (IS_ERR(local->wep_tx_tfm)) if (fips_enabled)
return -EOPNOTSUPP; return -EOPNOTSUPP;
auth_alg = WLAN_AUTH_SHARED_KEY; auth_alg = WLAN_AUTH_SHARED_KEY;
break; break;
......
...@@ -222,7 +222,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_p2k); ...@@ -222,7 +222,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_p2k);
* @payload_len is the length of payload (_not_ including IV/ICV length). * @payload_len is the length of payload (_not_ including IV/ICV length).
* @ta is the transmitter addresses. * @ta is the transmitter addresses.
*/ */
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, int ieee80211_tkip_encrypt_data(struct arc4_ctx *ctx,
struct ieee80211_key *key, struct ieee80211_key *key,
struct sk_buff *skb, struct sk_buff *skb,
u8 *payload, size_t payload_len) u8 *payload, size_t payload_len)
...@@ -231,7 +231,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, ...@@ -231,7 +231,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
ieee80211_get_tkip_p2k(&key->conf, skb, rc4key); ieee80211_get_tkip_p2k(&key->conf, skb, rc4key);
return ieee80211_wep_encrypt_data(tfm, rc4key, 16, return ieee80211_wep_encrypt_data(ctx, rc4key, 16,
payload, payload_len); payload, payload_len);
} }
...@@ -239,7 +239,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, ...@@ -239,7 +239,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
* beginning of the buffer containing IEEE 802.11 header payload, i.e., * beginning of the buffer containing IEEE 802.11 header payload, i.e.,
* including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
* length of payload, including IV, Ext. IV, MIC, ICV. */ * length of payload, including IV, Ext. IV, MIC, ICV. */
int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, int ieee80211_tkip_decrypt_data(struct arc4_ctx *ctx,
struct ieee80211_key *key, struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta, u8 *payload, size_t payload_len, u8 *ta,
u8 *ra, int only_iv, int queue, u8 *ra, int only_iv, int queue,
...@@ -297,7 +297,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, ...@@ -297,7 +297,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key); tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key);
res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); res = ieee80211_wep_decrypt_data(ctx, rc4key, 16, pos, payload_len - 12);
done: done:
if (res == TKIP_DECRYPT_OK) { if (res == TKIP_DECRYPT_OK) {
/* /*
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/crypto.h> #include <linux/crypto.h>
#include "key.h" #include "key.h"
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, int ieee80211_tkip_encrypt_data(struct arc4_ctx *ctx,
struct ieee80211_key *key, struct ieee80211_key *key,
struct sk_buff *skb, struct sk_buff *skb,
u8 *payload, size_t payload_len); u8 *payload, size_t payload_len);
...@@ -24,7 +24,7 @@ enum { ...@@ -24,7 +24,7 @@ enum {
TKIP_DECRYPT_INVALID_KEYIDX = -2, TKIP_DECRYPT_INVALID_KEYIDX = -2,
TKIP_DECRYPT_REPLAY = -3, TKIP_DECRYPT_REPLAY = -3,
}; };
int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, int ieee80211_tkip_decrypt_data(struct arc4_ctx *ctx,
struct ieee80211_key *key, struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta, u8 *payload, size_t payload_len, u8 *ta,
u8 *ra, int only_iv, int queue, u8 *ra, int only_iv, int queue,
......
...@@ -30,30 +30,9 @@ int ieee80211_wep_init(struct ieee80211_local *local) ...@@ -30,30 +30,9 @@ int ieee80211_wep_init(struct ieee80211_local *local)
/* start WEP IV from a random value */ /* start WEP IV from a random value */
get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN); get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN);
local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, 0);
if (IS_ERR(local->wep_tx_tfm)) {
local->wep_rx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_tx_tfm);
}
local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, 0);
if (IS_ERR(local->wep_rx_tfm)) {
crypto_free_cipher(local->wep_tx_tfm);
local->wep_tx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_rx_tfm);
}
return 0; return 0;
} }
void ieee80211_wep_free(struct ieee80211_local *local)
{
if (!IS_ERR(local->wep_tx_tfm))
crypto_free_cipher(local->wep_tx_tfm);
if (!IS_ERR(local->wep_rx_tfm))
crypto_free_cipher(local->wep_rx_tfm);
}
static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
{ {
/* /*
...@@ -131,21 +110,17 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, ...@@ -131,21 +110,17 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
/* Perform WEP encryption using given key. data buffer must have tailroom /* Perform WEP encryption using given key. data buffer must have tailroom
* for 4-byte ICV. data_len must not include this ICV. Note: this function * for 4-byte ICV. data_len must not include this ICV. Note: this function
* does _not_ add IV. data = RC4(data | CRC32(data)) */ * does _not_ add IV. data = RC4(data | CRC32(data)) */
int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
size_t klen, u8 *data, size_t data_len) size_t klen, u8 *data, size_t data_len)
{ {
__le32 icv; __le32 icv;
int i;
if (IS_ERR(tfm))
return -1;
icv = cpu_to_le32(~crc32_le(~0, data, data_len)); icv = cpu_to_le32(~crc32_le(~0, data, data_len));
put_unaligned(icv, (__le32 *)(data + data_len)); put_unaligned(icv, (__le32 *)(data + data_len));
crypto_cipher_setkey(tfm, rc4key, klen); arc4_setkey(ctx, rc4key, klen);
for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++) arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
crypto_cipher_encrypt_one(tfm, data + i, data + i); memzero_explicit(ctx, sizeof(*ctx));
return 0; return 0;
} }
...@@ -184,7 +159,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, ...@@ -184,7 +159,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
/* Add room for ICV */ /* Add room for ICV */
skb_put(skb, IEEE80211_WEP_ICV_LEN); skb_put(skb, IEEE80211_WEP_ICV_LEN);
return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3, return ieee80211_wep_encrypt_data(&local->wep_tx_ctx, rc4key, keylen + 3,
iv + IEEE80211_WEP_IV_LEN, len); iv + IEEE80211_WEP_IV_LEN, len);
} }
...@@ -192,18 +167,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, ...@@ -192,18 +167,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
/* Perform WEP decryption using given key. data buffer includes encrypted /* Perform WEP decryption using given key. data buffer includes encrypted
* payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
* Return 0 on success and -1 on ICV mismatch. */ * Return 0 on success and -1 on ICV mismatch. */
int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, int ieee80211_wep_decrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
size_t klen, u8 *data, size_t data_len) size_t klen, u8 *data, size_t data_len)
{ {
__le32 crc; __le32 crc;
int i;
if (IS_ERR(tfm))
return -1;
crypto_cipher_setkey(tfm, rc4key, klen); arc4_setkey(ctx, rc4key, klen);
for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++) arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
crypto_cipher_decrypt_one(tfm, data + i, data + i); memzero_explicit(ctx, sizeof(*ctx));
crc = cpu_to_le32(~crc32_le(~0, data, data_len)); crc = cpu_to_le32(~crc32_le(~0, data, data_len));
if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0) if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0)
...@@ -256,7 +227,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, ...@@ -256,7 +227,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
/* Copy rest of the WEP key (the secret part) */ /* Copy rest of the WEP key (the secret part) */
memcpy(rc4key + 3, key->conf.key, key->conf.keylen); memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, if (ieee80211_wep_decrypt_data(&local->wep_rx_ctx, rc4key, klen,
skb->data + hdrlen + skb->data + hdrlen +
IEEE80211_WEP_IV_LEN, len)) IEEE80211_WEP_IV_LEN, len))
ret = -1; ret = -1;
......
...@@ -17,13 +17,12 @@ ...@@ -17,13 +17,12 @@
#include "key.h" #include "key.h"
int ieee80211_wep_init(struct ieee80211_local *local); int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_free(struct ieee80211_local *local); int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len); size_t klen, u8 *data, size_t data_len);
int ieee80211_wep_encrypt(struct ieee80211_local *local, int ieee80211_wep_encrypt(struct ieee80211_local *local,
struct sk_buff *skb, struct sk_buff *skb,
const u8 *key, int keylen, int keyidx); const u8 *key, int keylen, int keyidx);
int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, int ieee80211_wep_decrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
size_t klen, u8 *data, size_t data_len); size_t klen, u8 *data, size_t data_len);
ieee80211_rx_result ieee80211_rx_result
......
...@@ -242,7 +242,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ...@@ -242,7 +242,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
/* Add room for ICV */ /* Add room for ICV */
skb_put(skb, IEEE80211_TKIP_ICV_LEN); skb_put(skb, IEEE80211_TKIP_ICV_LEN);
return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm, return ieee80211_tkip_encrypt_data(&tx->local->wep_tx_ctx,
key, skb, pos, len); key, skb, pos, len);
} }
...@@ -293,7 +293,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) ...@@ -293,7 +293,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_DECRYPTED) if (status->flag & RX_FLAG_DECRYPTED)
hwaccel = 1; hwaccel = 1;
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, res = ieee80211_tkip_decrypt_data(&rx->local->wep_rx_ctx,
key, skb->data + hdrlen, key, skb->data + hdrlen,
skb->len - hdrlen, rx->sta->sta.addr, skb->len - hdrlen, rx->sta->sta.addr,
hdr->addr1, hwaccel, rx->security_idx, hdr->addr1, hwaccel, rx->security_idx,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment