wpa_supplicant: Add SAE handshake support for WPA3-PSK

Under WPA3-Personal, SAE authentication is used to derive PMK
which is more secure and immune to offline dictionary attacks.
1. Add modules to generate SAE commit/confirm for the handshake
2. Add modules that build and parse SAE data in Auth frames
3. Add WPA3 association and key mgmt definitions
4. Invert y-bit while solving for ECC co-ordinate -
     Once an X co-ordinate is obtained, solving for Y co-ordinate
     using an elliptical curve equation results in 2 possible values,
     Y and (P - Y), where p is the prime number. The co-ordinates are
     used for deriving keys in SAE handshake. As par the 802.11 spec
     if LSB of X is same as LSB of Y then Y is chosen, (P - Y) otherwise.
     This is not what is implemented, so fix this behavior to obtain the
     correct Y co-ordinate.
This commit is contained in:
Nachiket Kukade 2020-04-29 18:45:29 +05:30
parent 8f5f828ad6
commit 6b76228fcb
14 changed files with 464 additions and 72 deletions

View file

@ -56,6 +56,7 @@ typedef enum {
WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */
WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */
WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */
WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */
WIFI_AUTH_MAX
} wifi_auth_mode_t;

View file

@ -50,6 +50,7 @@ set(srcs "port/os_xtensa.c"
"src/esp_supplicant/esp_wpa_main.c"
"src/esp_supplicant/esp_wpas_glue.c"
"src/esp_supplicant/esp_wps.c"
"src/esp_supplicant/esp_wpa3.c"
"src/rsn_supp/pmksa_cache.c"
"src/rsn_supp/wpa.c"
"src/rsn_supp/wpa_ie.c"

View file

@ -159,6 +159,7 @@
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@ -225,6 +226,32 @@
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
#define WLAN_EID_VENDOR_SPECIFIC 221
#define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240
#define WLAN_EID_DILS 241
#define WLAN_EID_FRAGMENT 242
#define WLAN_EID_EXTENSION 255
/* Element ID Extension (EID 255) values */
#define WLAN_EID_EXT_ASSOC_DELAY_INFO 1
#define WLAN_EID_EXT_FILS_REQ_PARAMS 2
#define WLAN_EID_EXT_FILS_KEY_CONFIRM 3
#define WLAN_EID_EXT_FILS_SESSION 4
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7
#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
#define WLAN_EID_EXT_FILS_PUBLIC_KEY 12
#define WLAN_EID_EXT_FILS_NONCE 13
#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
#define WLAN_EID_EXT_OWE_DH_PARAM 32
#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
#define WLAN_EID_EXT_HE_CAPABILITIES 35
#define WLAN_EID_EXT_HE_OPERATION 36
/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */

View file

@ -35,7 +35,7 @@ void bin_clear_free(void *bin, size_t len)
}
}
int sae_set_group(struct sae_data *sae, u16 group)
int sae_set_group(struct sae_data *sae, int group)
{
struct sae_temporary_data *tmp;
@ -47,6 +47,8 @@ int sae_set_group(struct sae_data *sae, u16 group)
/* First, check if this is an ECC group */
tmp->ec = crypto_ec_init(group);
if (tmp->ec) {
wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
group);
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
@ -57,6 +59,8 @@ int sae_set_group(struct sae_data *sae, u16 group)
/* Not an ECC group, check FFC */
tmp->dh = dh_groups_get(group);
if (tmp->dh) {
wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
group);
sae->group = group;
tmp->prime_len = tmp->dh->prime_len;
if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
@ -84,6 +88,8 @@ int sae_set_group(struct sae_data *sae, u16 group)
}
/* Unsupported group */
wpa_printf(MSG_DEBUG,
"SAE: Group %d not supported by the crypto library", group);
return -1;
}
@ -105,6 +111,7 @@ void sae_clear_temp_data(struct sae_data *sae)
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@ -423,12 +430,13 @@ static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len)
size_t password_len, const char *identifier)
{
u8 counter, k = 40;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[2];
size_t len[2];
const u8 *addr[3];
size_t len[3];
size_t num_elem;
u8 dummy_password[32];
size_t dummy_password_len;
int pwd_seed_odd = 0;
@ -460,10 +468,13 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
if (identifier)
wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
identifier);
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* base = password
* base = password [|| identifier]
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* base || counter)
*/
@ -471,8 +482,15 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
addr[0] = password;
len[0] = password_len;
addr[1] = &counter;
len[1] = sizeof(counter);
num_elem = 1;
if (identifier) {
addr[num_elem] = (const u8 *) identifier;
len[num_elem] = os_strlen(identifier);
num_elem++;
}
addr[num_elem] = &counter;
len[num_elem] = sizeof(counter);
num_elem++;
/*
* Continue for at least k iterations to protect against side-channel
@ -490,8 +508,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
}
wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
pwd_seed) < 0)
if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
addr, len, pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
@ -549,12 +567,13 @@ fail:
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len)
size_t password_len, const char *identifier)
{
u8 counter;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[2];
size_t len[2];
const u8 *addr[3];
size_t len[3];
size_t num_elem;
int found = 0;
if (sae->tmp->pwe_ffc == NULL) {
@ -569,14 +588,21 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* password || counter)
* password [|| identifier] || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
addr[0] = password;
len[0] = password_len;
addr[1] = &counter;
len[1] = sizeof(counter);
num_elem = 1;
if (identifier) {
addr[num_elem] = (const u8 *) identifier;
len[num_elem] = os_strlen(identifier);
num_elem++;
}
addr[num_elem] = &counter;
len[num_elem] = sizeof(counter);
num_elem++;
for (counter = 1; !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@ -589,8 +615,8 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
}
wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
pwd_seed) < 0)
if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
addr, len, pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
if (res < 0)
@ -697,13 +723,15 @@ fail:
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
struct sae_data *sae)
const char *identifier, struct sae_data *sae)
{
if (sae->tmp == NULL ||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
password_len) < 0) ||
password_len,
identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len) < 0) ||
password_len,
identifier) < 0) ||
sae_derive_commit(sae) < 0)
return -1;
return 0;
@ -838,7 +866,7 @@ int sae_process_commit(struct sae_data *sae)
}
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token)
const struct wpabuf *token, const char *identifier)
{
u8 *pos;
@ -872,6 +900,16 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
if (identifier) {
/* Password Identifier element */
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + os_strlen(identifier));
wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
wpabuf_put_str(buf, identifier);
wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
identifier);
}
}
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
@ -915,25 +953,71 @@ u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
return WLAN_STATUS_SUCCESS;
}
static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
{
int ret = end - pos >= 3 &&
pos[0] == WLAN_EID_EXTENSION &&
pos[1] >= 1 &&
end - pos - 2 >= pos[1] &&
pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
return ret;
}
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
size_t *token_len)
{
if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) {
size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
sae->tmp->prime_len);
size_t scalar_elem_len, tlen;
const u8 *elem;
if (token)
*token = NULL;
if (token_len)
*token_len = 0;
scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
if (scalar_elem_len >= (size_t) (end - *pos))
return; /* No extra data beyond peer scalar and element */
/* It is a bit difficult to parse this now that there is an
* optional variable length Anti-Clogging Token field and
* optional variable length Password Identifier element in the
* frame. We are sending out fixed length Anti-Clogging Token
* fields, so use that length as a requirement for the received
* token and check for the presence of possible Password
* Identifier element based on the element header information.
*/
tlen = end - (*pos + scalar_elem_len);
if (tlen < SHA256_MAC_LEN) {
wpa_printf(MSG_DEBUG,
"SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
(unsigned int) tlen);
return;
}
elem = *pos + scalar_elem_len;
if (sae_is_password_id_elem(elem, end)) {
/* Password Identifier element takes out all available
* extra octets, so there can be no Anti-Clogging token in
* this frame. */
return;
}
elem += SHA256_MAC_LEN;
if (sae_is_password_id_elem(elem, end)) {
/* Password Identifier element is included in the end, so
* remove its length from the Anti-Clogging token field. */
tlen -= 2 + elem[1];
}
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
if (token)
*token = *pos;
if (token_len)
*token_len = tlen;
*pos += tlen;
} else {
if (token)
*token = NULL;
if (token_len)
*token_len = 0;
}
}
static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
@ -973,7 +1057,6 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
crypto_bignum_deinit(sae->peer_commit_scalar, 0);
sae->peer_commit_scalar = peer_scalar;
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
@ -983,12 +1066,12 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
return WLAN_STATUS_SUCCESS;
}
static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
u8 prime[SAE_MAX_ECC_PRIME_LEN];
if (2 * sae->tmp->prime_len > end - pos) {
if (2 * sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@ -999,8 +1082,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* element x and y coordinates < p */
if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
os_memcmp(pos + sae->tmp->prime_len, prime,
if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
os_memcmp(*pos + sae->tmp->prime_len, prime,
sae->tmp->prime_len) >= 0) {
wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
"element");
@ -1008,13 +1091,13 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
}
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
pos, sae->tmp->prime_len);
*pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len);
*pos + sae->tmp->prime_len, sae->tmp->prime_len);
crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
sae->tmp->peer_commit_element_ecc =
crypto_ec_point_from_bin(sae->tmp->ec, pos);
crypto_ec_point_from_bin(sae->tmp->ec, *pos);
if (sae->tmp->peer_commit_element_ecc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@ -1024,26 +1107,28 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
*pos += 2 * sae->tmp->prime_len;
return WLAN_STATUS_SUCCESS;
}
static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
struct crypto_bignum *res, *one;
const u8 one_bin[1] = { 0x01 };
if (sae->tmp->prime_len > end - pos) {
if (sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
sae->tmp->prime_len);
crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
sae->tmp->peer_commit_element_ffc =
crypto_bignum_init_set(pos, sae->tmp->prime_len);
crypto_bignum_init_set(*pos, sae->tmp->prime_len);
if (sae->tmp->peer_commit_element_ffc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* 1 < element < p - 1 */
@ -1071,10 +1156,12 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
}
crypto_bignum_deinit(res, 0);
*pos += sae->tmp->prime_len;
return WLAN_STATUS_SUCCESS;
}
static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
if (sae->tmp->dh)
@ -1082,6 +1169,41 @@ static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
return sae_parse_commit_element_ecc(sae, pos, end);
}
static int sae_parse_password_identifier(struct sae_data *sae,
const u8 *pos, const u8 *end)
{
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
pos, end - pos);
if (!sae_is_password_id_elem(pos, end)) {
if (sae->tmp->pw_id) {
wpa_printf(MSG_DEBUG,
"SAE: No Password Identifier included, but expected one (%s)",
sae->tmp->pw_id);
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
}
os_free(sae->tmp->pw_id);
sae->tmp->pw_id = NULL;
return WLAN_STATUS_SUCCESS; /* No Password Identifier */
}
if (sae->tmp->pw_id &&
(pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
wpa_printf(MSG_DEBUG,
"SAE: The included Password Identifier does not match the expected one (%s)",
sae->tmp->pw_id);
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
}
os_free(sae->tmp->pw_id);
sae->tmp->pw_id = os_malloc(pos[1]);
if (!sae->tmp->pw_id)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
sae->tmp->pw_id[pos[1] - 1] = '\0';
return WLAN_STATUS_SUCCESS;
}
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups)
{
@ -1105,7 +1227,12 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* commit-element */
res = sae_parse_commit_element(sae, pos, end);
res = sae_parse_commit_element(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
/* Optional Password Identifier element */
res = sae_parse_password_identifier(sae, pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
@ -1220,6 +1347,7 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
if (sae->send_confirm < 0xffff)
sae->send_confirm++;
if (sae->tmp->ec)
@ -1277,4 +1405,19 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
return 0;
}
const char * sae_state_txt(enum sae_state state)
{
switch (state) {
case SAE_NOTHING:
return "Nothing";
case SAE_COMMITTED:
return "Committed";
case SAE_CONFIRMED:
return "Confirmed";
case SAE_ACCEPTED:
return "Accepted";
}
return "?";
}
#endif /* CONFIG_WPA3_SAE */

View file

@ -5,14 +5,12 @@
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifdef CONFIG_WPA3_SAE
#ifndef SAE_H
#define SAE_H
#include "esp_err.h"
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/wpa_debug.h"
@ -47,6 +45,7 @@ struct sae_temporary_data {
struct crypto_bignum *prime_buf;
struct crypto_bignum *order_buf;
struct wpabuf *anti_clogging_token;
char *pw_id;
};
enum {
@ -54,32 +53,38 @@ enum {
SAE_MSG_CONFIRM = 2,
};
enum sae_state {
SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED
};
struct sae_data {
enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
enum sae_state state;
u16 send_confirm;
u8 pmk[SAE_PMK_LEN];
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
u16 group;
int sync;
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
struct sae_temporary_data *tmp;
};
int sae_set_group(struct sae_data *sae, u16 group);
int sae_set_group(struct sae_data *sae, int group);
void sae_clear_temp_data(struct sae_data *sae);
void sae_clear_data(struct sae_data *sae);
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
struct sae_data *sae);
const char *identifier, struct sae_data *sae);
int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token);
const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
#endif /* SAE_H */
#endif /* CONFIG_WPA3_SAE */

