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