[wpa_supplicant] Cumulative patch from 6151c9b90

Bug: 130813391
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: DPP test: act.py -c ../WifiDppConfig.json -tc WifiDppTest
Test: Regression test passed (Bug: 130831127)

6151c9b90 EAP-pwd server: Remove unused srandom() call
d2d1a324c EAP-pwd peer: Fix reassembly buffer handling
fe76f487e EAP-pwd server: Fix reassembly buffer handling
a9d224f56 EAP-pwd server: Fix a memory leak on error path
90ee1bf5f EAP-MSCHAPv2: Propagate GetAsymetricStartKey() failures up from getKey()
824cb5a53 RSN: Ignore IGTK configuration errors with swapped KeyID values
dfdabd917 RSN: Report completion only after IGTK configuration
bce3d4f70 autoscan: Disable when we move above WPA_SCANNING state
eb3234c07 SAE: Use open authentication to reassociate for PMKSA caching
fe01cd006 Fix FILS ERP association event with 4-way HS offload drivers
323a51cc0 nl80211: Handle NL80211_CMD_PROBE_CLIENT command response
28f19a3ae nl80211: More detailed PROBE_CLIENT debug print
31cf52bf2 Do not clear FT IEs twice in sme_deinit()
01ac337b3 Stop SA Query on disconnection
7a206c504 Add debug print on stopping SA Query procedure
710c69238 P2PS: Cleanup pending_p2ps_group flag
0be8b9238 mka: Avoid memory leak in unexpected case in RECEIVE
984d5b7e1 mesh: Fix random llid generation in an error case
10cf866ba mesh: Fix operations after SAE state machine removing the STA
153d4c501 mesh: Fix SAE reauthentication processing
2f6805139 Fix hostapd BSS_TM_REQ handling of bss_term parameter
e6ac47b47 Fix debug print in GET_PREF_FREQ_LIST handler
2e70e807c D-Bus: Fix P2P GroupStarted signal not to use uninitialized IP buffer
c5fff8bbd nl80211: Update assoc_freq and bss->freq based on real association info
091c22771 nl80211: Clear bss->freq on station mode disconnection
cb5db189e Remove the unused crypto_ec_cofactor() function
8b093db2c EAP-pwd: Remove unused checks for cofactor > 1 cases
92e1b96c2 EAP-pwd: Disallow ECC groups with a prime under 256 bits
6fe3ee722 tests: EAP-pwd local failure in crypto_bignum_rand()
6570949b2 OpenSSL: Fix server side openssl_ecdh_curves configuration with 1.0.2
52b1cb5d7 tests: crypto_hash_finish() failure in eap_pwd_kdf()
56ac1f9df RRM: Set last beacon report indication in the last element only
6f484978f Document BSS expiration configurables
8f36c84a2 bsd: Fix a typo in error message
dd1a8cef4 Remove unnecessary copying of SSID and BSSID for external_auth
4ffb0fefe hostapd: Support external authentication offload in AP mode
236e793e7 nl80211: External authentication in driver-based AP SME mode
2ab19f4be Reset beacon_set_done on disabling interface

Change-Id: I5642b46d79aee83dd4f4307bf781d57b318831bd
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index d45ab84..de40171 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -364,4 +364,14 @@
 	return hapd->driver->channel_info(hapd->drv_priv, ci);
 }
 
+static inline int
+hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
+				      struct external_auth *params)
+{
+	if (!hapd->driver || !hapd->drv_priv ||
+	    !hapd->driver->send_external_auth_status)
+		return -1;
+	return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 77742f4..20c8e8f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -352,6 +352,7 @@
 		return;
 	}
 	hapd->started = 0;
+	hapd->beacon_set_done = 0;
 
 	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
 	iapp_deinit(hapd->iapp);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 28aca46..5cd2562 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -701,6 +701,21 @@
 }
 
 
+static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
+					      struct sta_info *sta, u16 status)
+{
+	struct external_auth params;
+
+	os_memset(&params, 0, sizeof(params));
+	params.status = status;
+	params.bssid = sta->addr;
+	if (status == WLAN_STATUS_SUCCESS && sta->sae)
+		params.pmkid = sta->sae->pmkid;
+
+	hostapd_drv_send_external_auth_status(hapd, &params);
+}
+
+
 void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
 #ifndef CONFIG_NO_VLAN
