]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PASN: Encode the public key properly
authorIlan Peer <ilan.peer@intel.com>
Mon, 15 Mar 2021 12:57:01 +0000 (14:57 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 16 Mar 2021 10:31:31 +0000 (12:31 +0200)
When a public key is included in the PASN Parameters element, it should
be encoded using the RFC 5480 conventions, and thus the first octet of
the Ephemeral Public Key field should indicate whether the public key is
compressed and the actual key part starts from the second octet.

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
src/common/wpa_common.c
src/common/wpa_common.h
wpa_supplicant/pasn_supplicant.c

index 66933b200d7645321042fddbfa363013761097c7..cba8868aeac63d1243c5745840f517c307aafa55 100644 (file)
@@ -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, true, 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;
index 04d49ee4cd628d22f6a6b7d88599eda61c330639..493da18d72650b680f824e54ffced5d9c5ade94c 100644 (file)
@@ -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,22 @@ 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 indicates whether the public key is
+                * compressed, as defined in RFC 5480 section 2.2.
+                */
+               wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1);
+               wpabuf_put_u8(buf, compressed ? WPA_PASN_PUBKEY_COMPRESSED_0 :
+                             WPA_PASN_PUBKEY_UNCOMPRESSED);
+
                wpabuf_put_buf(buf, pubkey);
        }
 }
index 0e9f252ad4907e53efb3375fa7d2c9d304fee14e..e51e19483e7975b07629b06a3a2e6f9893145a0a 100644 (file)
@@ -546,6 +546,11 @@ struct wpa_pasn_params_data {
        const u8 *pubkey;
 };
 
+/* See RFC 5480 section 2.2 */
+#define WPA_PASN_PUBKEY_COMPRESSED_0 0x02
+#define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
+#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
+
 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,
index 4f5ac589b9a1730122c3ff245bd2786bd1d4c598..35d732ed55cf066f36a4e5feafe5a75f8af361e6 100644 (file)
@@ -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, true, 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, false, 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");