[PATCH RFC] staging: ks7010: remove custom Michael MIC implementation

From: Tobin C. Harding
Date: Fri Mar 31 2017 - 00:48:09 EST


ks7010 currently uses a custom implementation of the Michael MIC
algorithm. The kernel has an implementation of this algorithm
already, we should use it.

Remove the custom implementation. Implement helper functions that call
the in-tree implementation through the crypto API. Update the
makefile. Replace driver calls to the custom implementation with calls
to the newly defined helper functions.

Signed-off-by: Tobin C. Harding <me@xxxxxxxx>
---
drivers/staging/ks7010/Makefile | 2 +-
drivers/staging/ks7010/ks_hostif.c | 48 +++++++-----
drivers/staging/ks7010/ks_wlan.h | 3 +
drivers/staging/ks7010/mic.c | 131 +++++++++++++++++++++++++++++++
drivers/staging/ks7010/mic.h | 22 ++++++
drivers/staging/ks7010/michael_mic.c | 148 -----------------------------------
drivers/staging/ks7010/michael_mic.h | 25 ------
7 files changed, 186 insertions(+), 193 deletions(-)
create mode 100644 drivers/staging/ks7010/mic.c
create mode 100644 drivers/staging/ks7010/mic.h
delete mode 100644 drivers/staging/ks7010/michael_mic.c
delete mode 100644 drivers/staging/ks7010/michael_mic.h

diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile
index 69fcf8d..195b570 100644
--- a/drivers/staging/ks7010/Makefile
+++ b/drivers/staging/ks7010/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_KS7010) += ks7010.o

ccflags-y += -DKS_WLAN_DEBUG=0
-ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o
+ks7010-y := mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index da7c42e..68ecbf7 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -12,7 +12,7 @@
#include "ks_wlan.h"
#include "ks_hostif.h"
#include "eap_packet.h"
-#include "michael_mic.h"
+#include "mic.h"

#include <linux/etherdevice.h>
#include <linux/if_ether.h>
@@ -315,7 +315,6 @@ void hostif_data_indication(struct ks_wlan_private *priv)
unsigned short auth_type;
unsigned char temp[256];

- unsigned char RecvMIC[8];
char buf[128];
struct ether_hdr *eth_hdr;
unsigned short eth_proto;
@@ -323,8 +322,8 @@ void hostif_data_indication(struct ks_wlan_private *priv)
struct mic_failure_t *mic_failure;
struct ieee802_1x_hdr *aa1x_hdr;
struct wpa_eapol_key *eap_key;
- struct michel_mic_t michel_mic;
union iwreq_data wrqu;
+ struct wpa_key_t *key;

DPRINTK(3, "\n");

@@ -337,6 +336,7 @@ void hostif_data_indication(struct ks_wlan_private *priv)

auth_type = get_WORD(priv); /* AuthType */
get_WORD(priv); /* Reserve Area */
+ key = &priv->wpa.key[auth_type - 1];