@@ -739,14 +754,18 @@
 	sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
 	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
 			       sta->sae->pmk, sta->sae->pmkid);
+	sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
 }
 
 
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
-		       const u8 *bssid, u8 auth_transaction, int allow_reuse)
+		       const u8 *bssid, u8 auth_transaction, int allow_reuse,
+		       int *sta_removed)
 {
 	int ret;
 
+	*sta_removed = 0;
+
 	if (auth_transaction != 1 && auth_transaction != 2)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
@@ -847,7 +866,7 @@
 			 * additional events.
 			 */
 			return sae_sm_step(hapd, sta, bssid, auth_transaction,
-					   0);
+					   0, sta_removed);
 		}
 		break;
 	case SAE_CONFIRMED:
@@ -880,8 +899,9 @@
 			wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
 				   ") doing reauthentication",
 				   MAC2STR(sta->addr));
-			ap_free_sta(hapd, sta);
 			wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+			ap_free_sta(hapd, sta);
+			*sta_removed = 1;
 		} else if (auth_transaction == 1) {
 			wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
@@ -963,6 +983,7 @@
 	int *groups = hapd->conf->sae_groups;
 	int default_groups[] = { 19, 0 };
 	const u8 *pos, *end;
+	int sta_removed = 0;
 
 	if (!groups)
 		groups = default_groups;
@@ -1157,7 +1178,7 @@
 		}
 
 		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
-				   allow_reuse);
+				   allow_reuse, &sta_removed);
 	} else if (auth_transaction == 2) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -1198,7 +1219,8 @@
 			}
 			sta->sae->rc = peer_send_confirm;
 		}
-		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0);
+		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
+			&sta_removed);
 	} else {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -1210,7 +1232,7 @@
 	}
 
 reply:
-	if (resp != WLAN_STATUS_SUCCESS) {
+	if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
 		pos = mgmt->u.auth.variable;
 		end = ((const u8 *) mgmt) + len;
 
@@ -1220,6 +1242,7 @@
 		    !data && end - pos >= 2)
 			data = wpabuf_alloc_copy(pos, 2);
 
+		sae_sme_send_external_auth_status(hapd, sta, resp);
 		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				data ? wpabuf_head(data) : (u8 *) "",
@@ -1227,8 +1250,9 @@
 	}
 
 remove_sta:
