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 51 : int sae_set_group(struct sae_data *sae, int group)
21 : {
22 : struct sae_temporary_data *tmp;
23 :
24 51 : sae_clear_data(sae);
25 51 : tmp = sae->tmp = os_zalloc(sizeof(*tmp));
26 51 : if (tmp == NULL)
27 0 : return -1;
28 :
29 : /* First, check if this is an ECC group */
30 51 : tmp->ec = crypto_ec_init(group);
31 51 : if (tmp->ec) {
32 41 : sae->group = group;
33 41 : tmp->prime_len = crypto_ec_prime_len(tmp->ec);
34 41 : tmp->prime = crypto_ec_get_prime(tmp->ec);
35 41 : tmp->order = crypto_ec_get_order(tmp->ec);
36 41 : 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 0 : return -1;
70 : }
71 :
72 :
73 189 : void sae_clear_temp_data(struct sae_data *sae)
74 : {
75 : struct sae_temporary_data *tmp;
76 189 : if (sae == NULL || sae->tmp == NULL)
77 327 : return;
78 51 : tmp = sae->tmp;
79 51 : crypto_ec_deinit(tmp->ec);
80 51 : crypto_bignum_deinit(tmp->prime_buf, 0);
81 51 : crypto_bignum_deinit(tmp->order_buf, 0);
82 51 : crypto_bignum_deinit(tmp->sae_rand, 1);
83 51 : crypto_bignum_deinit(tmp->pwe_ffc, 1);
84 51 : crypto_bignum_deinit(tmp->own_commit_scalar, 0);
85 51 : crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
86 51 : crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
87 51 : crypto_ec_point_deinit(tmp->pwe_ecc, 1);
88 51 : crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
89 51 : crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
90 51 : os_free(sae->tmp);
91 51 : sae->tmp = NULL;
92 : }
93 :
94 :
95 1124 : void sae_clear_data(struct sae_data *sae)
96 : {
97 1124 : if (sae == NULL)
98 2099 : return;
99 149 : sae_clear_temp_data(sae);
100 149 : crypto_bignum_deinit(sae->peer_commit_scalar, 0);
101 149 : 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 96 : static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
115 : {
116 : u8 val[SAE_MAX_PRIME_LEN];
117 96 : int iter = 0;
118 96 : struct crypto_bignum *bn = NULL;
119 96 : int order_len_bits = crypto_bignum_bits(sae->tmp->order);
120 96 : size_t order_len = (order_len_bits + 7) / 8;
121 :
122 96 : if (order_len > sizeof(val))
123 0 : return NULL;
124 :
125 : for (;;) {
126 100 : if (iter++ > 100)
127 0 : return NULL;
128 100 : if (random_get_bytes(val, order_len) < 0)
129 0 : return NULL;
130 100 : if (order_len_bits % 8)
131 12 : buf_shift_right(val, order_len, 8 - order_len_bits % 8);
132 100 : bn = crypto_bignum_init_set(val, order_len);
133 100 : if (bn == NULL)
134 0 : return NULL;
135 200 : if (crypto_bignum_is_zero(bn) ||
136 200 : crypto_bignum_is_one(bn) ||
137 100 : crypto_bignum_cmp(bn, sae->tmp->order) >= 0)
138 4 : continue;
139 96 : break;
140 4 : }
141 :
142 96 : os_memset(val, 0, order_len);
143 96 : return bn;
144 : }
145 :
146 :
147 48 : static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
148 : {
149 48 : crypto_bignum_deinit(sae->tmp->sae_rand, 1);
150 48 : sae->tmp->sae_rand = sae_get_rand(sae);
151 48 : if (sae->tmp->sae_rand == NULL)
152 0 : return NULL;
153 48 : return sae_get_rand(sae);
154 : }
155 :
156 :
157 48 : static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
158 : {
159 576 : wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
160 576 : " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
161 48 : if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
162 20 : os_memcpy(key, addr1, ETH_ALEN);
163 20 : os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
164 : } else {
165 28 : os_memcpy(key, addr2, ETH_ALEN);
166 28 : os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
167 : }
168 48 : }
169 :
170 :
171 114 : 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 114 : if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
180 114 : sae->tmp->prime_len) < 0)
181 0 : return -1;
182 :
183 114 : 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 114 : bits = crypto_ec_prime_len_bits(sae->tmp->ec);
187 114 : sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
188 114 : prime, sae->tmp->prime_len, pwd_value, bits);
189 114 : if (bits % 8)
190 6 : buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
191 114 : wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
192 114 : pwd_value, sae->tmp->prime_len);
193 :
194 114 : if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
195 0 : return 0;
196 :
197 114 : y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
198 :
199 114 : x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
200 114 : if (x == NULL)
201 0 : return -1;
202 114 : if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
203 44 : crypto_bignum_deinit(x, 0);
204 44 : wpa_printf(MSG_DEBUG, "SAE: No solution found");
205 44 : return 0;
206 : }
207 70 : crypto_bignum_deinit(x, 0);
208 :
209 70 : wpa_printf(MSG_DEBUG, "SAE: PWE found");
210 :
211 70 : 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 20 : 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 38 : 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 38 : u8 counter, k = 4;
293 : u8 addrs[2 * ETH_ALEN];
294 : const u8 *addr[2];
295 : size_t len[2];
296 38 : int found = 0;
297 : struct crypto_ec_point *pwe_tmp;
298 :
299 38 : if (sae->tmp->pwe_ecc == NULL) {
300 38 : sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
301 38 : if (sae->tmp->pwe_ecc == NULL)
302 0 : return -1;
303 : }
304 38 : pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
305 38 : if (pwe_tmp == NULL)
306 0 : return -1;
307 :
308 38 : 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 38 : sae_pwd_seed_key(addr1, addr2, addrs);
317 :
318 38 : addr[0] = password;
319 38 : len[0] = password_len;
320 38 : addr[1] = &counter;
321 38 : 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 152 : for (counter = 1; counter < k || !found; counter++) {
329 : u8 pwd_seed[SHA256_MAC_LEN];
330 : int res;
331 :
332 114 : 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 114 : wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
339 114 : if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
340 : pwd_seed) < 0)
341 0 : break;
342 185 : res = sae_test_pwd_seed_ecc(sae, pwd_seed,
343 : found ? pwe_tmp :
344 71 : sae->tmp->pwe_ecc);
345 114 : if (res < 0)
346 0 : break;
347 114 : if (res == 0)
348 44 : continue;
349 70 : if (found) {
350 32 : wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
351 : "already selected)");
352 : } else {
353 38 : wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
354 38 : found = 1;
355 : }
356 : }
357 :
358 38 : crypto_ec_point_deinit(pwe_tmp, 1);
359 :
360 38 : 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 40 : 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 38 : 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 38 : if (!sae->tmp->own_commit_element_ecc) {
427 76 : sae->tmp->own_commit_element_ecc =
428 38 : crypto_ec_point_init(sae->tmp->ec);
429 38 : if (!sae->tmp->own_commit_element_ecc)
430 0 : return -1;
431 : }
432 :
433 38 : if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
434 76 : sae->tmp->own_commit_element_ecc) < 0 ||
435 38 : crypto_ec_point_invert(sae->tmp->ec,
436 38 : 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 38 : 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 20 : sae->tmp->own_commit_element_ffc) < 0 ||
457 20 : 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 48 : static int sae_derive_commit(struct sae_data *sae)
469 : {
470 : struct crypto_bignum *mask;
471 48 : int ret = -1;
472 :
473 48 : mask = sae_get_rand_and_mask(sae);
474 48 : 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 48 : if (!sae->tmp->own_commit_scalar) {
481 48 : sae->tmp->own_commit_scalar = crypto_bignum_init();
482 48 : if (!sae->tmp->own_commit_scalar)
483 0 : goto fail;
484 : }
485 48 : crypto_bignum_add(sae->tmp->sae_rand, mask,
486 48 : sae->tmp->own_commit_scalar);
487 48 : crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
488 48 : sae->tmp->own_commit_scalar);
489 :
490 48 : if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
491 0 : goto fail;
492 48 : if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
493 0 : goto fail;
494 :
495 48 : ret = 0;
496 : fail:
497 48 : crypto_bignum_deinit(mask, 1);
498 48 : return ret;
499 : }
500 :
501 :
502 48 : 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 48 : if (sae->tmp == NULL)
507 0 : return -1;
508 48 : if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
509 : password_len) < 0)
510 0 : return -1;
511 48 : if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
512 : password_len) < 0)
513 0 : return -1;
514 48 : if (sae_derive_commit(sae) < 0)
515 0 : return -1;
516 48 : return 0;
517 : }
518 :
519 :
520 30 : static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
521 : {
522 : struct crypto_ec_point *K;
523 30 : int ret = -1;
524 :
525 30 : K = crypto_ec_point_init(sae->tmp->ec);
526 30 : 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 30 : if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
537 60 : sae->peer_commit_scalar, K) < 0 ||
538 30 : crypto_ec_point_add(sae->tmp->ec, K,
539 60 : sae->tmp->peer_commit_element_ecc, K) < 0 ||
540 60 : crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
541 60 : crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
542 30 : 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 30 : wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
548 :
549 30 : ret = 0;
550 : fail:
551 30 : crypto_ec_point_deinit(K, 1);
552 30 : 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 20 : sae->tmp->prime, K) < 0 ||
574 10 : crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
575 20 : 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 40 : 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 40 : int ret = -1;
601 :
602 40 : tmp = crypto_bignum_init();
603 40 : 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 40 : os_memset(null_key, 0, sizeof(null_key));
613 40 : hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
614 : keyseed);
615 40 : wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
616 :
617 40 : crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
618 : tmp);
619 40 : crypto_bignum_mod(tmp, sae->tmp->order, tmp);
620 40 : crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
621 40 : wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
622 40 : sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
623 40 : val, sae->tmp->prime_len, keys, sizeof(keys));
624 40 : os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
625 40 : os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
626 40 : wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
627 40 : wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
628 :
629 40 : ret = 0;
630 : fail:
631 40 : crypto_bignum_deinit(tmp, 0);
632 40 : return ret;
633 : }
634 :
635 :
636 40 : int sae_process_commit(struct sae_data *sae)
637 : {
638 : u8 k[SAE_MAX_PRIME_LEN];
639 80 : if (sae->tmp == NULL ||
640 110 : (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
641 90 : (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
642 40 : sae_derive_keys(sae, k) < 0)
643 0 : return -1;
644 40 : return 0;
645 : }
646 :
647 :
648 48 : void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
649 : const struct wpabuf *token)
650 : {
651 : u8 *pos;
652 :
653 48 : if (sae->tmp == NULL)
654 48 : return;
655 :
656 48 : wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
657 48 : if (token)
658 5 : wpabuf_put_buf(buf, token);
659 48 : pos = wpabuf_put(buf, sae->tmp->prime_len);
660 96 : crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
661 96 : sae->tmp->prime_len, sae->tmp->prime_len);
662 48 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
663 48 : pos, sae->tmp->prime_len);
664 48 : if (sae->tmp->ec) {
665 38 : pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
666 76 : crypto_ec_point_to_bin(sae->tmp->ec,
667 38 : sae->tmp->own_commit_element_ecc,
668 38 : pos, pos + sae->tmp->prime_len);
669 38 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
670 38 : pos, sae->tmp->prime_len);
671 76 : wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
672 76 : pos + sae->tmp->prime_len, sae->tmp->prime_len);
673 : } else {
674 10 : pos = wpabuf_put(buf, sae->tmp->prime_len);
675 20 : 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 48 : static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
684 : u16 group)
685 : {
686 48 : 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 45 : 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 45 : 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 45 : 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 45 : 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 45 : return WLAN_STATUS_SUCCESS;
723 : }
724 :
725 :
726 45 : 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 45 : if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
731 10 : size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
732 5 : sae->tmp->prime_len);
733 5 : wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
734 5 : if (token)
735 5 : *token = *pos;
736 5 : if (token_len)
737 5 : *token_len = tlen;
738 5 : *pos += tlen;
739 : } else {
740 40 : if (token)
741 20 : *token = NULL;
742 40 : if (token_len)
743 20 : *token_len = 0;
744 : }
745 45 : }
746 :
747 :
748 45 : 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 45 : 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 45 : peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
759 45 : 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 45 : 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 90 : if (crypto_bignum_is_zero(peer_scalar) ||
778 45 : 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 45 : crypto_bignum_deinit(sae->peer_commit_scalar, 0);
786 45 : sae->peer_commit_scalar = peer_scalar;
787 45 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
788 45 : *pos, sae->tmp->prime_len);
789 45 : *pos += sae->tmp->prime_len;
790 :
791 45 : return WLAN_STATUS_SUCCESS;
792 : }
793 :
794 :
795 35 : 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 35 : 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 35 : if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
807 35 : sae->tmp->prime_len) < 0)
808 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
809 :
810 : /* element x and y coordinates < p */
811 70 : if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
812 35 : 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 35 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
820 35 : pos, sae->tmp->prime_len);
821 70 : wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
822 70 : pos + sae->tmp->prime_len, sae->tmp->prime_len);
823 :
824 35 : crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
825 70 : sae->tmp->peer_commit_element_ecc =
826 35 : crypto_ec_point_from_bin(sae->tmp->ec, pos);
827 35 : if (sae->tmp->peer_commit_element_ecc == NULL)
828 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
829 :
830 35 : if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
831 35 : 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 35 : 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 20 : crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
870 30 : 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 45 : static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
883 : const u8 *end)
884 : {
885 45 : if (sae->tmp->dh)
886 10 : return sae_parse_commit_element_ffc(sae, pos, end);
887 35 : return sae_parse_commit_element_ecc(sae, pos, end);
888 : }
889 :
890 :
891 48 : 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 48 : const u8 *pos = data, *end = data + len;
895 : u16 res;
896 :
897 : /* Check Finite Cyclic Group */
898 48 : if (pos + 2 > end)
899 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
900 48 : res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
901 48 : if (res != WLAN_STATUS_SUCCESS)
902 3 : return res;
903 45 : pos += 2;
904 :
905 : /* Optional Anti-Clogging Token */
906 45 : sae_parse_commit_token(sae, &pos, end, token, token_len);
907 :
908 : /* commit-scalar */
909 45 : res = sae_parse_commit_scalar(sae, &pos, end);
910 45 : if (res != WLAN_STATUS_SUCCESS)
911 0 : return res;
912 :
913 : /* commit-element */
914 45 : return sae_parse_commit_element(sae, pos, end);
915 : }
916 :
917 :
918 80 : 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 80 : addr[0] = sc;
938 80 : len[0] = 2;
939 80 : crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
940 80 : sae->tmp->prime_len);
941 80 : addr[1] = scalar_b1;
942 80 : len[1] = sae->tmp->prime_len;
943 80 : addr[2] = element1;
944 80 : len[2] = element1_len;
945 80 : crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
946 80 : sae->tmp->prime_len);
947 80 : addr[3] = scalar_b2;
948 80 : len[3] = sae->tmp->prime_len;
949 80 : addr[4] = element2;
950 80 : len[4] = element2_len;
951 80 : hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
952 : confirm);
953 80 : }
954 :
955 :
956 60 : 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 60 : crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
967 60 : element_b1 + sae->tmp->prime_len);
968 60 : crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
969 60 : element_b2 + sae->tmp->prime_len);
970 :
971 60 : sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
972 60 : scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
973 60 : }
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 40 : void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
997 : {
998 : const u8 *sc;
999 :
1000 40 : if (sae->tmp == NULL)
1001 40 : return;
1002 :
1003 : /* Send-Confirm */
1004 40 : sc = wpabuf_put(buf, 0);
1005 40 : wpabuf_put_le16(buf, sae->send_confirm);
1006 40 : sae->send_confirm++;
1007 :
1008 40 : if (sae->tmp->ec)
1009 30 : sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
1010 30 : sae->tmp->own_commit_element_ecc,
1011 30 : sae->peer_commit_scalar,
1012 30 : sae->tmp->peer_commit_element_ecc,
1013 30 : 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 40 : int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
1024 : {
1025 : u8 verifier[SHA256_MAC_LEN];
1026 :
1027 40 : if (len < 2 + SHA256_MAC_LEN) {
1028 0 : wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
1029 0 : return -1;
1030 : }
1031 :
1032 40 : wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
1033 :
1034 40 : if (sae->tmp == NULL) {
1035 0 : wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
1036 0 : return -1;
1037 : }
1038 :
1039 40 : if (sae->tmp->ec)
1040 30 : sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
1041 30 : sae->tmp->peer_commit_element_ecc,
1042 30 : sae->tmp->own_commit_scalar,
1043 30 : 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 40 : 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 40 : return 0;
1062 : }
|