From 76504c992da93be41c383a402f4a701001c6d9e5 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 1 Jun 2011 14:40:13 +0200 Subject: wireless-next: WAPI support for hardware-accelerated drivers Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24551 Tested-by: Janusz DZIEDZIC Reviewed-by: Janusz DZIEDZIC Change-Id: I0300854865f8de07413164fd4461a9c8aae5dff3 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/26976 Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33473 Reviewed-by: Philippe LANGLAIS --- include/linux/ieee80211.h | 3 ++ include/linux/nl80211.h | 5 ++-- include/linux/wireless.h | 6 ++++ net/mac80211/Makefile | 1 + net/mac80211/ieee80211_i.h | 2 +- net/mac80211/key.c | 4 +++ net/mac80211/key.h | 2 ++ net/mac80211/main.c | 1 + net/mac80211/rx.c | 4 +++ net/mac80211/tx.c | 6 ++++ net/mac80211/wapi.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/wapi.h | 27 ++++++++++++++++++ net/wireless/nl80211.c | 13 +++++---- net/wireless/util.c | 8 ++++++ net/wireless/wext-compat.c | 39 ++++++++++++++++++++++--- 15 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 net/mac80211/wapi.c create mode 100644 net/mac80211/wapi.h diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index bf56b6f7827..69cd37de72c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1305,6 +1305,7 @@ enum ieee80211_key_len { WLAN_KEY_LEN_CCMP = 16, WLAN_KEY_LEN_TKIP = 32, WLAN_KEY_LEN_AES_CMAC = 16, + WLAN_KEY_LEN_SMS4 = 32, }; /** @@ -1434,12 +1435,14 @@ enum ieee80211_sa_query_action { #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 +#define WLAN_CIPHER_SUITE_SMS4 0x000FAC07 /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 #define WLAN_AKM_SUITE_SAE 0x000FAC08 #define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09 +#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC03 #define WLAN_MAX_KEY_LEN 32 diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c7ccaae15af..2df5ae66bf6 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1236,8 +1236,8 @@ enum nl80211_attrs { #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 -#define NL80211_MAX_NR_CIPHER_SUITES 5 -#define NL80211_MAX_NR_AKM_SUITES 2 +#define NL80211_MAX_NR_CIPHER_SUITES 6 +#define NL80211_MAX_NR_AKM_SUITES 3 /** * enum nl80211_iftype - (virtual) interface types @@ -2033,6 +2033,7 @@ enum nl80211_mfp { enum nl80211_wpa_versions { NL80211_WPA_VERSION_1 = 1 << 0, NL80211_WPA_VERSION_2 = 1 << 1, + NL80211_WAPI_VERSION_1 = 1 << 2, }; /** diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 4395b28bb86..f3e2375ee24 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -586,6 +586,7 @@ #define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 #define IW_AUTH_WPA_VERSION_WPA 0x00000002 #define IW_AUTH_WPA_VERSION_WPA2 0x00000004 +#define IW_AUTH_WPA_VERSION_WAPI 0x00000008 /* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT * values (bit field) */ @@ -595,10 +596,12 @@ #define IW_AUTH_CIPHER_CCMP 0x00000008 #define IW_AUTH_CIPHER_WEP104 0x00000010 #define IW_AUTH_CIPHER_AES_CMAC 0x00000020 +#define IW_AUTH_CIPHER_SMS4 0x00000040 /* IW_AUTH_KEY_MGMT values (bit field) */ #define IW_AUTH_KEY_MGMT_802_1X 1 #define IW_AUTH_KEY_MGMT_PSK 2 +#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 /* IW_AUTH_80211_AUTH_ALG values (bit field) */ #define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 @@ -624,6 +627,7 @@ #define IW_ENCODE_ALG_CCMP 3 #define IW_ENCODE_ALG_PMK 4 #define IW_ENCODE_ALG_AES_CMAC 5 +#define IW_ENCODE_ALG_SMS4 6 /* struct iw_encode_ext ->ext_flags */ #define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 #define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 @@ -644,6 +648,8 @@ #define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 #define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 #define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 +#define IW_ENC_CAPA_WAPI 0x00000020 +#define IW_ENC_CAPA_CIPHER_SMS4 0x00000040 /* Event capability macros - in (struct iw_range *)->event_capa * Because we have more than 32 possible events, we use an array of diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index fdb54e61d63..ed3dd35f708 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -6,6 +6,7 @@ mac80211-y := \ sta_info.o \ wep.o \ wpa.o \ + wapi.o \ scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 090b0ec1e05..4473e1c926d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -42,7 +42,7 @@ struct ieee80211_local; #define TOTAL_MAX_TX_BUFFER 512 /* Required encryption head and tailroom */ -#define IEEE80211_ENCRYPT_HEADROOM 8 +#define IEEE80211_ENCRYPT_HEADROOM 20 #define IEEE80211_ENCRYPT_TAILROOM 18 /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f825e2f0a57..c9ecfe2494c 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -369,6 +369,10 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, return ERR_PTR(err); } break; + case WLAN_CIPHER_SUITE_SMS4: + key->conf.iv_len = WAPI_IV_LEN; + key->conf.icv_len = WAPI_ICV_LEN; + break; } memcpy(key->conf.key, key_data, key_len); INIT_LIST_HEAD(&key->list); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index d801d535133..63b60054aa2 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -28,6 +28,8 @@ #define CCMP_PN_LEN 6 #define TKIP_IV_LEN 8 #define TKIP_ICV_LEN 4 +#define WAPI_IV_LEN 18 +#define WAPI_ICV_LEN 16 #define NUM_RX_DATA_QUEUES 17 diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 866f269183c..75adf347871 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -695,6 +695,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_SMS4, /* keep last -- depends on hw flags! */ WLAN_CIPHER_SUITE_AES_CMAC diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7fa8c6be7bf..a9749de0adb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -27,6 +27,7 @@ #include "wpa.h" #include "tkip.h" #include "wme.h" +#include "wapi.h" /* * monitor mode reception @@ -1042,6 +1043,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) case WLAN_CIPHER_SUITE_AES_CMAC: result = ieee80211_crypto_aes_cmac_decrypt(rx); break; + case WLAN_CIPHER_SUITE_SMS4: + result = ieee80211_crypto_wapi_decrypt(rx); + break; default: /* * We can reach here only with HW-only algorithms diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3104c844b54..93b51cfe7d2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -30,6 +30,7 @@ #include "mesh.h" #include "wep.h" #include "wpa.h" +#include "wapi.h" #include "wme.h" #include "rate.h" @@ -587,6 +588,11 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) if (!ieee80211_is_mgmt(hdr->frame_control)) tx->key = NULL; break; + + case WLAN_CIPHER_SUITE_SMS4: + if (tx->ethertype == ETH_P_WAPI) + tx->key = NULL; + break; } if (!skip_hw && tx->key && diff --git a/net/mac80211/wapi.c b/net/mac80211/wapi.c new file mode 100644 index 00000000000..4780808ad2f --- /dev/null +++ b/net/mac80211/wapi.c @@ -0,0 +1,71 @@ +/* + * Software WAPI encryption implementation + * Copyright (c) 2011, ST-Ericsson + * Author: Janusz Dziedzic + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ieee80211_i.h" +#include "wapi.h" + + +static int ieee80211_wapi_decrypt(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int hdrlen = ieee80211_hdrlen(hdr->frame_control); + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + int data_len; + + if (!(status->flag & RX_FLAG_DECRYPTED)) { + /* TODO - SMS4 decryption for firmware without + * SMS4 support */ + return RX_DROP_UNUSABLE; + } + + + data_len = skb->len - hdrlen - WAPI_IV_LEN - WAPI_ICV_LEN; + if (data_len < 0) + return RX_DROP_UNUSABLE; + + /* Trim ICV */ + skb_trim(skb, skb->len - WAPI_ICV_LEN); + + /* Remove IV */ + memmove(skb->data + WAPI_IV_LEN, skb->data, hdrlen); + skb_pull(skb, WAPI_IV_LEN); + + return RX_CONTINUE; +} + +ieee80211_rx_result +ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx) +{ + struct sk_buff *skb = rx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_is_data(hdr->frame_control)) + return RX_CONTINUE; + + if (ieee80211_wapi_decrypt(rx->local, rx->skb, rx->key)) + return RX_DROP_UNUSABLE; + + return RX_CONTINUE; +} diff --git a/net/mac80211/wapi.h b/net/mac80211/wapi.h new file mode 100644 index 00000000000..f06eee0cb7c --- /dev/null +++ b/net/mac80211/wapi.h @@ -0,0 +1,27 @@ +/* + * Software WAPI encryption implementation + * Copyright (c) 2011, ST-Ericsson + * Author: Janusz Dziedzic + * + * 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 WAPI_H +#define WAPI_H + +#include +#include +#include "ieee80211_i.h" +#include "key.h" + +#ifndef ETH_P_WAPI +#define ETH_P_WAPI 0x88B4 +#endif + + +ieee80211_rx_result +ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx); + +#endif /* WAPI_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cea338150d0..36b01d0a706 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -92,7 +92,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, - [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, + [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, @@ -183,7 +183,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, [NL80211_KEY_IDX] = { .type = NLA_U8 }, [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, - [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, + [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, [NL80211_KEY_TYPE] = { .type = NLA_U32 }, @@ -3863,13 +3863,15 @@ static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) static bool nl80211_valid_wpa_versions(u32 wpa_versions) { return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | - NL80211_WPA_VERSION_2)); + NL80211_WPA_VERSION_2 | + NL80211_WAPI_VERSION_1)); } static bool nl80211_valid_akm_suite(u32 akm) { return akm == WLAN_AKM_SUITE_8021X || - akm == WLAN_AKM_SUITE_PSK; + akm == WLAN_AKM_SUITE_PSK || + akm == WLAN_AKM_SUITE_WAPI_PSK; } static bool nl80211_valid_cipher_suite(u32 cipher) @@ -3878,7 +3880,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) cipher == WLAN_CIPHER_SUITE_WEP104 || cipher == WLAN_CIPHER_SUITE_TKIP || cipher == WLAN_CIPHER_SUITE_CCMP || - cipher == WLAN_CIPHER_SUITE_AES_CMAC; + cipher == WLAN_CIPHER_SUITE_AES_CMAC || + cipher == WLAN_CIPHER_SUITE_SMS4; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 4d7b83fbc32..68d3f691cb5 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -199,6 +199,10 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, if (params->key_len != WLAN_KEY_LEN_AES_CMAC) return -EINVAL; break; + case WLAN_CIPHER_SUITE_SMS4: + if (params->key_len != WLAN_KEY_LEN_SMS4) + return -EINVAL; + break; default: /* * We don't know anything about this algorithm, @@ -222,6 +226,10 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, if (params->seq_len != 6) return -EINVAL; break; + case WLAN_CIPHER_SUITE_SMS4: + if (params->seq_len != 16) + return -EINVAL; + break; } } diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 0bf169bb770..ac23c31c82c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -214,6 +214,11 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->encoding_size[range->num_encoding_sizes++] = WLAN_KEY_LEN_WEP104; break; + + case WLAN_CIPHER_SUITE_SMS4: + range->enc_capa |= (IW_ENC_CAPA_CIPHER_SMS4 | + IW_ENC_CAPA_WAPI); + break; } } @@ -699,6 +704,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, case IW_ENCODE_ALG_AES_CMAC: cipher = WLAN_CIPHER_SUITE_AES_CMAC; break; + case IW_ENCODE_ALG_SMS4: + cipher = WLAN_CIPHER_SUITE_SMS4; + break; default: return -EOPNOTSUPP; } @@ -959,17 +967,21 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) { if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2| + IW_AUTH_WPA_VERSION_WAPI| IW_AUTH_WPA_VERSION_DISABLED)) return -EINVAL; if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| - IW_AUTH_WPA_VERSION_WPA2))) + IW_AUTH_WPA_VERSION_WPA2| + IW_AUTH_WPA_VERSION_WAPI))) return -EINVAL; if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) wdev->wext.connect.crypto.wpa_versions &= - ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); + ~(NL80211_WPA_VERSION_1| + NL80211_WPA_VERSION_2| + NL80211_WAPI_VERSION_1); if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) wdev->wext.connect.crypto.wpa_versions |= @@ -979,6 +991,10 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) wdev->wext.connect.crypto.wpa_versions |= NL80211_WPA_VERSION_2; + if (wpa_versions & IW_AUTH_WPA_VERSION_WAPI) + wdev->wext.connect.crypto.wpa_versions |= + NL80211_WAPI_VERSION_1; + return 0; } @@ -1001,6 +1017,9 @@ static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) WLAN_CIPHER_SUITE_AES_CMAC; else if (cipher & IW_AUTH_CIPHER_NONE) wdev->wext.connect.crypto.cipher_group = 0; + else if (cipher & IW_AUTH_CIPHER_SMS4) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_SMS4; else return -EINVAL; @@ -1037,7 +1056,12 @@ static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) nr_ciphers++; } - BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); + if (cipher & IW_AUTH_CIPHER_SMS4) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_SMS4; + nr_ciphers++; + } + + BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 6); wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; @@ -1050,7 +1074,8 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) int nr_akm_suites = 0; if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | - IW_AUTH_KEY_MGMT_PSK)) + IW_AUTH_KEY_MGMT_PSK | + IW_AUTH_KEY_MGMT_WAPI_PSK)) return -EINVAL; if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { @@ -1065,6 +1090,12 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) nr_akm_suites++; } + if (key_mgt & IW_AUTH_KEY_MGMT_WAPI_PSK) { + wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = + WLAN_AKM_SUITE_WAPI_PSK; + nr_akm_suites++; + } + wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; return 0; -- cgit v1.2.3