-	if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
-				   status_code != WLAN_STATUS_SUCCESS)) {
+	if (!sta_removed && sta->added_unassoc &&
+	    (resp != WLAN_STATUS_SUCCESS ||
+	     status_code != WLAN_STATUS_SUCCESS)) {
 		hostapd_drv_sta_remove(hapd, sta->addr);
 		sta->added_unassoc = 0;
 	}
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index a28ddbd..12109ce 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -704,14 +704,6 @@
 void crypto_ec_deinit(struct crypto_ec *e);
 
 /**
- * crypto_ec_cofactor - Set the cofactor into the big number
- * @e: EC context from crypto_ec_init()
- * @cofactor: Cofactor of curve.
- * Returns: 0 on success, -1 on failure
- */
-int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor);
-
-/**
  * crypto_ec_prime_len - Get length of the prime in octets
  * @e: EC context from crypto_ec_init()
  * Returns: Length of the prime defining the group
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index d391f48..aad40af 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -310,6 +310,9 @@
 
 	os_free(ctx);
 
+	if (TEST_FAIL())
+		return -1;
+
 	return 0;
 }
 
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index 980fa42..ed30efa 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -278,6 +278,9 @@
 
 	os_free(ctx);
 
+	if (TEST_FAIL())
+		return -1;
+
 	return ret;
 }
 
diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c
index 8099193..1724456 100644
--- a/src/crypto/crypto_linux.c
+++ b/src/crypto/crypto_linux.c
@@ -386,6 +386,9 @@
 	}
 
 	crypto_hash_deinit(ctx);
+
+	if (TEST_FAIL())
+		return -1;
 	return 0;
 }
 
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 0f52101..1b0c1ec 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1054,6 +1054,9 @@
 	HMAC_CTX_free(ctx->ctx);
 	bin_clear_free(ctx, sizeof(*ctx));
 
+	if (TEST_FAIL())
+		return -1;
+
 	if (res == 1) {
 		*len = mdlen;
 		return 0;
@@ -1317,6 +1320,8 @@
 
 int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
 {
+	if (TEST_FAIL())
+		return -1;
 	return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
 }
 
@@ -1631,13 +1636,6 @@
 }
 
 
-int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
-{
-	return EC_GROUP_get_cofactor(e->group, (BIGNUM *) cofactor,
-				     e->bnctx) == 0 ? -1 : 0;
-}
-
-
 struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
 {
 	if (TEST_FAIL())
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 10cdae6..976a008 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -953,6 +953,8 @@
 	ret = 0;
 done:
 	bin_clear_free(ctx, sizeof(*ctx));
+	if (TEST_FAIL())
+		return -1;
 	return ret;
 }
 
@@ -1083,6 +1085,8 @@
 	int ret = 0;
 	WC_RNG rng;
 
+	if (TEST_FAIL())
+		return -1;
 	if (wc_InitRng(&rng) != 0)
 		return -1;
 	if (mp_rand_prime((mp_int *) r,
@@ -1348,16 +1352,6 @@
 }
 
 
-int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
-{
-	if (!e || !cofactor)
-		return -1;
-
-	mp_set((mp_int *) cofactor, e->key.dp->cofactor);
-	return 0;
-}
-
-
 struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
 {
 	if (TEST_FAIL())
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 7fde21c..620254a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -5055,6 +5055,9 @@
 		return -1;
 #else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
 #ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+		SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#endif
 		if (SSL_CTX_set1_curves_list(ssl_ctx,
 					     params->openssl_ecdh_curves) !=
 		    1) {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 23423d9..e7c8f31 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2156,17 +2156,19 @@
  *	use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give
  *	the real status code for failures. Used only for the request interface
  *	from user space to the driver.
+ * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
  */
 struct external_auth {
 	enum {
 		EXT_AUTH_START,
 		EXT_AUTH_ABORT,
 	} action;
-	u8 bssid[ETH_ALEN];
-	u8 ssid[SSID_MAX_LEN];
+	const u8 *bssid;
+	const u8 *ssid;
 	size_t ssid_len;
 	unsigned int key_mgmt_suite;
 	u16 status;
+	const u8 *pmkid;
 };
 
 /**
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8621aa0..4675496 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -143,7 +143,7 @@
 	ireq->i_data = arg;
 
 	if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
+		wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
 			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
 		return -1;
 	}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 661e34e..21d1398 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -307,6 +307,7 @@
 		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
 	drv->associated = 0;
 	os_memset(drv->bssid, 0, ETH_ALEN);
+	drv->first_bss->freq = 0;
 }
 
 
@@ -2469,6 +2470,16 @@
 	if (nl80211_action_subscribe_ap(bss))
 		goto out_err;
 
+	if (bss->drv->device_ap_sme) {
+		u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+		/* Register for all Authentication frames */
+		if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0)
+		    < 0)
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
+	}
+
 	nl80211_mgmt_handle_register_eloop(bss);
 	return 0;
 
@@ -4160,6 +4171,9 @@
 	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
 		goto fail;
 
+	if (drv->device_ap_sme && (params->key_mgmt_suites & WPA_KEY_MGMT_SAE))
+	     nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT);
+
 	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
 		   params->pairwise_ciphers);
 	num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
@@ -8272,6 +8286,7 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
+	u64 cookie;
 	int ret;
 
 	if (!drv->poll_command_supported) {
@@ -8285,11 +8300,16 @@
 		return;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
 			   MACSTR " failed: ret=%d (%s)",
 			   MAC2STR(addr), ret, strerror(-ret));
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Client probe request addr=" MACSTR
+			   " cookie=%llu", MAC2STR(addr),
+			   (long long unsigned int) cookie);
 	}
 }
 
@@ -10792,15 +10812,27 @@
 	struct nl_msg *msg = NULL;
 	int ret = -1;
 