View file

@ -58,6 +58,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
return WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPA3_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
#endif /* CONFIG_WPA3_SAE */
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;

View file

@ -54,6 +54,7 @@
#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)

View file

@ -478,9 +478,11 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
* such that p 3 (mod 4)
* y_ = (y2 ^ ((p+1)/4)) mod p
*
* if y_bit: y = p-y_
* else y = y_`
* if LSB of both x and y are same: y = y_
* else y = p - y_
* y_bit is LSB of x
*/
y_bit = (y_bit != 0);
y_sqr = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, x);
@ -490,9 +492,9 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4));
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL));
if (y_bit) {
if (y_bit != mbedtls_mpi_get_bit(y, 0))
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y));
}
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&((mbedtls_ecp_point* )p)->X, (const mbedtls_mpi*) x));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&((mbedtls_ecp_point *)p)->Z, 1));
} else {

View file

@ -64,7 +64,8 @@ enum {
WPA_AUTH_CCKM = 0x06,
WPA2_AUTH_CCKM = 0x07,
WPA2_AUTH_PSK_SHA256= 0x08,
WPA2_AUTH_INVALID = 0x09,
WPA3_AUTH_PSK = 0x09,
WPA2_AUTH_INVALID = 0x0a,
};
typedef enum {
@ -121,6 +122,10 @@ struct wpa_funcs {
int (*wpa_parse_wpa_ie)(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data);
int (*wpa_config_bss)(u8 *bssid);
int (*wpa_michael_mic_failure)(u16 is_unicast);
#ifdef CONFIG_WPA3_SAE
u8 *(*wpa3_build_sae_msg)(u8 *bssid, u32 type, u32 *len);
int (*wpa3_parse_sae_msg)(u8 *buf, u32 len, u32 type);
#endif
};
struct wpa2_funcs {
@ -209,6 +214,7 @@ int esp_wifi_ipc_internal(wifi_ipc_config_t *cfg, bool sync);
int esp_wifi_register_wpa2_cb_internal(struct wpa2_funcs *cb);
int esp_wifi_unregister_wpa2_cb_internal(void);
bool esp_wifi_sta_prof_is_wpa2_internal(void);
bool esp_wifi_sta_prof_is_wpa3_internal(void);
esp_err_t esp_wifi_sta_wpa2_ent_disable_internal(wifi_wpa2_param_t *param);
esp_err_t esp_wifi_sta_wpa2_ent_enable_internal(wifi_wpa2_param_t *param);
esp_err_t esp_wifi_set_wpa2_ent_state_internal(wpa2_ent_eap_state_t state);

View file

@ -0,0 +1,165 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef CONFIG_WPA3_SAE
#include "../common/sae.h"
#include "esp_wifi_driver.h"
#include "rsn_supp/wpa.h"
static struct sae_data g_sae_data;
int g_allowed_groups[] = { IANA_SECP256R1, 0 };
static struct wpabuf *wpa3_build_sae_commit(u8 *bssid)
{
int default_group = IANA_SECP256R1;
struct wpabuf *buf;
u8 own_addr[ETH_ALEN];
const u8 *pw;
memset(&g_sae_data, 0, sizeof(g_sae_data));
if (sae_set_group(&g_sae_data, default_group)) {
wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group);
return NULL;
}
esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr);
if (!bssid) {
wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!");
return NULL;
}
pw = (const u8 *)esp_wifi_sta_get_prof_password_internal();
if (sae_prepare_commit(own_addr, bssid, pw, strlen((const char *)pw), NULL, &g_sae_data) < 0) {
wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!");
return NULL;
}
// For reuse PWE after retry case
// memcpy(g_sae_data.tmp->bssid, bssid, ETH_ALEN);
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
sae_write_commit(&g_sae_data, buf, NULL, NULL); //no token
g_sae_data.state = SAE_COMMITTED;
return buf;
}
static struct wpabuf *wpa3_build_sae_confirm(void)
{
struct wpabuf *buf;
if (g_sae_data.state != SAE_COMMITTED)
return NULL;
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
sae_write_confirm(&g_sae_data, buf);
g_sae_data.state = SAE_CONFIRMED;
return buf;
}
static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, u32 *sae_msg_len)
{
struct wpabuf *buf = NULL;
switch (sae_msg_type) {
case SAE_MSG_COMMIT:
buf = wpa3_build_sae_commit(bssid);
break;
case SAE_MSG_CONFIRM:
buf = wpa3_build_sae_confirm();
break;
default:
break;
}
if (buf) {
*sae_msg_len = (u32)wpabuf_len(buf);
return wpabuf_mhead_u8(buf);
} else
return NULL;
}
static int wpa3_parse_sae_commit(u8 *buf, u32 len)
{
int ret;
if (g_sae_data.state != SAE_COMMITTED) {
wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
g_sae_data.state);
return -1;
}
ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups);
if (ret) {
wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret);
return -1;
}
ret = sae_process_commit(&g_sae_data);
if (ret) {
wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret);
return -1;
}
return 0;
}
static int wpa3_parse_sae_confirm(u8 *buf, u32 len)
{
if (g_sae_data.state != SAE_CONFIRMED) {
wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
g_sae_data.state);
return -1;
}
sae_check_confirm(&g_sae_data, buf, len);
g_sae_data.state = SAE_ACCEPTED;
wpa_set_pmk(g_sae_data.pmk);
memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN);
return 0;
}
static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type)
{
int ret = 0;
switch (sae_msg_type) {
case SAE_MSG_COMMIT:
ret = wpa3_parse_sae_commit(buf, len);
break;
case SAE_MSG_CONFIRM:
ret = wpa3_parse_sae_confirm(buf, len);
break;
default:
wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!",
sae_msg_type);
ret = -1;
break;
}
return ret;
}
void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb)
{
wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg;
wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg;
}
#endif /* CONFIG_WPA3_SAE */

View file

@ -0,0 +1,23 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ESP_WPA3_H
#define ESP_WPA3_H
#include "esp_wifi_driver.h"
void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb);
#endif /* ESP_WPA3_H */

View file

@ -32,6 +32,7 @@
#include "esp_wifi_driver.h"
#include "esp_private/wifi.h"
#include "esp_wpa3_i.h"
void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,
u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid)
@ -74,7 +75,7 @@ void wpa_config_profile()
{
if (esp_wifi_sta_prof_is_wpa_internal()) {
wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal());
} else if (esp_wifi_sta_prof_is_wpa2_internal()) {
} else if (esp_wifi_sta_prof_is_wpa2_internal() || esp_wifi_sta_prof_is_wpa3_internal()) {
wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal());
} else {
WPA_ASSERT(0);
@ -201,6 +202,9 @@ int esp_supplicant_init(void)
wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper;
wpa_cb->wpa_config_bss = NULL;//wpa_config_bss;
wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure;
#ifdef CONFIG_WPA3_SAE
esp_wifi_register_wpa3_cb(wpa_cb);
#endif /* CONFIG_WPA3_SAE */
esp_wifi_register_wpa_cb_internal(wpa_cb);

View file

@ -2077,6 +2077,10 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */
} else if (auth_mode == WPA2_AUTH_PSK_SHA256) {
sm->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
} else if (auth_mode == WPA3_AUTH_PSK) {
sm->key_mgmt = WPA_KEY_MGMT_SAE; /* for WPA3 PSK */
} else {
sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */
}
}
@ -2143,6 +2147,8 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)
* Here only handle passphrase string. Need extra step to handle 32B, 64Hex raw
* PMK.
*/
if (sm->key_mgmt == WPA_KEY_MGMT_SAE)
return;
/* This is really SLOW, so just re cacl while reset param */
if (esp_wifi_sta_get_reset_param_internal() != 0) {

View file

@ -204,6 +204,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPA3_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
#endif /* CONFIG_WPA3_SAE */
} else {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
key_mgmt);