cfg80211: Allow user space to specify non-IEs to SAE Authentication
authorJouni Malinen <j@w1.fi>
Sun, 30 Sep 2012 16:29:39 +0000 (19:29 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 17 Oct 2012 09:02:11 +0000 (11:02 +0200)
SAE extends Authentication frames with fields that are not information
elements. NL80211_ATTR_IE is not suitable for these, so introduce a new
attribute that can be used to specify the fields needed for SAE in
station mode.

Signed-off-by: Jouni Malinen <j@w1.fi>
[change to verify that SAE is only used with authenticate command]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/sme.c

index 1b49890822449df661d576219181b10c64d57a6c..60cebfac3e3c39c208dafa4dcaee79bc529b0ec6 100644 (file)
@@ -1152,6 +1152,9 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
  * @key: WEP key for shared key authentication
+ * @sae_data: Non-IE data to use with SAE or %NULL. This starts with
+ *     Authentication transaction sequence number field.
+ * @sae_data_len: Length of sae_data buffer in octets
  */
 struct cfg80211_auth_request {
        struct cfg80211_bss *bss;
@@ -1160,6 +1163,8 @@ struct cfg80211_auth_request {
        enum nl80211_auth_type auth_type;
        const u8 *key;
        u8 key_len, key_idx;
+       const u8 *sae_data;
+       size_t sae_data_len;
 };
 
 /**
index 7df9b500c80493e944591a2192b07253f1b42669..179a0c2e2f61b427ce7353a1f81cc3beecda6440 100644 (file)
@@ -1273,6 +1273,9 @@ enum nl80211_commands {
  *     the connection request from a station. nl80211_connect_failed_reason
  *     enum has different reasons of connection failure.
  *
+ * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
+ *     with the Authentication transaction sequence number field.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1530,6 +1533,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_CONN_FAILED_REASON,
 
+       NL80211_ATTR_SAE_DATA,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2489,6 +2494,7 @@ enum nl80211_bss_status {
  * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
  * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
  * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
  * @__NL80211_AUTHTYPE_NUM: internal
  * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
  * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -2500,6 +2506,7 @@ enum nl80211_auth_type {
        NL80211_AUTHTYPE_SHARED_KEY,
        NL80211_AUTHTYPE_FT,
        NL80211_AUTHTYPE_NETWORK_EAP,
+       NL80211_AUTHTYPE_SAE,
 
        /* keep last */
        __NL80211_AUTHTYPE_NUM,
@@ -3028,6 +3035,9 @@ enum nl80211_ap_sme_features {
  *     in the interface combinations, even when it's only used for scan
  *     and remain-on-channel. This could be due to, for example, the
  *     remain-on-channel implementation requiring a channel context.
+ * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
+ *     equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
+ *     mode
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3035,6 +3045,7 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_INACTIVITY_TIMER                = 1 << 2,
        NL80211_FEATURE_CELL_BASE_REG_HINTS             = 1 << 3,
        NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL        = 1 << 4,
+       NL80211_FEATURE_SAE                             = 1 << 5,
 };
 
 /**
index a343be4a52bd0e16b0fdb41e565f39f3d705c823..b8eb743fe7daf737baf3a0bd79884f0551da17f1 100644 (file)
@@ -320,13 +320,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx);
+                        const u8 *key, int key_len, int key_idx,
+                        const u8 *sae_data, int sae_data_len);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx);
+                      const u8 *key, int key_len, int key_idx,
+                      const u8 *sae_data, int sae_data_len);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
index 8016fee0752b0325a20409b7b1b93b5433c73872..460d493257412f1a6f5e037b1528b965c0c20730 100644 (file)
@@ -273,7 +273,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx)
+                        const u8 *key, int key_len, int key_idx,
+                        const u8 *sae_data, int sae_data_len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
@@ -293,6 +294,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 
        req.ie = ie;
        req.ie_len = ie_len;
+       req.sae_data = sae_data;
+       req.sae_data_len = sae_data_len;
        req.auth_type = auth_type;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -319,7 +322,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx)
+                      const u8 *key, int key_len, int key_idx,
+                      const u8 *sae_data, int sae_data_len)
 {
        int err;
 
@@ -327,7 +331,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                   ssid, ssid_len, ie, ie_len,
-                                  key, key_len, key_idx);
+                                  key, key_len, key_idx,
+                                  sae_data, sae_data_len);
        wdev_unlock(dev->ieee80211_ptr);
        mutex_unlock(&rdev->devlist_mtx);
 
index 0418a6d5c1a683f95542c64628e66f487ddea196..74d8123ada7701b4be8afa078f896f807abfaf0d 100644 (file)
@@ -23,7 +23,6 @@
 #include "nl80211.h"
 #include "reg.h"
 
-static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                                   struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
@@ -355,6 +354,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
        [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
        [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
+       [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
 };
 
 /* policy for the key attributes */
@@ -2490,6 +2490,30 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
+                                   enum nl80211_auth_type auth_type,
+                                   enum nl80211_commands cmd)
+{
+       if (auth_type > NL80211_AUTHTYPE_MAX)
+               return false;
+
+       switch (cmd) {
+       case NL80211_CMD_AUTHENTICATE:
+               if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
+                   auth_type == NL80211_AUTHTYPE_SAE)
+                       return false;
+               return true;
+       case NL80211_CMD_CONNECT:
+       case NL80211_CMD_START_AP:
+               /* SAE not supported yet */
+               if (auth_type == NL80211_AUTHTYPE_SAE)
+                       return false;
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2559,7 +2583,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
                params.auth_type = nla_get_u32(
                        info->attrs[NL80211_ATTR_AUTH_TYPE]);
-               if (!nl80211_valid_auth_type(params.auth_type))
+               if (!nl80211_valid_auth_type(rdev, params.auth_type,
+                                            NL80211_CMD_START_AP))
                        return -EINVAL;
        } else
                params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -4852,11 +4877,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        return res;
 }
 