+	/* External auth command/status is intended for drivers that implement
+	 * intenral SME but want to offload authentication processing (e.g.,
+	 * SAE) to hostapd/wpa_supplicant. Do nott send the status to drivers
+	 * which do not support AP SME or use wpa_supplicant/hostapd SME.
+	 */
+	if (!bss->drv->device_ap_sme ||
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+		return -1;
+
 	wpa_dbg(drv->ctx, MSG_DEBUG,
 		"nl80211: External auth status: %u", params->status);
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
 	if (!msg ||
 	    nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
-	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
-		    params->ssid) ||
-	    nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid))
+	    (params->ssid && params->ssid_len &&
+	     nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+	    (params->pmkid &&
+	     nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
+	    (params->bssid &&
+	     nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
 		goto fail;
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index ffddd94..ee7b4da 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -267,8 +267,6 @@
 		event.assoc_info.req_ies_len = nla_len(req_ie);
 	}
 
-	event.assoc_info.freq = drv->assoc_freq;
-
 	/* When this association was initiated outside of wpa_supplicant,
 	 * drv->ssid needs to be set here to satisfy later checking. */
 	ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid);
@@ -279,6 +277,9 @@
 			   wpa_ssid_txt(drv->ssid, drv->ssid_len));
 	}
 
+	event.assoc_info.freq = drv->assoc_freq;
+	drv->first_bss->freq = drv->assoc_freq;
+
 	nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
 
 	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -408,6 +409,7 @@
 	}
 
 	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+	drv->first_bss->freq = drv->assoc_freq;
 
 	if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
 	    (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
@@ -1436,16 +1438,23 @@
 				       struct nlattr **tb)
 {
 	union wpa_event_data data;
+	const u8 *addr;
+	u64 cookie = 0;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
-	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	if (!addr)
+		return;
+	if (tb[NL80211_ATTR_COOKIE])
+		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+	wpa_printf(MSG_DEBUG, "nl80211: Probe client event (addr=" MACSTR
+		   " ack=%d cookie=%llu)", MAC2STR(addr),
+		   tb[NL80211_ATTR_ACK] != NULL,
+		   (long long unsigned int) cookie);
+	if (!tb[NL80211_ATTR_ACK])
 		return;
 
 	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.client_poll.addr,
-		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
+	os_memcpy(data.client_poll.addr, addr, ETH_ALEN);
 	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
 }
 
@@ -2269,11 +2278,9 @@
 	event.external_auth.ssid_len = nla_len(tb[NL80211_ATTR_SSID]);
 	if (event.external_auth.ssid_len > SSID_MAX_LEN)
 		return;
-	os_memcpy(event.external_auth.ssid, nla_data(tb[NL80211_ATTR_SSID]),
-		  event.external_auth.ssid_len);
+	event.external_auth.ssid = nla_data(tb[NL80211_ATTR_SSID]);
 
-	os_memcpy(event.external_auth.bssid, nla_data(tb[NL80211_ATTR_BSSID]),
-		  ETH_ALEN);
+	event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
 
 	wpa_printf(MSG_DEBUG,
 		   "nl80211: External auth action: %u, AKM: 0x%x",
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 4288b52..884150e 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -85,10 +85,23 @@
 }
 
 
+static int eap_pwd_suitable_group(u16 num)
+{
+	/* Do not allow ECC groups with prime under 256 bits based on guidance
+	 * for the similar design in SAE. */
+	return num == 19 || num == 20 || num == 21 ||
+		num == 28 || num == 29 || num == 30;
+}
+
+
 EAP_PWD_group * get_eap_pwd_group(u16 num)
 {
 	EAP_PWD_group *grp;
 
+	if (!eap_pwd_suitable_group(num)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
+		return NULL;
+	}
 	grp = os_zalloc(sizeof(EAP_PWD_group));
 	if (!grp)
 		return NULL;
@@ -138,7 +151,7 @@
 	u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
 		       * mask */
 	size_t primebytelen = 0, primebitlen;
-	struct crypto_bignum *x_candidate = NULL, *cofactor = NULL;
+	struct crypto_bignum *x_candidate = NULL;
 	const struct crypto_bignum *prime;
 	u8 mask, found_ctr = 0, is_odd = 0;
 
@@ -148,21 +161,15 @@
 	os_memset(x_bin, 0, sizeof(x_bin));
 
 	prime = crypto_ec_get_prime(grp->group);
-	cofactor = crypto_bignum_init();
 	grp->pwe = crypto_ec_point_init(grp->group);
 	tmp1 = crypto_bignum_init();
 	pm1 = crypto_bignum_init();
 	one = crypto_bignum_init_set((const u8 *) "\x01", 1);
-	if (!cofactor || !grp->pwe || !tmp1 || !pm1 || !one) {
+	if (!grp->pwe || !tmp1 || !pm1 || !one) {
 		wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
 		goto fail;
 	}
 
-	if (crypto_ec_cofactor(grp->group, cofactor) < 0) {
-		wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
-			   "curve");
-		goto fail;
-	}
 	primebitlen = crypto_ec_prime_len_bits(grp->group);
 	primebytelen = crypto_ec_prime_len(grp->group);
 	if ((prfbuf = os_malloc(primebytelen)) == NULL) {
@@ -327,19 +334,6 @@
 		goto fail;
 	}
 
-	if (!crypto_bignum_is_one(cofactor)) {
-		/* make sure the point is not in a small sub-group */
-		if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor,
-					grp->pwe) != 0) {
-			wpa_printf(MSG_INFO,
-				   "EAP-pwd: cannot multiply generator by order");
-			goto fail;
-		}
-		if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) {
-			wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity");
-			goto fail;
-		}
-	}
 	wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
 
 	if (0) {
@@ -349,7 +343,6 @@
 		ret = 1;
 	}
 	/* cleanliness and order.... */
