struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
- if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
#ifdef CONFIG_SAE
sae_deinit_pt(tmp->pt);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(tmp->pk);
+#endif /* CONFIG_SAE_PK */
os_free(tmp);
}
}
}
+#ifdef CONFIG_SAE_PK
+static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
+{
+ struct sae_password_entry *pw;
+
+ if (bss->ssid.wpa_passphrase &&
+ sae_pk_valid_password(bss->ssid.wpa_passphrase))
+ return true;
+
+ for (pw = bss->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk && sae_pk_valid_password(pw->password))
+ return true;
+ }
+
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_SAE_PK
+ if (full_config && hostapd_sae_pk_in_use(bss) &&
+ hostapd_sae_pk_password_without_pk(bss)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
+ return -1;
+ }
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
return 2;
return with_id;
}
+
+
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE_PK
+ struct sae_password_entry *pw;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->pk)
+ return true;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ return false;
+}
+
+
+#ifdef CONFIG_SAE_PK
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
+{
+ bool with_pk = false;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ return false;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk)
+ return false;
+ with_pk = true;
+ }
+
+ return with_pk;
+}
+#endif /* CONFIG_SAE_PK */
auth_alg == WLAN_AUTH_SAE) {
if (auth_transaction == 1 && sta &&
(resp == WLAN_STATUS_SUCCESS ||
- resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ resp == WLAN_STATUS_SAE_PK)) {
wpa_printf(MSG_DEBUG,
"TESTING: Postpone SAE Commit transmission until Confirm is ready");
os_free(sta->sae_postponed_commit);
const char *rx_id = NULL;
int use_pt = 0;
struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
use_pt = sta->sae->tmp->h2e;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
+ os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
+#endif /* CONFIG_SAE_PK */
}
if (rx_id && hapd->conf->sae_pwe != 3)
use_pt = 1;
else if (status_code == WLAN_STATUS_SUCCESS)
use_pt = 0;
- else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
continue;
password = pw->password;
pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
break;
}
if (!password) {
if (update && use_pt &&
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
- NULL, NULL) < 0)
+ NULL, pk) < 0)
return NULL;
if (update && !use_pt &&
if (buf == NULL)
return NULL;
- sae_write_confirm(sta->sae, buf);
+ if (sae_write_confirm(sta->sae, buf) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
return buf;
}
data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+#ifdef CONFIG_SAE_PK
+ if (!data && sta->sae->tmp && sta->sae->tmp->reject_group)
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+#endif /* CONFIG_SAE_PK */
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
- WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
+ if (sta->sae->tmp && sta->sae->tmp->pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (sta->sae->tmp && sta->sae->tmp->h2e)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- if (sta->sae->tmp)
- sta->sae->tmp->h2e = status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ if (sta->sae->tmp) {
+ sta->sae->tmp->h2e =
+ (status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
+ sta->sae->tmp->pk =
+ status_code == WLAN_STATUS_SAE_PK;
+ }
ret = auth_sae_send_commit(hapd, sta, bssid,
!allow_reuse, status_code);
if (ret)
sae_pwe = 1;
else if (id_in_use == 1 && sae_pwe == 0)
sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ if (sae_pwe == 0 && hostapd_sae_pk_in_use(hapd->conf))
+ sae_pwe = 2;
+#endif /* CONFIG_SAE_PK */
return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
(sae_pwe == 1 &&
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)) ||
(sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS ||
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK));
}
static int check_sae_rejected_groups(struct hostapd_data *hapd,
- const struct wpabuf *groups)
+ struct sae_data *sae, bool pk)
{
+ const struct wpabuf *groups;
size_t i, count;
const u8 *pos;
+ if (!sae->tmp)
+ return 0;
+ groups = sae->tmp->peer_rejected_groups;
if (!groups)
return 0;
group = WPA_GET_LE16(pos);
pos += 2;
enabled = sae_is_group_enabled(hapd, group);
- wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
- group, enabled ? "enabled" : "disabled");
+
+#ifdef CONFIG_SAE_PK
+ /* TODO: Could check more explicitly against the matching
+ * sae_password entry only for the somewhat theoretical case of
+ * different passwords using different groups for SAE-PK K_AP
+ * values. */
+ if (pk) {
+ struct sae_password_entry *pw;
+
+ enabled = false;
+ for (pw = hapd->conf->sae_passwords; pw;
+ pw = pw->next) {
+ if (pw->pk && pw->pk->group == group) {
+ enabled = true;
+ break;
+ }
+ }
+ }
+#endif /* CONFIG_SAE_PK */
+
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s%s",
+ group, enabled ? "enabled" : "disabled",
+ pk ? " (PK)" : "");
if (enabled)
return 1;
}
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, groups, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (sta->sae->tmp &&
- check_sae_rejected_groups(
- hapd, sta->sae->tmp->peer_rejected_groups)) {
+ if (check_sae_rejected_groups(hapd, sta->sae,
+ status_code ==
+ WLAN_STATUS_SAE_PK)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp)
h2e = sta->sae->tmp->h2e;
- if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
sta->addr, h2e);
if (hapd->conf->beacon_prot)
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
+ case 11: /* Bits 88-95 */
+#ifdef CONFIG_SAE_PK
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ *pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
+#endif /* CONFIG_SAE_PK */
+ break;
}
}
#endif /* CONFIG_SAE */
if (len < 11 && hapd->conf->beacon_prot)
len = 11;
+#ifdef CONFIG_SAE_PK
+ if (len < 12 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ len = 12;
+#endif /* CONFIG_SAE_PK */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
+ bool sae_pk = false;
+
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+#endif /* CONFIG_SAE_PK */
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
!wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
(hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
- !hostapd_sae_pw_id_in_use(hapd->conf)) ||
+ !hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
hapd->conf->sae_pwe == 3 ||
len < 3)
return pos;
*pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos;
}