cfg80211: Allow user space to specify non-IEs to SAE Authentication
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>
This commit is contained in:
		
					parent
					
						
							
								0f4126e891
							
						
					
				
			
			
				commit
				
					
						e39e5b5e72
					
				
			
		
					 6 changed files with 77 additions and 18 deletions
				
			
		|  | @ -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; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -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, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jouni Malinen
				Jouni Malinen