-	crypto_bignum_deinit(cofactor, 1);
 	crypto_bignum_deinit(x_candidate, 1);
 	crypto_bignum_deinit(pm1, 0);
 	crypto_bignum_deinit(tmp1, 1);
@@ -451,7 +444,6 @@
 	struct crypto_ec_point *element;
 	const struct crypto_bignum *prime;
 	size_t prime_len;
-	struct crypto_bignum *cofactor = NULL;
 
 	prime = crypto_ec_get_prime(group->group);
 	prime_len = crypto_ec_prime_len(group->group);
@@ -476,35 +468,7 @@
 		goto fail;
 	}
 
-	cofactor = crypto_bignum_init();
-	if (!cofactor || crypto_ec_cofactor(group->group, cofactor) < 0) {
-		wpa_printf(MSG_INFO,
-			   "EAP-pwd: Unable to get cofactor for curve");
-		goto fail;
-	}
-
-	if (!crypto_bignum_is_one(cofactor)) {
-		struct crypto_ec_point *point;
-		int ok = 1;
-
-		/* check to ensure peer's element is not in a small sub-group */
-		point = crypto_ec_point_init(group->group);
-		if (!point ||
-		    crypto_ec_point_mul(group->group, element,
-					cofactor, point) != 0 ||
-		    crypto_ec_point_is_at_infinity(group->group, point))
-			ok = 0;
-		crypto_ec_point_deinit(point, 0);
-
-		if (!ok) {
-			wpa_printf(MSG_INFO,
-				   "EAP-pwd: Small sub-group check on peer element failed");
-			goto fail;
-		}
-	}
-
 out:
-	crypto_bignum_deinit(cofactor, 0);
 	return element;
 fail:
 	crypto_ec_point_deinit(element, 0);
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 877495c..249baec 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -856,9 +856,13 @@
 
 	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
 	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
-	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 0, 0);
+	if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1,
+				    0) < 0 ||
+	    get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				    MSCHAPV2_KEY_LEN, 0, 0) < 0) {
+		os_free(key);
+		return NULL;
+	}
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
 			key, key_len);
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 4be4fcf..76fcad4 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -309,7 +309,7 @@
 				const u8 *payload, size_t payload_len)
 {
 	struct crypto_ec_point *K = NULL;
-	struct crypto_bignum *mask = NULL, *cofactor = NULL;
+	struct crypto_bignum *mask = NULL;
 	const u8 *ptr = payload;
 	u8 *scalar, *element;
 	size_t prime_len, order_len;
@@ -527,21 +527,14 @@
 
 	data->private_value = crypto_bignum_init();
 	data->my_element = crypto_ec_point_init(data->grp->group);
-	cofactor = crypto_bignum_init();
 	data->my_scalar = crypto_bignum_init();
 	mask = crypto_bignum_init();
-	if (!data->private_value || !data->my_element || !cofactor ||
+	if (!data->private_value || !data->my_element ||
 	    !data->my_scalar || !mask) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
 		goto fin;
 	}
 
-	if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
-		wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
-			   "for curve");
-		goto fin;
-	}
-
 	if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
 				  data->my_scalar) < 0)
 		goto fin;
@@ -595,17 +588,8 @@
 		goto fin;
 	}
 
