diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 66933b200..cba8868ae 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, 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; diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 04d49ee4c..493da18d7 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,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); } } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 0e9f252ad..e51e19483 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 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, diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index 4f5ac589b..35d732ed5 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, 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");