Browse Source

Fix SAE state validation on AP

Confirm-before-commit validation step allowed execution to continue on
error case. This could result in segfault in sae_check_confirm() if the
temporary SAE data was not available (as it would not be, e.g., in case
of an extra SAE confirm message being received after successful
exchange). Fix this by stopping SAE processing immediately after
detecting unexpected state for confirm message. In addition, make the
public sae.c functions verify sae->tmp before dereferencing it to make
this type of bugs less likely to result in critical issues.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 11 years ago
parent
commit
b64afe22aa
2 changed files with 18 additions and 1 deletions
  1. 2 0
      src/ap/ieee802_11.c
  2. 16 1
      src/common/sae.c

+ 2 - 0
src/ap/ieee802_11.c

@@ -471,6 +471,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 				       HOSTAPD_LEVEL_DEBUG,
 				       "SAE confirm before commit");
 			resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+			goto failed;
 		}
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -502,6 +503,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 	}
 
+failed:
 	sta->auth_alg = WLAN_AUTH_SAE;
 
 	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,

+ 16 - 1
src/common/sae.c

@@ -503,6 +503,8 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
 		       const u8 *password, size_t password_len,
 		       struct sae_data *sae)
 {
+	if (sae->tmp == NULL)
+		return -1;
 	if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
 					  password_len) < 0)
 		return -1;
@@ -634,7 +636,8 @@ fail:
 int sae_process_commit(struct sae_data *sae)
 {
 	u8 k[SAE_MAX_PRIME_LEN];
-	if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
+	if (sae->tmp == NULL ||
+	    (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
 	    (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
 	    sae_derive_keys(sae, k) < 0)
 		return -1;
@@ -646,6 +649,10 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
 		      const struct wpabuf *token)
 {
 	u8 *pos;
+
+	if (sae->tmp == NULL)
+		return;
+
 	wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
 	if (token)
 		wpabuf_put_buf(buf, token);
@@ -990,6 +997,9 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
 {
 	const u8 *sc;
 
+	if (sae->tmp == NULL)
+		return;
+
 	/* Send-Confirm */
 	sc = wpabuf_put(buf, 0);
 	wpabuf_put_le16(buf, sae->send_confirm);
@@ -1021,6 +1031,11 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
 
 	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
 
+	if (sae->tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
+		return -1;
+	}
+
 	if (sae->tmp->ec)
 		sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
 				   sae->tmp->peer_commit_element_ecc,