-	/* ensure that the shared key isn't in a small sub-group */
-	if (!crypto_bignum_is_one(cofactor)) {
-		if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) {
-			wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
-				   "shared key point by order");
-			goto fin;
-		}
-	}
-
 	/*
-	 * This check is strictly speaking just for the case above where
+	 * This check is strictly speaking just for the case where
 	 * co-factor > 1 but it was suggested that even though this is probably
 	 * never going to happen it is a simple and safe check "just to be
 	 * sure" so let's be safe.
@@ -644,7 +628,6 @@
 
 fin:
 	crypto_bignum_deinit(mask, 1);
-	crypto_bignum_deinit(cofactor, 1);
 	crypto_ec_point_deinit(K, 1);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
@@ -949,6 +932,13 @@
 	 * buffer and ACK the fragment
 	 */
 	if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+		if (!data->inbuf) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-pwd: No buffer for reassembly");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			return NULL;
+		}
 		data->in_frag_pos += len;
 		if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
 			wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
@@ -975,7 +965,7 @@
 	/*
 	 * we're buffering and this is the last fragment
 	 */
-	if (data->in_frag_pos) {
+	if (data->in_frag_pos && data->inbuf) {
 		wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
 			   (int) len);
 		pos = wpabuf_head_u8(data->inbuf);
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 6c47bb6..e9e03b0 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -551,9 +551,13 @@
 	if (key == NULL)
 		return NULL;
 	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
-	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 1);
+	if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0,
+				    1) < 0 ||
+	    get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				    MSCHAPV2_KEY_LEN, 1, 1) < 0) {
+		os_free(key);
+		return NULL;
+	}
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 
 	return key;
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 9799c81..e720a28 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -311,7 +311,7 @@
 static void eap_pwd_build_confirm_req(struct eap_sm *sm,
 				      struct eap_pwd_data *data, u8 id)
 {
-	struct crypto_hash *hash;
+	struct crypto_hash *hash = NULL;
 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
 	u16 grp;
 	size_t prime_len, order_len;
@@ -392,6 +392,7 @@
 
 	/* all done with the random function */
 	eap_pwd_h_final(hash, conf);
+	hash = NULL;
 	os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
 
 	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
@@ -404,6 +405,7 @@
 	bin_clear_free(cruft, prime_len * 2);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
+	eap_pwd_h_final(hash, NULL);
 }
 
 
@@ -648,7 +650,6 @@
 			    const u8 *payload, size_t payload_len)
 {
 	const u8 *ptr;
-	struct crypto_bignum *cofactor = NULL;
 	struct crypto_ec_point *K = NULL;
 	int res = 0;
 	size_t prime_len, order_len;
@@ -667,20 +668,13 @@
 	}
 
 	data->k = crypto_bignum_init();
-	cofactor = crypto_bignum_init();
 	K = crypto_ec_point_init(data->grp->group);
-	if (!data->k || !cofactor || !K) {
+	if (!data->k || !K) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
 			   "fail");
 		goto fin;
 	}
 
-	if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
-		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
-			   "cofactor for curve");
-		goto fin;
-	}
-
 	/* element, x then y, followed by scalar */
 	ptr = payload;
 	data->peer_element = eap_pwd_get_element(data->grp, ptr);
@@ -718,18 +712,8 @@
 		goto fin;
 	}
 
-	/* ensure that the shared key isn't in a small sub-group */
-	if (!crypto_bignum_is_one(cofactor)) {
-		if (crypto_ec_point_mul(data->grp->group, K, cofactor,
-					K) != 0) {
-			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
-				   "multiply shared key point by order!\n");
-			goto fin;
-		}
-	}
-
 	/*
-	 * This check is strictly speaking just for the case above where
+	 * This check is strictly speaking just for the case where
 	 * co-factor > 1 but it was suggested that even though this is probably
 	 * never going to happen it is a simple and safe check "just to be
 	 * sure" so let's be safe.
@@ -748,7 +732,6 @@
 
 fin:
 	crypto_ec_point_deinit(K, 1);
-	crypto_bignum_deinit(cofactor, 1);
 
 	if (res)
 		eap_pwd_state(data, PWD_Confirm_Req);
@@ -761,7 +744,7 @@
 eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
 			     const u8 *payload, size_t payload_len)
 {
-	struct crypto_hash *hash;
+	struct crypto_hash *hash = NULL;
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
@@ -836,6 +819,7 @@
 
 	/* all done */
 	eap_pwd_h_final(hash, conf);
