Branch data Line data Source code
1 : : /*
2 : : * Simultaneous authentication of equals
3 : : * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "crypto/crypto.h"
13 : : #include "crypto/sha256.h"
14 : : #include "crypto/random.h"
15 : : #include "crypto/dh_groups.h"
16 : : #include "ieee802_11_defs.h"
17 : : #include "sae.h"
18 : :
19 : :
20 : 16 : int sae_set_group(struct sae_data *sae, int group)
21 : : {
22 : : struct sae_temporary_data *tmp;
23 : :
24 : 16 : sae_clear_data(sae);
25 : 16 : tmp = sae->tmp = os_zalloc(sizeof(*tmp));
26 [ - + ]: 16 : if (tmp == NULL)
27 : 0 : return -1;
28 : :
29 : : /* First, check if this is an ECC group */
30 : 16 : tmp->ec = crypto_ec_init(group);
31 [ + + ]: 16 : if (tmp->ec) {
32 : 11 : sae->group = group;
33 : 11 : tmp->prime_len = crypto_ec_prime_len(tmp->ec);
34 : 11 : tmp->prime = crypto_ec_get_prime(tmp->ec);
35 : 11 : tmp->order = crypto_ec_get_order(tmp->ec);
36 : 11 : return 0;
37 : : }
38 : :
39 : : /* Not an ECC group, check FFC */
40 : 5 : tmp->dh = dh_groups_get(group);
41 [ + - ]: 5 : if (tmp->dh) {
42 : 5 : sae->group = group;
43 : 5 : tmp->prime_len = tmp->dh->prime_len;
44 [ - + ]: 5 : if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
45 : 0 : sae_clear_data(sae);
46 : 0 : return -1;
47 : : }
48 : :
49 : 5 : tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
50 : 5 : tmp->prime_len);
51 [ - + ]: 5 : if (tmp->prime_buf == NULL) {
52 : 0 : sae_clear_data(sae);
53 : 0 : return -1;
54 : : }
55 : 5 : tmp->prime = tmp->prime_buf;
56 : :
57 : 5 : tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
58 : 5 : tmp->dh->order_len);
59 [ - + ]: 5 : if (tmp->order_buf == NULL) {
60 : 0 : sae_clear_data(sae);
61 : 0 : return -1;
62 : : }
63 : 5 : tmp->order = tmp->order_buf;
64 : :
65 : 5 : return 0;
66 : : }
67 : :
68 : : /* Unsupported group */
69 : 16 : return -1;
70 : : }
71 : :
72 : :
73 : 48 : void sae_clear_temp_data(struct sae_data *sae)
74 : : {
75 : : struct sae_temporary_data *tmp;
76 [ + - ][ + + ]: 48 : if (sae == NULL || sae->tmp == NULL)
77 : 48 : return;
78 : 16 : tmp = sae->tmp;
79 : 16 : crypto_ec_deinit(tmp->ec);
80 : 16 : crypto_bignum_deinit(tmp->prime_buf, 0);
81 : 16 : crypto_bignum_deinit(tmp->order_buf, 0);
82 : 16 : crypto_bignum_deinit(tmp->sae_rand, 1);
83 : 16 : crypto_bignum_deinit(tmp->pwe_ffc, 1);
84 : 16 : crypto_bignum_deinit(tmp->own_commit_scalar, 0);
85 : 16 : crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
86 : 16 : crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
87 : 16 : crypto_ec_point_deinit(tmp->pwe_ecc, 1);
88 : 16 : crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
89 : 16 : crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
90 : 16 : os_free(sae->tmp);
91 : 16 : sae->tmp = NULL;
92 : : }
93 : :
94 : :
95 : 316 : void sae_clear_data(struct sae_data *sae)
96 : : {
97 [ + + ]: 316 : if (sae == NULL)
98 : 316 : return;
99 : 32 : sae_clear_temp_data(sae);
100 : 32 : crypto_bignum_deinit(sae->peer_commit_scalar, 0);
101 : 32 : os_memset(sae, 0, sizeof(*sae));
102 : : }
103 : :
104 : :
105 : 9 : static void buf_shift_right(u8 *buf, size_t len, size_t bits)
106 : : {
107 : : size_t i;
108 [ + + ]: 970 : for (i = len - 1; i > 0; i--)
109 : 961 : buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
110 : 9 : buf[0] >>= bits;
111 : 9 : }
112 : :
113 : :
114 : 32 : static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
115 : : {
116 : : u8 val[SAE_MAX_PRIME_LEN];
117 : 32 : int iter = 0;
118 : 32 : struct crypto_bignum *bn = NULL;
119 : 32 : int order_len_bits = crypto_bignum_bits(sae->tmp->order);
120 : 32 : size_t order_len = (order_len_bits + 7) / 8;
121 : :
122 [ - + ]: 32 : if (order_len > sizeof(val))
123 : 0 : return NULL;
124 : :
125 : : for (;;) {
126 [ - + ]: 39 : if (iter++ > 100)
127 : 0 : return NULL;
128 [ - + ]: 39 : if (random_get_bytes(val, order_len) < 0)
129 : 0 : return NULL;
130 [ + + ]: 39 : if (order_len_bits % 8)
131 : 6 : buf_shift_right(val, order_len, 8 - order_len_bits % 8);
132 : 39 : bn = crypto_bignum_init_set(val, order_len);
133 [ - + ]: 39 : if (bn == NULL)
134 : 0 : return NULL;
135 [ + - + - ]: 78 : if (crypto_bignum_is_zero(bn) ||
136 [ + + ]: 78 : crypto_bignum_is_one(bn) ||
137 : 39 : crypto_bignum_cmp(bn, sae->tmp->order) >= 0)
138 : 7 : continue;
139 : 32 : break;
140 : 7 : }
141 : :
142 : 32 : os_memset(val, 0, order_len);
143 : 32 : return bn;
144 : : }
145 : :
146 : :
147 : 16 : static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
148 : : {
149 : 16 : crypto_bignum_deinit(sae->tmp->sae_rand, 1);
150 : 16 : sae->tmp->sae_rand = sae_get_rand(sae);
151 [ - + ]: 16 : if (sae->tmp->sae_rand == NULL)
152 : 0 : return NULL;
153 : 16 : return sae_get_rand(sae);
154 : : }
155 : :
156 : :
157 : 16 : static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
158 : : {
159 : 16 : wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
160 : 192 : " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
161 [ + - ]: 16 : if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
162 : 16 : os_memcpy(key, addr1, ETH_ALEN);
163 : 16 : os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
164 : : } else {
165 : 0 : os_memcpy(key, addr2, ETH_ALEN);
166 : 0 : os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
167 : : }
168 : 16 : }
169 : :
170 : :
171 : 33 : static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
172 : : struct crypto_ec_point *pwe)
173 : : {
174 : : u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
175 : : struct crypto_bignum *x;
176 : : int y_bit;
177 : : size_t bits;
178 : :
179 [ - + ]: 33 : if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
180 : 33 : sae->tmp->prime_len) < 0)
181 : 0 : return -1;
182 : :
183 : 33 : wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
184 : :
185 : : /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
186 : 33 : bits = crypto_ec_prime_len_bits(sae->tmp->ec);
187 : 33 : sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
188 : 33 : prime, sae->tmp->prime_len, pwd_value, bits);
189 [ + + ]: 33 : if (bits % 8)
190 : 3 : buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
191 : 33 : wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
192 : 33 : pwd_value, sae->tmp->prime_len);
193 : :
194 [ - + ]: 33 : if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
195 : 0 : return 0;
196 : :
197 : 33 : y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
198 : :
199 : 33 : x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
200 [ - + ]: 33 : if (x == NULL)
201 : 0 : return -1;
202 [ + + ]: 33 : if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
203 : 15 : crypto_bignum_deinit(x, 0);
204 : 15 : wpa_printf(MSG_DEBUG, "SAE: No solution found");
205 : 15 : return 0;
206 : : }
207 : 18 : crypto_bignum_deinit(x, 0);
208 : :
209 : 18 : wpa_printf(MSG_DEBUG, "SAE: PWE found");
210 : :
211 : 33 : return 1;
212 : : }
213 : :
214 : :
215 : 5 : static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
216 : : struct crypto_bignum *pwe)
217 : : {
218 : : u8 pwd_value[SAE_MAX_PRIME_LEN];
219 : 5 : size_t bits = sae->tmp->prime_len * 8;
220 : : u8 exp[1];
221 : : struct crypto_bignum *a, *b;
222 : : int res;
223 : :
224 : 5 : wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
225 : :
226 : : /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
227 : 5 : sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
228 : 10 : sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
229 : : bits);
230 [ - + ]: 5 : if (bits % 8)
231 : 0 : buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
232 : 5 : wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
233 : 5 : sae->tmp->prime_len);
234 : :
235 [ - + ]: 5 : if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
236 : : {
237 : 0 : wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
238 : 0 : return 0;
239 : : }
240 : :
241 : : /* PWE = pwd-value^((p-1)/r) modulo p */
242 : :
243 : 5 : a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
244 : :
245 [ + + ]: 5 : if (sae->tmp->dh->safe_prime) {
246 : : /*
247 : : * r = (p-1)/2 for the group used here, so this becomes:
248 : : * PWE = pwd-value^2 modulo p
249 : : */
250 : 2 : exp[0] = 2;
251 : 2 : b = crypto_bignum_init_set(exp, sizeof(exp));
252 : : } else {
253 : : /* Calculate exponent: (p-1)/r */
254 : 3 : exp[0] = 1;
255 : 3 : b = crypto_bignum_init_set(exp, sizeof(exp));
256 [ + - + - ]: 6 : if (b == NULL ||
257 [ - + ]: 6 : crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
258 : 3 : crypto_bignum_div(b, sae->tmp->order, b) < 0) {
259 : 0 : crypto_bignum_deinit(b, 0);
260 : 0 : b = NULL;
261 : : }
262 : : }
263 : :
264 [ + - ][ - + ]: 5 : if (a == NULL || b == NULL)
265 : 0 : res = -1;
266 : : else
267 : 5 : res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
268 : :
269 : 5 : crypto_bignum_deinit(a, 0);
270 : 5 : crypto_bignum_deinit(b, 0);
271 : :
272 [ - + ]: 5 : if (res < 0) {
273 : 0 : wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
274 : 0 : return -1;
275 : : }
276 : :
277 : : /* if (PWE > 1) --> found */
278 [ + - ][ - + ]: 5 : if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
279 : 0 : wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
280 : 0 : return 0;
281 : : }
282 : :
283 : 5 : wpa_printf(MSG_DEBUG, "SAE: PWE found");
284 : 5 : return 1;
285 : : }
286 : :
287 : :
288 : 11 : static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
289 : : const u8 *addr2, const u8 *password,
290 : : size_t password_len)
291 : : {
292 : 11 : u8 counter, k = 4;
293 : : u8 addrs[2 * ETH_ALEN];
294 : : const u8 *addr[2];
295 : : size_t len[2];
296 : 11 : int found = 0;
297 : : struct crypto_ec_point *pwe_tmp;
298 : :
299 [ + - ]: 11 : if (sae->tmp->pwe_ecc == NULL) {
300 : 11 : sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
301 [ - + ]: 11 : if (sae->tmp->pwe_ecc == NULL)
302 : 0 : return -1;
303 : : }
304 : 11 : pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
305 [ - + ]: 11 : if (pwe_tmp == NULL)
306 : 0 : return -1;
307 : :
308 : 11 : wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
309 : : password, password_len);
310 : :
311 : : /*
312 : : * H(salt, ikm) = HMAC-SHA256(salt, ikm)
313 : : * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
314 : : * password || counter)
315 : : */
316 : 11 : sae_pwd_seed_key(addr1, addr2, addrs);
317 : :
318 : 11 : addr[0] = password;
319 : 11 : len[0] = password_len;
320 : 11 : addr[1] = &counter;
321 : 11 : len[1] = sizeof(counter);
322 : :
323 : : /*
324 : : * Continue for at least k iterations to protect against side-channel
325 : : * attacks that attempt to determine the number of iterations required
326 : : * in the loop.
327 : : */
328 [ + + ][ - + ]: 44 : for (counter = 1; counter < k || !found; counter++) {
329 : : u8 pwd_seed[SHA256_MAC_LEN];
330 : : int res;
331 : :
332 [ - + ]: 33 : if (counter > 200) {
333 : : /* This should not happen in practice */
334 : 0 : wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
335 : 0 : break;
336 : : }
337 : :
338 : 33 : wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
339 [ - + ]: 33 : if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
340 : : pwd_seed) < 0)
341 : 0 : break;
342 [ + + ]: 33 : res = sae_test_pwd_seed_ecc(sae, pwd_seed,
343 : : found ? pwe_tmp :
344 : 22 : sae->tmp->pwe_ecc);
345 [ - + ]: 33 : if (res < 0)
346 : 0 : break;
347 [ + + ]: 33 : if (res == 0)
348 : 15 : continue;
349 [ + + ]: 18 : if (found) {
350 : 7 : wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
351 : : "already selected)");
352 : : } else {
353 : 11 : wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
354 : 11 : found = 1;
355 : : }
356 : : }
357 : :
358 : 11 : crypto_ec_point_deinit(pwe_tmp, 1);
359 : :
360 [ + - ]: 11 : return found ? 0 : -1;
361 : : }
362 : :
363 : :
364 : 5 : static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
365 : : const u8 *addr2, const u8 *password,
366 : : size_t password_len)
367 : : {
368 : : u8 counter;
369 : : u8 addrs[2 * ETH_ALEN];
370 : : const u8 *addr[2];
371 : : size_t len[2];
372 : 5 : int found = 0;
373 : :
374 [ + - ]: 5 : if (sae->tmp->pwe_ffc == NULL) {
375 : 5 : sae->tmp->pwe_ffc = crypto_bignum_init();
376 [ - + ]: 5 : if (sae->tmp->pwe_ffc == NULL)
377 : 0 : return -1;
378 : : }
379 : :
380 : 5 : wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
381 : : password, password_len);
382 : :
383 : : /*
384 : : * H(salt, ikm) = HMAC-SHA256(salt, ikm)
385 : : * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
386 : : * password || counter)
387 : : */
388 : 5 : sae_pwd_seed_key(addr1, addr2, addrs);
389 : :
390 : 5 : addr[0] = password;
391 : 5 : len[0] = password_len;
392 : 5 : addr[1] = &counter;
393 : 5 : len[1] = sizeof(counter);
394 : :
395 [ + + ]: 10 : for (counter = 1; !found; counter++) {
396 : : u8 pwd_seed[SHA256_MAC_LEN];
397 : : int res;
398 : :
399 [ - + ]: 5 : if (counter > 200) {
400 : : /* This should not happen in practice */
401 : 0 : wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
402 : 0 : break;
403 : : }
404 : :
405 : 5 : wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
406 [ - + ]: 5 : if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
407 : : pwd_seed) < 0)
408 : 0 : break;
409 : 5 : res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
410 [ - + ]: 5 : if (res < 0)
411 : 0 : break;
412 [ + - ]: 5 : if (res > 0) {
413 : 5 : wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
414 : 5 : found = 1;
415 : : }
416 : : }
417 : :
418 [ + - ]: 5 : return found ? 0 : -1;
419 : : }
420 : :
421 : :
422 : 11 : static int sae_derive_commit_element_ecc(struct sae_data *sae,
423 : : struct crypto_bignum *mask)
424 : : {
425 : : /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
426 [ + - ]: 11 : if (!sae->tmp->own_commit_element_ecc) {
427 : 22 : sae->tmp->own_commit_element_ecc =
428 : 11 : crypto_ec_point_init(sae->tmp->ec);
429 [ - + ]: 11 : if (!sae->tmp->own_commit_element_ecc)
430 : 0 : return -1;
431 : : }
432 : :
433 [ + - ]: 11 : if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
434 [ - + ]: 11 : sae->tmp->own_commit_element_ecc) < 0 ||
435 : 11 : crypto_ec_point_invert(sae->tmp->ec,
436 : 11 : sae->tmp->own_commit_element_ecc) < 0) {
437 : 0 : wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
438 : 0 : return -1;
439 : : }
440 : :
441 : 11 : return 0;
442 : : }
443 : :
444 : :
445 : 5 : static int sae_derive_commit_element_ffc(struct sae_data *sae,
446 : : struct crypto_bignum *mask)
447 : : {
448 : : /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
449 [ + - ]: 5 : if (!sae->tmp->own_commit_element_ffc) {
450 : 5 : sae->tmp->own_commit_element_ffc = crypto_bignum_init();
451 [ - + ]: 5 : if (!sae->tmp->own_commit_element_ffc)
452 : 0 : return -1;
453 : : }
454 : :
455 [ + - ]: 5 : if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
456 [ - + ]: 5 : sae->tmp->own_commit_element_ffc) < 0 ||
457 : 5 : crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
458 : 5 : sae->tmp->prime,
459 : 5 : sae->tmp->own_commit_element_ffc) < 0) {
460 : 0 : wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
461 : 0 : return -1;
462 : : }
463 : :
464 : 5 : return 0;
465 : : }
466 : :
467 : :
468 : 16 : static int sae_derive_commit(struct sae_data *sae)
469 : : {
470 : : struct crypto_bignum *mask;
471 : 16 : int ret = -1;
472 : :
473 : 16 : mask = sae_get_rand_and_mask(sae);
474 [ - + ]: 16 : if (mask == NULL) {
475 : 0 : wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
476 : 0 : return -1;
477 : : }
478 : :
479 : : /* commit-scalar = (rand + mask) modulo r */
480 [ + - ]: 16 : if (!sae->tmp->own_commit_scalar) {
481 : 16 : sae->tmp->own_commit_scalar = crypto_bignum_init();
482 [ - + ]: 16 : if (!sae->tmp->own_commit_scalar)
483 : 0 : goto fail;
484 : : }
485 : 16 : crypto_bignum_add(sae->tmp->sae_rand, mask,
486 : 16 : sae->tmp->own_commit_scalar);
487 : 16 : crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
488 : 16 : sae->tmp->own_commit_scalar);
489 : :
490 [ + + ][ - + ]: 16 : if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
491 : 0 : goto fail;
492 [ + + ][ - + ]: 16 : if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
493 : 0 : goto fail;
494 : :
495 : 16 : ret = 0;
496 : : fail:
497 : 16 : crypto_bignum_deinit(mask, 1);
498 : 16 : return ret;
499 : : }
500 : :
501 : :
502 : 16 : int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
503 : : const u8 *password, size_t password_len,
504 : : struct sae_data *sae)
505 : : {
506 [ + + ][ - + ]: 16 : if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
507 : : password_len) < 0)
508 : 0 : return -1;
509 [ + + ][ - + ]: 16 : if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
510 : : password_len) < 0)
511 : 0 : return -1;
512 [ - + ]: 16 : if (sae_derive_commit(sae) < 0)
513 : 0 : return -1;
514 : 16 : return 0;
515 : : }
516 : :
517 : :
518 : 11 : static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
519 : : {
520 : : struct crypto_ec_point *K;
521 : 11 : int ret = -1;
522 : :
523 : 11 : K = crypto_ec_point_init(sae->tmp->ec);
524 [ - + ]: 11 : if (K == NULL)
525 : 0 : goto fail;
526 : :
527 : : /*
528 : : * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
529 : : * PEER-COMMIT-ELEMENT)))
530 : : * If K is identity element (point-at-infinity), reject
531 : : * k = F(K) (= x coordinate)
532 : : */
533 : :
534 [ + - ]: 11 : if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
535 [ + - ]: 11 : sae->peer_commit_scalar, K) < 0 ||
536 : 11 : crypto_ec_point_add(sae->tmp->ec, K,
537 [ + - ]: 11 : sae->tmp->peer_commit_element_ecc, K) < 0 ||
538 [ + - ]: 22 : crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
539 [ - + ]: 22 : crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
540 : 11 : crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
541 : 0 : wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
542 : 0 : goto fail;
543 : : }
544 : :
545 : 11 : wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
546 : :
547 : 11 : ret = 0;
548 : : fail:
549 : 11 : crypto_ec_point_deinit(K, 1);
550 : 11 : return ret;
551 : : }
552 : :
553 : :
554 : 5 : static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
555 : : {
556 : : struct crypto_bignum *K;
557 : 5 : int ret = -1;
558 : :
559 : 5 : K = crypto_bignum_init();
560 [ - + ]: 5 : if (K == NULL)
561 : 0 : goto fail;
562 : :
563 : : /*
564 : : * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
565 : : * PEER-COMMIT-ELEMENT)))
566 : : * If K is identity element (one), reject.
567 : : * k = F(K) (= x coordinate)
568 : : */
569 : :
570 [ + - ]: 5 : if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
571 [ + - ]: 5 : sae->tmp->prime, K) < 0 ||
572 : 5 : crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
573 [ + - ]: 5 : sae->tmp->prime, K) < 0 ||
574 : 5 : crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
575 [ + - ]: 5 : ||
576 [ - + ]: 10 : crypto_bignum_is_one(K) ||
577 : 5 : crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
578 : : 0) {
579 : 0 : wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
580 : 0 : goto fail;
581 : : }
582 : :
583 : 5 : wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
584 : :
585 : 5 : ret = 0;
586 : : fail:
587 : 5 : crypto_bignum_deinit(K, 1);
588 : 5 : return ret;
589 : : }
590 : :
591 : :
592 : 16 : static int sae_derive_keys(struct sae_data *sae, const u8 *k)
593 : : {
594 : : u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
595 : : u8 keyseed[SHA256_MAC_LEN];
596 : : u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
597 : : struct crypto_bignum *tmp;
598 : 16 : int ret = -1;
599 : :
600 : 16 : tmp = crypto_bignum_init();
601 [ - + ]: 16 : if (tmp == NULL)
602 : 0 : goto fail;
603 : :
604 : : /* keyseed = H(<0>32, k)
605 : : * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
606 : : * (commit-scalar + peer-commit-scalar) modulo r)
607 : : * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
608 : : */
609 : :
610 : 16 : os_memset(null_key, 0, sizeof(null_key));
611 : 16 : hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
612 : : keyseed);
613 : 16 : wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
614 : :
615 : 16 : crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
616 : : tmp);
617 : 16 : crypto_bignum_mod(tmp, sae->tmp->order, tmp);
618 : 16 : crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
619 : 16 : wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
620 : 16 : sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
621 : 16 : val, sae->tmp->prime_len, keys, sizeof(keys));
622 : 16 : os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
623 : 16 : os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
624 : 16 : wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
625 : 16 : wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
626 : :
627 : 16 : ret = 0;
628 : : fail:
629 : 16 : crypto_bignum_deinit(tmp, 0);
630 : 16 : return ret;
631 : : }
632 : :
633 : :
634 : 16 : int sae_process_commit(struct sae_data *sae)
635 : : {
636 : : u8 k[SAE_MAX_PRIME_LEN];
637 [ + + ][ + - ]: 16 : if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
[ + + ]
638 [ + - - + ]: 21 : (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
639 : 16 : sae_derive_keys(sae, k) < 0)
640 : 0 : return -1;
641 : 16 : return 0;
642 : : }
643 : :
644 : :
645 : 16 : void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
646 : : const struct wpabuf *token)
647 : : {
648 : : u8 *pos;
649 : 16 : wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
650 [ - + ]: 16 : if (token)
651 : 0 : wpabuf_put_buf(buf, token);
652 : 16 : pos = wpabuf_put(buf, sae->tmp->prime_len);
653 : 16 : crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
654 : 32 : sae->tmp->prime_len, sae->tmp->prime_len);
655 : 16 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
656 : 16 : pos, sae->tmp->prime_len);
657 [ + + ]: 16 : if (sae->tmp->ec) {
658 : 11 : pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
659 : 11 : crypto_ec_point_to_bin(sae->tmp->ec,
660 : 11 : sae->tmp->own_commit_element_ecc,
661 : 11 : pos, pos + sae->tmp->prime_len);
662 : 11 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
663 : 11 : pos, sae->tmp->prime_len);
664 : 11 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
665 : 22 : pos + sae->tmp->prime_len, sae->tmp->prime_len);
666 : : } else {
667 : 5 : pos = wpabuf_put(buf, sae->tmp->prime_len);
668 : 5 : crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
669 : 10 : sae->tmp->prime_len, sae->tmp->prime_len);
670 : 5 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
671 : 5 : pos, sae->tmp->prime_len);
672 : : }
673 : 16 : }
674 : :
675 : :
676 : 20 : static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
677 : : u16 group)
678 : : {
679 [ + + ]: 20 : if (allowed_groups) {
680 : : int i;
681 [ + + ]: 62 : for (i = 0; allowed_groups[i] > 0; i++) {
682 [ + + ]: 59 : if (allowed_groups[i] == group)
683 : 11 : break;
684 : : }
685 [ + + ]: 14 : if (allowed_groups[i] != group) {
686 : 3 : wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
687 : : "enabled in the current configuration",
688 : : group);
689 : 3 : return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
690 : : }
691 : : }
692 : :
693 [ - + ][ # # ]: 17 : if (sae->state == SAE_COMMITTED && group != sae->group) {
694 : 0 : wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
695 : 0 : return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
696 : : }
697 : :
698 [ + + ][ - + ]: 17 : if (group != sae->group && sae_set_group(sae, group) < 0) {
699 : 0 : wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
700 : : group);
701 : 0 : return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
702 : : }
703 : :
704 [ - + ]: 17 : if (sae->tmp == NULL) {
705 : 0 : wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
706 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
707 : : }
708 : :
709 [ + + ][ - + ]: 17 : if (sae->tmp->dh && !allowed_groups) {
710 : 0 : wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
711 : : "explicit configuration enabling it", group);
712 : 0 : return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
713 : : }
714 : :
715 : 20 : return WLAN_STATUS_SUCCESS;
716 : : }
717 : :
718 : :
719 : 17 : static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
720 : : const u8 *end, const u8 **token,
721 : : size_t *token_len)
722 : : {
723 [ + + ][ + + ]: 17 : if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
724 [ + - ]: 1 : size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
725 : 1 : sae->tmp->prime_len);
726 : 1 : wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
727 [ + - ]: 1 : if (token)
728 : 1 : *token = *pos;
729 [ + - ]: 1 : if (token_len)
730 : 1 : *token_len = tlen;
731 : 1 : *pos += tlen;
732 : : } else {
733 [ + - ]: 16 : if (token)
734 : 16 : *token = NULL;
735 [ + - ]: 16 : if (token_len)
736 : 16 : *token_len = 0;
737 : : }
738 : 17 : }
739 : :
740 : :
741 : 17 : static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
742 : : const u8 *end)
743 : : {
744 : : struct crypto_bignum *peer_scalar;
745 : :
746 [ - + ]: 17 : if (*pos + sae->tmp->prime_len > end) {
747 : 0 : wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
748 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
749 : : }
750 : :
751 : 17 : peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
752 [ - + ]: 17 : if (peer_scalar == NULL)
753 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
754 : :
755 : : /*
756 : : * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
757 : : * the peer and it is in Authenticated state, the new Commit Message
758 : : * shall be dropped if the peer-scalar is identical to the one used in
759 : : * the existing protocol instance.
760 : : */
761 [ - + ]: 17 : if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
[ # # # # ]
762 : 0 : crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
763 : 0 : wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
764 : : "peer-commit-scalar");
765 : 0 : crypto_bignum_deinit(peer_scalar, 0);
766 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
767 : : }
768 : :
769 : : /* 0 < scalar < r */
770 [ + - - + ]: 34 : if (crypto_bignum_is_zero(peer_scalar) ||
771 : 17 : crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
772 : 0 : wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
773 : 0 : crypto_bignum_deinit(peer_scalar, 0);
774 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
775 : : }
776 : :
777 : :
778 : 17 : crypto_bignum_deinit(sae->peer_commit_scalar, 0);
779 : 17 : sae->peer_commit_scalar = peer_scalar;
780 : 17 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
781 : 17 : *pos, sae->tmp->prime_len);
782 : 17 : *pos += sae->tmp->prime_len;
783 : :
784 : 17 : return WLAN_STATUS_SUCCESS;
785 : : }
786 : :
787 : :
788 : 12 : static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
789 : : const u8 *end)
790 : : {
791 : : u8 prime[SAE_MAX_ECC_PRIME_LEN];
792 : :
793 [ - + ]: 12 : if (pos + 2 * sae->tmp->prime_len > end) {
794 : 0 : wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
795 : : "commit-element");
796 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
797 : : }
798 : :
799 [ - + ]: 12 : if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
800 : 12 : sae->tmp->prime_len) < 0)
801 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
802 : :
803 : : /* element x and y coordinates < p */
804 [ + - ][ - + ]: 12 : if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
805 : 12 : os_memcmp(pos + sae->tmp->prime_len, prime,
806 : : sae->tmp->prime_len) >= 0) {
807 : 0 : wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
808 : : "element");
809 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
810 : : }
811 : :
812 : 12 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
813 : 12 : pos, sae->tmp->prime_len);
814 : 12 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
815 : 24 : pos + sae->tmp->prime_len, sae->tmp->prime_len);
816 : :
817 : 12 : crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
818 : 24 : sae->tmp->peer_commit_element_ecc =
819 : 12 : crypto_ec_point_from_bin(sae->tmp->ec, pos);
820 [ - + ]: 12 : if (sae->tmp->peer_commit_element_ecc == NULL)
821 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
822 : :
823 [ - + ]: 12 : if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
824 : 12 : sae->tmp->peer_commit_element_ecc)) {
825 : 0 : wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
826 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
827 : : }
828 : :
829 : 12 : return WLAN_STATUS_SUCCESS;
830 : : }
831 : :
832 : :
833 : 5 : static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
834 : : const u8 *end)
835 : : {
836 : : struct crypto_bignum *res;
837 : :
838 [ - + ]: 5 : if (pos + sae->tmp->prime_len > end) {
839 : 0 : wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
840 : : "commit-element");
841 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
842 : : }
843 : 5 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
844 : 5 : sae->tmp->prime_len);
845 : :
846 : 5 : crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
847 : 10 : sae->tmp->peer_commit_element_ffc =
848 : 5 : crypto_bignum_init_set(pos, sae->tmp->prime_len);
849 [ - + ]: 5 : if (sae->tmp->peer_commit_element_ffc == NULL)
850 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
851 [ + - + - ]: 10 : if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
852 [ - + ]: 10 : crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
853 : 5 : crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
854 : 5 : sae->tmp->prime) >= 0) {
855 : 0 : wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
856 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
857 : : }
858 : :
859 : : /* scalar-op(r, ELEMENT) = 1 modulo p */
860 : 5 : res = crypto_bignum_init();
861 [ + - + - ]: 10 : if (res == NULL ||
862 : 5 : crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
863 [ - + ]: 5 : sae->tmp->order, sae->tmp->prime, res) < 0 ||
864 : 5 : !crypto_bignum_is_one(res)) {
865 : 0 : wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
866 : 0 : crypto_bignum_deinit(res, 0);
867 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
868 : : }
869 : 5 : crypto_bignum_deinit(res, 0);
870 : :
871 : 5 : return WLAN_STATUS_SUCCESS;
872 : : }
873 : :
874 : :
875 : 17 : static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
876 : : const u8 *end)
877 : : {
878 [ + + ]: 17 : if (sae->tmp->dh)
879 : 5 : return sae_parse_commit_element_ffc(sae, pos, end);
880 : 17 : return sae_parse_commit_element_ecc(sae, pos, end);
881 : : }
882 : :
883 : :
884 : 20 : u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
885 : : const u8 **token, size_t *token_len, int *allowed_groups)
886 : : {
887 : 20 : const u8 *pos = data, *end = data + len;
888 : : u16 res;
889 : :
890 : : /* Check Finite Cyclic Group */
891 [ - + ]: 20 : if (pos + 2 > end)
892 : 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
893 : 20 : res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
894 [ + + ]: 20 : if (res != WLAN_STATUS_SUCCESS)
895 : 3 : return res;
896 : 17 : pos += 2;
897 : :
898 : : /* Optional Anti-Clogging Token */
899 : 17 : sae_parse_commit_token(sae, &pos, end, token, token_len);
900 : :
901 : : /* commit-scalar */
902 : 17 : res = sae_parse_commit_scalar(sae, &pos, end);
903 [ - + ]: 17 : if (res != WLAN_STATUS_SUCCESS)
904 : 0 : return res;
905 : :
906 : : /* commit-element */
907 : 20 : return sae_parse_commit_element(sae, pos, end);
908 : : }
909 : :
910 : :
911 : 32 : static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
912 : : const struct crypto_bignum *scalar1,
913 : : const u8 *element1, size_t element1_len,
914 : : const struct crypto_bignum *scalar2,
915 : : const u8 *element2, size_t element2_len,
916 : : u8 *confirm)
917 : : {
918 : : const u8 *addr[5];
919 : : size_t len[5];
920 : : u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
921 : :
922 : : /* Confirm
923 : : * CN(key, X, Y, Z, ...) =
924 : : * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
925 : : * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
926 : : * peer-commit-scalar, PEER-COMMIT-ELEMENT)
927 : : * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
928 : : * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
929 : : */
930 : 32 : addr[0] = sc;
931 : 32 : len[0] = 2;
932 : 32 : crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
933 : 32 : sae->tmp->prime_len);
934 : 32 : addr[1] = scalar_b1;
935 : 32 : len[1] = sae->tmp->prime_len;
936 : 32 : addr[2] = element1;
937 : 32 : len[2] = element1_len;
938 : 32 : crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
939 : 32 : sae->tmp->prime_len);
940 : 32 : addr[3] = scalar_b2;
941 : 32 : len[3] = sae->tmp->prime_len;
942 : 32 : addr[4] = element2;
943 : 32 : len[4] = element2_len;
944 : 32 : hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
945 : : confirm);
946 : 32 : }
947 : :
948 : :
949 : 22 : static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
950 : : const struct crypto_bignum *scalar1,
951 : : const struct crypto_ec_point *element1,
952 : : const struct crypto_bignum *scalar2,
953 : : const struct crypto_ec_point *element2,
954 : : u8 *confirm)
955 : : {
956 : : u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
957 : : u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
958 : :
959 : 22 : crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
960 : 22 : element_b1 + sae->tmp->prime_len);
961 : 22 : crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
962 : 22 : element_b2 + sae->tmp->prime_len);
963 : :
964 : 22 : sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
965 : 22 : scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
966 : 22 : }
967 : :
968 : :
969 : 10 : static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
970 : : const struct crypto_bignum *scalar1,
971 : : const struct crypto_bignum *element1,
972 : : const struct crypto_bignum *scalar2,
973 : : const struct crypto_bignum *element2,
974 : : u8 *confirm)
975 : : {
976 : : u8 element_b1[SAE_MAX_PRIME_LEN];
977 : : u8 element_b2[SAE_MAX_PRIME_LEN];
978 : :
979 : 10 : crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
980 : 10 : sae->tmp->prime_len);
981 : 10 : crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
982 : 10 : sae->tmp->prime_len);
983 : :
984 : 10 : sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
985 : 10 : scalar2, element_b2, sae->tmp->prime_len, confirm);
986 : 10 : }
987 : :
988 : :
989 : 16 : void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
990 : : {
991 : : const u8 *sc;
992 : :
993 : : /* Send-Confirm */
994 : 16 : sc = wpabuf_put(buf, 0);
995 : 16 : wpabuf_put_le16(buf, sae->send_confirm);
996 : 16 : sae->send_confirm++;
997 : :
998 [ + + ]: 16 : if (sae->tmp->ec)
999 : 11 : sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
1000 : 11 : sae->tmp->own_commit_element_ecc,
1001 : 11 : sae->peer_commit_scalar,
1002 : 11 : sae->tmp->peer_commit_element_ecc,
1003 : 11 : wpabuf_put(buf, SHA256_MAC_LEN));
1004 : : else
1005 : 5 : sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
1006 : 5 : sae->tmp->own_commit_element_ffc,
1007 : 5 : sae->peer_commit_scalar,
1008 : 5 : sae->tmp->peer_commit_element_ffc,
1009 : 5 : wpabuf_put(buf, SHA256_MAC_LEN));
1010 : 16 : }
1011 : :
1012 : :
1013 : 16 : int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
1014 : : {
1015 : : u8 verifier[SHA256_MAC_LEN];
1016 : :
1017 [ - + ]: 16 : if (len < 2 + SHA256_MAC_LEN) {
1018 : 0 : wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
1019 : 0 : return -1;
1020 : : }
1021 : :
1022 : 16 : wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
1023 : :
1024 [ + + ]: 16 : if (sae->tmp->ec)
1025 : 11 : sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
1026 : 11 : sae->tmp->peer_commit_element_ecc,
1027 : 11 : sae->tmp->own_commit_scalar,
1028 : 11 : sae->tmp->own_commit_element_ecc,
1029 : : verifier);
1030 : : else
1031 : 5 : sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
1032 : 5 : sae->tmp->peer_commit_element_ffc,
1033 : 5 : sae->tmp->own_commit_scalar,
1034 : 5 : sae->tmp->own_commit_element_ffc,
1035 : : verifier);
1036 : :
1037 [ - + ]: 16 : if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) {
1038 : 0 : wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
1039 : 0 : wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
1040 : : data + 2, SHA256_MAC_LEN);
1041 : 0 : wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
1042 : : verifier, SHA256_MAC_LEN);
1043 : 0 : return -1;
1044 : : }
1045 : :
1046 : 16 : return 0;
1047 : : }
|