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 /meta/recipes-connectivity/wpa-supplicant | |
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>
Diffstat (limited to 'meta/recipes-connectivity/wpa-supplicant')
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" |