net/mac80211: move WEP handling to ARC4 library interface
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 12 Jun 2019 16:19:54 +0000 (18:19 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 20 Jun 2019 06:18:33 +0000 (14:18 +0800)
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: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
net/mac80211/Kconfig
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/tkip.c
net/mac80211/tkip.h
net/mac80211/wep.c
net/mac80211/wep.h
net/mac80211/wpa.c

index be471fe950488c59373469dea14078dd95c993b0..8e0b0b8d5e41a785289577b982d1198230939f7c 100644 (file)
@@ -2,7 +2,7 @@ config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
        depends on CFG80211
        select CRYPTO
-       select CRYPTO_ARC4
+       select CRYPTO_LIB_ARC4
        select CRYPTO_AES
        select CRYPTO_CCM
        select CRYPTO_GCM
index 52e6a091b7e40800a989fdb12fe6acfffb00124f..83c6d2844427dfa0d2f758a2bbd688622890a35a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <net/net_namespace.h>
 #include <linux/rcupdate.h>
+#include <linux/fips.h>
 #include <linux/if_ether.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
@@ -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_TKIP:
        case WLAN_CIPHER_SUITE_WEP104:
-               if (IS_ERR(local->wep_tx_tfm))
+               if (WARN_ON_ONCE(fips_enabled))
                        return -EINVAL;
-               break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
        case WLAN_CIPHER_SUITE_AES_CMAC:
index 073a8235ae1bd8cfcd28640a31bbb66bb4d22f96..412da8cfbc365e79490db49472cff3cf6e3bf6b5 100644 (file)
@@ -1258,8 +1258,8 @@ struct ieee80211_local {
 
        struct rate_control_ref *rate_ctrl;
 
-       struct crypto_cipher *wep_tx_tfm;
-       struct crypto_cipher *wep_rx_tfm;
+       struct arc4_ctx wep_tx_ctx;
+       struct arc4_ctx wep_rx_ctx;
        u32 wep_iv;
 
        /* see iface.c */
index f06fbd03d23566795db87ba52df192cdeee6936f..6c5bbaebd02cebd2b563c5acdbece8dbe2210d22 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/list.h>
 #include <linux/crypto.h>
 #include <linux/rcupdate.h>
+#include <crypto/arc4.h>
 #include <net/mac80211.h>
 
 #define NUM_DEFAULT_KEYS 4
index 2b608044ae23be931715e02c7119d41407f24e52..93c4a2d0623ea05acc2d11a7d20e18fe835054d9 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <net/mac80211.h>
 #include <linux/module.h>
+#include <linux/fips.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
@@ -733,8 +734,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
 
 static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
 {
-       bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
-                         IS_ERR(local->wep_rx_tfm));
+       bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */
        bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE);
        int n_suites = 0, r = 0, w = 0;
        u32 *suites;
@@ -1301,7 +1301,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  fail_rate:
        rtnl_unlock();
        ieee80211_led_exit(local);
-       ieee80211_wep_free(local);
  fail_flows:
        destroy_workqueue(local->workqueue);
  fail_workqueue:
@@ -1358,7 +1357,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        destroy_workqueue(local->workqueue);
        wiphy_unregister(local->hw.wiphy);
-       ieee80211_wep_free(local);
        ieee80211_led_exit(local);
        kfree(local->int_scan_req);
 }
index b7a9fe3d5fcb75dfb15e27c536d19066993b0c6d..048a07b101b45b8b1444b8612b7f0316c6698e87 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/fips.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
@@ -5038,7 +5039,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                auth_alg = WLAN_AUTH_OPEN;
                break;
        case NL80211_AUTHTYPE_SHARED_KEY:
-               if (IS_ERR(local->wep_tx_tfm))
+               if (fips_enabled)
                        return -EOPNOTSUPP;
                auth_alg = WLAN_AUTH_SHARED_KEY;
                break;
