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