+	hash = NULL;
 
 	ptr = (u8 *) payload;
 	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -855,6 +839,7 @@
 
 fin:
 	bin_clear_free(cruft, prime_len * 2);
+	eap_pwd_h_final(hash, NULL);
 }
 
 
@@ -927,6 +912,12 @@
 	 * the first and all intermediate fragments have the M bit set
 	 */
 	if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+		if (!data->inbuf) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-pwd: No buffer for reassembly");
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
 		if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
 			wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
 				   "attack detected! (%d+%d > %d)",
@@ -947,7 +938,7 @@
 	 * last fragment won't have the M bit set (but we're obviously
 	 * buffering fragments so that's how we know it's the last)
 	 */
-	if (data->in_frag_pos) {
+	if (data->in_frag_pos && data->inbuf) {
 		pos = wpabuf_head_u8(data->inbuf);
 		len = data->in_frag_pos;
 		wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
@@ -1047,14 +1038,6 @@
 int eap_server_pwd_register(void)
 {
 	struct eap_method *eap;
-	struct timeval tp;
-	struct timezone tz;
-	u32 sr;
-
-	sr = 0xdeaddada;
-	(void) gettimeofday(&tp, &tz);
-	sr ^= (tp.tv_sec ^ tp.tv_usec);
-	srandom(sr);
 
 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 				      EAP_VENDOR_IETF, EAP_TYPE_PWD,
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 8cdce30..1c4dc3e 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -214,6 +214,10 @@
 	SM_ENTRY(CP, RECEIVE);
 	/* RECEIVE state machine not keep with Figure 12-2 in
 	 * IEEE Std 802.1X-2010 */
+	if (sm->oki) {
+		ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+		os_free(sm->oki);
+	}
 	sm->oki = sm->lki;
 	sm->oan = sm->lan;
 	sm->otx = sm->ltx;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index a7adbad..66a8643 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1021,8 +1021,6 @@
 	}
 	os_memset(&gd, 0, sizeof(gd));
 
-	wpa_supplicant_key_neg_complete(sm, sm->bssid,
-					key_info & WPA_KEY_INFO_SECURE);
 	return 0;
 }
 
@@ -1060,9 +1058,27 @@
 			   broadcast_ether_addr,
 			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
 			   igtk->igtk, len) < 0) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"WPA: Failed to configure IGTK to the driver");
-		return -1;
+		if (keyidx == 0x0400 || keyidx == 0x0500) {
+			/* Assume the AP has broken PMF implementation since it
+			 * seems to have swapped the KeyID bytes. The AP cannot
+			 * be trusted to implement BIP correctly or provide a
+			 * valid IGTK, so do not try to configure this key with
+			 * swapped KeyID bytes. Instead, continue without
+			 * configuring the IGTK so that the driver can drop any
+			 * received group-addressed robust management frames due
+			 * to missing keys.
+			 *
+			 * Normally, this error behavior would result in us
+			 * disconnecting, but there are number of deployed APs
+			 * with this broken behavior, so as an interoperability
+			 * workaround, allow the connection to proceed. */
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: Ignore IGTK configuration error due to invalid IGTK KeyID byte order");
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to configure IGTK to the driver");
+			return -1;
+		}
 	}
 
 	if (wnm_sleep) {
@@ -1503,8 +1519,11 @@
 	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
 
 	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
-		wpa_supplicant_key_neg_complete(sm, sm->bssid,
-						key_info & WPA_KEY_INFO_SECURE);
+		/* No GTK to be set to the driver */
+	} else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: No GTK KDE included in EAPOL-Key msg 3/4");
+		goto failed;
 	} else if (ie.gtk &&
 	    wpa_supplicant_pairwise_gtk(sm, key,
 					ie.gtk, ie.gtk_len, key_info) < 0) {
@@ -1519,6 +1538,10 @@
 		goto failed;
 	}
 
+	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
+		wpa_supplicant_key_neg_complete(sm, sm->bssid,
+						key_info & WPA_KEY_INFO_SECURE);
+
 	if (ie.gtk)
 		wpa_sm_set_rekey_offload(sm);