-static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
-{
-       return auth_type <= NL80211_AUTHTYPE_MAX;
-}
-
 static bool nl80211_valid_wpa_versions(u32 wpa_versions)
 {
        return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
@@ -4868,8 +4888,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
-       const u8 *bssid, *ssid, *ie = NULL;
-       int err, ssid_len, ie_len = 0;
+       const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
+       int err, ssid_len, ie_len = 0, sae_data_len = 0;
        enum nl80211_auth_type auth_type;
        struct key_parse key;
        bool local_state_change;
@@ -4945,9 +4965,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        }
 
        auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-       if (!nl80211_valid_auth_type(auth_type))
+       if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
                return -EINVAL;
 
+       if (auth_type == NL80211_AUTHTYPE_SAE &&
+           !info->attrs[NL80211_ATTR_SAE_DATA])
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_SAE_DATA]) {
+               if (auth_type != NL80211_AUTHTYPE_SAE)
+                       return -EINVAL;
+               sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
+               sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
+               /* need to include at least Auth Transaction and Status Code */
+               if (sae_data_len < 4)
+                       return -EINVAL;
+       }
+
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
        /*
@@ -4959,7 +4993,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 
        return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                  ssid, ssid_len, ie, ie_len,
-                                 key.p.key, key.p.key_len, key.idx);
+                                 key.p.key, key.p.key_len, key.idx,
+                                 sae_data, sae_data_len);
 }
 
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
@@ -5596,7 +5631,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
                connect.auth_type =
                        nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-               if (!nl80211_valid_auth_type(connect.auth_type))
+               if (!nl80211_valid_auth_type(rdev, connect.auth_type,
+                                            NL80211_CMD_CONNECT))
                        return -EINVAL;
        } else
                connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
index 6f39cb808302380e05fa70d9a68925f7a35dcae3..055d596436161304303fff2a73ba520968df8501 100644 (file)
@@ -179,7 +179,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            params->ssid, params->ssid_len,
                                            NULL, 0,
                                            params->key, params->key_len,
-                                           params->key_idx);
+                                           params->key_idx, NULL, 0);
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;