index b3622823bad23b9a34a58b09fea1dd3e067bbcf2..96b87fc7122e93da23292f1fd91ea4a1608692cf 100644 (file)
@@ -222,7 +222,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_p2k);
  * @payload_len is the length of payload (_not_ including IV/ICV length).
  * @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 sk_buff *skb,
                                u8 *payload, size_t payload_len)
@@ -231,7 +231,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
 
        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);
 }
 
@@ -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.,
  * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
  * 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,
                                u8 *payload, size_t payload_len, u8 *ta,
                                u8 *ra, int only_iv, int queue,
@@ -297,7 +297,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 
        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:
        if (res == TKIP_DECRYPT_OK) {
                /*
index a1bcbfbefe7c32ca5e0fe6d080818acebb624b9b..798583056201f1e8186fd5974d94f9f802b74807 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/crypto.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 sk_buff *skb,
                                u8 *payload, size_t payload_len);
@@ -24,7 +24,7 @@ enum {
        TKIP_DECRYPT_INVALID_KEYIDX = -2,
        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,
                                u8 *payload, size_t payload_len, u8 *ta,
                                u8 *ra, int only_iv, int queue,
index bfe9ed9f4c48d6f4e52faf6f274474ebda2ac9b6..9f567373696700c96249ca3d8954d7fb0afda89e 100644 (file)
@@ -30,30 +30,9 @@ int ieee80211_wep_init(struct ieee80211_local *local)
        /* start WEP IV from a random value */
        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;
 }
 
-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)
 {
        /*
@@ -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
  * for 4-byte ICV. data_len must not include this ICV. Note: this function
  * 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)
 {
        __le32 icv;
-       int i;
-
-       if (IS_ERR(tfm))
-               return -1;
 
        icv = cpu_to_le32(~crc32_le(~0, data, data_len));
        put_unaligned(icv, (__le32 *)(data + data_len));
 
-       crypto_cipher_setkey(tfm, rc4key, klen);
-       for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++)
-               crypto_cipher_encrypt_one(tfm, data + i, data + i);
+       arc4_setkey(ctx, rc4key, klen);
+       arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
+       memzero_explicit(ctx, sizeof(*ctx));
 
        return 0;
 }
@@ -184,7 +159,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
        /* Add room for ICV */
        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);
 }
 
@@ -192,18 +167,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
 /* Perform WEP decryption using given key. data buffer includes encrypted
  * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
  * 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)
 {
        __le32 crc;
-       int i;
-
-       if (IS_ERR(tfm))
-               return -1;
 
-       crypto_cipher_setkey(tfm, rc4key, klen);
-       for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++)
-               crypto_cipher_decrypt_one(tfm, data + i, data + i);
+       arc4_setkey(ctx, rc4key, klen);
+       arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
+       memzero_explicit(ctx, sizeof(*ctx));
 
        crc = cpu_to_le32(~crc32_le(~0, data, data_len));
        if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0)
@@ -256,7 +227,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
        /* Copy rest of the WEP key (the secret part) */
        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 +
                                       IEEE80211_WEP_IV_LEN, len))
                ret = -1;
index 9615749d1f654b0bce70626b033c4224fc324f91..3644f4a5bb875a4267218b40c7e4bc3a15050a2b 100644 (file)
 #include "key.h"
 
 int ieee80211_wep_init(struct ieee80211_local *local);
-void ieee80211_wep_free(struct ieee80211_local *local);
-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);
 int ieee80211_wep_encrypt(struct ieee80211_local *local,
                          struct sk_buff *skb,
                          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);
 
 ieee80211_rx_result
index 58d0b258b684cdd8124266e1b392c4cd77fec5a7..02e8ab7b2b4c33d0a2cf0225713bed601e3a49a9 100644 (file)
@@ -242,7 +242,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        /* Add room for ICV */
        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);
 }
 
@@ -293,7 +293,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        if (status->flag & RX_FLAG_DECRYPTED)
                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,
                                          skb->len - hdrlen, rx->sta->sta.addr,
                                          hdr->addr1, hwaccel, rx->security_idx,