diff options
| author | Adrian Bunk <bunk@stusta.de> | 2019-06-19 21:04:22 +0300 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2019-06-30 22:34:23 +0100 |
| commit | ee0e9eaafed96587b6f1c6b995cd7d5927170c21 (patch) | |
| tree | c3e3b3602923c23aa0614a44b3b4049e6f340dea | |
| parent | 76c220e5fe43aef1014e6eec7f0136c2b34be308 (diff) | |
| download | poky-ee0e9eaafed96587b6f1c6b995cd7d5927170c21.tar.gz | |
wpa-supplicant: Fix CVE-2019-9494 CVE-2019-9495 CVE-2019-9496 CVE-2019-9497 CVE-2019-9498 CVE-2019-9499 CVE-2019-11555
(From OE-Core rev: ae8e0440fc1177bf44e46804e1f5927cb86f8324)
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
17 files changed, 2146 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch new file mode 100644 index 0000000000..45e6e87dfe --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From fe76f487e28bdc61940f304f153a954cf36935ea Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Wed, 17 Apr 2019 01:55:32 +0300 | ||
| 4 | Subject: [PATCH 1/3] EAP-pwd server: Fix reassembly buffer handling | ||
| 5 | |||
| 6 | data->inbuf allocation might fail and if that were to happen, the next | ||
| 7 | fragment in the exchange could have resulted in NULL pointer | ||
| 8 | dereference. Unexpected fragment with more bit might also be able to | ||
| 9 | trigger this. Fix that by explicitly checking for data->inbuf to be | ||
| 10 | available before using it. | ||
| 11 | |||
| 12 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 13 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 14 | Upstream-Status: Backport | ||
| 15 | CVE: CVE-2019-11555 | ||
| 16 | --- | ||
| 17 | src/eap_server/eap_server_pwd.c | 8 +++++++- | ||
| 18 | 1 file changed, 7 insertions(+), 1 deletion(-) | ||
| 19 | |||
| 20 | diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c | ||
| 21 | index 11bef55..38e2af8 100644 | ||
| 22 | --- a/src/eap_server/eap_server_pwd.c | ||
| 23 | +++ b/src/eap_server/eap_server_pwd.c | ||
| 24 | @@ -912,6 +912,12 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv, | ||
| 25 | * the first and all intermediate fragments have the M bit set | ||
| 26 | */ | ||
| 27 | if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) { | ||
| 28 | + if (!data->inbuf) { | ||
| 29 | + wpa_printf(MSG_DEBUG, | ||
| 30 | + "EAP-pwd: No buffer for reassembly"); | ||
| 31 | + eap_pwd_state(data, FAILURE); | ||
| 32 | + return; | ||
| 33 | + } | ||
| 34 | if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) { | ||
| 35 | wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow " | ||
| 36 | "attack detected! (%d+%d > %d)", | ||
| 37 | @@ -932,7 +938,7 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv, | ||
| 38 | * last fragment won't have the M bit set (but we're obviously | ||
| 39 | * buffering fragments so that's how we know it's the last) | ||
| 40 | */ | ||
| 41 | - if (data->in_frag_pos) { | ||
| 42 | + if (data->in_frag_pos && data->inbuf) { | ||
| 43 | pos = wpabuf_head_u8(data->inbuf); | ||
| 44 | len = data->in_frag_pos; | ||
| 45 | wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", | ||
| 46 | -- | ||
| 47 | 2.7.4 | ||
| 48 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch new file mode 100644 index 0000000000..e64d140c7b --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | From d42c477cc794163a3757956bbffca5cea000923c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Tue, 26 Feb 2019 11:43:03 +0200 | ||
| 4 | Subject: [PATCH 01/14] OpenSSL: Use constant time operations for private | ||
| 5 | bignums | ||
| 6 | |||
| 7 | This helps in reducing measurable timing differences in operations | ||
| 8 | involving private information. BoringSSL has removed BN_FLG_CONSTTIME | ||
| 9 | and expects specific constant time functions to be called instead, so a | ||
| 10 | bit different approach is needed depending on which library is used. | ||
| 11 | |||
| 12 | The main operation that needs protection against side channel attacks is | ||
| 13 | BN_mod_exp() that depends on private keys (the public key validation | ||
| 14 | step in crypto_dh_derive_secret() is an exception that can use the | ||
| 15 | faster version since it does not depend on private keys). | ||
| 16 | |||
| 17 | crypto_bignum_div() is currently used only in SAE FFC case with not | ||
| 18 | safe-prime groups and only with values that do not depend on private | ||
| 19 | keys, so it is not critical to protect it. | ||
| 20 | |||
| 21 | crypto_bignum_inverse() is currently used only in SAE FFC PWE | ||
| 22 | derivation. The additional protection here is targeting only OpenSSL. | ||
| 23 | BoringSSL may need conversion to using BN_mod_inverse_blinded(). | ||
| 24 | |||
| 25 | This is related to CVE-2019-9494 and CVE-2019-9495. | ||
| 26 | |||
| 27 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 28 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 29 | Upstream-Status: Backport | ||
| 30 | CVE: CVE-2019-9494 | ||
| 31 | CVE: CVE-2019-9495 | ||
| 32 | --- | ||
| 33 | src/crypto/crypto_openssl.c | 20 +++++++++++++++----- | ||
| 34 | 1 file changed, 15 insertions(+), 5 deletions(-) | ||
| 35 | |||
| 36 | diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c | ||
| 37 | index 9c2ba58..ac53cc8 100644 | ||
| 38 | --- a/src/crypto/crypto_openssl.c | ||
| 39 | +++ b/src/crypto/crypto_openssl.c | ||
| 40 | @@ -607,7 +607,8 @@ int crypto_mod_exp(const u8 *base, size_t base_len, | ||
| 41 | bn_result == NULL) | ||
| 42 | goto error; | ||
| 43 | |||
| 44 | - if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1) | ||
| 45 | + if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus, | ||
| 46 | + ctx, NULL) != 1) | ||
| 47 | goto error; | ||
| 48 | |||
| 49 | *result_len = BN_bn2bin(bn_result, result); | ||
| 50 | @@ -1360,8 +1361,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a, | ||
| 51 | bnctx = BN_CTX_new(); | ||
| 52 | if (bnctx == NULL) | ||
| 53 | return -1; | ||
| 54 | - res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b, | ||
| 55 | - (const BIGNUM *) c, bnctx); | ||
| 56 | + res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a, | ||
| 57 | + (const BIGNUM *) b, (const BIGNUM *) c, | ||
| 58 | + bnctx, NULL); | ||
| 59 | BN_CTX_free(bnctx); | ||
| 60 | |||
| 61 | return res ? 0 : -1; | ||
| 62 | @@ -1380,6 +1382,11 @@ int crypto_bignum_inverse(const struct crypto_bignum *a, | ||
| 63 | bnctx = BN_CTX_new(); | ||
| 64 | if (bnctx == NULL) | ||
| 65 | return -1; | ||
| 66 | +#ifdef OPENSSL_IS_BORINGSSL | ||
| 67 | + /* TODO: use BN_mod_inverse_blinded() ? */ | ||
| 68 | +#else /* OPENSSL_IS_BORINGSSL */ | ||
| 69 | + BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME); | ||
| 70 | +#endif /* OPENSSL_IS_BORINGSSL */ | ||
| 71 | res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a, | ||
| 72 | (const BIGNUM *) b, bnctx); | ||
| 73 | BN_CTX_free(bnctx); | ||
| 74 | @@ -1413,6 +1420,9 @@ int crypto_bignum_div(const struct crypto_bignum *a, | ||
| 75 | bnctx = BN_CTX_new(); | ||
| 76 | if (bnctx == NULL) | ||
| 77 | return -1; | ||
| 78 | +#ifndef OPENSSL_IS_BORINGSSL | ||
| 79 | + BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME); | ||
| 80 | +#endif /* OPENSSL_IS_BORINGSSL */ | ||
| 81 | res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a, | ||
| 82 | (const BIGNUM *) b, bnctx); | ||
| 83 | BN_CTX_free(bnctx); | ||
| 84 | @@ -1504,8 +1514,8 @@ int crypto_bignum_legendre(const struct crypto_bignum *a, | ||
| 85 | /* exp = (p-1) / 2 */ | ||
| 86 | !BN_sub(exp, (const BIGNUM *) p, BN_value_one()) || | ||
| 87 | !BN_rshift1(exp, exp) || | ||
| 88 | - !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p, | ||
| 89 | - bnctx)) | ||
| 90 | + !BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp, | ||
| 91 | + (const BIGNUM *) p, bnctx, NULL)) | ||
| 92 | goto fail; | ||
| 93 | |||
| 94 | if (BN_is_word(tmp, 1)) | ||
| 95 | -- | ||
| 96 | 2.7.4 | ||
| 97 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0002-Add-helper-functions-for-constant-time-operations.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0002-Add-helper-functions-for-constant-time-operations.patch new file mode 100644 index 0000000000..fd6f2ce158 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0002-Add-helper-functions-for-constant-time-operations.patch | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | From 6e34f618d37ddbb5854c42e2ad4fca83492fa7b7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Wed, 27 Feb 2019 18:38:30 +0200 | ||
| 4 | Subject: [PATCH 02/14] Add helper functions for constant time operations | ||
| 5 | |||
| 6 | These functions can be used to help implement constant time operations | ||
| 7 | for various cryptographic operations that must minimize externally | ||
| 8 | observable differences in processing (both in timing and also in | ||
| 9 | internal cache use, etc.). | ||
| 10 | |||
| 11 | This is related to CVE-2019-9494 and CVE-2019-9495. | ||
| 12 | |||
| 13 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 14 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 15 | Upstream-Status: Backport | ||
| 16 | CVE: CVE-2019-9494 | ||
| 17 | CVE: CVE-2019-9495 | ||
| 18 | --- | ||
| 19 | src/utils/const_time.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||
| 20 | 1 file changed, 191 insertions(+) | ||
| 21 | create mode 100644 src/utils/const_time.h | ||
| 22 | |||
| 23 | diff --git a/src/utils/const_time.h b/src/utils/const_time.h | ||
| 24 | new file mode 100644 | ||
| 25 | index 0000000..ab8f611 | ||
| 26 | --- /dev/null | ||
| 27 | +++ b/src/utils/const_time.h | ||
| 28 | @@ -0,0 +1,191 @@ | ||
| 29 | +/* | ||
| 30 | + * Helper functions for constant time operations | ||
| 31 | + * Copyright (c) 2019, The Linux Foundation | ||
| 32 | + * | ||
| 33 | + * This software may be distributed under the terms of the BSD license. | ||
| 34 | + * See README for more details. | ||
| 35 | + * | ||
| 36 | + * These helper functions can be used to implement logic that needs to minimize | ||
| 37 | + * externally visible differences in execution path by avoiding use of branches, | ||
| 38 | + * avoiding early termination or other time differences, and forcing same memory | ||
| 39 | + * access pattern regardless of values. | ||
| 40 | + */ | ||
| 41 | + | ||
| 42 | +#ifndef CONST_TIME_H | ||
| 43 | +#define CONST_TIME_H | ||
| 44 | + | ||
| 45 | + | ||
| 46 | +#if defined(__clang__) | ||
| 47 | +#define NO_UBSAN_UINT_OVERFLOW \ | ||
| 48 | + __attribute__((no_sanitize("unsigned-integer-overflow"))) | ||
| 49 | +#else | ||
| 50 | +#define NO_UBSAN_UINT_OVERFLOW | ||
| 51 | +#endif | ||
| 52 | + | ||
| 53 | + | ||
| 54 | +/** | ||
| 55 | + * const_time_fill_msb - Fill all bits with MSB value | ||
| 56 | + * @val: Input value | ||
| 57 | + * Returns: Value with all the bits set to the MSB of the input val | ||
| 58 | + */ | ||
| 59 | +static inline unsigned int const_time_fill_msb(unsigned int val) | ||
| 60 | +{ | ||
| 61 | + /* Move the MSB to LSB and multiple by -1 to fill in all bits. */ | ||
| 62 | + return (val >> (sizeof(val) * 8 - 1)) * ~0U; | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | + | ||
| 66 | +/* Returns: -1 if val is zero; 0 if val is not zero */ | ||
| 67 | +static inline unsigned int const_time_is_zero(unsigned int val) | ||
| 68 | + NO_UBSAN_UINT_OVERFLOW | ||
| 69 | +{ | ||
| 70 | + /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */ | ||
| 71 | + return const_time_fill_msb(~val & (val - 1)); | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | + | ||
| 75 | +/* Returns: -1 if a == b; 0 if a != b */ | ||
| 76 | +static inline unsigned int const_time_eq(unsigned int a, unsigned int b) | ||
| 77 | +{ | ||
| 78 | + return const_time_is_zero(a ^ b); | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | + | ||
| 82 | +/* Returns: -1 if a == b; 0 if a != b */ | ||
| 83 | +static inline u8 const_time_eq_u8(unsigned int a, unsigned int b) | ||
| 84 | +{ | ||
| 85 | + return (u8) const_time_eq(a, b); | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | + | ||
| 89 | +/** | ||
| 90 | + * const_time_eq_bin - Constant time memory comparison | ||
| 91 | + * @a: First buffer to compare | ||
| 92 | + * @b: Second buffer to compare | ||
| 93 | + * @len: Number of octets to compare | ||
| 94 | + * Returns: -1 if buffers are equal, 0 if not | ||
| 95 | + * | ||
| 96 | + * This function is meant for comparing passwords or hash values where | ||
| 97 | + * difference in execution time or memory access pattern could provide external | ||
| 98 | + * observer information about the location of the difference in the memory | ||
| 99 | + * buffers. The return value does not behave like memcmp(), i.e., | ||
| 100 | + * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike | ||
| 101 | + * memcmp(), the execution time of const_time_eq_bin() does not depend on the | ||
| 102 | + * contents of the compared memory buffers, but only on the total compared | ||
| 103 | + * length. | ||
| 104 | + */ | ||
| 105 | +static inline unsigned int const_time_eq_bin(const void *a, const void *b, | ||
| 106 | + size_t len) | ||
| 107 | +{ | ||
| 108 | + const u8 *aa = a; | ||
| 109 | + const u8 *bb = b; | ||
| 110 | + size_t i; | ||
| 111 | + u8 res = 0; | ||
| 112 | + | ||
| 113 | + for (i = 0; i < len; i++) | ||
| 114 | + res |= aa[i] ^ bb[i]; | ||
| 115 | + | ||
| 116 | + return const_time_is_zero(res); | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | + | ||
| 120 | +/** | ||
| 121 | + * const_time_select - Constant time unsigned int selection | ||
| 122 | + * @mask: 0 (false) or -1 (true) to identify which value to select | ||
| 123 | + * @true_val: Value to select for the true case | ||
| 124 | + * @false_val: Value to select for the false case | ||
| 125 | + * Returns: true_val if mask == -1, false_val if mask == 0 | ||
| 126 | + */ | ||
| 127 | +static inline unsigned int const_time_select(unsigned int mask, | ||
| 128 | + unsigned int true_val, | ||
| 129 | + unsigned int false_val) | ||
| 130 | +{ | ||
| 131 | + return (mask & true_val) | (~mask & false_val); | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | + | ||
| 135 | +/** | ||
| 136 | + * const_time_select_int - Constant time int selection | ||
| 137 | + * @mask: 0 (false) or -1 (true) to identify which value to select | ||
| 138 | + * @true_val: Value to select for the true case | ||
| 139 | + * @false_val: Value to select for the false case | ||
| 140 | + * Returns: true_val if mask == -1, false_val if mask == 0 | ||
| 141 | + */ | ||
| 142 | +static inline int const_time_select_int(unsigned int mask, int true_val, | ||
| 143 | + int false_val) | ||
| 144 | +{ | ||
| 145 | + return (int) const_time_select(mask, (unsigned int) true_val, | ||
| 146 | + (unsigned int) false_val); | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | + | ||
| 150 | +/** | ||
| 151 | + * const_time_select_u8 - Constant time u8 selection | ||
| 152 | + * @mask: 0 (false) or -1 (true) to identify which value to select | ||
| 153 | + * @true_val: Value to select for the true case | ||
| 154 | + * @false_val: Value to select for the false case | ||
| 155 | + * Returns: true_val if mask == -1, false_val if mask == 0 | ||
| 156 | + */ | ||
| 157 | +static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val) | ||
| 158 | +{ | ||
| 159 | + return (u8) const_time_select(mask, true_val, false_val); | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | + | ||
| 163 | +/** | ||
| 164 | + * const_time_select_s8 - Constant time s8 selection | ||
| 165 | + * @mask: 0 (false) or -1 (true) to identify which value to select | ||
| 166 | + * @true_val: Value to select for the true case | ||
| 167 | + * @false_val: Value to select for the false case | ||
| 168 | + * Returns: true_val if mask == -1, false_val if mask == 0 | ||
| 169 | + */ | ||
| 170 | +static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val) | ||
| 171 | +{ | ||
| 172 | + return (s8) const_time_select(mask, (unsigned int) true_val, | ||
| 173 | + (unsigned int) false_val); | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | + | ||
| 177 | +/** | ||
| 178 | + * const_time_select_bin - Constant time binary buffer selection copy | ||
| 179 | + * @mask: 0 (false) or -1 (true) to identify which value to copy | ||
| 180 | + * @true_val: Buffer to copy for the true case | ||
| 181 | + * @false_val: Buffer to copy for the false case | ||
| 182 | + * @len: Number of octets to copy | ||
| 183 | + * @dst: Destination buffer for the copy | ||
| 184 | + * | ||
| 185 | + * This function copies the specified buffer into the destination buffer using | ||
| 186 | + * operations with identical memory access pattern regardless of which buffer | ||
| 187 | + * is being copied. | ||
| 188 | + */ | ||
| 189 | +static inline void const_time_select_bin(u8 mask, const u8 *true_val, | ||
| 190 | + const u8 *false_val, size_t len, | ||
| 191 | + u8 *dst) | ||
| 192 | +{ | ||
| 193 | + size_t i; | ||
| 194 | + | ||
| 195 | + for (i = 0; i < len; i++) | ||
| 196 | + dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]); | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | + | ||
| 200 | +static inline int const_time_memcmp(const void *a, const void *b, size_t len) | ||
| 201 | +{ | ||
| 202 | + const u8 *aa = a; | ||
| 203 | + const u8 *bb = b; | ||
| 204 | + int diff, res = 0; | ||
| 205 | + unsigned int mask; | ||
| 206 | + | ||
| 207 | + if (len == 0) | ||
| 208 | + return 0; | ||
| 209 | + do { | ||
| 210 | + len--; | ||
| 211 | + diff = (int) aa[len] - (int) bb[len]; | ||
| 212 | + mask = const_time_is_zero((unsigned int) diff); | ||
| 213 | + res = const_time_select_int(mask, res, diff); | ||
| 214 | + } while (len); | ||
| 215 | + | ||
| 216 | + return res; | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +#endif /* CONST_TIME_H */ | ||
| 220 | -- | ||
| 221 | 2.7.4 | ||
| 222 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch new file mode 100644 index 0000000000..95ea809ef2 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From d2d1a324ce937628e4d9d9999fe113819b7d4478 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Wed, 17 Apr 2019 02:21:20 +0300 | ||
| 4 | Subject: [PATCH 3/3] EAP-pwd peer: Fix reassembly buffer handling | ||
| 5 | |||
| 6 | Unexpected fragment might result in data->inbuf not being allocated | ||
| 7 | before processing and that could have resulted in NULL pointer | ||
| 8 | dereference. Fix that by explicitly checking for data->inbuf to be | ||
| 9 | available before using it. | ||
| 10 | |||
| 11 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 12 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 13 | Upstream-Status: Backport | ||
| 14 | CVE: CVE-2019-11555 | ||
| 15 | --- | ||
| 16 | src/eap_peer/eap_pwd.c | 9 ++++++++- | ||
| 17 | 1 file changed, 8 insertions(+), 1 deletion(-) | ||
| 18 | |||
| 19 | diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c | ||
| 20 | index 46894a5..76fcad4 100644 | ||
| 21 | --- a/src/eap_peer/eap_pwd.c | ||
| 22 | +++ b/src/eap_peer/eap_pwd.c | ||
| 23 | @@ -932,6 +932,13 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, | ||
| 24 | * buffer and ACK the fragment | ||
| 25 | */ | ||
| 26 | if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) { | ||
| 27 | + if (!data->inbuf) { | ||
| 28 | + wpa_printf(MSG_DEBUG, | ||
| 29 | + "EAP-pwd: No buffer for reassembly"); | ||
| 30 | + ret->methodState = METHOD_DONE; | ||
| 31 | + ret->decision = DECISION_FAIL; | ||
| 32 | + return NULL; | ||
| 33 | + } | ||
| 34 | data->in_frag_pos += len; | ||
| 35 | if (data->in_frag_pos > wpabuf_size(data->inbuf)) { | ||
| 36 | wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " | ||
| 37 | @@ -958,7 +965,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, | ||
| 38 | /* | ||
| 39 | * we're buffering and this is the last fragment | ||
| 40 | */ | ||
| 41 | - if (data->in_frag_pos) { | ||
| 42 | + if (data->in_frag_pos && data->inbuf) { | ||
| 43 | wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", | ||
| 44 | (int) len); | ||
| 45 | pos = wpabuf_head_u8(data->inbuf); | ||
| 46 | -- | ||
| 47 | 2.7.4 | ||
| 48 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch new file mode 100644 index 0000000000..790041f259 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | From c93461c1d98f52681717a088776ab32fd97872b0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Fri, 8 Mar 2019 00:24:12 +0200 | ||
| 4 | Subject: [PATCH 03/14] OpenSSL: Use constant time selection for | ||
| 5 | crypto_bignum_legendre() | ||
| 6 | |||
| 7 | Get rid of the branches that depend on the result of the Legendre | ||
| 8 | operation. This is needed to avoid leaking information about different | ||
| 9 | temporary results in blinding mechanisms. | ||
| 10 | |||
| 11 | This is related to CVE-2019-9494 and CVE-2019-9495. | ||
| 12 | |||
| 13 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 14 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 15 | Upstream-Status: Backport | ||
| 16 | CVE: CVE-2019-9494 | ||
| 17 | CVE: CVE-2019-9495 | ||
| 18 | --- | ||
| 19 | src/crypto/crypto_openssl.c | 15 +++++++++------ | ||
| 20 | 1 file changed, 9 insertions(+), 6 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c | ||
| 23 | index ac53cc8..0f52101 100644 | ||
| 24 | --- a/src/crypto/crypto_openssl.c | ||
| 25 | +++ b/src/crypto/crypto_openssl.c | ||
| 26 | @@ -24,6 +24,7 @@ | ||
| 27 | #endif /* CONFIG_ECC */ | ||
| 28 | |||
| 29 | #include "common.h" | ||
| 30 | +#include "utils/const_time.h" | ||
| 31 | #include "wpabuf.h" | ||
| 32 | #include "dh_group5.h" | ||
| 33 | #include "sha1.h" | ||
| 34 | @@ -1500,6 +1501,7 @@ int crypto_bignum_legendre(const struct crypto_bignum *a, | ||
| 35 | BN_CTX *bnctx; | ||
| 36 | BIGNUM *exp = NULL, *tmp = NULL; | ||
| 37 | int res = -2; | ||
| 38 | + unsigned int mask; | ||
| 39 | |||
| 40 | if (TEST_FAIL()) | ||
| 41 | return -2; | ||
| 42 | @@ -1518,12 +1520,13 @@ int crypto_bignum_legendre(const struct crypto_bignum *a, | ||
| 43 | (const BIGNUM *) p, bnctx, NULL)) | ||
| 44 | goto fail; | ||
| 45 | |||
| 46 | - if (BN_is_word(tmp, 1)) | ||
| 47 | - res = 1; | ||
| 48 | - else if (BN_is_zero(tmp)) | ||
| 49 | - res = 0; | ||
| 50 | - else | ||
| 51 | - res = -1; | ||
| 52 | + /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use | ||
| 53 | + * constant time selection to avoid branches here. */ | ||
| 54 | + res = -1; | ||
| 55 | + mask = const_time_eq(BN_is_word(tmp, 1), 1); | ||
| 56 | + res = const_time_select_int(mask, 1, res); | ||
| 57 | + mask = const_time_eq(BN_is_zero(tmp), 1); | ||
| 58 | + res = const_time_select_int(mask, 0, res); | ||
| 59 | |||
| 60 | fail: | ||
| 61 | BN_clear_free(tmp); | ||
| 62 | -- | ||
| 63 | 2.7.4 | ||
| 64 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch new file mode 100644 index 0000000000..471380c443 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch | |||
| @@ -0,0 +1,327 @@ | |||
| 1 | From aaf65feac67c3993935634eefe5bc76b9fce03aa Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Tue, 26 Feb 2019 11:59:45 +0200 | ||
| 4 | Subject: [PATCH 04/14] EAP-pwd: Use constant time and memory access for | ||
| 5 | finding the PWE | ||
| 6 | |||
| 7 | This algorithm could leak information to external observers in form of | ||
| 8 | timing differences or memory access patterns (cache use). While the | ||
| 9 | previous implementation had protection against the most visible timing | ||
| 10 | differences (looping 40 rounds and masking the legendre operation), it | ||
| 11 | did not protect against memory access patterns between the two possible | ||
| 12 | code paths in the masking operations. That might be sufficient to allow | ||
| 13 | an unprivileged process running on the same device to be able to | ||
| 14 | determine which path is being executed through a cache attack and based | ||
| 15 | on that, determine information about the used password. | ||
| 16 | |||
| 17 | Convert the PWE finding loop to use constant time functions and | ||
| 18 | identical memory access path without different branches for the QR/QNR | ||
| 19 | cases to minimize possible side-channel information similarly to the | ||
| 20 | changes done for SAE authentication. (CVE-2019-9495) | ||
| 21 | |||
| 22 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 23 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 24 | Upstream-Status: Backport | ||
| 25 | CVE: CVE-2019-9495 | ||
| 26 | --- | ||
| 27 | src/eap_common/eap_pwd_common.c | 187 +++++++++++++++++++++------------------- | ||
| 28 | 1 file changed, 99 insertions(+), 88 deletions(-) | ||
| 29 | |||
| 30 | diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c | ||
| 31 | index 02fe01e..e49aaf8 100644 | ||
| 32 | --- a/src/eap_common/eap_pwd_common.c | ||
| 33 | +++ b/src/eap_common/eap_pwd_common.c | ||
| 34 | @@ -8,11 +8,15 @@ | ||
| 35 | |||
| 36 | #include "includes.h" | ||
| 37 | #include "common.h" | ||
| 38 | +#include "utils/const_time.h" | ||
| 39 | #include "crypto/sha256.h" | ||
| 40 | #include "crypto/crypto.h" | ||
| 41 | #include "eap_defs.h" | ||
| 42 | #include "eap_pwd_common.h" | ||
| 43 | |||
| 44 | +#define MAX_ECC_PRIME_LEN 66 | ||
| 45 | + | ||
| 46 | + | ||
| 47 | /* The random function H(x) = HMAC-SHA256(0^32, x) */ | ||
| 48 | struct crypto_hash * eap_pwd_h_init(void) | ||
| 49 | { | ||
| 50 | @@ -102,6 +106,15 @@ EAP_PWD_group * get_eap_pwd_group(u16 num) | ||
| 51 | } | ||
| 52 | |||
| 53 | |||
| 54 | +static void buf_shift_right(u8 *buf, size_t len, size_t bits) | ||
| 55 | +{ | ||
| 56 | + size_t i; | ||
| 57 | + for (i = len - 1; i > 0; i--) | ||
| 58 | + buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits); | ||
| 59 | + buf[0] >>= bits; | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | + | ||
| 63 | /* | ||
| 64 | * compute a "random" secret point on an elliptic curve based | ||
| 65 | * on the password and identities. | ||
| 66 | @@ -113,17 +126,27 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 67 | const u8 *token) | ||
| 68 | { | ||
| 69 | struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL; | ||
| 70 | + struct crypto_bignum *qr_or_qnr = NULL; | ||
| 71 | + u8 qr_bin[MAX_ECC_PRIME_LEN]; | ||
| 72 | + u8 qnr_bin[MAX_ECC_PRIME_LEN]; | ||
| 73 | + u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN]; | ||
| 74 | + u8 x_bin[MAX_ECC_PRIME_LEN]; | ||
| 75 | struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL; | ||
| 76 | struct crypto_hash *hash; | ||
| 77 | unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr; | ||
| 78 | - int is_odd, ret = 0, check, found = 0; | ||
| 79 | - size_t primebytelen, primebitlen; | ||
| 80 | - struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; | ||
| 81 | + int ret = 0, check, res; | ||
| 82 | + u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* | ||
| 83 | + * mask */ | ||
| 84 | + size_t primebytelen = 0, primebitlen; | ||
| 85 | + struct crypto_bignum *x_candidate = NULL, *cofactor = NULL; | ||
| 86 | const struct crypto_bignum *prime; | ||
| 87 | + u8 mask, found_ctr = 0, is_odd = 0; | ||
| 88 | |||
| 89 | if (grp->pwe) | ||
| 90 | return -1; | ||
| 91 | |||
| 92 | + os_memset(x_bin, 0, sizeof(x_bin)); | ||
| 93 | + | ||
| 94 | prime = crypto_ec_get_prime(grp->group); | ||
| 95 | cofactor = crypto_bignum_init(); | ||
| 96 | grp->pwe = crypto_ec_point_init(grp->group); | ||
| 97 | @@ -152,8 +175,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 98 | |||
| 99 | /* get a random quadratic residue and nonresidue */ | ||
| 100 | while (!qr || !qnr) { | ||
| 101 | - int res; | ||
| 102 | - | ||
| 103 | if (crypto_bignum_rand(tmp1, prime) < 0) | ||
| 104 | goto fail; | ||
| 105 | res = crypto_bignum_legendre(tmp1, prime); | ||
| 106 | @@ -167,6 +188,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 107 | if (!tmp1) | ||
| 108 | goto fail; | ||
| 109 | } | ||
| 110 | + if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), | ||
| 111 | + primebytelen) < 0 || | ||
| 112 | + crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), | ||
| 113 | + primebytelen) < 0) | ||
| 114 | + goto fail; | ||
| 115 | |||
| 116 | os_memset(prfbuf, 0, primebytelen); | ||
| 117 | ctr = 0; | ||
| 118 | @@ -194,17 +220,16 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 119 | eap_pwd_h_update(hash, &ctr, sizeof(ctr)); | ||
| 120 | eap_pwd_h_final(hash, pwe_digest); | ||
| 121 | |||
| 122 | - crypto_bignum_deinit(rnd, 1); | ||
| 123 | - rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN); | ||
| 124 | - if (!rnd) { | ||
| 125 | - wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd"); | ||
| 126 | - goto fail; | ||
| 127 | - } | ||
| 128 | + is_odd = const_time_select_u8( | ||
| 129 | + found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01); | ||
| 130 | if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN, | ||
| 131 | (u8 *) "EAP-pwd Hunting And Pecking", | ||
| 132 | os_strlen("EAP-pwd Hunting And Pecking"), | ||
| 133 | prfbuf, primebitlen) < 0) | ||
| 134 | goto fail; | ||
| 135 | + if (primebitlen % 8) | ||
| 136 | + buf_shift_right(prfbuf, primebytelen, | ||
| 137 | + 8 - primebitlen % 8); | ||
| 138 | |||
| 139 | crypto_bignum_deinit(x_candidate, 1); | ||
| 140 | x_candidate = crypto_bignum_init_set(prfbuf, primebytelen); | ||
| 141 | @@ -214,24 +239,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 142 | goto fail; | ||
| 143 | } | ||
| 144 | |||
| 145 | - /* | ||
| 146 | - * eap_pwd_kdf() returns a string of bits 0..primebitlen but | ||
| 147 | - * BN_bin2bn will treat that string of bits as a big endian | ||
| 148 | - * number. If the primebitlen is not an even multiple of 8 | ||
| 149 | - * then excessive bits-- those _after_ primebitlen-- so now | ||
| 150 | - * we have to shift right the amount we masked off. | ||
| 151 | - */ | ||
| 152 | - if ((primebitlen % 8) && | ||
| 153 | - crypto_bignum_rshift(x_candidate, | ||
| 154 | - (8 - (primebitlen % 8)), | ||
| 155 | - x_candidate) < 0) | ||
| 156 | - goto fail; | ||
| 157 | - | ||
| 158 | if (crypto_bignum_cmp(x_candidate, prime) >= 0) | ||
| 159 | continue; | ||
| 160 | |||
| 161 | - wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", | ||
| 162 | - prfbuf, primebytelen); | ||
| 163 | + wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate", | ||
| 164 | + prfbuf, primebytelen); | ||
| 165 | + const_time_select_bin(found, x_bin, prfbuf, primebytelen, | ||
| 166 | + x_bin); | ||
| 167 | |||
| 168 | /* | ||
| 169 | * compute y^2 using the equation of the curve | ||
| 170 | @@ -261,13 +275,15 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 171 | * Flip a coin, multiply by the random quadratic residue or the | ||
| 172 | * random quadratic nonresidue and record heads or tails. | ||
| 173 | */ | ||
| 174 | - if (crypto_bignum_is_odd(tmp1)) { | ||
| 175 | - crypto_bignum_mulmod(tmp2, qr, prime, tmp2); | ||
| 176 | - check = 1; | ||
| 177 | - } else { | ||
| 178 | - crypto_bignum_mulmod(tmp2, qnr, prime, tmp2); | ||
| 179 | - check = -1; | ||
| 180 | - } | ||
| 181 | + mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1); | ||
| 182 | + check = const_time_select_s8(mask, 1, -1); | ||
| 183 | + const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen, | ||
| 184 | + qr_or_qnr_bin); | ||
| 185 | + crypto_bignum_deinit(qr_or_qnr, 1); | ||
| 186 | + qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen); | ||
| 187 | + if (!qr_or_qnr || | ||
| 188 | + crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0) | ||
| 189 | + goto fail; | ||
| 190 | |||
| 191 | /* | ||
| 192 | * Now it's safe to do legendre, if check is 1 then it's | ||
| 193 | @@ -275,59 +291,12 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 194 | * change result), if check is -1 then it's the opposite test | ||
| 195 | * (multiplying a qr by qnr would make a qnr). | ||
| 196 | */ | ||
| 197 | - if (crypto_bignum_legendre(tmp2, prime) == check) { | ||
| 198 | - if (found == 1) | ||
| 199 | - continue; | ||
| 200 | - | ||
| 201 | - /* need to unambiguously identify the solution */ | ||
| 202 | - is_odd = crypto_bignum_is_odd(rnd); | ||
| 203 | - | ||
| 204 | - /* | ||
| 205 | - * We know x_candidate is a quadratic residue so set | ||
| 206 | - * it here. | ||
| 207 | - */ | ||
| 208 | - if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe, | ||
| 209 | - x_candidate, | ||
| 210 | - is_odd) != 0) { | ||
| 211 | - wpa_printf(MSG_INFO, | ||
| 212 | - "EAP-pwd: Could not solve for y"); | ||
| 213 | - continue; | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - /* | ||
| 217 | - * If there's a solution to the equation then the point | ||
| 218 | - * must be on the curve so why check again explicitly? | ||
| 219 | - * OpenSSL code says this is required by X9.62. We're | ||
| 220 | - * not X9.62 but it can't hurt just to be sure. | ||
| 221 | - */ | ||
| 222 | - if (!crypto_ec_point_is_on_curve(grp->group, | ||
| 223 | - grp->pwe)) { | ||
| 224 | - wpa_printf(MSG_INFO, | ||
| 225 | - "EAP-pwd: point is not on curve"); | ||
| 226 | - continue; | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - if (!crypto_bignum_is_one(cofactor)) { | ||
| 230 | - /* make sure the point is not in a small | ||
| 231 | - * sub-group */ | ||
| 232 | - if (crypto_ec_point_mul(grp->group, grp->pwe, | ||
| 233 | - cofactor, | ||
| 234 | - grp->pwe) != 0) { | ||
| 235 | - wpa_printf(MSG_INFO, | ||
| 236 | - "EAP-pwd: cannot multiply generator by order"); | ||
| 237 | - continue; | ||
| 238 | - } | ||
| 239 | - if (crypto_ec_point_is_at_infinity(grp->group, | ||
| 240 | - grp->pwe)) { | ||
| 241 | - wpa_printf(MSG_INFO, | ||
| 242 | - "EAP-pwd: point is at infinity"); | ||
| 243 | - continue; | ||
| 244 | - } | ||
| 245 | - } | ||
| 246 | - wpa_printf(MSG_DEBUG, | ||
| 247 | - "EAP-pwd: found a PWE in %d tries", ctr); | ||
| 248 | - found = 1; | ||
| 249 | - } | ||
| 250 | + res = crypto_bignum_legendre(tmp2, prime); | ||
| 251 | + if (res == -2) | ||
| 252 | + goto fail; | ||
| 253 | + mask = const_time_eq(res, check); | ||
| 254 | + found_ctr = const_time_select_u8(found, found_ctr, ctr); | ||
| 255 | + found |= mask; | ||
| 256 | } | ||
| 257 | if (found == 0) { | ||
| 258 | wpa_printf(MSG_INFO, | ||
| 259 | @@ -335,6 +304,44 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 260 | num); | ||
| 261 | goto fail; | ||
| 262 | } | ||
| 263 | + | ||
| 264 | + /* | ||
| 265 | + * We know x_candidate is a quadratic residue so set it here. | ||
| 266 | + */ | ||
| 267 | + crypto_bignum_deinit(x_candidate, 1); | ||
| 268 | + x_candidate = crypto_bignum_init_set(x_bin, primebytelen); | ||
| 269 | + if (!x_candidate || | ||
| 270 | + crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate, | ||
| 271 | + is_odd) != 0) { | ||
| 272 | + wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y"); | ||
| 273 | + goto fail; | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + /* | ||
| 277 | + * If there's a solution to the equation then the point must be on the | ||
| 278 | + * curve so why check again explicitly? OpenSSL code says this is | ||
| 279 | + * required by X9.62. We're not X9.62 but it can't hurt just to be sure. | ||
| 280 | + */ | ||
| 281 | + if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) { | ||
| 282 | + wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); | ||
| 283 | + goto fail; | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + if (!crypto_bignum_is_one(cofactor)) { | ||
| 287 | + /* make sure the point is not in a small sub-group */ | ||
| 288 | + if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor, | ||
| 289 | + grp->pwe) != 0) { | ||
| 290 | + wpa_printf(MSG_INFO, | ||
| 291 | + "EAP-pwd: cannot multiply generator by order"); | ||
| 292 | + goto fail; | ||
| 293 | + } | ||
| 294 | + if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) { | ||
| 295 | + wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity"); | ||
| 296 | + goto fail; | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr); | ||
| 300 | + | ||
| 301 | if (0) { | ||
| 302 | fail: | ||
| 303 | crypto_ec_point_deinit(grp->pwe, 1); | ||
| 304 | @@ -344,14 +351,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, | ||
| 305 | /* cleanliness and order.... */ | ||
| 306 | crypto_bignum_deinit(cofactor, 1); | ||
| 307 | crypto_bignum_deinit(x_candidate, 1); | ||
| 308 | - crypto_bignum_deinit(rnd, 1); | ||
| 309 | crypto_bignum_deinit(pm1, 0); | ||
| 310 | crypto_bignum_deinit(tmp1, 1); | ||
| 311 | crypto_bignum_deinit(tmp2, 1); | ||
| 312 | crypto_bignum_deinit(qr, 1); | ||
| 313 | crypto_bignum_deinit(qnr, 1); | ||
| 314 | + crypto_bignum_deinit(qr_or_qnr, 1); | ||
| 315 | crypto_bignum_deinit(one, 0); | ||
| 316 | - os_free(prfbuf); | ||
| 317 | + bin_clear_free(prfbuf, primebytelen); | ||
| 318 | + os_memset(qr_bin, 0, sizeof(qr_bin)); | ||
| 319 | + os_memset(qnr_bin, 0, sizeof(qnr_bin)); | ||
| 320 | + os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin)); | ||
| 321 | + os_memset(pwe_digest, 0, sizeof(pwe_digest)); | ||
| 322 | |||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | -- | ||
| 326 | 2.7.4 | ||
| 327 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch new file mode 100644 index 0000000000..6a567c5fb6 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | From 6513db3e96c43c2e36805cf5ead349765d18eaf7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Tue, 26 Feb 2019 13:05:09 +0200 | ||
| 4 | Subject: [PATCH 05/14] SAE: Minimize timing differences in PWE derivation | ||
| 5 | |||
| 6 | The QR test result can provide information about the password to an | ||
| 7 | attacker, so try to minimize differences in how the | ||
| 8 | sae_test_pwd_seed_ecc() result is used. (CVE-2019-9494) | ||
| 9 | |||
| 10 | Use heap memory for the dummy password to allow the same password length | ||
| 11 | to be used even with long passwords. | ||
| 12 | |||
| 13 | Use constant time selection functions to track the real vs. dummy | ||
| 14 | variables so that the exact same operations can be performed for both QR | ||
| 15 | test results. | ||
| 16 | |||
| 17 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 18 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 19 | Upstream-Status: Backport | ||
| 20 | CVE: CVE-2019-9494 | ||
| 21 | --- | ||
| 22 | src/common/sae.c | 106 ++++++++++++++++++++++++++++++------------------------- | ||
| 23 | 1 file changed, 57 insertions(+), 49 deletions(-) | ||
| 24 | |||
| 25 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 26 | index 8129a7c..d55323b 100644 | ||
| 27 | --- a/src/common/sae.c | ||
| 28 | +++ b/src/common/sae.c | ||
| 29 | @@ -9,6 +9,7 @@ | ||
| 30 | #include "includes.h" | ||
| 31 | |||
| 32 | #include "common.h" | ||
| 33 | +#include "utils/const_time.h" | ||
| 34 | #include "crypto/crypto.h" | ||
| 35 | #include "crypto/sha256.h" | ||
| 36 | #include "crypto/random.h" | ||
| 37 | @@ -292,15 +293,12 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 38 | const u8 *prime, | ||
| 39 | const struct crypto_bignum *qr, | ||
| 40 | const struct crypto_bignum *qnr, | ||
| 41 | - struct crypto_bignum **ret_x_cand) | ||
| 42 | + u8 *pwd_value) | ||
| 43 | { | ||
| 44 | - u8 pwd_value[SAE_MAX_ECC_PRIME_LEN]; | ||
| 45 | struct crypto_bignum *y_sqr, *x_cand; | ||
| 46 | int res; | ||
| 47 | size_t bits; | ||
| 48 | |||
| 49 | - *ret_x_cand = NULL; | ||
| 50 | - | ||
| 51 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); | ||
| 52 | |||
| 53 | /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ | ||
| 54 | @@ -309,7 +307,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 55 | prime, sae->tmp->prime_len, pwd_value, bits) < 0) | ||
| 56 | return -1; | ||
| 57 | if (bits % 8) | ||
| 58 | - buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); | ||
| 59 | + buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8); | ||
| 60 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", | ||
| 61 | pwd_value, sae->tmp->prime_len); | ||
| 62 | |||
| 63 | @@ -320,20 +318,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 64 | if (!x_cand) | ||
| 65 | return -1; | ||
| 66 | y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); | ||
| 67 | - if (!y_sqr) { | ||
| 68 | - crypto_bignum_deinit(x_cand, 1); | ||
| 69 | + crypto_bignum_deinit(x_cand, 1); | ||
| 70 | + if (!y_sqr) | ||
| 71 | return -1; | ||
| 72 | - } | ||
| 73 | |||
| 74 | res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); | ||
| 75 | crypto_bignum_deinit(y_sqr, 1); | ||
| 76 | - if (res <= 0) { | ||
| 77 | - crypto_bignum_deinit(x_cand, 1); | ||
| 78 | - return res; | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - *ret_x_cand = x_cand; | ||
| 82 | - return 1; | ||
| 83 | + return res; | ||
| 84 | } | ||
| 85 | |||
| 86 | |||
| 87 | @@ -454,25 +445,30 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 88 | const u8 *addr[3]; | ||
| 89 | size_t len[3]; | ||
| 90 | size_t num_elem; | ||
| 91 | - u8 dummy_password[32]; | ||
| 92 | - size_t dummy_password_len; | ||
| 93 | + u8 *dummy_password, *tmp_password; | ||
| 94 | int pwd_seed_odd = 0; | ||
| 95 | u8 prime[SAE_MAX_ECC_PRIME_LEN]; | ||
| 96 | size_t prime_len; | ||
| 97 | - struct crypto_bignum *x = NULL, *qr, *qnr; | ||
| 98 | + struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL; | ||
| 99 | + u8 x_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 100 | + u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 101 | size_t bits; | ||
| 102 | - int res; | ||
| 103 | + int res = -1; | ||
| 104 | + u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* | ||
| 105 | + * mask */ | ||
| 106 | |||
| 107 | - dummy_password_len = password_len; | ||
| 108 | - if (dummy_password_len > sizeof(dummy_password)) | ||
| 109 | - dummy_password_len = sizeof(dummy_password); | ||
| 110 | - if (random_get_bytes(dummy_password, dummy_password_len) < 0) | ||
| 111 | - return -1; | ||
| 112 | + os_memset(x_bin, 0, sizeof(x_bin)); | ||
| 113 | + | ||
| 114 | + dummy_password = os_malloc(password_len); | ||
| 115 | + tmp_password = os_malloc(password_len); | ||
| 116 | + if (!dummy_password || !tmp_password || | ||
| 117 | + random_get_bytes(dummy_password, password_len) < 0) | ||
| 118 | + goto fail; | ||
| 119 | |||
| 120 | prime_len = sae->tmp->prime_len; | ||
| 121 | if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), | ||
| 122 | prime_len) < 0) | ||
| 123 | - return -1; | ||
| 124 | + goto fail; | ||
| 125 | bits = crypto_ec_prime_len_bits(sae->tmp->ec); | ||
| 126 | |||
| 127 | /* | ||
| 128 | @@ -481,7 +477,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 129 | */ | ||
| 130 | if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, | ||
| 131 | &qr, &qnr) < 0) | ||
| 132 | - return -1; | ||
| 133 | + goto fail; | ||
| 134 | |||
| 135 | wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", | ||
| 136 | password, password_len); | ||
| 137 | @@ -497,7 +493,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 138 | */ | ||
| 139 | sae_pwd_seed_key(addr1, addr2, addrs); | ||
| 140 | |||
| 141 | - addr[0] = password; | ||
| 142 | + addr[0] = tmp_password; | ||
| 143 | len[0] = password_len; | ||
| 144 | num_elem = 1; | ||
| 145 | if (identifier) { | ||
| 146 | @@ -514,9 +510,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 147 | * attacks that attempt to determine the number of iterations required | ||
| 148 | * in the loop. | ||
| 149 | */ | ||
| 150 | - for (counter = 1; counter <= k || !x; counter++) { | ||
| 151 | + for (counter = 1; counter <= k || !found; counter++) { | ||
| 152 | u8 pwd_seed[SHA256_MAC_LEN]; | ||
| 153 | - struct crypto_bignum *x_cand; | ||
| 154 | |||
| 155 | if (counter > 200) { | ||
| 156 | /* This should not happen in practice */ | ||
| 157 | @@ -524,36 +519,45 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | |||
| 161 | - wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); | ||
| 162 | + wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter); | ||
| 163 | + const_time_select_bin(found, dummy_password, password, | ||
| 164 | + password_len, tmp_password); | ||
| 165 | if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, | ||
| 166 | addr, len, pwd_seed) < 0) | ||
| 167 | break; | ||
| 168 | |||
| 169 | res = sae_test_pwd_seed_ecc(sae, pwd_seed, | ||
| 170 | - prime, qr, qnr, &x_cand); | ||
| 171 | + prime, qr, qnr, x_cand_bin); | ||
| 172 | + const_time_select_bin(found, x_bin, x_cand_bin, prime_len, | ||
| 173 | + x_bin); | ||
| 174 | + pwd_seed_odd = const_time_select_u8( | ||
| 175 | + found, pwd_seed_odd, | ||
| 176 | + pwd_seed[SHA256_MAC_LEN - 1] & 0x01); | ||
| 177 | + os_memset(pwd_seed, 0, sizeof(pwd_seed)); | ||
| 178 | if (res < 0) | ||
| 179 | goto fail; | ||
| 180 | - if (res > 0 && !x) { | ||
| 181 | - wpa_printf(MSG_DEBUG, | ||
| 182 | - "SAE: Selected pwd-seed with counter %u", | ||
| 183 | - counter); | ||
| 184 | - x = x_cand; | ||
| 185 | - pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; | ||
| 186 | - os_memset(pwd_seed, 0, sizeof(pwd_seed)); | ||
| 187 | + /* Need to minimize differences in handling res == 0 and 1 here | ||
| 188 | + * to avoid differences in timing and instruction cache access, | ||
| 189 | + * so use const_time_select_*() to make local copies of the | ||
| 190 | + * values based on whether this loop iteration was the one that | ||
| 191 | + * found the pwd-seed/x. */ | ||
| 192 | + | ||
| 193 | + /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them | ||
| 194 | + * (with res converted to 0/0xff) handles this in constant time. | ||
| 195 | + */ | ||
| 196 | + found |= res * 0xff; | ||
| 197 | + wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x", | ||
| 198 | + res, found); | ||
| 199 | + } | ||
| 200 | |||
| 201 | - /* | ||
| 202 | - * Use a dummy password for the following rounds, if | ||
| 203 | - * any. | ||
| 204 | - */ | ||
| 205 | - addr[0] = dummy_password; | ||
| 206 | - len[0] = dummy_password_len; | ||
| 207 | - } else if (res > 0) { | ||
| 208 | - crypto_bignum_deinit(x_cand, 1); | ||
| 209 | - } | ||
| 210 | + if (!found) { | ||
| 211 | + wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); | ||
| 212 | + res = -1; | ||
| 213 | + goto fail; | ||
| 214 | } | ||
| 215 | |||
| 216 | + x = crypto_bignum_init_set(x_bin, prime_len); | ||
| 217 | if (!x) { | ||
| 218 | - wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); | ||
| 219 | res = -1; | ||
| 220 | goto fail; | ||
| 221 | } | ||
| 222 | @@ -566,7 +570,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 223 | res = crypto_ec_point_solve_y_coord(sae->tmp->ec, | ||
| 224 | sae->tmp->pwe_ecc, x, | ||
| 225 | pwd_seed_odd); | ||
| 226 | - crypto_bignum_deinit(x, 1); | ||
| 227 | if (res < 0) { | ||
| 228 | /* | ||
| 229 | * This should not happen since we already checked that there | ||
| 230 | @@ -578,6 +581,11 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 231 | fail: | ||
| 232 | crypto_bignum_deinit(qr, 0); | ||
| 233 | crypto_bignum_deinit(qnr, 0); | ||
| 234 | + os_free(dummy_password); | ||
| 235 | + bin_clear_free(tmp_password, password_len); | ||
| 236 | + crypto_bignum_deinit(x, 1); | ||
| 237 | + os_memset(x_bin, 0, sizeof(x_bin)); | ||
| 238 | + os_memset(x_cand_bin, 0, sizeof(x_cand_bin)); | ||
| 239 | |||
| 240 | return res; | ||
| 241 | } | ||
| 242 | -- | ||
| 243 | 2.7.4 | ||
| 244 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch new file mode 100644 index 0000000000..5209559659 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | From 362704dda04507e7ebb8035122e83d9f0ae7c320 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Tue, 26 Feb 2019 19:34:38 +0200 | ||
| 4 | Subject: [PATCH 06/14] SAE: Avoid branches in is_quadratic_residue_blind() | ||
| 5 | |||
| 6 | Make the non-failure path in the function proceed without branches based | ||
| 7 | on r_odd and in constant time to minimize risk of observable differences | ||
| 8 | in timing or cache use. (CVE-2019-9494) | ||
| 9 | |||
| 10 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 11 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 12 | Upstream-Status: Backport | ||
| 13 | CVE: CVE-2019-9494 | ||
| 14 | --- | ||
| 15 | src/common/sae.c | 64 ++++++++++++++++++++++++++++++++------------------------ | ||
| 16 | 1 file changed, 37 insertions(+), 27 deletions(-) | ||
| 17 | |||
| 18 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 19 | index d55323b..5df9b95 100644 | ||
| 20 | --- a/src/common/sae.c | ||
| 21 | +++ b/src/common/sae.c | ||
| 22 | @@ -232,12 +232,14 @@ get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits, | ||
| 23 | |||
| 24 | static int is_quadratic_residue_blind(struct sae_data *sae, | ||
| 25 | const u8 *prime, size_t bits, | ||
| 26 | - const struct crypto_bignum *qr, | ||
| 27 | - const struct crypto_bignum *qnr, | ||
| 28 | + const u8 *qr, const u8 *qnr, | ||
| 29 | const struct crypto_bignum *y_sqr) | ||
| 30 | { | ||
| 31 | - struct crypto_bignum *r, *num; | ||
| 32 | + struct crypto_bignum *r, *num, *qr_or_qnr = NULL; | ||
| 33 | int r_odd, check, res = -1; | ||
| 34 | + u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 35 | + size_t prime_len = sae->tmp->prime_len; | ||
| 36 | + unsigned int mask; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Use the blinding technique to mask y_sqr while determining | ||
| 40 | @@ -248,7 +250,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae, | ||
| 41 | * r = a random number between 1 and p-1, inclusive | ||
| 42 | * num = (v * r * r) modulo p | ||
| 43 | */ | ||
| 44 | - r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd); | ||
| 45 | + r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd); | ||
| 46 | if (!r) | ||
| 47 | return -1; | ||
| 48 | |||
| 49 | @@ -258,41 +260,45 @@ static int is_quadratic_residue_blind(struct sae_data *sae, | ||
| 50 | crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0) | ||
| 51 | goto fail; | ||
| 52 | |||
| 53 | - if (r_odd) { | ||
| 54 | - /* | ||
| 55 | - * num = (num * qr) module p | ||
| 56 | - * LGR(num, p) = 1 ==> quadratic residue | ||
| 57 | - */ | ||
| 58 | - if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0) | ||
| 59 | - goto fail; | ||
| 60 | - check = 1; | ||
| 61 | - } else { | ||
| 62 | - /* | ||
| 63 | - * num = (num * qnr) module p | ||
| 64 | - * LGR(num, p) = -1 ==> quadratic residue | ||
| 65 | - */ | ||
| 66 | - if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0) | ||
| 67 | - goto fail; | ||
| 68 | - check = -1; | ||
| 69 | - } | ||
| 70 | + /* | ||
| 71 | + * Need to minimize differences in handling different cases, so try to | ||
| 72 | + * avoid branches and timing differences. | ||
| 73 | + * | ||
| 74 | + * If r_odd: | ||
| 75 | + * num = (num * qr) module p | ||
| 76 | + * LGR(num, p) = 1 ==> quadratic residue | ||
| 77 | + * else: | ||
| 78 | + * num = (num * qnr) module p | ||
| 79 | + * LGR(num, p) = -1 ==> quadratic residue | ||
| 80 | + */ | ||
| 81 | + mask = const_time_is_zero(r_odd); | ||
| 82 | + const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin); | ||
| 83 | + qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len); | ||
| 84 | + if (!qr_or_qnr || | ||
| 85 | + crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0) | ||
| 86 | + goto fail; | ||
| 87 | + /* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */ | ||
| 88 | + check = const_time_select_int(mask, -1, 1); | ||
| 89 | |||
| 90 | res = crypto_bignum_legendre(num, sae->tmp->prime); | ||
| 91 | if (res == -2) { | ||
| 92 | res = -1; | ||
| 93 | goto fail; | ||
| 94 | } | ||
| 95 | - res = res == check; | ||
| 96 | + /* branchless version of res = res == check | ||
| 97 | + * (res is -1, 0, or 1; check is -1 or 1) */ | ||
| 98 | + mask = const_time_eq(res, check); | ||
| 99 | + res = const_time_select_int(mask, 1, 0); | ||
| 100 | fail: | ||
| 101 | crypto_bignum_deinit(num, 1); | ||
| 102 | crypto_bignum_deinit(r, 1); | ||
| 103 | + crypto_bignum_deinit(qr_or_qnr, 1); | ||
| 104 | return res; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 109 | - const u8 *prime, | ||
| 110 | - const struct crypto_bignum *qr, | ||
| 111 | - const struct crypto_bignum *qnr, | ||
| 112 | + const u8 *prime, const u8 *qr, const u8 *qnr, | ||
| 113 | u8 *pwd_value) | ||
| 114 | { | ||
| 115 | struct crypto_bignum *y_sqr, *x_cand; | ||
| 116 | @@ -452,6 +458,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 117 | struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL; | ||
| 118 | u8 x_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 119 | u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 120 | + u8 qr_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 121 | + u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
| 122 | size_t bits; | ||
| 123 | int res = -1; | ||
| 124 | u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* | ||
| 125 | @@ -476,7 +484,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 126 | * (qnr) modulo p for blinding purposes during the loop. | ||
| 127 | */ | ||
| 128 | if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, | ||
| 129 | - &qr, &qnr) < 0) | ||
| 130 | + &qr, &qnr) < 0 || | ||
| 131 | + crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 || | ||
| 132 | + crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0) | ||
| 133 | goto fail; | ||
| 134 | |||
| 135 | wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", | ||
| 136 | @@ -527,7 +537,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
| 137 | break; | ||
| 138 | |||
| 139 | res = sae_test_pwd_seed_ecc(sae, pwd_seed, | ||
| 140 | - prime, qr, qnr, x_cand_bin); | ||
| 141 | + prime, qr_bin, qnr_bin, x_cand_bin); | ||
| 142 | const_time_select_bin(found, x_bin, x_cand_bin, prime_len, | ||
| 143 | x_bin); | ||
| 144 | pwd_seed_odd = const_time_select_u8( | ||
| 145 | -- | ||
| 146 | 2.7.4 | ||
| 147 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch new file mode 100644 index 0000000000..6cfa7220e1 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | From 90839597cc4016b33f00055b12d59174c62770a3 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Sat, 2 Mar 2019 12:24:09 +0200 | ||
| 4 | Subject: [PATCH 07/14] SAE: Mask timing of MODP groups 22, 23, 24 | ||
| 5 | |||
| 6 | These groups have significant probability of coming up with pwd-value | ||
| 7 | that is equal or greater than the prime and as such, need for going | ||
| 8 | through the PWE derivation loop multiple times. This can result in | ||
| 9 | sufficient timing different to allow an external observer to determine | ||
| 10 | how many rounds are needed and that can leak information about the used | ||
| 11 | password. | ||
| 12 | |||
| 13 | Force at least 40 loop rounds for these MODP groups similarly to the ECC | ||
| 14 | group design to mask timing. This behavior is not described in IEEE Std | ||
| 15 | 802.11-2016 for SAE, but it does not result in different values (i.e., | ||
| 16 | only different timing), so such implementation specific countermeasures | ||
| 17 | can be done without breaking interoperability with other implementation. | ||
| 18 | |||
| 19 | Note: These MODP groups 22, 23, and 24 are not considered sufficiently | ||
| 20 | strong to be used with SAE (or more or less anything else). As such, | ||
| 21 | they should never be enabled in runtime configuration for any production | ||
| 22 | use cases. These changes to introduce additional protection to mask | ||
| 23 | timing is only for completeness of implementation and not an indication | ||
| 24 | that these groups should be used. | ||
| 25 | |||
| 26 | This is related to CVE-2019-9494. | ||
| 27 | |||
| 28 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 29 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 30 | Upstream-Status: Backport | ||
| 31 | CVE: CVE-2019-9494 | ||
| 32 | --- | ||
| 33 | src/common/sae.c | 38 ++++++++++++++++++++++++++++---------- | ||
| 34 | 1 file changed, 28 insertions(+), 10 deletions(-) | ||
| 35 | |||
| 36 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 37 | index 5df9b95..75b1b4a 100644 | ||
| 38 | --- a/src/common/sae.c | ||
| 39 | +++ b/src/common/sae.c | ||
| 40 | @@ -601,22 +601,27 @@ fail: | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | +static int sae_modp_group_require_masking(int group) | ||
| 45 | +{ | ||
| 46 | + /* Groups for which pwd-value is likely to be >= p frequently */ | ||
| 47 | + return group == 22 || group == 23 || group == 24; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | + | ||
| 51 | static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, | ||
| 52 | const u8 *addr2, const u8 *password, | ||
| 53 | size_t password_len, const char *identifier) | ||
| 54 | { | ||
| 55 | - u8 counter; | ||
| 56 | + u8 counter, k; | ||
| 57 | u8 addrs[2 * ETH_ALEN]; | ||
| 58 | const u8 *addr[3]; | ||
| 59 | size_t len[3]; | ||
| 60 | size_t num_elem; | ||
| 61 | int found = 0; | ||
| 62 | + struct crypto_bignum *pwe = NULL; | ||
| 63 | |||
| 64 | - if (sae->tmp->pwe_ffc == NULL) { | ||
| 65 | - sae->tmp->pwe_ffc = crypto_bignum_init(); | ||
| 66 | - if (sae->tmp->pwe_ffc == NULL) | ||
| 67 | - return -1; | ||
| 68 | - } | ||
| 69 | + crypto_bignum_deinit(sae->tmp->pwe_ffc, 1); | ||
| 70 | + sae->tmp->pwe_ffc = NULL; | ||
| 71 | |||
| 72 | wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", | ||
| 73 | password, password_len); | ||
| 74 | @@ -640,7 +645,9 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, | ||
| 75 | len[num_elem] = sizeof(counter); | ||
| 76 | num_elem++; | ||
| 77 | |||
| 78 | - for (counter = 1; !found; counter++) { | ||
| 79 | + k = sae_modp_group_require_masking(sae->group) ? 40 : 1; | ||
| 80 | + | ||
| 81 | + for (counter = 1; counter <= k || !found; counter++) { | ||
| 82 | u8 pwd_seed[SHA256_MAC_LEN]; | ||
| 83 | int res; | ||
| 84 | |||
| 85 | @@ -650,19 +657,30 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | |||
| 89 | - wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); | ||
| 90 | + wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter); | ||
| 91 | if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, | ||
| 92 | addr, len, pwd_seed) < 0) | ||
| 93 | break; | ||
| 94 | - res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc); | ||
| 95 | + if (!pwe) { | ||
| 96 | + pwe = crypto_bignum_init(); | ||
| 97 | + if (!pwe) | ||
| 98 | + break; | ||
| 99 | + } | ||
| 100 | + res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe); | ||
| 101 | if (res < 0) | ||
| 102 | break; | ||
| 103 | if (res > 0) { | ||
| 104 | - wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); | ||
| 105 | found = 1; | ||
| 106 | + if (!sae->tmp->pwe_ffc) { | ||
| 107 | + wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); | ||
| 108 | + sae->tmp->pwe_ffc = pwe; | ||
| 109 | + pwe = NULL; | ||
| 110 | + } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | + crypto_bignum_deinit(pwe, 1); | ||
| 115 | + | ||
| 116 | return found ? 0 : -1; | ||
| 117 | } | ||
| 118 | |||
| 119 | -- | ||
| 120 | 2.7.4 | ||
| 121 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch new file mode 100644 index 0000000000..7b8616a66d --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | From f8f20717f87eff1f025f48ed585c7684debacf72 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Sat, 2 Mar 2019 12:45:33 +0200 | ||
| 4 | Subject: [PATCH 08/14] SAE: Use const_time selection for PWE in FFC | ||
| 5 | |||
| 6 | This is an initial step towards making the FFC case use strictly | ||
| 7 | constant time operations similarly to the ECC case. | ||
| 8 | sae_test_pwd_seed_ffc() does not yet have constant time behavior, | ||
| 9 | though. | ||
| 10 | |||
| 11 | This is related to CVE-2019-9494. | ||
| 12 | |||
| 13 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 14 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 15 | Upstream-Status: Backport | ||
| 16 | CVE: CVE-2019-9494 | ||
| 17 | --- | ||
| 18 | src/common/sae.c | 53 +++++++++++++++++++++++++++++++++++------------------ | ||
| 19 | 1 file changed, 35 insertions(+), 18 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 22 | index 75b1b4a..fa9a145 100644 | ||
| 23 | --- a/src/common/sae.c | ||
| 24 | +++ b/src/common/sae.c | ||
| 25 | @@ -612,17 +612,28 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, | ||
| 26 | const u8 *addr2, const u8 *password, | ||
| 27 | size_t password_len, const char *identifier) | ||
| 28 | { | ||
| 29 | - u8 counter, k; | ||
| 30 | + u8 counter, k, sel_counter = 0; | ||
| 31 | u8 addrs[2 * ETH_ALEN]; | ||
| 32 | const u8 *addr[3]; | ||
| 33 | size_t len[3]; | ||
| 34 | size_t num_elem; | ||
| 35 | - int found = 0; | ||
| 36 | - struct crypto_bignum *pwe = NULL; | ||
| 37 | + u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* | ||
| 38 | + * mask */ | ||
| 39 | + u8 mask; | ||
| 40 | + struct crypto_bignum *pwe; | ||
| 41 | + size_t prime_len = sae->tmp->prime_len * 8; | ||
| 42 | + u8 *pwe_buf; | ||
| 43 | |||
| 44 | crypto_bignum_deinit(sae->tmp->pwe_ffc, 1); | ||
| 45 | sae->tmp->pwe_ffc = NULL; | ||
| 46 | |||
| 47 | + /* Allocate a buffer to maintain selected and candidate PWE for constant | ||
| 48 | + * time selection. */ | ||
| 49 | + pwe_buf = os_zalloc(prime_len * 2); | ||
| 50 | + pwe = crypto_bignum_init(); | ||
| 51 | + if (!pwe_buf || !pwe) | ||
| 52 | + goto fail; | ||
| 53 | + | ||
| 54 | wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", | ||
| 55 | password, password_len); | ||
| 56 | |||
| 57 | @@ -661,27 +672,33 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, | ||
| 58 | if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, | ||
| 59 | addr, len, pwd_seed) < 0) | ||
| 60 | break; | ||
| 61 | - if (!pwe) { | ||
| 62 | - pwe = crypto_bignum_init(); | ||
| 63 | - if (!pwe) | ||
| 64 | - break; | ||
| 65 | - } | ||
| 66 | res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe); | ||
| 67 | + /* res is -1 for fatal failure, 0 if a valid PWE was not found, | ||
| 68 | + * or 1 if a valid PWE was found. */ | ||
| 69 | if (res < 0) | ||
| 70 | break; | ||
| 71 | - if (res > 0) { | ||
| 72 | - found = 1; | ||
| 73 | - if (!sae->tmp->pwe_ffc) { | ||
| 74 | - wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); | ||
| 75 | - sae->tmp->pwe_ffc = pwe; | ||
| 76 | - pwe = NULL; | ||
| 77 | - } | ||
| 78 | - } | ||
| 79 | + /* Store the candidate PWE into the second half of pwe_buf and | ||
| 80 | + * the selected PWE in the beginning of pwe_buf using constant | ||
| 81 | + * time selection. */ | ||
| 82 | + if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len, | ||
| 83 | + prime_len) < 0) | ||
| 84 | + break; | ||
| 85 | + const_time_select_bin(found, pwe_buf, pwe_buf + prime_len, | ||
| 86 | + prime_len, pwe_buf); | ||
| 87 | + sel_counter = const_time_select_u8(found, sel_counter, counter); | ||
| 88 | + mask = const_time_eq_u8(res, 1); | ||
| 89 | + found = const_time_select_u8(found, found, mask); | ||
| 90 | } | ||
| 91 | |||
| 92 | - crypto_bignum_deinit(pwe, 1); | ||
| 93 | + if (!found) | ||
| 94 | + goto fail; | ||
| 95 | |||
| 96 | - return found ? 0 : -1; | ||
| 97 | + wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter); | ||
| 98 | + sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len); | ||
| 99 | +fail: | ||
| 100 | + crypto_bignum_deinit(pwe, 1); | ||
| 101 | + bin_clear_free(pwe_buf, prime_len * 2); | ||
| 102 | + return sae->tmp->pwe_ffc ? 0 : -1; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | -- | ||
| 107 | 2.7.4 | ||
| 108 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch new file mode 100644 index 0000000000..d2ae8188e1 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | From cff138b0747fa39765cbc641b66cfa5d7f1735d1 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Sat, 2 Mar 2019 16:05:56 +0200 | ||
| 4 | Subject: [PATCH 09/14] SAE: Use constant time operations in | ||
| 5 | sae_test_pwd_seed_ffc() | ||
| 6 | |||
| 7 | Try to avoid showing externally visible timing or memory access | ||
| 8 | differences regardless of whether the derived pwd-value is smaller than | ||
| 9 | the group prime. | ||
| 10 | |||
| 11 | This is related to CVE-2019-9494. | ||
| 12 | |||
| 13 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 14 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 15 | Upstream-Status: Backport | ||
| 16 | CVE: CVE-2019-9494 | ||
| 17 | --- | ||
| 18 | src/common/sae.c | 75 ++++++++++++++++++++++++++++++++++---------------------- | ||
| 19 | 1 file changed, 46 insertions(+), 29 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 22 | index fa9a145..eaf825d 100644 | ||
| 23 | --- a/src/common/sae.c | ||
| 24 | +++ b/src/common/sae.c | ||
| 25 | @@ -334,14 +334,17 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 26 | } | ||
| 27 | |||
| 28 | |||
| 29 | +/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided | ||
| 30 | + * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */ | ||
| 31 | static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 32 | struct crypto_bignum *pwe) | ||
| 33 | { | ||
| 34 | u8 pwd_value[SAE_MAX_PRIME_LEN]; | ||
| 35 | size_t bits = sae->tmp->prime_len * 8; | ||
| 36 | u8 exp[1]; | ||
| 37 | - struct crypto_bignum *a, *b; | ||
| 38 | - int res; | ||
| 39 | + struct crypto_bignum *a, *b = NULL; | ||
| 40 | + int res, is_val; | ||
| 41 | + u8 pwd_value_valid; | ||
| 42 | |||
| 43 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); | ||
| 44 | |||
| 45 | @@ -353,16 +356,29 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 46 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, | ||
| 47 | sae->tmp->prime_len); | ||
| 48 | |||
| 49 | - if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) | ||
| 50 | - { | ||
| 51 | - wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); | ||
| 52 | - return 0; | ||
| 53 | - } | ||
| 54 | + /* Check whether pwd-value < p */ | ||
| 55 | + res = const_time_memcmp(pwd_value, sae->tmp->dh->prime, | ||
| 56 | + sae->tmp->prime_len); | ||
| 57 | + /* pwd-value >= p is invalid, so res is < 0 for the valid cases and | ||
| 58 | + * the negative sign can be used to fill the mask for constant time | ||
| 59 | + * selection */ | ||
| 60 | + pwd_value_valid = const_time_fill_msb(res); | ||
| 61 | + | ||
| 62 | + /* If pwd-value >= p, force pwd-value to be < p and perform the | ||
| 63 | + * calculations anyway to hide timing difference. The derived PWE will | ||
| 64 | + * be ignored in that case. */ | ||
| 65 | + pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0); | ||
| 66 | |||
| 67 | /* PWE = pwd-value^((p-1)/r) modulo p */ | ||
| 68 | |||
| 69 | + res = -1; | ||
| 70 | a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); | ||
| 71 | + if (!a) | ||
| 72 | + goto fail; | ||
| 73 | |||
| 74 | + /* This is an optimization based on the used group that does not depend | ||
| 75 | + * on the password in any way, so it is fine to use separate branches | ||
| 76 | + * for this step without constant time operations. */ | ||
| 77 | if (sae->tmp->dh->safe_prime) { | ||
| 78 | /* | ||
| 79 | * r = (p-1)/2 for the group used here, so this becomes: | ||
| 80 | @@ -376,33 +392,34 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, | ||
| 81 | b = crypto_bignum_init_set(exp, sizeof(exp)); | ||
| 82 | if (b == NULL || | ||
| 83 | crypto_bignum_sub(sae->tmp->prime, b, b) < 0 || | ||
| 84 | - crypto_bignum_div(b, sae->tmp->order, b) < 0) { | ||
| 85 | - crypto_bignum_deinit(b, 0); | ||
| 86 | - b = NULL; | ||
| 87 | - } | ||
| 88 | + crypto_bignum_div(b, sae->tmp->order, b) < 0) | ||
| 89 | + goto fail; | ||
| 90 | } | ||
| 91 | |||
| 92 | - if (a == NULL || b == NULL) | ||
| 93 | - res = -1; | ||
| 94 | - else | ||
| 95 | - res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); | ||
| 96 | - | ||
| 97 | - crypto_bignum_deinit(a, 0); | ||
| 98 | - crypto_bignum_deinit(b, 0); | ||
| 99 | + if (!b) | ||
| 100 | + goto fail; | ||
| 101 | |||
| 102 | - if (res < 0) { | ||
| 103 | - wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); | ||
| 104 | - return -1; | ||
| 105 | - } | ||
| 106 | + res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); | ||
| 107 | + if (res < 0) | ||
| 108 | + goto fail; | ||
| 109 | |||
| 110 | - /* if (PWE > 1) --> found */ | ||
| 111 | - if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { | ||
| 112 | - wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); | ||
| 113 | - return 0; | ||
| 114 | - } | ||
| 115 | + /* There were no fatal errors in calculations, so determine the return | ||
| 116 | + * value using constant time operations. We get here for number of | ||
| 117 | + * invalid cases which are cleared here after having performed all the | ||
| 118 | + * computation. PWE is valid if pwd-value was less than prime and | ||
| 119 | + * PWE > 1. Start with pwd-value check first and then use constant time | ||
| 120 | + * operations to clear res to 0 if PWE is 0 or 1. | ||
| 121 | + */ | ||
| 122 | + res = const_time_select_u8(pwd_value_valid, 1, 0); | ||
| 123 | + is_val = crypto_bignum_is_zero(pwe); | ||
| 124 | + res = const_time_select_u8(const_time_is_zero(is_val), res, 0); | ||
| 125 | + is_val = crypto_bignum_is_one(pwe); | ||
| 126 | + res = const_time_select_u8(const_time_is_zero(is_val), res, 0); | ||
| 127 | |||
| 128 | - wpa_printf(MSG_DEBUG, "SAE: PWE found"); | ||
| 129 | - return 1; | ||
| 130 | +fail: | ||
| 131 | + crypto_bignum_deinit(a, 1); | ||
| 132 | + crypto_bignum_deinit(b, 1); | ||
| 133 | + return res; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | -- | ||
| 138 | 2.7.4 | ||
| 139 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch new file mode 100644 index 0000000000..9d2c6983d4 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | From ac8fa9ef198640086cf2ce7c94673be2b6a018a0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Tue, 5 Mar 2019 23:43:25 +0200 | ||
| 4 | Subject: [PATCH 10/14] SAE: Fix confirm message validation in error cases | ||
| 5 | |||
| 6 | Explicitly verify that own and peer commit scalar/element are available | ||
| 7 | when trying to check SAE confirm message. It could have been possible to | ||
| 8 | hit a NULL pointer dereference if the peer element could not have been | ||
| 9 | parsed. (CVE-2019-9496) | ||
| 10 | |||
| 11 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 12 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 13 | Upstream-Status: Backport | ||
| 14 | CVE: CVE-2019-9496 | ||
| 15 | --- | ||
| 16 | src/common/sae.c | 14 +++++++++++--- | ||
| 17 | 1 file changed, 11 insertions(+), 3 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
| 20 | index eaf825d..5a50294 100644 | ||
| 21 | --- a/src/common/sae.c | ||
| 22 | +++ b/src/common/sae.c | ||
| 23 | @@ -1487,23 +1487,31 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) | ||
| 24 | |||
| 25 | wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); | ||
| 26 | |||
| 27 | - if (sae->tmp == NULL) { | ||
| 28 | + if (!sae->tmp || !sae->peer_commit_scalar || | ||
| 29 | + !sae->tmp->own_commit_scalar) { | ||
| 30 | wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); | ||
| 31 | return -1; | ||
| 32 | } | ||
| 33 | |||
| 34 | - if (sae->tmp->ec) | ||
| 35 | + if (sae->tmp->ec) { | ||
| 36 | + if (!sae->tmp->peer_commit_element_ecc || | ||
| 37 | + !sae->tmp->own_commit_element_ecc) | ||
| 38 | + return -1; | ||
| 39 | sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, | ||
| 40 | sae->tmp->peer_commit_element_ecc, | ||
| 41 | sae->tmp->own_commit_scalar, | ||
| 42 | sae->tmp->own_commit_element_ecc, | ||
| 43 | verifier); | ||
| 44 | - else | ||
| 45 | + } else { | ||
| 46 | + if (!sae->tmp->peer_commit_element_ffc || | ||
| 47 | + !sae->tmp->own_commit_element_ffc) | ||
| 48 | + return -1; | ||
| 49 | sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, | ||
| 50 | sae->tmp->peer_commit_element_ffc, | ||
| 51 | sae->tmp->own_commit_scalar, | ||
| 52 | sae->tmp->own_commit_element_ffc, | ||
| 53 | verifier); | ||
| 54 | + } | ||
| 55 | |||
| 56 | if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) { | ||
| 57 | wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); | ||
| 58 | -- | ||
| 59 | 2.7.4 | ||
| 60 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch new file mode 100644 index 0000000000..87095bf7f4 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | From 70ff850e89fbc8bc7da515321b4d15b5eef70581 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 3 | Date: Sun, 31 Mar 2019 17:13:06 +0200 | ||
| 4 | Subject: [PATCH 11/14] EAP-pwd server: Verify received scalar and element | ||
| 5 | |||
| 6 | When processing an EAP-pwd Commit frame, the peer's scalar and element | ||
| 7 | (elliptic curve point) were not validated. This allowed an adversary to | ||
| 8 | bypass authentication, and impersonate any user if the crypto | ||
| 9 | implementation did not verify the validity of the EC point. | ||
| 10 | |||
| 11 | Fix this vulnerability by assuring the received scalar lies within the | ||
| 12 | valid range, and by checking that the received element is not the point | ||
| 13 | at infinity and lies on the elliptic curve being used. (CVE-2019-9498) | ||
| 14 | |||
| 15 | The vulnerability is only exploitable if OpenSSL version 1.0.2 or lower | ||
| 16 | is used, or if LibreSSL or wolfssl is used. Newer versions of OpenSSL | ||
| 17 | (and also BoringSSL) implicitly validate the elliptic curve point in | ||
| 18 | EC_POINT_set_affine_coordinates_GFp(), preventing the attack. | ||
| 19 | |||
| 20 | Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 21 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 22 | Upstream-Status: Backport | ||
| 23 | CVE: CVE-2019-9498 | ||
| 24 | --- | ||
| 25 | src/eap_server/eap_server_pwd.c | 20 ++++++++++++++++++++ | ||
| 26 | 1 file changed, 20 insertions(+) | ||
| 27 | |||
| 28 | diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c | ||
| 29 | index d0fa54a..74979da 100644 | ||
| 30 | --- a/src/eap_server/eap_server_pwd.c | ||
| 31 | +++ b/src/eap_server/eap_server_pwd.c | ||
| 32 | @@ -718,6 +718,26 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 33 | goto fin; | ||
| 34 | } | ||
| 35 | |||
| 36 | + /* verify received scalar */ | ||
| 37 | + if (crypto_bignum_is_zero(data->peer_scalar) || | ||
| 38 | + crypto_bignum_is_one(data->peer_scalar) || | ||
| 39 | + crypto_bignum_cmp(data->peer_scalar, | ||
| 40 | + crypto_ec_get_order(data->grp->group)) >= 0) { | ||
| 41 | + wpa_printf(MSG_INFO, | ||
| 42 | + "EAP-PWD (server): received scalar is invalid"); | ||
| 43 | + goto fin; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /* verify received element */ | ||
| 47 | + if (!crypto_ec_point_is_on_curve(data->grp->group, | ||
| 48 | + data->peer_element) || | ||
| 49 | + crypto_ec_point_is_at_infinity(data->grp->group, | ||
| 50 | + data->peer_element)) { | ||
| 51 | + wpa_printf(MSG_INFO, | ||
| 52 | + "EAP-PWD (server): received element is invalid"); | ||
| 53 | + goto fin; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | /* check to ensure peer's element is not in a small sub-group */ | ||
| 57 | if (!crypto_bignum_is_one(cofactor)) { | ||
| 58 | if (crypto_ec_point_mul(data->grp->group, data->peer_element, | ||
| 59 | -- | ||
| 60 | 2.7.4 | ||
| 61 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0012-EAP-pwd-server-Detect-reflection-attacks.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0012-EAP-pwd-server-Detect-reflection-attacks.patch new file mode 100644 index 0000000000..32d134db41 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0012-EAP-pwd-server-Detect-reflection-attacks.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From d63edfa90243e9a7de6ae5c275032f2cc79fef95 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 3 | Date: Sun, 31 Mar 2019 17:26:01 +0200 | ||
| 4 | Subject: [PATCH 12/14] EAP-pwd server: Detect reflection attacks | ||
| 5 | |||
| 6 | When processing an EAP-pwd Commit frame, verify that the peer's scalar | ||
| 7 | and elliptic curve element differ from the one sent by the server. This | ||
| 8 | prevents reflection attacks where the adversary reflects the scalar and | ||
| 9 | element sent by the server. (CVE-2019-9497) | ||
| 10 | |||
| 11 | The vulnerability allows an adversary to complete the EAP-pwd handshake | ||
| 12 | as any user. However, the adversary does not learn the negotiated | ||
| 13 | session key, meaning the subsequent 4-way handshake would fail. As a | ||
| 14 | result, this cannot be abused to bypass authentication unless EAP-pwd is | ||
| 15 | used in non-WLAN cases without any following key exchange that would | ||
| 16 | require the attacker to learn the MSK. | ||
| 17 | |||
| 18 | Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 19 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 20 | Upstream-Status: Backport | ||
| 21 | CVE: CVE-2019-9497 | ||
| 22 | --- | ||
| 23 | src/eap_server/eap_server_pwd.c | 9 +++++++++ | ||
| 24 | 1 file changed, 9 insertions(+) | ||
| 25 | |||
| 26 | diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c | ||
| 27 | index 74979da..16057e9 100644 | ||
| 28 | --- a/src/eap_server/eap_server_pwd.c | ||
| 29 | +++ b/src/eap_server/eap_server_pwd.c | ||
| 30 | @@ -753,6 +753,15 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | + /* detect reflection attacks */ | ||
| 35 | + if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 || | ||
| 36 | + crypto_ec_point_cmp(data->grp->group, data->my_element, | ||
| 37 | + data->peer_element) == 0) { | ||
| 38 | + wpa_printf(MSG_INFO, | ||
| 39 | + "EAP-PWD (server): detected reflection attack!"); | ||
| 40 | + goto fin; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | /* compute the shared key, k */ | ||
| 44 | if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe, | ||
| 45 | data->peer_scalar, K) < 0) || | ||
| 46 | -- | ||
| 47 | 2.7.4 | ||
| 48 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch new file mode 100644 index 0000000000..c6e61cb803 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | From 8ad8585f91823ddcc3728155e288e0f9f872e31a Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 3 | Date: Sun, 31 Mar 2019 17:43:44 +0200 | ||
| 4 | Subject: [PATCH 13/14] EAP-pwd client: Verify received scalar and element | ||
| 5 | |||
| 6 | When processing an EAP-pwd Commit frame, the server's scalar and element | ||
| 7 | (elliptic curve point) were not validated. This allowed an adversary to | ||
| 8 | bypass authentication, and act as a rogue Access Point (AP) if the | ||
| 9 | crypto implementation did not verify the validity of the EC point. | ||
| 10 | |||
| 11 | Fix this vulnerability by assuring the received scalar lies within the | ||
| 12 | valid range, and by checking that the received element is not the point | ||
| 13 | at infinity and lies on the elliptic curve being used. (CVE-2019-9499) | ||
| 14 | |||
| 15 | The vulnerability is only exploitable if OpenSSL version 1.0.2 or lower | ||
| 16 | is used, or if LibreSSL or wolfssl is used. Newer versions of OpenSSL | ||
| 17 | (and also BoringSSL) implicitly validate the elliptic curve point in | ||
| 18 | EC_POINT_set_affine_coordinates_GFp(), preventing the attack. | ||
| 19 | |||
| 20 | Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu> | ||
| 21 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 22 | Upstream-Status: Backport | ||
| 23 | CVE: CVE-2019-9499 | ||
| 24 | --- | ||
| 25 | src/eap_peer/eap_pwd.c | 20 ++++++++++++++++++++ | ||
| 26 | 1 file changed, 20 insertions(+) | ||
| 27 | |||
| 28 | diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c | ||
| 29 | index 761c16a..5a05e54 100644 | ||
| 30 | --- a/src/eap_peer/eap_pwd.c | ||
| 31 | +++ b/src/eap_peer/eap_pwd.c | ||
| 32 | @@ -594,6 +594,26 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 33 | goto fin; | ||
| 34 | } | ||
| 35 | |||
| 36 | + /* verify received scalar */ | ||
| 37 | + if (crypto_bignum_is_zero(data->server_scalar) || | ||
| 38 | + crypto_bignum_is_one(data->server_scalar) || | ||
| 39 | + crypto_bignum_cmp(data->server_scalar, | ||
| 40 | + crypto_ec_get_order(data->grp->group)) >= 0) { | ||
| 41 | + wpa_printf(MSG_INFO, | ||
| 42 | + "EAP-PWD (peer): received scalar is invalid"); | ||
| 43 | + goto fin; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /* verify received element */ | ||
| 47 | + if (!crypto_ec_point_is_on_curve(data->grp->group, | ||
| 48 | + data->server_element) || | ||
| 49 | + crypto_ec_point_is_at_infinity(data->grp->group, | ||
| 50 | + data->server_element)) { | ||
| 51 | + wpa_printf(MSG_INFO, | ||
| 52 | + "EAP-PWD (peer): received element is invalid"); | ||
| 53 | + goto fin; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | /* check to ensure server's element is not in a small sub-group */ | ||
| 57 | if (!crypto_bignum_is_one(cofactor)) { | ||
| 58 | if (crypto_ec_point_mul(data->grp->group, data->server_element, | ||
| 59 | -- | ||
| 60 | 2.7.4 | ||
| 61 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch new file mode 100644 index 0000000000..e944ef110f --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch | |||
| @@ -0,0 +1,335 @@ | |||
| 1 | From 16d4f1069118aa19bfce013493e1ac5783f92f1d Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
| 3 | Date: Fri, 5 Apr 2019 02:12:50 +0300 | ||
| 4 | Subject: [PATCH 14/14] EAP-pwd: Check element x,y coordinates explicitly | ||
| 5 | |||
| 6 | This adds an explicit check for 0 < x,y < prime based on RFC 5931, | ||
| 7 | 2.8.5.2.2 requirement. The earlier checks might have covered this | ||
| 8 | implicitly, but it is safer to avoid any dependency on implicit checks | ||
| 9 | and specific crypto library behavior. (CVE-2019-9498 and CVE-2019-9499) | ||
| 10 | |||
| 11 | Furthermore, this moves the EAP-pwd element and scalar parsing and | ||
| 12 | validation steps into shared helper functions so that there is no need | ||
| 13 | to maintain two separate copies of this common functionality between the | ||
| 14 | server and peer implementations. | ||
| 15 | |||
| 16 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
| 17 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
| 18 | Upstream-Status: Backport | ||
| 19 | CVE: CVE-2019-9498 | ||
| 20 | CVE: CVE-2019-9499 | ||
| 21 | --- | ||
| 22 | src/eap_common/eap_pwd_common.c | 106 ++++++++++++++++++++++++++++++++++++++++ | ||
| 23 | src/eap_common/eap_pwd_common.h | 3 ++ | ||
| 24 | src/eap_peer/eap_pwd.c | 45 ++--------------- | ||
| 25 | src/eap_server/eap_server_pwd.c | 45 ++--------------- | ||
| 26 | 4 files changed, 117 insertions(+), 82 deletions(-) | ||
| 27 | |||
| 28 | diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c | ||
| 29 | index e49aaf8..c28b56d 100644 | ||
| 30 | --- a/src/eap_common/eap_pwd_common.c | ||
| 31 | +++ b/src/eap_common/eap_pwd_common.c | ||
| 32 | @@ -428,3 +428,109 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, | ||
| 33 | |||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | + | ||
| 37 | + | ||
| 38 | +static int eap_pwd_element_coord_ok(const struct crypto_bignum *prime, | ||
| 39 | + const u8 *buf, size_t len) | ||
| 40 | +{ | ||
| 41 | + struct crypto_bignum *val; | ||
| 42 | + int ok = 1; | ||
| 43 | + | ||
| 44 | + val = crypto_bignum_init_set(buf, len); | ||
| 45 | + if (!val || crypto_bignum_is_zero(val) || | ||
| 46 | + crypto_bignum_cmp(val, prime) >= 0) | ||
| 47 | + ok = 0; | ||
| 48 | + crypto_bignum_deinit(val, 0); | ||
| 49 | + return ok; | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group, | ||
| 54 | + const u8 *buf) | ||
| 55 | +{ | ||
| 56 | + struct crypto_ec_point *element; | ||
| 57 | + const struct crypto_bignum *prime; | ||
| 58 | + size_t prime_len; | ||
| 59 | + struct crypto_bignum *cofactor = NULL; | ||
| 60 | + | ||
| 61 | + prime = crypto_ec_get_prime(group->group); | ||
| 62 | + prime_len = crypto_ec_prime_len(group->group); | ||
| 63 | + | ||
| 64 | + /* RFC 5931, 2.8.5.2.2: 0 < x,y < p */ | ||
| 65 | + if (!eap_pwd_element_coord_ok(prime, buf, prime_len) || | ||
| 66 | + !eap_pwd_element_coord_ok(prime, buf + prime_len, prime_len)) { | ||
| 67 | + wpa_printf(MSG_INFO, "EAP-pwd: Invalid coordinate in element"); | ||
| 68 | + return NULL; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + element = crypto_ec_point_from_bin(group->group, buf); | ||
| 72 | + if (!element) { | ||
| 73 | + wpa_printf(MSG_INFO, "EAP-pwd: EC point from element failed"); | ||
| 74 | + return NULL; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /* RFC 5931, 2.8.5.2.2: on curve and not the point at infinity */ | ||
| 78 | + if (!crypto_ec_point_is_on_curve(group->group, element) || | ||
| 79 | + crypto_ec_point_is_at_infinity(group->group, element)) { | ||
| 80 | + wpa_printf(MSG_INFO, "EAP-pwd: Invalid element"); | ||
| 81 | + goto fail; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + cofactor = crypto_bignum_init(); | ||
| 85 | + if (!cofactor || crypto_ec_cofactor(group->group, cofactor) < 0) { | ||
| 86 | + wpa_printf(MSG_INFO, | ||
| 87 | + "EAP-pwd: Unable to get cofactor for curve"); | ||
| 88 | + goto fail; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + if (!crypto_bignum_is_one(cofactor)) { | ||
| 92 | + struct crypto_ec_point *point; | ||
| 93 | + int ok = 1; | ||
| 94 | + | ||
| 95 | + /* check to ensure peer's element is not in a small sub-group */ | ||
| 96 | + point = crypto_ec_point_init(group->group); | ||
| 97 | + if (!point || | ||
| 98 | + crypto_ec_point_mul(group->group, element, | ||
| 99 | + cofactor, point) != 0 || | ||
| 100 | + crypto_ec_point_is_at_infinity(group->group, point)) | ||
| 101 | + ok = 0; | ||
| 102 | + crypto_ec_point_deinit(point, 0); | ||
| 103 | + | ||
| 104 | + if (!ok) { | ||
| 105 | + wpa_printf(MSG_INFO, | ||
| 106 | + "EAP-pwd: Small sub-group check on peer element failed"); | ||
| 107 | + goto fail; | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | +out: | ||
| 112 | + crypto_bignum_deinit(cofactor, 0); | ||
| 113 | + return element; | ||
| 114 | +fail: | ||
| 115 | + crypto_ec_point_deinit(element, 0); | ||
| 116 | + element = NULL; | ||
| 117 | + goto out; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | + | ||
| 121 | +struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf) | ||
| 122 | +{ | ||
| 123 | + struct crypto_bignum *scalar; | ||
| 124 | + const struct crypto_bignum *order; | ||
| 125 | + size_t order_len; | ||
| 126 | + | ||
| 127 | + order = crypto_ec_get_order(group->group); | ||
| 128 | + order_len = crypto_ec_order_len(group->group); | ||
| 129 | + | ||
| 130 | + /* RFC 5931, 2.8.5.2: 1 < scalar < r */ | ||
| 131 | + scalar = crypto_bignum_init_set(buf, order_len); | ||
| 132 | + if (!scalar || crypto_bignum_is_zero(scalar) || | ||
| 133 | + crypto_bignum_is_one(scalar) || | ||
| 134 | + crypto_bignum_cmp(scalar, order) >= 0) { | ||
| 135 | + wpa_printf(MSG_INFO, "EAP-pwd: received scalar is invalid"); | ||
| 136 | + crypto_bignum_deinit(scalar, 0); | ||
| 137 | + scalar = NULL; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + return scalar; | ||
| 141 | +} | ||
| 142 | diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h | ||
| 143 | index 6b07cf8..2387e59 100644 | ||
| 144 | --- a/src/eap_common/eap_pwd_common.h | ||
| 145 | +++ b/src/eap_common/eap_pwd_common.h | ||
| 146 | @@ -67,5 +67,8 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, | ||
| 147 | struct crypto_hash * eap_pwd_h_init(void); | ||
| 148 | void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); | ||
| 149 | void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); | ||
| 150 | +struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group, | ||
| 151 | + const u8 *buf); | ||
| 152 | +struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf); | ||
| 153 | |||
| 154 | #endif /* EAP_PWD_COMMON_H */ | ||
| 155 | diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c | ||
| 156 | index 5a05e54..f37b974 100644 | ||
| 157 | --- a/src/eap_peer/eap_pwd.c | ||
| 158 | +++ b/src/eap_peer/eap_pwd.c | ||
| 159 | @@ -308,7 +308,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 160 | const struct wpabuf *reqData, | ||
| 161 | const u8 *payload, size_t payload_len) | ||
| 162 | { | ||
| 163 | - struct crypto_ec_point *K = NULL, *point = NULL; | ||
| 164 | + struct crypto_ec_point *K = NULL; | ||
| 165 | struct crypto_bignum *mask = NULL, *cofactor = NULL; | ||
| 166 | const u8 *ptr = payload; | ||
| 167 | u8 *scalar = NULL, *element = NULL; | ||
| 168 | @@ -572,63 +572,27 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 169 | /* process the request */ | ||
| 170 | data->k = crypto_bignum_init(); | ||
| 171 | K = crypto_ec_point_init(data->grp->group); | ||
| 172 | - point = crypto_ec_point_init(data->grp->group); | ||
| 173 | - if (!data->k || !K || !point) { | ||
| 174 | + if (!data->k || !K) { | ||
| 175 | wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " | ||
| 176 | "fail"); | ||
| 177 | goto fin; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* element, x then y, followed by scalar */ | ||
| 181 | - data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr); | ||
| 182 | + data->server_element = eap_pwd_get_element(data->grp, ptr); | ||
| 183 | if (!data->server_element) { | ||
| 184 | wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " | ||
| 185 | "fail"); | ||
| 186 | goto fin; | ||
| 187 | } | ||
| 188 | ptr += prime_len * 2; | ||
| 189 | - data->server_scalar = crypto_bignum_init_set(ptr, order_len); | ||
| 190 | + data->server_scalar = eap_pwd_get_scalar(data->grp, ptr); | ||
| 191 | if (!data->server_scalar) { | ||
| 192 | wpa_printf(MSG_INFO, | ||
| 193 | "EAP-PWD (peer): setting peer scalar fail"); | ||
| 194 | goto fin; | ||
| 195 | } | ||
| 196 | |||
| 197 | - /* verify received scalar */ | ||
| 198 | - if (crypto_bignum_is_zero(data->server_scalar) || | ||
| 199 | - crypto_bignum_is_one(data->server_scalar) || | ||
| 200 | - crypto_bignum_cmp(data->server_scalar, | ||
| 201 | - crypto_ec_get_order(data->grp->group)) >= 0) { | ||
| 202 | - wpa_printf(MSG_INFO, | ||
| 203 | - "EAP-PWD (peer): received scalar is invalid"); | ||
| 204 | - goto fin; | ||
| 205 | - } | ||
| 206 | - | ||
| 207 | - /* verify received element */ | ||
| 208 | - if (!crypto_ec_point_is_on_curve(data->grp->group, | ||
| 209 | - data->server_element) || | ||
| 210 | - crypto_ec_point_is_at_infinity(data->grp->group, | ||
| 211 | - data->server_element)) { | ||
| 212 | - wpa_printf(MSG_INFO, | ||
| 213 | - "EAP-PWD (peer): received element is invalid"); | ||
| 214 | - goto fin; | ||
| 215 | - } | ||
| 216 | - | ||
| 217 | - /* check to ensure server's element is not in a small sub-group */ | ||
| 218 | - if (!crypto_bignum_is_one(cofactor)) { | ||
| 219 | - if (crypto_ec_point_mul(data->grp->group, data->server_element, | ||
| 220 | - cofactor, point) < 0) { | ||
| 221 | - wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " | ||
| 222 | - "server element by order!\n"); | ||
| 223 | - goto fin; | ||
| 224 | - } | ||
| 225 | - if (crypto_ec_point_is_at_infinity(data->grp->group, point)) { | ||
| 226 | - wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " | ||
| 227 | - "is at infinity!\n"); | ||
| 228 | - goto fin; | ||
| 229 | - } | ||
| 230 | - } | ||
| 231 | - | ||
| 232 | /* compute the shared key, k */ | ||
| 233 | if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, | ||
| 234 | data->server_scalar, K) < 0 || | ||
| 235 | @@ -702,7 +666,6 @@ fin: | ||
| 236 | crypto_bignum_deinit(mask, 1); | ||
| 237 | crypto_bignum_deinit(cofactor, 1); | ||
| 238 | crypto_ec_point_deinit(K, 1); | ||
| 239 | - crypto_ec_point_deinit(point, 1); | ||
| 240 | if (data->outbuf == NULL) | ||
| 241 | eap_pwd_state(data, FAILURE); | ||
| 242 | else | ||
| 243 | diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c | ||
| 244 | index 16057e9..f6c75cf 100644 | ||
| 245 | --- a/src/eap_server/eap_server_pwd.c | ||
| 246 | +++ b/src/eap_server/eap_server_pwd.c | ||
| 247 | @@ -669,7 +669,7 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 248 | { | ||
| 249 | const u8 *ptr; | ||
| 250 | struct crypto_bignum *cofactor = NULL; | ||
| 251 | - struct crypto_ec_point *K = NULL, *point = NULL; | ||
| 252 | + struct crypto_ec_point *K = NULL; | ||
| 253 | int res = 0; | ||
| 254 | size_t prime_len, order_len; | ||
| 255 | |||
| 256 | @@ -688,9 +688,8 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 257 | |||
| 258 | data->k = crypto_bignum_init(); | ||
| 259 | cofactor = crypto_bignum_init(); | ||
| 260 | - point = crypto_ec_point_init(data->grp->group); | ||
| 261 | K = crypto_ec_point_init(data->grp->group); | ||
| 262 | - if (!data->k || !cofactor || !point || !K) { | ||
| 263 | + if (!data->k || !cofactor || !K) { | ||
| 264 | wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " | ||
| 265 | "fail"); | ||
| 266 | goto fin; | ||
| 267 | @@ -704,55 +703,20 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 268 | |||
| 269 | /* element, x then y, followed by scalar */ | ||
| 270 | ptr = payload; | ||
| 271 | - data->peer_element = crypto_ec_point_from_bin(data->grp->group, ptr); | ||
| 272 | + data->peer_element = eap_pwd_get_element(data->grp, ptr); | ||
| 273 | if (!data->peer_element) { | ||
| 274 | wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " | ||
| 275 | "fail"); | ||
| 276 | goto fin; | ||
| 277 | } | ||
| 278 | ptr += prime_len * 2; | ||
| 279 | - data->peer_scalar = crypto_bignum_init_set(ptr, order_len); | ||
| 280 | + data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr); | ||
| 281 | if (!data->peer_scalar) { | ||
| 282 | wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " | ||
| 283 | "fail"); | ||
| 284 | goto fin; | ||
| 285 | } | ||
| 286 | |||
| 287 | - /* verify received scalar */ | ||
| 288 | - if (crypto_bignum_is_zero(data->peer_scalar) || | ||
| 289 | - crypto_bignum_is_one(data->peer_scalar) || | ||
| 290 | - crypto_bignum_cmp(data->peer_scalar, | ||
| 291 | - crypto_ec_get_order(data->grp->group)) >= 0) { | ||
| 292 | - wpa_printf(MSG_INFO, | ||
| 293 | - "EAP-PWD (server): received scalar is invalid"); | ||
| 294 | - goto fin; | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - /* verify received element */ | ||
| 298 | - if (!crypto_ec_point_is_on_curve(data->grp->group, | ||
| 299 | - data->peer_element) || | ||
| 300 | - crypto_ec_point_is_at_infinity(data->grp->group, | ||
| 301 | - data->peer_element)) { | ||
| 302 | - wpa_printf(MSG_INFO, | ||
| 303 | - "EAP-PWD (server): received element is invalid"); | ||
| 304 | - goto fin; | ||
| 305 | - } | ||
| 306 | - | ||
| 307 | - /* check to ensure peer's element is not in a small sub-group */ | ||
| 308 | - if (!crypto_bignum_is_one(cofactor)) { | ||
| 309 | - if (crypto_ec_point_mul(data->grp->group, data->peer_element, | ||
| 310 | - cofactor, point) != 0) { | ||
| 311 | - wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " | ||
| 312 | - "multiply peer element by order"); | ||
| 313 | - goto fin; | ||
| 314 | - } | ||
| 315 | - if (crypto_ec_point_is_at_infinity(data->grp->group, point)) { | ||
| 316 | - wpa_printf(MSG_INFO, "EAP-PWD (server): peer element " | ||
| 317 | - "is at infinity!\n"); | ||
| 318 | - goto fin; | ||
| 319 | - } | ||
| 320 | - } | ||
| 321 | - | ||
| 322 | /* detect reflection attacks */ | ||
| 323 | if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 || | ||
| 324 | crypto_ec_point_cmp(data->grp->group, data->my_element, | ||
| 325 | @@ -804,7 +768,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, | ||
| 326 | |||
| 327 | fin: | ||
| 328 | crypto_ec_point_deinit(K, 1); | ||
| 329 | - crypto_ec_point_deinit(point, 1); | ||
| 330 | crypto_bignum_deinit(cofactor, 1); | ||
| 331 | |||
| 332 | if (res) | ||
| 333 | -- | ||
| 334 | 2.7.4 | ||
| 335 | |||
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.7.bb b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.7.bb index fe5fa2b82e..277bbaec63 100644 --- a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.7.bb +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.7.bb | |||
| @@ -25,6 +25,22 @@ SRC_URI = "http://w1.fi/releases/wpa_supplicant-${PV}.tar.gz \ | |||
| 25 | file://wpa_supplicant.conf-sane \ | 25 | file://wpa_supplicant.conf-sane \ |
| 26 | file://99_wpa_supplicant \ | 26 | file://99_wpa_supplicant \ |
| 27 | file://0001-replace-systemd-install-Alias-with-WantedBy.patch \ | 27 | file://0001-replace-systemd-install-Alias-with-WantedBy.patch \ |
| 28 | file://0001-OpenSSL-Use-constant-time-operations-for-private-big.patch \ | ||
| 29 | file://0002-Add-helper-functions-for-constant-time-operations.patch \ | ||
| 30 | file://0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch \ | ||
| 31 | file://0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch \ | ||
| 32 | file://0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch \ | ||
| 33 | file://0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch \ | ||
| 34 | file://0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch \ | ||
| 35 | file://0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch \ | ||
| 36 | file://0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch \ | ||
| 37 | file://0010-SAE-Fix-confirm-message-validation-in-error-cases.patch \ | ||
| 38 | file://0011-EAP-pwd-server-Verify-received-scalar-and-element.patch \ | ||
| 39 | file://0012-EAP-pwd-server-Detect-reflection-attacks.patch \ | ||
| 40 | file://0013-EAP-pwd-client-Verify-received-scalar-and-element.patch \ | ||
| 41 | file://0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch \ | ||
| 42 | file://0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch \ | ||
| 43 | file://0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch \ | ||
| 28 | " | 44 | " |
| 29 | SRC_URI[md5sum] = "a68538fb62766f40f890125026c42c10" | 45 | SRC_URI[md5sum] = "a68538fb62766f40f890125026c42c10" |
| 30 | SRC_URI[sha256sum] = "76ea6b06b7a2ea8e6d9eb1a9166166f1656e6d48c7508914f592100c95c73074" | 46 | SRC_URI[sha256sum] = "76ea6b06b7a2ea8e6d9eb1a9166166f1656e6d48c7508914f592100c95c73074" |
