diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2015-06-29 11:02:15 -0700 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2015-06-29 11:02:15 -0700 |
| commit | 4171258d30a612645aa061cede62233b5c58ca2a (patch) | |
| tree | c12afc44bece384cf603ba0579ef9191ea63925e /src/common | |
| parent | a3dc30964aa24aea2b518246f6812663a1103490 (diff) | |
| download | android_external_wpa_supplicant_8-4171258d30a612645aa061cede62233b5c58ca2a.tar.gz android_external_wpa_supplicant_8-4171258d30a612645aa061cede62233b5c58ca2a.tar.bz2 android_external_wpa_supplicant_8-4171258d30a612645aa061cede62233b5c58ca2a.zip | |
Cumulative patch from commit 8c43ef8449bd4d2d0983db394770bd73f572b12d
8c43ef8 P2PS: Fix attribute addition in p2p_buf_add_service_instance()
a9ea609 P2PS: Fix p2p_find last parameter handling
6c73149 AP: Increase maximum value accepted for cwmin/cwmax
575e4f5 SAE: Reject FFC commit-element with value p-1
a406244 P2PS: Do not reply to ProbeReq on another channel when starting Listen
0c2b3f6 SAE: Reject commit-scalar value 1
4f39908 Send CTRL-EVENT-NETWORK-NOT-FOUND if no suitable network was found
123df27 D-Bus: Fix typos in debug print
ded14ce Android: Fix nl80211 build if BOARD_*_PRIVATE_LIB is unspecified
a140721 Android: Rename ANDROID_P2P_STUB to ANDROID_LIB_STUB
2ba4de3 D-Bus: Add documentation for wpas_dbus_signal_peer_groups_changed()
e48b5e2 D-Bus: Fix typo in dbus signal function documentation
09d5048 D-Bus: Add function documentation for wpas_dbus_unregister_interface()
adfbbd2 D-Bus: Add function documentation for wpas_dbus_register_interface()
c5967f0 D-Bus: Fix wpas_dbus_signal_p2p_invitation_result() documentation
4457f41 radius: Fix NULL dereference issue on allocation failure
f826fb1 OpenSSL: Handle EC_POINT_is_on_curve() error case
bbb5008 SAE: Use random "password" in extra hunting-and-pecking loops
eb5fee0 SAE: Add side-channel protection to PWE derivation with ECC
16841ab crypto: Add functions for computing the Legendre symbol and EC y^2
c4a13b4 OpenSSL: Add support for Brainpool Elliptic Curves
4584b66 SAE: Increase security parameter k to 40 based on Dragonfly recommendation
fdd731b SAE: Fix PWE generation to use minimum loop count (k) properly
8ec3332 SAE: Merge sae_derive_commit() error case return statements
d93abd4 SAE: Merge sae_get_rand() error case return statements
6a58444 SAE: Verify that own/peer commit-scalar and COMMIT-ELEMENT are different
4e7e688 Add crypto_ec_point_cmp()
8e2a3a4 dbus: Do not initialize variable twice
c1a14ef Do not check unsigned size is less than zero
fdc5608 OpenSSL: Remove SSL_CTX_{get,set}_app_data() compatibility wrapper
ba54933 libtommath: Fix mp_init_multi() stdarg use on error path
f6332b0 wpa_gui: Initialize WpaGuiApp::w in the constructor
f6df3f3 Use os_* wrapper more consistently
91b7a5e Use unsigned/signed printf format more consistently
59bae74 HS 2.0R2: Fix memory leak on error path in hs20-osu-client
c5ca73d P2P: Use offsetof() instead of local implementation
c3c5b5f ERP server: Make erp_send_finish_reauth() easier for static analyzers
6ce1bea bsd: Remove redundant NULL check in bsd_init()
c99df20 Remove redundant NULL check in ieee802_1x_encapsulate_radius()
2eb5967 AP: Add more 2.4 GHz channels for 20/40 MHz HT co-ex scan
5ed6519 hw_features: Merge similar return cases
4e37dd6 SAE: Simplify sae_prepare_commit() error path
04e6c4c Fix SAE group selection in an error case
3dce85c HS 2.0: Add WLAN RADIUS attributes in OSEN case
efd5d26 Remove unnecessary wpa_ie_len check from wpa_parse_wpa_ie_wpa()
ce8963f Remove WEP40/WEP104 cipher suite support for WPA/WPA2
ee140ef FT: Stop association attempt if Auth response processing fails (SME)
1887be4 Make check_20mhz_bss() static
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Bug: 22062116
Change-Id: Ie1d175f1faab24bf39ce81ead7a078e1e236badd
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/hw_features_common.c | 26 | ||||
| -rw-r--r-- | src/common/hw_features_common.h | 1 | ||||
| -rw-r--r-- | src/common/ieee802_11_common.c | 4 | ||||
| -rw-r--r-- | src/common/sae.c | 391 | ||||
| -rw-r--r-- | src/common/sae.h | 3 | ||||
| -rw-r--r-- | src/common/wpa_common.c | 49 | ||||
| -rw-r--r-- | src/common/wpa_common.h | 11 | ||||
| -rw-r--r-- | src/common/wpa_ctrl.h | 2 |
8 files changed, 327 insertions, 160 deletions
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index e61f8242..e589a1a4 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -176,10 +176,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode, size_t i; int match; - if (!mode || !scan_res || !pri_chan || !sec_chan) - return 0; - - if (pri_chan == sec_chan) + if (!mode || !scan_res || !pri_chan || !sec_chan || + pri_chan == sec_chan) return 0; pri_freq = hw_get_freq(mode, pri_chan); @@ -237,7 +235,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode, } -int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end) +static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, + int end) { struct ieee802_11_elems elems; struct ieee80211_ht_operation *oper; @@ -372,11 +371,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, if (data->vht_enabled) switch (vht_oper_chwidth) { case VHT_CHANWIDTH_USE_HT: - if (center_segment1) - return -1; - if (center_segment0 != 0 && - 5000 + center_segment0 * 5 != data->center_freq1 && - 2407 + center_segment0 * 5 != data->center_freq1) + if (center_segment1 || + (center_segment0 != 0 && + 5000 + center_segment0 * 5 != data->center_freq1 && + 2407 + center_segment0 * 5 != data->center_freq1)) return -1; break; case VHT_CHANWIDTH_80P80MHZ: @@ -392,11 +390,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, /* fall through */ case VHT_CHANWIDTH_80MHZ: data->bandwidth = 80; - if (vht_oper_chwidth == 1 && center_segment1) - return -1; - if (vht_oper_chwidth == 3 && !center_segment1) - return -1; - if (!sec_channel_offset) + if ((vht_oper_chwidth == 1 && center_segment1) || + (vht_oper_chwidth == 3 && !center_segment1) || + !sec_channel_offset) return -1; if (!center_segment0) { if (channel <= 48) diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h index 7f43d00c..7360b4e3 100644 --- a/src/common/hw_features_common.h +++ b/src/common/hw_features_common.h @@ -26,7 +26,6 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan); int check_40mhz_5g(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan); -int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end); int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan); diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 82dd7074..5385faf7 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -504,14 +504,14 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], ac->aifs = v; } else if (os_strcmp(pos, "cwmin") == 0) { v = atoi(val); - if (v < 0 || v > 12) { + if (v < 0 || v > 15) { wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); return -1; } ac->cwmin = v; } else if (os_strcmp(pos, "cwmax") == 0) { v = atoi(val); - if (v < 0 || v > 12) { + if (v < 0 || v > 15) { wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); return -1; } diff --git a/src/common/sae.c b/src/common/sae.c index 58889580..503fa1d7 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -1,6 +1,6 @@ /* * Simultaneous authentication of equals - * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -124,9 +124,7 @@ static struct crypto_bignum * sae_get_rand(struct sae_data *sae) return NULL; for (;;) { - if (iter++ > 100) - return NULL; - if (random_get_bytes(val, order_len) < 0) + if (iter++ > 100 || random_get_bytes(val, order_len) < 0) return NULL; if (order_len_bits % 8) buf_shift_right(val, order_len, 8 - order_len_bits % 8); @@ -171,17 +169,107 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key) } +static struct crypto_bignum * +get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits, + int *r_odd) +{ + for (;;) { + struct crypto_bignum *r; + u8 tmp[SAE_MAX_ECC_PRIME_LEN]; + + if (random_get_bytes(tmp, prime_len) < 0) + break; + if (prime_bits % 8) + buf_shift_right(tmp, prime_len, 8 - prime_bits % 8); + if (os_memcmp(tmp, prime, prime_len) >= 0) + continue; + r = crypto_bignum_init_set(tmp, prime_len); + if (!r) + break; + if (crypto_bignum_is_zero(r)) { + crypto_bignum_deinit(r, 0); + continue; + } + + *r_odd = tmp[prime_len - 1] & 0x01; + return r; + } + + return NULL; +} + + +static int is_quadratic_residue_blind(struct sae_data *sae, + const u8 *prime, size_t bits, + const struct crypto_bignum *qr, + const struct crypto_bignum *qnr, + const struct crypto_bignum *y_sqr) +{ + struct crypto_bignum *r, *num; + int r_odd, check, res = -1; + + /* + * Use the blinding technique to mask y_sqr while determining + * whether it is a quadratic residue modulo p to avoid leaking + * timing information while determining the Legendre symbol. + * + * v = y_sqr + * r = a random number between 1 and p-1, inclusive + * num = (v * r * r) modulo p + */ + r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd); + if (!r) + return -1; + + num = crypto_bignum_init(); + if (!num || + crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 || + crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0) + goto fail; + + if (r_odd) { + /* + * num = (num * qr) module p + * LGR(num, p) = 1 ==> quadratic residue + */ + if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0) + goto fail; + check = 1; + } else { + /* + * num = (num * qnr) module p + * LGR(num, p) = -1 ==> quadratic residue + */ + if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0) + goto fail; + check = -1; + } + + res = crypto_bignum_legendre(num, sae->tmp->prime); + if (res == -2) { + res = -1; + goto fail; + } + res = res == check; +fail: + crypto_bignum_deinit(num, 1); + crypto_bignum_deinit(r, 1); + return res; +} + + static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, - struct crypto_ec_point *pwe) + const u8 *prime, + const struct crypto_bignum *qr, + const struct crypto_bignum *qnr, + struct crypto_bignum **ret_x_cand) { - u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN]; - struct crypto_bignum *x; - int y_bit; + u8 pwd_value[SAE_MAX_ECC_PRIME_LEN]; + struct crypto_bignum *y_sqr, *x_cand; + int res; size_t bits; - if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), - sae->tmp->prime_len) < 0) - return -1; + *ret_x_cand = NULL; wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); @@ -197,20 +285,23 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) return 0; - y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; - - x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); - if (x == NULL) + x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); + if (!x_cand) + return -1; + y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); + if (!y_sqr) { + crypto_bignum_deinit(x_cand, 1); return -1; - if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) { - crypto_bignum_deinit(x, 0); - wpa_printf(MSG_DEBUG, "SAE: No solution found"); - return 0; } - crypto_bignum_deinit(x, 0); - wpa_printf(MSG_DEBUG, "SAE: PWE found"); + res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); + crypto_bignum_deinit(y_sqr, 1); + if (res <= 0) { + crypto_bignum_deinit(x_cand, 1); + return res; + } + *ret_x_cand = x_cand; return 1; } @@ -288,24 +379,77 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, } +static int get_random_qr_qnr(const u8 *prime, size_t prime_len, + const struct crypto_bignum *prime_bn, + size_t prime_bits, struct crypto_bignum **qr, + struct crypto_bignum **qnr) +{ + *qr = NULL; + *qnr = NULL; + + while (!(*qr) || !(*qnr)) { + u8 tmp[SAE_MAX_ECC_PRIME_LEN]; + struct crypto_bignum *q; + int res; + + if (random_get_bytes(tmp, prime_len) < 0) + break; + if (prime_bits % 8) + buf_shift_right(tmp, prime_len, 8 - prime_bits % 8); + if (os_memcmp(tmp, prime, prime_len) >= 0) + continue; + q = crypto_bignum_init_set(tmp, prime_len); + if (!q) + break; + res = crypto_bignum_legendre(q, prime_bn); + + if (res == 1 && !(*qr)) + *qr = q; + else if (res == -1 && !(*qnr)) + *qnr = q; + else + crypto_bignum_deinit(q, 0); + } + + return (*qr && *qnr) ? 0 : -1; +} + + static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len) { - u8 counter, k = 4; + u8 counter, k = 40; u8 addrs[2 * ETH_ALEN]; const u8 *addr[2]; size_t len[2]; - int found = 0; - struct crypto_ec_point *pwe_tmp; + u8 dummy_password[32]; + size_t dummy_password_len; + int pwd_seed_odd = 0; + u8 prime[SAE_MAX_ECC_PRIME_LEN]; + size_t prime_len; + struct crypto_bignum *x = NULL, *qr, *qnr; + size_t bits; + int res; - if (sae->tmp->pwe_ecc == NULL) { - sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec); - if (sae->tmp->pwe_ecc == NULL) - return -1; - } - pwe_tmp = crypto_ec_point_init(sae->tmp->ec); - if (pwe_tmp == NULL) + dummy_password_len = password_len; + if (dummy_password_len > sizeof(dummy_password)) + dummy_password_len = sizeof(dummy_password); + if (random_get_bytes(dummy_password, dummy_password_len) < 0) + return -1; + + prime_len = sae->tmp->prime_len; + if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), + prime_len) < 0) + return -1; + bits = crypto_ec_prime_len_bits(sae->tmp->ec); + + /* + * Create a random quadratic residue (qr) and quadratic non-residue + * (qnr) modulo p for blinding purposes during the loop. + */ + if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, + &qr, &qnr) < 0) return -1; wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", @@ -313,8 +457,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, /* * H(salt, ikm) = HMAC-SHA256(salt, ikm) + * base = password * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), - * password || counter) + * base || counter) */ sae_pwd_seed_key(addr1, addr2, addrs); @@ -328,9 +473,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, * attacks that attempt to determine the number of iterations required * in the loop. */ - for (counter = 1; counter < k || !found; counter++) { + for (counter = 1; counter <= k || !x; counter++) { u8 pwd_seed[SHA256_MAC_LEN]; - int res; + struct crypto_bignum *x_cand; if (counter > 200) { /* This should not happen in practice */ @@ -342,25 +487,58 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, pwd_seed) < 0) break; + res = sae_test_pwd_seed_ecc(sae, pwd_seed, - found ? pwe_tmp : - sae->tmp->pwe_ecc); + prime, qr, qnr, &x_cand); if (res < 0) - break; - if (res == 0) - continue; - if (found) { - wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was " - "already selected)"); - } else { - wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); - found = 1; + goto fail; + if (res > 0 && !x) { + wpa_printf(MSG_DEBUG, + "SAE: Selected pwd-seed with counter %u", + counter); + x = x_cand; + pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; + os_memset(pwd_seed, 0, sizeof(pwd_seed)); + + /* + * Use a dummy password for the following rounds, if + * any. + */ + addr[0] = dummy_password; + len[0] = dummy_password_len; + } else if (res > 0) { + crypto_bignum_deinit(x_cand, 1); } } - crypto_ec_point_deinit(pwe_tmp, 1); + if (!x) { + wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); + res = -1; + goto fail; + } - return found ? 0 : -1; + if (!sae->tmp->pwe_ecc) + sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec); + if (!sae->tmp->pwe_ecc) + res = -1; + else + res = crypto_ec_point_solve_y_coord(sae->tmp->ec, + sae->tmp->pwe_ecc, x, + pwd_seed_odd); + crypto_bignum_deinit(x, 1); + if (res < 0) { + /* + * This should not happen since we already checked that there + * is a result. + */ + wpa_printf(MSG_DEBUG, "SAE: Could not solve y"); + } + +fail: + crypto_bignum_deinit(qr, 0); + crypto_bignum_deinit(qnr, 0); + + return res; } @@ -472,27 +650,41 @@ static int sae_derive_commit(struct sae_data *sae) { struct crypto_bignum *mask; int ret = -1; + unsigned int counter = 0; + + do { + counter++; + if (counter > 100) { + /* + * This cannot really happen in practice if the random + * number generator is working. Anyway, to avoid even a + * theoretical infinite loop, break out after 100 + * attemps. + */ + return -1; + } - mask = sae_get_rand_and_mask(sae); - if (mask == NULL) { - wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); - return -1; - } - - /* commit-scalar = (rand + mask) modulo r */ - if (!sae->tmp->own_commit_scalar) { - sae->tmp->own_commit_scalar = crypto_bignum_init(); - if (!sae->tmp->own_commit_scalar) - goto fail; - } - crypto_bignum_add(sae->tmp->sae_rand, mask, - sae->tmp->own_commit_scalar); - crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order, - sae->tmp->own_commit_scalar); + mask = sae_get_rand_and_mask(sae); + if (mask == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); + return -1; + } - if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) - goto fail; - if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0) + /* commit-scalar = (rand + mask) modulo r */ + if (!sae->tmp->own_commit_scalar) { + sae->tmp->own_commit_scalar = crypto_bignum_init(); + if (!sae->tmp->own_commit_scalar) + goto fail; + } + crypto_bignum_add(sae->tmp->sae_rand, mask, + sae->tmp->own_commit_scalar); + crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order, + sae->tmp->own_commit_scalar); + } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) || + crypto_bignum_is_one(sae->tmp->own_commit_scalar)); + + if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) || + (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)) goto fail; ret = 0; @@ -506,15 +698,12 @@ 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; - if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, - password_len) < 0) - return -1; - if (sae_derive_commit(sae) < 0) + if (sae->tmp == NULL || + (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, + password_len) < 0) || + (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, + password_len) < 0) || + sae_derive_commit(sae) < 0) return -1; return 0; } @@ -780,8 +969,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, return WLAN_STATUS_UNSPECIFIED_FAILURE; } - /* 0 < scalar < r */ + /* 1 < scalar < r */ if (crypto_bignum_is_zero(peer_scalar) || + crypto_bignum_is_one(peer_scalar) || crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) { wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar"); crypto_bignum_deinit(peer_scalar, 0); @@ -847,7 +1037,8 @@ static u16 sae_parse_commit_element_ecc(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; + struct crypto_bignum *res, *one; + const u8 one_bin[1] = { 0x01 }; if (pos + sae->tmp->prime_len > end) { wpa_printf(MSG_DEBUG, "SAE: Not enough data for " @@ -862,18 +1053,23 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, crypto_bignum_init_set(pos, sae->tmp->prime_len); if (sae->tmp->peer_commit_element_ffc == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; - if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) || + /* 1 < element < p - 1 */ + res = crypto_bignum_init(); + one = crypto_bignum_init_set(one_bin, sizeof(one_bin)); + if (!res || !one || + crypto_bignum_sub(sae->tmp->prime, one, res) || + crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) || crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) || - crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, - sae->tmp->prime) >= 0) { + crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) { + crypto_bignum_deinit(res, 0); + crypto_bignum_deinit(one, 0); wpa_printf(MSG_DEBUG, "SAE: Invalid peer element"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } + crypto_bignum_deinit(one, 0); /* scalar-op(r, ELEMENT) = 1 modulo p */ - res = crypto_bignum_init(); - if (res == NULL || - crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc, + if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc, sae->tmp->order, sae->tmp->prime, res) < 0 || !crypto_bignum_is_one(res)) { wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)"); @@ -918,7 +1114,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, return res; /* commit-element */ - return sae_parse_commit_element(sae, pos, end); + res = sae_parse_commit_element(sae, pos, end); + if (res != WLAN_STATUS_SUCCESS) + return res; + + /* + * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as + * the values we sent which would be evidence of a reflection attack. + */ + if (!sae->tmp->own_commit_scalar || + crypto_bignum_cmp(sae->tmp->own_commit_scalar, + sae->peer_commit_scalar) != 0 || + (sae->tmp->dh && + (!sae->tmp->own_commit_element_ffc || + crypto_bignum_cmp(sae->tmp->own_commit_element_ffc, + sae->tmp->peer_commit_element_ffc) != 0)) || + (sae->tmp->ec && + (!sae->tmp->own_commit_element_ecc || + crypto_ec_point_cmp(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + sae->tmp->peer_commit_element_ecc) != 0))) + return WLAN_STATUS_SUCCESS; /* scalars/elements are different */ + + /* + * This is a reflection attack - return special value to trigger caller + * to silently discard the frame instead of replying with a specific + * status code. + */ + return SAE_SILENTLY_DISCARD; } diff --git a/src/common/sae.h b/src/common/sae.h index 3ebf40cf..c07026cd 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -18,6 +18,9 @@ #define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN) #define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN) +/* Special value returned by sae_parse_commit() */ +#define SAE_SILENTLY_DISCARD 65535 + struct sae_temporary_data { u8 kck[SAE_KCK_LEN]; struct crypto_bignum *own_commit_scalar; diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index a0747b4b..e485b5bf 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -432,14 +432,10 @@ static int rsn_selector_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) return WPA_CIPHER_NONE; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) - return WPA_CIPHER_WEP40; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) return WPA_CIPHER_TKIP; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) return WPA_CIPHER_CCMP; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) - return WPA_CIPHER_WEP104; #ifdef CONFIG_IEEE80211W if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) return WPA_CIPHER_AES_128_CMAC; @@ -499,8 +495,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) static int wpa_cipher_valid_group(int cipher) { return wpa_cipher_valid_pairwise(cipher) || - cipher == WPA_CIPHER_WEP104 || - cipher == WPA_CIPHER_WEP40 || cipher == WPA_CIPHER_GTK_NOT_USED; } @@ -695,14 +689,10 @@ static int wpa_selector_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) return WPA_CIPHER_NONE; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) - return WPA_CIPHER_WEP40; if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) return WPA_CIPHER_TKIP; if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) return WPA_CIPHER_CCMP; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) - return WPA_CIPHER_WEP104; return 0; } @@ -737,11 +727,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, data->num_pmkid = 0; data->mgmt_group_cipher = 0; - if (wpa_ie_len == 0) { - /* No WPA IE - fail silently */ - return -1; - } - if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) wpa_ie_len); @@ -1363,10 +1348,6 @@ int wpa_cipher_key_len(int cipher) return 16; case WPA_CIPHER_TKIP: return 32; - case WPA_CIPHER_WEP104: - return 13; - case WPA_CIPHER_WEP40: - return 5; } return 0; @@ -1382,9 +1363,6 @@ int wpa_cipher_rsc_len(int cipher) case WPA_CIPHER_GCMP: case WPA_CIPHER_TKIP: return 6; - case WPA_CIPHER_WEP104: - case WPA_CIPHER_WEP40: - return 0; } return 0; @@ -1404,9 +1382,6 @@ int wpa_cipher_to_alg(int cipher) return WPA_ALG_GCMP; case WPA_CIPHER_TKIP: return WPA_ALG_TKIP; - case WPA_CIPHER_WEP104: - case WPA_CIPHER_WEP40: - return WPA_ALG_WEP; case WPA_CIPHER_AES_128_CMAC: return WPA_ALG_IGTK; case WPA_CIPHER_BIP_GMAC_128: @@ -1444,12 +1419,6 @@ u32 wpa_cipher_to_suite(int proto, int cipher) if (cipher & WPA_CIPHER_TKIP) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); - if (cipher & WPA_CIPHER_WEP104) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); - if (cipher & WPA_CIPHER_WEP40) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); if (cipher & WPA_CIPHER_NONE) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); @@ -1553,10 +1522,6 @@ int wpa_pick_group_cipher(int ciphers) return WPA_CIPHER_GTK_NOT_USED; if (ciphers & WPA_CIPHER_TKIP) return WPA_CIPHER_TKIP; - if (ciphers & WPA_CIPHER_WEP104) - return WPA_CIPHER_WEP104; - if (ciphers & WPA_CIPHER_WEP40) - return WPA_CIPHER_WEP40; return -1; } @@ -1654,20 +1619,6 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) return -1; pos += ret; } - if (ciphers & WPA_CIPHER_WEP104) { - ret = os_snprintf(pos, end - pos, "%sWEP104", - pos == start ? "" : delim); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_WEP40) { - ret = os_snprintf(pos, end - pos, "%sWEP40", - pos == start ? "" : delim); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } if (ciphers & WPA_CIPHER_NONE) { ret = os_snprintf(pos, end - pos, "%sNONE", pos == start ? "" : delim); diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 29c3503c..d7a590fc 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -22,8 +22,8 @@ (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256) #define WPA_ALLOWED_GROUP_CIPHERS \ -(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \ -WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \ +(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \ +WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \ WPA_CIPHER_GTK_NOT_USED) #define WPA_SELECTOR_LEN 4 @@ -40,13 +40,8 @@ WPA_CIPHER_GTK_NOT_USED) #define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) #define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0) #define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) -#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) #define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -#if 0 -#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) -#endif #define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) -#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) #define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) @@ -68,13 +63,11 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) -#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) #if 0 #define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) #endif #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index e3a816f2..e7005232 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -68,6 +68,8 @@ extern "C" { #define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " /** A BSS entry was removed (followed by BSS entry id and BSSID) */ #define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " +/** No suitable network was found */ +#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND " /** Change in the signal level was reported by the driver */ #define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE " /** Regulatory domain channel */ |