eth_hdr = (struct ether_hdr *)(priv->rxp);
eth_proto = ntohs(eth_hdr->h_proto);
@@ -372,18 +372,25 @@ void hostif_data_indication(struct ks_wlan_private *priv)
&& priv->wpa.group_suite ==
IW_AUTH_CIPHER_TKIP))
&& priv->wpa.key[auth_type - 1].key_len) {
+ u8 micrx[MICHAEL_MIC_LEN];
+ u8 mic[MICHAEL_MIC_LEN];
+ u8 *addr;
DPRINTK(4, "TKIP: protocol=%04X: size=%u\n",
eth_proto, priv->rx_size);
- /* MIC save */
- memcpy(&RecvMIC[0],
- (priv->rxp) + ((priv->rx_size) - 8), 8);
- priv->rx_size = priv->rx_size - 8;
+
+ addr = priv->rxp + priv->rx_size - MICHAEL_MIC_LEN;
+ memcpy(micrx, addr, MICHAEL_MIC_LEN);
+ priv->rx_size -= MICHAEL_MIC_LEN;
+
if (auth_type > 0 && auth_type < 4) { /* auth_type check */
- MichaelMICFunction(&michel_mic, (uint8_t *) priv->wpa.key[auth_type - 1].rx_mic_key, (uint8_t *) priv->rxp, (int)priv->rx_size, (uint8_t) 0, /* priority */
- (uint8_t *)
- michel_mic.Result);
+ u8 priority = 0;
+ ks_wlan_mic(priv->rx_tfm_mic,
+ key->rx_mic_key, priority,
+ priv->rxp, priv->rx_size,
+ mic);
}
- if (memcmp(michel_mic.Result, RecvMIC, 8)) {
+
+ if (memcmp(mic, micrx, MICHAEL_MIC_LEN) != 0) {
now = jiffies;
mic_failure = &priv->wpa.mic_failure;
/* MIC FAILURE */
@@ -1112,7 +1119,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet)
int result = 0;
unsigned short eth_proto;
struct ether_hdr *eth_hdr;
- struct michel_mic_t michel_mic;
unsigned short keyinfo = 0;
struct ieee802_1x_hdr *aa1x_hdr;
struct wpa_eapol_key *eap_key;
@@ -1220,13 +1226,17 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet)
pp->auth_type = cpu_to_le16((uint16_t) TYPE_AUTH); /* no encryption */
} else {
if (priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP) {
- MichaelMICFunction(&michel_mic, (uint8_t *) priv->wpa.key[0].tx_mic_key, (uint8_t *) &pp->data[0], (int)packet_len, (uint8_t) 0, /* priority */
- (uint8_t *) michel_mic.
- Result);
- memcpy(p, michel_mic.Result, 8);
- length += 8;
- packet_len += 8;
- p += 8;
+ struct wpa_key_t *key = &priv->wpa.key[0];
+ u8 priority = 0;
+ u8 mic[MICHAEL_MIC_LEN];
+
+ ks_wlan_mic(priv->tx_tfm_mic, key->tx_mic_key,
+ priority, pp->data, packet_len, mic);
+
+ memcpy(p, mic, MICHAEL_MIC_LEN);
+ length += MICHAEL_MIC_LEN;
+ packet_len += MICHAEL_MIC_LEN;
+ p += MICHAEL_MIC_LEN;
pp->auth_type =
cpu_to_le16((uint16_t) TYPE_DATA);

diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h
index 9ab80e1..be475fa 100644
--- a/drivers/staging/ks7010/ks_wlan.h
+++ b/drivers/staging/ks7010/ks_wlan.h
@@ -496,6 +496,9 @@ struct ks_wlan_private {
unsigned long last_wakeup;

uint wakeup_count; /* for detect wakeup loop */
+
+ struct crypto_shash *rx_tfm_mic;
+ struct crypto_shash *tx_tfm_mic;
};

int ks_wlan_net_start(struct net_device *dev);
diff --git a/drivers/staging/ks7010/mic.c b/drivers/staging/ks7010/mic.c
new file mode 100644
index 0000000..5c66fc6
--- /dev/null
+++ b/drivers/staging/ks7010/mic.c
@@ -0,0 +1,131 @@
+/*
+ * MIC helpers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Borrows heavily from drivers/net/wireless/intersil/orinoco
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/if_ether.h>
+#include <linux/scatterlist.h>
+#include <crypto/hash.h>
+
+#include "ks_wlan.h"
+#include "mic.h"
+
+/**
+ * ks_wlan_mic_init() - Michael MIC crypto setup.
+ *
+ * Calls kernel to locate Michael MIC algorithm and allocates
+ * receive and transmit transforms.
+ */
+int ks_wlan_mic_init(struct ks_wlan_private *priv)
+{
+ priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->tx_tfm_mic)) {
+ pr_debug("ks_wlan_mic_init: could not allocate "
+ "crypto API michael_mic\n");
+ priv->tx_tfm_mic = NULL;
+ return -ENOMEM;
+ }
+
+ priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(priv->rx_tfm_mic)) {
+ pr_debug("ks_wlan_mic_init: could not allocate "
+ "crypto API michael_mic\n");
+ priv->rx_tfm_mic = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * ks_wlan_mic_free() - Free crypto data structures.
+ */
+void ks_wlan_mic_free(struct ks_wlan_private *priv)
+{
+ if (priv->tx_tfm_mic)
+ crypto_free_shash(priv->tx_tfm_mic);
+ if (priv->rx_tfm_mic)
+ crypto_free_shash(priv->rx_tfm_mic);
+}
+
+/**
+ * ks_wlan_mic() - Calculate Message Integrity Check
+ *
+ * @tfm_michael: Transform allocated prior.
+ * @key: Key value.
+ * @priority: Usually 0.
+ * @data: DA, SA, and data to check.
+ * @data_len: Length of data.
+ * @mic: MIC result (8 bytes).
+ *
+ * The destination (DA) and source (SA) addresses are passed in at the front of
+ * data. The message integrity check format is built up as specified
+ * by IEEE802.11. The MIC is calculated on @data *not* including DA and SA.
+ */
+int ks_wlan_mic(struct crypto_shash *tfm_michael, u8 *key,
+ u8 priority, u8 *data, size_t data_len, u8 *mic)
+{
+ SHASH_DESC_ON_STACK(desc, tfm_michael);
+ u8 hdr[ETH_HLEN + 2]; /* 16 bytes */
+ u8 *da, *sa;
+ int ret;
+
+ /*
+ * IEEE802.11i page 47
+ * Figure 43g TKIP MIC processing format
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7|
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ */
+
+ if (!tfm_michael) {
+ pr_warning("ks_wlan_mic: tfm_michael == NULL\n");
+ return -EINVAL;
+ }
+
+ da = data;
+ sa = data + ETH_ALEN;
+ data += 2 * ETH_ALEN;
+ data_len -= 2 * ETH_ALEN;
+
+ memcpy(&hdr[0], da, ETH_ALEN);
+ memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
+ hdr[ETH_ALEN * 2] = priority;
+ hdr[ETH_ALEN * 2 + 1] = 0;
+ hdr[ETH_ALEN * 2 + 2] = 0;
+ hdr[ETH_ALEN * 2 + 3] = 0;
+
+ desc->tfm = tfm_michael;
+ desc->flags = 0;
+
+ ret = crypto_shash_setkey(tfm_michael, key, MIC_KEY_SIZE);
+ if (ret)
+ return ret;
+
+ ret = crypto_shash_init(desc);
+ if (ret)
+ return ret;
+
+ ret = crypto_shash_update(desc, hdr, sizeof(hdr));
+ if (ret)
+ return ret;
+
+ ret = crypto_shash_update(desc, data, data_len);
+ if (ret)
+ return ret;
+
+ ret = crypto_shash_final(desc, mic);
+ shash_desc_zero(desc);
+
+ return ret;
+}
diff --git a/drivers/staging/ks7010/mic.h b/drivers/staging/ks7010/mic.h
new file mode 100644
index 0000000..eb048dc
--- /dev/null
+++ b/drivers/staging/ks7010/mic.h
@@ -0,0 +1,22 @@
+/*
+ * MIC helpers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _KS7010_MIC_H_
+#define _KS7010_MIC_H_
+
+#include <linux/types.h>
+#include <crypto/hash.h>
+#include "ks_wlan.h"
+
+#define MICHAEL_MIC_LEN 8
+
+int ks_wlan_mic_init(struct ks_wlan_private *priv);
+void ks_wlan_mic_free(struct ks_wlan_private *priv);
+int ks_wlan_mic(struct crypto_shash *tfm_michael, u8 *key,
+ u8 priority, u8 *data, size_t data_len, u8 *mic);
+
+#endif /* _KS7010_MIC_H_ */
diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c
deleted file mode 100644
index f6e70fa..0000000
--- a/drivers/staging/ks7010/michael_mic.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Driver for KeyStream wireless LAN
- *
- * Copyright (C) 2005-2008 KeyStream Corp.
- * Copyright (C) 2009 Renesas Technology Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include "michael_mic.h"
-
-// Rotation functions on 32 bit values
-#define ROL32(A, n) (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1)))
-#define ROR32(A, n) ROL32((A), 32 - (n))
-// Convert from Byte[] to UInt32 in a portable way
-#define getUInt32(A, B) ((uint32_t)(A[B + 0] << 0) \
- + (A[B + 1] << 8) + (A[B + 2] << 16) + (A[B + 3] << 24))
-
-// Convert from UInt32 to Byte[] in a portable way
-#define putUInt32(A, B, C) \
-do { \
- A[B + 0] = (uint8_t)(C & 0xff); \
- A[B + 1] = (uint8_t)((C >> 8) & 0xff); \
- A[B + 2] = (uint8_t)((C >> 16) & 0xff); \
- A[B + 3] = (uint8_t)((C >> 24) & 0xff); \
-} while (0)
-
-// Reset the state to the empty message.
-#define MichaelClear(A) \
-do { \
- A->L = A->K0; \
- A->R = A->K1; \
- A->nBytesInM = 0; \
-} while (0)
-
-static
-void MichaelInitializeFunction(struct michel_mic_t *Mic, uint8_t *key)
-{
- // Set the key
- Mic->K0 = getUInt32(key, 0);
- Mic->K1 = getUInt32(key, 4);
-
- //clear();
- MichaelClear(Mic);
-}
-
-#define MichaelBlockFunction(L, R) \
-do { \
- R ^= ROL32(L, 17); \
- L += R; \
- R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); \
- L += R; \
- R ^= ROL32(L, 3); \
- L += R; \
- R ^= ROR32(L, 2); \
- L += R; \
-} while (0)
-
-static
-void MichaelAppend(struct michel_mic_t *Mic, uint8_t *src, int nBytes)
-{
- int addlen;
-
- if (Mic->nBytesInM) {
- addlen = 4 - Mic->nBytesInM;
- if (addlen > nBytes)
- addlen = nBytes;
- memcpy(&Mic->M[Mic->nBytesInM], src, addlen);
- Mic->nBytesInM += addlen;
- src += addlen;
- nBytes -= addlen;
-
- if (Mic->nBytesInM < 4)
- return;
-
- Mic->L ^= getUInt32(Mic->M, 0);
- MichaelBlockFunction(Mic->L, Mic->R);
- Mic->nBytesInM = 0;
- }
-
- while (nBytes >= 4) {
- Mic->L ^= getUInt32(src, 0);
- MichaelBlockFunction(Mic->L, Mic->R);
- src += 4;
- nBytes -= 4;
- }
-
- if (nBytes > 0) {
- Mic->nBytesInM = nBytes;
- memcpy(Mic->M, src, nBytes);
- }
-}
-
-static
-void MichaelGetMIC(struct michel_mic_t *Mic, uint8_t *dst)
-{
- u8 *data = Mic->M;
-
- switch (Mic->nBytesInM) {
- case 0:
- Mic->L ^= 0x5a;
- break;
- case 1:
- Mic->L ^= data[0] | 0x5a00;
- break;
- case 2:
- Mic->L ^= data[0] | (data[1] << 8) | 0x5a0000;
- break;
- case 3:
- Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) |
- 0x5a000000;
- break;
- }
- MichaelBlockFunction(Mic->L, Mic->R);
- MichaelBlockFunction(Mic->L, Mic->R);
- // The appendByte function has already computed the result.
- putUInt32(dst, 0, Mic->L);
- putUInt32(dst, 4, Mic->R);
-
- // Reset to the empty message.
- MichaelClear(Mic);
-}
-
-void MichaelMICFunction(struct michel_mic_t *Mic, u8 *Key,
- u8 *Data, int Len, u8 priority,
- u8 *Result)
-{
- u8 pad_data[4] = { priority, 0, 0, 0 };
- // Compute the MIC value
- /*
- * IEEE802.11i page 47
- * Figure 43g TKIP MIC processing format
- * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
- * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet
- * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
- * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7|
- * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
- */
- MichaelInitializeFunction(Mic, Key);
- MichaelAppend(Mic, (uint8_t *) Data, 12); /* |DA|SA| */
- MichaelAppend(Mic, pad_data, 4); /* |Priority|0|0|0| */
- MichaelAppend(Mic, (uint8_t *) (Data + 12), Len - 12); /* |Data| */
- MichaelGetMIC(Mic, Result);
-}
diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h
deleted file mode 100644
index 248f849..0000000
--- a/drivers/staging/ks7010/michael_mic.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Driver for KeyStream wireless LAN
- *
- * Copyright (C) 2005-2008 KeyStream Corp.
- * Copyright (C) 2009 Renesas Technology Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* MichelMIC routine define */
-struct michel_mic_t {
- u32 K0; // Key
- u32 K1; // Key
- u32 L; // Current state
- u32 R; // Current state
- u8 M[4]; // Message accumulator (single word)
- int nBytesInM; // # bytes in M
- u8 Result[8];
-};
-
-void MichaelMICFunction(struct michel_mic_t *Mic, u8 *Key,
- u8 *Data, int Len, u8 priority,
- u8 *Result);
--
2.7.4