diff mbox series

[03/15] PASN: Properly set the public key

Message ID 20210315125713.23355-4-ilan.peer@intel.com
State Accepted
Headers show
Series Add additional PASN features | expand

Commit Message

Peer, Ilan March 15, 2021, 12:57 p.m. UTC
When a public key is included in the PASN parameters element,
it should be encoded using RFC 5480 conventions, and thus the
first octet of the public key should indicate if the public
key is compressed or not.

Fix the implementation to properly adhere to the convention
requirements (for both wpa_supplicant and hostapd).

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
---
 src/ap/ieee802_11.c              | 23 ++++++++++++++++++-----
 src/common/wpa_common.c          | 22 ++++++++++++++++++----
 src/common/wpa_common.h          |  7 ++++++-
 wpa_supplicant/pasn_supplicant.c | 24 ++++++++++++++++++------
 4 files changed, 60 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c378a1c95b..cc83ce6e02 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2937,7 +2937,7 @@  static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 
 	wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
 				  sta->pasn->wrapped_data_format,
-				  pubkey, NULL, 0);
+				  pubkey, 1, NULL, 0);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -3034,7 +3034,7 @@  static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 	const int *groups = hapd->conf->pasn_groups;
 	static const int default_groups[] = { 19, 0 };
 	u16 status = WLAN_STATUS_SUCCESS;
-	int ret;
+	int ret, inc_y;
 	bool derive_keys;
 	u32 i;
 
@@ -3118,9 +3118,22 @@  static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 
 	sta->pasn->group = pasn_params.group;
 
-	secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0,
-					 pasn_params.pubkey,
-					 pasn_params.pubkey_len);
+	if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+		inc_y = 1;
+	} else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+		   pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+		inc_y = 0;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid first octet in pubkey=0x%x",
+			   pasn_params.pubkey[0]);
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
+					 pasn_params.pubkey + 1,
+					 pasn_params.pubkey_len - 1);
 	if (!secret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 04d49ee4cd..600ffc8379 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3419,13 +3419,16 @@  int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
  * @pasn_group: Finite Cyclic Group ID for PASN authentication
  * @wrapped_data_format: Format of the data in the Wrapped Data IE
  * @pubkey: A buffer holding the local public key. Can be NULL
+ * @compressed: In case pubkey is included, indicates if the public key is
+ *     compressed (only x coordinate is included) or not (both x and y
+ *     coordinates are included)
  * @comeback: A buffer holding the comeback token. Can be NULL
  * @after: If comeback is set, defined the comeback time in seconds. -1 to not
  *	include the Comeback After field (frames from non-AP STA).
  */
 void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 			       u8 wrapped_data_format,
-			       struct wpabuf *pubkey,
+			       struct wpabuf *pubkey, bool compressed,
 			       struct wpabuf *comeback, int after)
 {
 	struct pasn_parameter_ie *params;
@@ -3465,13 +3468,24 @@  void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 
 		/*
 		 * 2 octets for the finite cyclic group + 2 octets public key
-		 * length + the actual key
+		 * length + 1 octet for the compressed/uncompressed indication +
+		 * the actual key.
 		 */
-		params->len += 2 + 1 + wpabuf_len(pubkey);
+		params->len += 2 + 1 + 1 + wpabuf_len(pubkey);
 		params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
 
 		wpabuf_put_le16(buf, pasn_group);
-		wpabuf_put_u8(buf, wpabuf_len(pubkey));
+
+		/*
+		 * The first octet should indicate if the public key is
+		 * compressed or not, as defined in RFC 5480 section 2.2.
+		 */
+		wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1);
+		if (compressed)
+			wpabuf_put_u8(buf, WPA_PASN_PUBKEY_COMPRESSED_0);
+		else
+			wpabuf_put_u8(buf, WPA_PASN_PUBKEY_UNCOMPRESSED);
+
 		wpabuf_put_buf(buf, pubkey);
 	}
 }
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 0e9f252ad4..55352d9996 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -546,6 +546,11 @@  struct wpa_pasn_params_data {
 	const u8 *pubkey;
 };
 
+/* See RFC 5480 section 2.2 */
+#define WPA_PASN_PUBKEY_COMPRESSED_0 0x2
+#define WPA_PASN_PUBKEY_COMPRESSED_1 0x3
+#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x4
+
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
 		     int use_sha384);
 
@@ -657,7 +662,7 @@  int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
 
 void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 			       u8 wrapped_data_format,
-			       struct wpabuf *pubkey,
+			       struct wpabuf *pubkey, bool compressed,
 			       struct wpabuf *comeback, int after);
 
 int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 4f5ac589b9..a18fd96f44 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -680,7 +680,7 @@  static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, NULL, -1);
+				  pubkey, 1, NULL, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -753,7 +753,7 @@  static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  NULL, NULL, -1);
+				  NULL, 0, NULL, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -1226,7 +1226,7 @@  int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 	u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
 	u8 mic_len;
 	u16 status;
-	int ret;
+	int ret, inc_y;
 	u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
 			      (WLAN_FC_STYPE_AUTH << 4));
 
@@ -1344,9 +1344,21 @@  int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	secret = crypto_ecdh_set_peerkey(pasn->ecdh, 0,
-					 pasn_params.pubkey,
-					 pasn_params.pubkey_len);
+	if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+		inc_y = 1;
+	} else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+		   pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+		inc_y = 0;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid first octet in pubkey=0x%x",
+			   pasn_params.pubkey[0]);
+		goto fail;
+	}
+
+	secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
+					 pasn_params.pubkey + 1,
+					 pasn_params.pubkey_len - 1);
 
 	if (!secret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");