blob: 981e788dc7518cc7986fc58e3646fc80f0688b82 [file] [log] [blame]
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001/*
2 * Simultaneous authentication of equals
Dmitry Shmidte4663042016-04-04 10:07:49 -07003 * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004 *
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) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070032 wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
33 group);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080034 sae->group = group;
35 tmp->prime_len = crypto_ec_prime_len(tmp->ec);
36 tmp->prime = crypto_ec_get_prime(tmp->ec);
37 tmp->order = crypto_ec_get_order(tmp->ec);
38 return 0;
39 }
40
41 /* Not an ECC group, check FFC */
42 tmp->dh = dh_groups_get(group);
43 if (tmp->dh) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070044 wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
45 group);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080046 sae->group = group;
47 tmp->prime_len = tmp->dh->prime_len;
48 if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
49 sae_clear_data(sae);
50 return -1;
51 }
52
53 tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
54 tmp->prime_len);
55 if (tmp->prime_buf == NULL) {
56 sae_clear_data(sae);
57 return -1;
58 }
59 tmp->prime = tmp->prime_buf;
60
61 tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
62 tmp->dh->order_len);
63 if (tmp->order_buf == NULL) {
64 sae_clear_data(sae);
65 return -1;
66 }
67 tmp->order = tmp->order_buf;
68
69 return 0;
70 }
71
72 /* Unsupported group */
Roshan Pius3a1667e2018-07-03 15:17:14 -070073 wpa_printf(MSG_DEBUG,
74 "SAE: Group %d not supported by the crypto library", group);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080075 return -1;
76}
77
78
79void sae_clear_temp_data(struct sae_data *sae)
80{
81 struct sae_temporary_data *tmp;
82 if (sae == NULL || sae->tmp == NULL)
83 return;
84 tmp = sae->tmp;
85 crypto_ec_deinit(tmp->ec);
86 crypto_bignum_deinit(tmp->prime_buf, 0);
87 crypto_bignum_deinit(tmp->order_buf, 0);
88 crypto_bignum_deinit(tmp->sae_rand, 1);
89 crypto_bignum_deinit(tmp->pwe_ffc, 1);
90 crypto_bignum_deinit(tmp->own_commit_scalar, 0);
91 crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
92 crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
93 crypto_ec_point_deinit(tmp->pwe_ecc, 1);
94 crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
95 crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -080096 wpabuf_free(tmp->anti_clogging_token);
Roshan Pius3a1667e2018-07-03 15:17:14 -070097 os_free(tmp->pw_id);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -080098 bin_clear_free(tmp, sizeof(*tmp));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080099 sae->tmp = NULL;
100}
101
102
103void sae_clear_data(struct sae_data *sae)
104{
105 if (sae == NULL)
106 return;
107 sae_clear_temp_data(sae);
108 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
109 os_memset(sae, 0, sizeof(*sae));
110}
111
112
113static void buf_shift_right(u8 *buf, size_t len, size_t bits)
114{
115 size_t i;
116 for (i = len - 1; i > 0; i--)
117 buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
118 buf[0] >>= bits;
119}
120
121
122static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
123{
124 u8 val[SAE_MAX_PRIME_LEN];
125 int iter = 0;
126 struct crypto_bignum *bn = NULL;
127 int order_len_bits = crypto_bignum_bits(sae->tmp->order);
128 size_t order_len = (order_len_bits + 7) / 8;
129
130 if (order_len > sizeof(val))
131 return NULL;
132
133 for (;;) {
Dmitry Shmidt41712582015-06-29 11:02:15 -0700134 if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800135 return NULL;
136 if (order_len_bits % 8)
137 buf_shift_right(val, order_len, 8 - order_len_bits % 8);
138 bn = crypto_bignum_init_set(val, order_len);
139 if (bn == NULL)
140 return NULL;
141 if (crypto_bignum_is_zero(bn) ||
142 crypto_bignum_is_one(bn) ||
Dmitry Shmidt71757432014-06-02 13:50:35 -0700143 crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
144 crypto_bignum_deinit(bn, 0);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800145 continue;
Dmitry Shmidt71757432014-06-02 13:50:35 -0700146 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800147 break;
148 }
149
150 os_memset(val, 0, order_len);
151 return bn;
152}
153
154
155static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
156{
157 crypto_bignum_deinit(sae->tmp->sae_rand, 1);
158 sae->tmp->sae_rand = sae_get_rand(sae);
159 if (sae->tmp->sae_rand == NULL)
160 return NULL;
161 return sae_get_rand(sae);
162}
163
164
165static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
166{
167 wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
168 " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
169 if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
170 os_memcpy(key, addr1, ETH_ALEN);
171 os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
172 } else {
173 os_memcpy(key, addr2, ETH_ALEN);
174 os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
175 }
176}
177
178
Dmitry Shmidt41712582015-06-29 11:02:15 -0700179static struct crypto_bignum *
180get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
181 int *r_odd)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800182{
Dmitry Shmidt41712582015-06-29 11:02:15 -0700183 for (;;) {
184 struct crypto_bignum *r;
185 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
186
187 if (random_get_bytes(tmp, prime_len) < 0)
188 break;
189 if (prime_bits % 8)
190 buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
191 if (os_memcmp(tmp, prime, prime_len) >= 0)
192 continue;
193 r = crypto_bignum_init_set(tmp, prime_len);
194 if (!r)
195 break;
196 if (crypto_bignum_is_zero(r)) {
197 crypto_bignum_deinit(r, 0);
198 continue;
199 }
200
201 *r_odd = tmp[prime_len - 1] & 0x01;
202 return r;
203 }
204
205 return NULL;
206}
207
208
209static int is_quadratic_residue_blind(struct sae_data *sae,
210 const u8 *prime, size_t bits,
211 const struct crypto_bignum *qr,
212 const struct crypto_bignum *qnr,
213 const struct crypto_bignum *y_sqr)
214{
215 struct crypto_bignum *r, *num;
216 int r_odd, check, res = -1;
217
218 /*
219 * Use the blinding technique to mask y_sqr while determining
220 * whether it is a quadratic residue modulo p to avoid leaking
221 * timing information while determining the Legendre symbol.
222 *
223 * v = y_sqr
224 * r = a random number between 1 and p-1, inclusive
225 * num = (v * r * r) modulo p
226 */
227 r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
228 if (!r)
229 return -1;
230
231 num = crypto_bignum_init();
232 if (!num ||
233 crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
234 crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
235 goto fail;
236
237 if (r_odd) {
238 /*
239 * num = (num * qr) module p
240 * LGR(num, p) = 1 ==> quadratic residue
241 */
242 if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
243 goto fail;
244 check = 1;
245 } else {
246 /*
247 * num = (num * qnr) module p
248 * LGR(num, p) = -1 ==> quadratic residue
249 */
250 if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
251 goto fail;
252 check = -1;
253 }
254
255 res = crypto_bignum_legendre(num, sae->tmp->prime);
256 if (res == -2) {
257 res = -1;
258 goto fail;
259 }
260 res = res == check;
261fail:
262 crypto_bignum_deinit(num, 1);
263 crypto_bignum_deinit(r, 1);
264 return res;
265}
266
267
268static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
269 const u8 *prime,
270 const struct crypto_bignum *qr,
271 const struct crypto_bignum *qnr,
272 struct crypto_bignum **ret_x_cand)
273{
274 u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
275 struct crypto_bignum *y_sqr, *x_cand;
276 int res;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800277 size_t bits;
278
Dmitry Shmidt41712582015-06-29 11:02:15 -0700279 *ret_x_cand = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800280
281 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
282
283 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
284 bits = crypto_ec_prime_len_bits(sae->tmp->ec);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700285 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
286 prime, sae->tmp->prime_len, pwd_value, bits) < 0)
287 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800288 if (bits % 8)
289 buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
290 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
291 pwd_value, sae->tmp->prime_len);
292
293 if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
294 return 0;
295
Dmitry Shmidt41712582015-06-29 11:02:15 -0700296 x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
297 if (!x_cand)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800298 return -1;
Dmitry Shmidt41712582015-06-29 11:02:15 -0700299 y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
300 if (!y_sqr) {
301 crypto_bignum_deinit(x_cand, 1);
302 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800303 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800304
Dmitry Shmidt41712582015-06-29 11:02:15 -0700305 res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
306 crypto_bignum_deinit(y_sqr, 1);
307 if (res <= 0) {
308 crypto_bignum_deinit(x_cand, 1);
309 return res;
310 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800311
Dmitry Shmidt41712582015-06-29 11:02:15 -0700312 *ret_x_cand = x_cand;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800313 return 1;
314}
315
316
317static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
318 struct crypto_bignum *pwe)
319{
320 u8 pwd_value[SAE_MAX_PRIME_LEN];
321 size_t bits = sae->tmp->prime_len * 8;
322 u8 exp[1];
323 struct crypto_bignum *a, *b;
324 int res;
325
326 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
327
328 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
Dmitry Shmidte4663042016-04-04 10:07:49 -0700329 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
330 sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
331 bits) < 0)
332 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800333 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
334 sae->tmp->prime_len);
335
336 if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
337 {
338 wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
339 return 0;
340 }
341
342 /* PWE = pwd-value^((p-1)/r) modulo p */
343
344 a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
345
346 if (sae->tmp->dh->safe_prime) {
347 /*
348 * r = (p-1)/2 for the group used here, so this becomes:
349 * PWE = pwd-value^2 modulo p
350 */
351 exp[0] = 2;
352 b = crypto_bignum_init_set(exp, sizeof(exp));
353 } else {
354 /* Calculate exponent: (p-1)/r */
355 exp[0] = 1;
356 b = crypto_bignum_init_set(exp, sizeof(exp));
357 if (b == NULL ||
358 crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
359 crypto_bignum_div(b, sae->tmp->order, b) < 0) {
360 crypto_bignum_deinit(b, 0);
361 b = NULL;
362 }
363 }
364
365 if (a == NULL || b == NULL)
366 res = -1;
367 else
368 res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
369
370 crypto_bignum_deinit(a, 0);
371 crypto_bignum_deinit(b, 0);
372
373 if (res < 0) {
374 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
375 return -1;
376 }
377
378 /* if (PWE > 1) --> found */
379 if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
380 wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
381 return 0;
382 }
383
384 wpa_printf(MSG_DEBUG, "SAE: PWE found");
385 return 1;
386}
387
388
Dmitry Shmidt41712582015-06-29 11:02:15 -0700389static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
390 const struct crypto_bignum *prime_bn,
391 size_t prime_bits, struct crypto_bignum **qr,
392 struct crypto_bignum **qnr)
393{
394 *qr = NULL;
395 *qnr = NULL;
396
397 while (!(*qr) || !(*qnr)) {
398 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
399 struct crypto_bignum *q;
400 int res;
401
402 if (random_get_bytes(tmp, prime_len) < 0)
403 break;
404 if (prime_bits % 8)
405 buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
406 if (os_memcmp(tmp, prime, prime_len) >= 0)
407 continue;
408 q = crypto_bignum_init_set(tmp, prime_len);
409 if (!q)
410 break;
411 res = crypto_bignum_legendre(q, prime_bn);
412
413 if (res == 1 && !(*qr))
414 *qr = q;
415 else if (res == -1 && !(*qnr))
416 *qnr = q;
417 else
418 crypto_bignum_deinit(q, 0);
419 }
420
421 return (*qr && *qnr) ? 0 : -1;
422}
423
424
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800425static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
426 const u8 *addr2, const u8 *password,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700427 size_t password_len, const char *identifier)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800428{
Dmitry Shmidt41712582015-06-29 11:02:15 -0700429 u8 counter, k = 40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800430 u8 addrs[2 * ETH_ALEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -0700431 const u8 *addr[3];
432 size_t len[3];
433 size_t num_elem;
Dmitry Shmidt41712582015-06-29 11:02:15 -0700434 u8 dummy_password[32];
435 size_t dummy_password_len;
436 int pwd_seed_odd = 0;
437 u8 prime[SAE_MAX_ECC_PRIME_LEN];
438 size_t prime_len;
439 struct crypto_bignum *x = NULL, *qr, *qnr;
440 size_t bits;
441 int res;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800442
Dmitry Shmidt41712582015-06-29 11:02:15 -0700443 dummy_password_len = password_len;
444 if (dummy_password_len > sizeof(dummy_password))
445 dummy_password_len = sizeof(dummy_password);
446 if (random_get_bytes(dummy_password, dummy_password_len) < 0)
447 return -1;
448
449 prime_len = sae->tmp->prime_len;
450 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
451 prime_len) < 0)
452 return -1;
453 bits = crypto_ec_prime_len_bits(sae->tmp->ec);
454
455 /*
456 * Create a random quadratic residue (qr) and quadratic non-residue
457 * (qnr) modulo p for blinding purposes during the loop.
458 */
459 if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
460 &qr, &qnr) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800461 return -1;
462
463 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
464 password, password_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700465 if (identifier)
466 wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
467 identifier);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800468
469 /*
470 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700471 * base = password [|| identifier]
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800472 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
Dmitry Shmidt41712582015-06-29 11:02:15 -0700473 * base || counter)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800474 */
475 sae_pwd_seed_key(addr1, addr2, addrs);
476
477 addr[0] = password;
478 len[0] = password_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700479 num_elem = 1;
480 if (identifier) {
481 addr[num_elem] = (const u8 *) identifier;
482 len[num_elem] = os_strlen(identifier);
483 num_elem++;
484 }
485 addr[num_elem] = &counter;
486 len[num_elem] = sizeof(counter);
487 num_elem++;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800488
489 /*
490 * Continue for at least k iterations to protect against side-channel
491 * attacks that attempt to determine the number of iterations required
492 * in the loop.
493 */
Dmitry Shmidt41712582015-06-29 11:02:15 -0700494 for (counter = 1; counter <= k || !x; counter++) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800495 u8 pwd_seed[SHA256_MAC_LEN];
Dmitry Shmidt41712582015-06-29 11:02:15 -0700496 struct crypto_bignum *x_cand;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800497
498 if (counter > 200) {
499 /* This should not happen in practice */
500 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
501 break;
502 }
503
504 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700505 if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
506 addr, len, pwd_seed) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800507 break;
Dmitry Shmidt41712582015-06-29 11:02:15 -0700508
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800509 res = sae_test_pwd_seed_ecc(sae, pwd_seed,
Dmitry Shmidt41712582015-06-29 11:02:15 -0700510 prime, qr, qnr, &x_cand);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800511 if (res < 0)
Dmitry Shmidt41712582015-06-29 11:02:15 -0700512 goto fail;
513 if (res > 0 && !x) {
514 wpa_printf(MSG_DEBUG,
515 "SAE: Selected pwd-seed with counter %u",
516 counter);
517 x = x_cand;
518 pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
519 os_memset(pwd_seed, 0, sizeof(pwd_seed));
520
521 /*
522 * Use a dummy password for the following rounds, if
523 * any.
524 */
525 addr[0] = dummy_password;
526 len[0] = dummy_password_len;
527 } else if (res > 0) {
528 crypto_bignum_deinit(x_cand, 1);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800529 }
530 }
531
Dmitry Shmidt41712582015-06-29 11:02:15 -0700532 if (!x) {
533 wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
534 res = -1;
535 goto fail;
536 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800537
Dmitry Shmidt41712582015-06-29 11:02:15 -0700538 if (!sae->tmp->pwe_ecc)
539 sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
540 if (!sae->tmp->pwe_ecc)
541 res = -1;
542 else
543 res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
544 sae->tmp->pwe_ecc, x,
545 pwd_seed_odd);
546 crypto_bignum_deinit(x, 1);
547 if (res < 0) {
548 /*
549 * This should not happen since we already checked that there
550 * is a result.
551 */
552 wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
553 }
554
555fail:
556 crypto_bignum_deinit(qr, 0);
557 crypto_bignum_deinit(qnr, 0);
558
559 return res;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800560}
561
562
563static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
564 const u8 *addr2, const u8 *password,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700565 size_t password_len, const char *identifier)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800566{
567 u8 counter;
568 u8 addrs[2 * ETH_ALEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -0700569 const u8 *addr[3];
570 size_t len[3];
571 size_t num_elem;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800572 int found = 0;
573
574 if (sae->tmp->pwe_ffc == NULL) {
575 sae->tmp->pwe_ffc = crypto_bignum_init();
576 if (sae->tmp->pwe_ffc == NULL)
577 return -1;
578 }
579
580 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
581 password, password_len);
582
583 /*
584 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
585 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700586 * password [|| identifier] || counter)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800587 */
588 sae_pwd_seed_key(addr1, addr2, addrs);
589
590 addr[0] = password;
591 len[0] = password_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700592 num_elem = 1;
593 if (identifier) {
594 addr[num_elem] = (const u8 *) identifier;
595 len[num_elem] = os_strlen(identifier);
596 num_elem++;
597 }
598 addr[num_elem] = &counter;
599 len[num_elem] = sizeof(counter);
600 num_elem++;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800601
602 for (counter = 1; !found; counter++) {
603 u8 pwd_seed[SHA256_MAC_LEN];
604 int res;
605
606 if (counter > 200) {
607 /* This should not happen in practice */
608 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
609 break;
610 }
611
612 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700613 if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
614 addr, len, pwd_seed) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800615 break;
616 res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
617 if (res < 0)
618 break;
619 if (res > 0) {
620 wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
621 found = 1;
622 }
623 }
624
625 return found ? 0 : -1;
626}
627
628
629static int sae_derive_commit_element_ecc(struct sae_data *sae,
630 struct crypto_bignum *mask)
631{
632 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
633 if (!sae->tmp->own_commit_element_ecc) {
634 sae->tmp->own_commit_element_ecc =
635 crypto_ec_point_init(sae->tmp->ec);
636 if (!sae->tmp->own_commit_element_ecc)
637 return -1;
638 }
639
640 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
641 sae->tmp->own_commit_element_ecc) < 0 ||
642 crypto_ec_point_invert(sae->tmp->ec,
643 sae->tmp->own_commit_element_ecc) < 0) {
644 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
645 return -1;
646 }
647
648 return 0;
649}
650
651
652static int sae_derive_commit_element_ffc(struct sae_data *sae,
653 struct crypto_bignum *mask)
654{
655 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
656 if (!sae->tmp->own_commit_element_ffc) {
657 sae->tmp->own_commit_element_ffc = crypto_bignum_init();
658 if (!sae->tmp->own_commit_element_ffc)
659 return -1;
660 }
661
662 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
663 sae->tmp->own_commit_element_ffc) < 0 ||
664 crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
665 sae->tmp->prime,
666 sae->tmp->own_commit_element_ffc) < 0) {
667 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
668 return -1;
669 }
670
671 return 0;
672}
673
674
675static int sae_derive_commit(struct sae_data *sae)
676{
677 struct crypto_bignum *mask;
678 int ret = -1;
Dmitry Shmidt41712582015-06-29 11:02:15 -0700679 unsigned int counter = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800680
Dmitry Shmidt41712582015-06-29 11:02:15 -0700681 do {
682 counter++;
683 if (counter > 100) {
684 /*
685 * This cannot really happen in practice if the random
686 * number generator is working. Anyway, to avoid even a
687 * theoretical infinite loop, break out after 100
688 * attemps.
689 */
690 return -1;
691 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800692
Dmitry Shmidt41712582015-06-29 11:02:15 -0700693 mask = sae_get_rand_and_mask(sae);
694 if (mask == NULL) {
695 wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
696 return -1;
697 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800698
Dmitry Shmidt41712582015-06-29 11:02:15 -0700699 /* commit-scalar = (rand + mask) modulo r */
700 if (!sae->tmp->own_commit_scalar) {
701 sae->tmp->own_commit_scalar = crypto_bignum_init();
702 if (!sae->tmp->own_commit_scalar)
703 goto fail;
704 }
705 crypto_bignum_add(sae->tmp->sae_rand, mask,
706 sae->tmp->own_commit_scalar);
707 crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
708 sae->tmp->own_commit_scalar);
709 } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
710 crypto_bignum_is_one(sae->tmp->own_commit_scalar));
711
712 if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
713 (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800714 goto fail;
715
716 ret = 0;
717fail:
718 crypto_bignum_deinit(mask, 1);
719 return ret;
720}
721
722
723int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
724 const u8 *password, size_t password_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700725 const char *identifier, struct sae_data *sae)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800726{
Dmitry Shmidt41712582015-06-29 11:02:15 -0700727 if (sae->tmp == NULL ||
728 (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700729 password_len,
730 identifier) < 0) ||
Dmitry Shmidt41712582015-06-29 11:02:15 -0700731 (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700732 password_len,
733 identifier) < 0) ||
Dmitry Shmidt41712582015-06-29 11:02:15 -0700734 sae_derive_commit(sae) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800735 return -1;
736 return 0;
737}
738
739
740static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
741{
742 struct crypto_ec_point *K;
743 int ret = -1;
744
745 K = crypto_ec_point_init(sae->tmp->ec);
746 if (K == NULL)
747 goto fail;
748
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800749 /*
750 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
751 * PEER-COMMIT-ELEMENT)))
752 * If K is identity element (point-at-infinity), reject
753 * k = F(K) (= x coordinate)
754 */
755
756 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
757 sae->peer_commit_scalar, K) < 0 ||
758 crypto_ec_point_add(sae->tmp->ec, K,
759 sae->tmp->peer_commit_element_ecc, K) < 0 ||
760 crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
761 crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
762 crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
763 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
764 goto fail;
765 }
766
767 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
768
769 ret = 0;
770fail:
771 crypto_ec_point_deinit(K, 1);
772 return ret;
773}
774
775
776static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
777{
778 struct crypto_bignum *K;
779 int ret = -1;
780
781 K = crypto_bignum_init();
782 if (K == NULL)
783 goto fail;
784
785 /*
786 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
787 * PEER-COMMIT-ELEMENT)))
788 * If K is identity element (one), reject.
789 * k = F(K) (= x coordinate)
790 */
791
792 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
793 sae->tmp->prime, K) < 0 ||
794 crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
795 sae->tmp->prime, K) < 0 ||
796 crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
797 ||
798 crypto_bignum_is_one(K) ||
799 crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
800 0) {
801 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
802 goto fail;
803 }
804
805 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
806
807 ret = 0;
808fail:
809 crypto_bignum_deinit(K, 1);
810 return ret;
811}
812
813
814static int sae_derive_keys(struct sae_data *sae, const u8 *k)
815{
816 u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
817 u8 keyseed[SHA256_MAC_LEN];
818 u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
819 struct crypto_bignum *tmp;
820 int ret = -1;
821
822 tmp = crypto_bignum_init();
823 if (tmp == NULL)
824 goto fail;
825
826 /* keyseed = H(<0>32, k)
827 * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
828 * (commit-scalar + peer-commit-scalar) modulo r)
829 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
830 */
831
832 os_memset(null_key, 0, sizeof(null_key));
833 hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
834 keyseed);
835 wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
836
837 crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
838 tmp);
839 crypto_bignum_mod(tmp, sae->tmp->order, tmp);
840 crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
841 wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700842 if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
843 val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
844 goto fail;
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800845 os_memset(keyseed, 0, sizeof(keyseed));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800846 os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
847 os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
Dmitry Shmidtd97138d2015-12-28 13:27:49 -0800848 os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800849 os_memset(keys, 0, sizeof(keys));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800850 wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
851 wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
852
853 ret = 0;
854fail:
855 crypto_bignum_deinit(tmp, 0);
856 return ret;
857}
858
859
860int sae_process_commit(struct sae_data *sae)
861{
862 u8 k[SAE_MAX_PRIME_LEN];
Dmitry Shmidt96be6222014-02-13 10:16:51 -0800863 if (sae->tmp == NULL ||
864 (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800865 (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
866 sae_derive_keys(sae, k) < 0)
867 return -1;
868 return 0;
869}
870
871
872void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700873 const struct wpabuf *token, const char *identifier)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800874{
875 u8 *pos;
Dmitry Shmidt96be6222014-02-13 10:16:51 -0800876
877 if (sae->tmp == NULL)
878 return;
879
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800880 wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800881 if (token) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800882 wpabuf_put_buf(buf, token);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800883 wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
884 wpabuf_head(token), wpabuf_len(token));
885 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800886 pos = wpabuf_put(buf, sae->tmp->prime_len);
887 crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
888 sae->tmp->prime_len, sae->tmp->prime_len);
889 wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
890 pos, sae->tmp->prime_len);
891 if (sae->tmp->ec) {
892 pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
893 crypto_ec_point_to_bin(sae->tmp->ec,
894 sae->tmp->own_commit_element_ecc,
895 pos, pos + sae->tmp->prime_len);
896 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
897 pos, sae->tmp->prime_len);
898 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
899 pos + sae->tmp->prime_len, sae->tmp->prime_len);
900 } else {
901 pos = wpabuf_put(buf, sae->tmp->prime_len);
902 crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
903 sae->tmp->prime_len, sae->tmp->prime_len);
904 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
905 pos, sae->tmp->prime_len);
906 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700907
908 if (identifier) {
909 /* Password Identifier element */
910 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
911 wpabuf_put_u8(buf, 1 + os_strlen(identifier));
912 wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
913 wpabuf_put_str(buf, identifier);
914 wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
915 identifier);
916 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800917}
918
919
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800920u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800921{
922 if (allowed_groups) {
923 int i;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800924 for (i = 0; allowed_groups[i] > 0; i++) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800925 if (allowed_groups[i] == group)
926 break;
927 }
928 if (allowed_groups[i] != group) {
929 wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
930 "enabled in the current configuration",
931 group);
932 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
933 }
934 }
935
936 if (sae->state == SAE_COMMITTED && group != sae->group) {
937 wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
938 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
939 }
940
941 if (group != sae->group && sae_set_group(sae, group) < 0) {
942 wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
943 group);
944 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
945 }
946
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800947 if (sae->tmp == NULL) {
948 wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
949 return WLAN_STATUS_UNSPECIFIED_FAILURE;
950 }
951
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800952 if (sae->tmp->dh && !allowed_groups) {
953 wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
954 "explicit configuration enabling it", group);
955 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
956 }
957
958 return WLAN_STATUS_SUCCESS;
959}
960
961
Roshan Pius3a1667e2018-07-03 15:17:14 -0700962static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
963{
964 return end - pos >= 3 &&
965 pos[0] == WLAN_EID_EXTENSION &&
966 pos[1] >= 1 &&
967 end - pos - 2 >= pos[1] &&
968 pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
969}
970
971
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800972static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
973 const u8 *end, const u8 **token,
974 size_t *token_len)
975{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700976 size_t scalar_elem_len, tlen;
977 const u8 *elem;
978
979 if (token)
980 *token = NULL;
981 if (token_len)
982 *token_len = 0;
983
984 scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
985 if (scalar_elem_len >= (size_t) (end - *pos))
986 return; /* No extra data beyond peer scalar and element */
987
988 /* It is a bit difficult to parse this now that there is an
989 * optional variable length Anti-Clogging Token field and
990 * optional variable length Password Identifier element in the
991 * frame. We are sending out fixed length Anti-Clogging Token
992 * fields, so use that length as a requirement for the received
993 * token and check for the presence of possible Password
994 * Identifier element based on the element header information.
995 */
996 tlen = end - (*pos + scalar_elem_len);
997
998 if (tlen < SHA256_MAC_LEN) {
999 wpa_printf(MSG_DEBUG,
1000 "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
1001 (unsigned int) tlen);
1002 return;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001003 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001004
1005 elem = *pos + scalar_elem_len;
1006 if (sae_is_password_id_elem(elem, end)) {
1007 /* Password Identifier element takes out all available
1008 * extra octets, so there can be no Anti-Clogging token in
1009 * this frame. */
1010 return;
1011 }
1012
1013 elem += SHA256_MAC_LEN;
1014 if (sae_is_password_id_elem(elem, end)) {
1015 /* Password Identifier element is included in the end, so
1016 * remove its length from the Anti-Clogging token field. */
1017 tlen -= 2 + elem[1];
1018 }
1019
1020 wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
1021 if (token)
1022 *token = *pos;
1023 if (token_len)
1024 *token_len = tlen;
1025 *pos += tlen;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001026}
1027
1028
1029static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
1030 const u8 *end)
1031{
1032 struct crypto_bignum *peer_scalar;
1033
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001034 if (sae->tmp->prime_len > end - *pos) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001035 wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
1036 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1037 }
1038
1039 peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1040 if (peer_scalar == NULL)
1041 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1042
1043 /*
1044 * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
1045 * the peer and it is in Authenticated state, the new Commit Message
1046 * shall be dropped if the peer-scalar is identical to the one used in
1047 * the existing protocol instance.
1048 */
1049 if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
1050 crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
1051 wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
1052 "peer-commit-scalar");
1053 crypto_bignum_deinit(peer_scalar, 0);
1054 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1055 }
1056
Dmitry Shmidt41712582015-06-29 11:02:15 -07001057 /* 1 < scalar < r */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001058 if (crypto_bignum_is_zero(peer_scalar) ||
Dmitry Shmidt41712582015-06-29 11:02:15 -07001059 crypto_bignum_is_one(peer_scalar) ||
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001060 crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
1061 wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
1062 crypto_bignum_deinit(peer_scalar, 0);
1063 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1064 }
1065
1066
1067 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
1068 sae->peer_commit_scalar = peer_scalar;
1069 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
1070 *pos, sae->tmp->prime_len);
1071 *pos += sae->tmp->prime_len;
1072
1073 return WLAN_STATUS_SUCCESS;
1074}
1075
1076
Roshan Pius3a1667e2018-07-03 15:17:14 -07001077static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001078 const u8 *end)
1079{
1080 u8 prime[SAE_MAX_ECC_PRIME_LEN];
1081
Roshan Pius3a1667e2018-07-03 15:17:14 -07001082 if (2 * sae->tmp->prime_len > end - *pos) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001083 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1084 "commit-element");
1085 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1086 }
1087
1088 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
1089 sae->tmp->prime_len) < 0)
1090 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1091
1092 /* element x and y coordinates < p */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001093 if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
1094 os_memcmp(*pos + sae->tmp->prime_len, prime,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001095 sae->tmp->prime_len) >= 0) {
1096 wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
1097 "element");
1098 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1099 }
1100
1101 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001102 *pos, sae->tmp->prime_len);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001103 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001104 *pos + sae->tmp->prime_len, sae->tmp->prime_len);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001105
1106 crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
1107 sae->tmp->peer_commit_element_ecc =
Roshan Pius3a1667e2018-07-03 15:17:14 -07001108 crypto_ec_point_from_bin(sae->tmp->ec, *pos);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001109 if (sae->tmp->peer_commit_element_ecc == NULL)
1110 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1111
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001112 if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
1113 sae->tmp->peer_commit_element_ecc)) {
1114 wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
1115 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1116 }
1117
Roshan Pius3a1667e2018-07-03 15:17:14 -07001118 *pos += 2 * sae->tmp->prime_len;
1119
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001120 return WLAN_STATUS_SUCCESS;
1121}
1122
1123
Roshan Pius3a1667e2018-07-03 15:17:14 -07001124static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001125 const u8 *end)
1126{
Dmitry Shmidt41712582015-06-29 11:02:15 -07001127 struct crypto_bignum *res, *one;
1128 const u8 one_bin[1] = { 0x01 };
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001129
Roshan Pius3a1667e2018-07-03 15:17:14 -07001130 if (sae->tmp->prime_len > end - *pos) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001131 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1132 "commit-element");
1133 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1134 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001135 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001136 sae->tmp->prime_len);
1137
1138 crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
1139 sae->tmp->peer_commit_element_ffc =
Roshan Pius3a1667e2018-07-03 15:17:14 -07001140 crypto_bignum_init_set(*pos, sae->tmp->prime_len);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001141 if (sae->tmp->peer_commit_element_ffc == NULL)
1142 return WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001143 /* 1 < element < p - 1 */
1144 res = crypto_bignum_init();
1145 one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
1146 if (!res || !one ||
1147 crypto_bignum_sub(sae->tmp->prime, one, res) ||
1148 crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001149 crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
Dmitry Shmidt41712582015-06-29 11:02:15 -07001150 crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
1151 crypto_bignum_deinit(res, 0);
1152 crypto_bignum_deinit(one, 0);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001153 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
1154 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1155 }
Dmitry Shmidt41712582015-06-29 11:02:15 -07001156 crypto_bignum_deinit(one, 0);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001157
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001158 /* scalar-op(r, ELEMENT) = 1 modulo p */
Dmitry Shmidt41712582015-06-29 11:02:15 -07001159 if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001160 sae->tmp->order, sae->tmp->prime, res) < 0 ||
1161 !crypto_bignum_is_one(res)) {
1162 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
1163 crypto_bignum_deinit(res, 0);
1164 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1165 }
1166 crypto_bignum_deinit(res, 0);
1167
Roshan Pius3a1667e2018-07-03 15:17:14 -07001168 *pos += sae->tmp->prime_len;
1169
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001170 return WLAN_STATUS_SUCCESS;
1171}
1172
1173
Roshan Pius3a1667e2018-07-03 15:17:14 -07001174static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001175 const u8 *end)
1176{
1177 if (sae->tmp->dh)
1178 return sae_parse_commit_element_ffc(sae, pos, end);
1179 return sae_parse_commit_element_ecc(sae, pos, end);
1180}
1181
1182
Roshan Pius3a1667e2018-07-03 15:17:14 -07001183static int sae_parse_password_identifier(struct sae_data *sae,
1184 const u8 *pos, const u8 *end)
1185{
1186 wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
1187 pos, end - pos);
1188 if (!sae_is_password_id_elem(pos, end)) {
1189 if (sae->tmp->pw_id) {
1190 wpa_printf(MSG_DEBUG,
1191 "SAE: No Password Identifier included, but expected one (%s)",
1192 sae->tmp->pw_id);
1193 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1194 }
1195 os_free(sae->tmp->pw_id);
1196 sae->tmp->pw_id = NULL;
1197 return WLAN_STATUS_SUCCESS; /* No Password Identifier */
1198 }
1199
1200 if (sae->tmp->pw_id &&
1201 (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
1202 os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
1203 wpa_printf(MSG_DEBUG,
1204 "SAE: The included Password Identifier does not match the expected one (%s)",
1205 sae->tmp->pw_id);
1206 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1207 }
1208
1209 os_free(sae->tmp->pw_id);
1210 sae->tmp->pw_id = os_malloc(pos[1]);
1211 if (!sae->tmp->pw_id)
1212 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1213 os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
1214 sae->tmp->pw_id[pos[1] - 1] = '\0';
1215 wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
1216 sae->tmp->pw_id, pos[1] - 1);
1217 return WLAN_STATUS_SUCCESS;
1218}
1219
1220
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001221u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
1222 const u8 **token, size_t *token_len, int *allowed_groups)
1223{
1224 const u8 *pos = data, *end = data + len;
1225 u16 res;
1226
1227 /* Check Finite Cyclic Group */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001228 if (end - pos < 2)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001229 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1230 res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
1231 if (res != WLAN_STATUS_SUCCESS)
1232 return res;
1233 pos += 2;
1234
1235 /* Optional Anti-Clogging Token */
1236 sae_parse_commit_token(sae, &pos, end, token, token_len);
1237
1238 /* commit-scalar */
1239 res = sae_parse_commit_scalar(sae, &pos, end);
1240 if (res != WLAN_STATUS_SUCCESS)
1241 return res;
1242
1243 /* commit-element */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001244 res = sae_parse_commit_element(sae, &pos, end);
1245 if (res != WLAN_STATUS_SUCCESS)
1246 return res;
1247
1248 /* Optional Password Identifier element */
1249 res = sae_parse_password_identifier(sae, pos, end);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001250 if (res != WLAN_STATUS_SUCCESS)
1251 return res;
1252
1253 /*
1254 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
1255 * the values we sent which would be evidence of a reflection attack.
1256 */
1257 if (!sae->tmp->own_commit_scalar ||
1258 crypto_bignum_cmp(sae->tmp->own_commit_scalar,
1259 sae->peer_commit_scalar) != 0 ||
1260 (sae->tmp->dh &&
1261 (!sae->tmp->own_commit_element_ffc ||
1262 crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
1263 sae->tmp->peer_commit_element_ffc) != 0)) ||
1264 (sae->tmp->ec &&
1265 (!sae->tmp->own_commit_element_ecc ||
1266 crypto_ec_point_cmp(sae->tmp->ec,
1267 sae->tmp->own_commit_element_ecc,
1268 sae->tmp->peer_commit_element_ecc) != 0)))
1269 return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
1270
1271 /*
1272 * This is a reflection attack - return special value to trigger caller
1273 * to silently discard the frame instead of replying with a specific
1274 * status code.
1275 */
1276 return SAE_SILENTLY_DISCARD;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001277}
1278
1279
1280static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
1281 const struct crypto_bignum *scalar1,
1282 const u8 *element1, size_t element1_len,
1283 const struct crypto_bignum *scalar2,
1284 const u8 *element2, size_t element2_len,
1285 u8 *confirm)
1286{
1287 const u8 *addr[5];
1288 size_t len[5];
1289 u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
1290
1291 /* Confirm
1292 * CN(key, X, Y, Z, ...) =
1293 * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
1294 * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
1295 * peer-commit-scalar, PEER-COMMIT-ELEMENT)
1296 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
1297 * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
1298 */
1299 addr[0] = sc;
1300 len[0] = 2;
1301 crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
1302 sae->tmp->prime_len);
1303 addr[1] = scalar_b1;
1304 len[1] = sae->tmp->prime_len;
1305 addr[2] = element1;
1306 len[2] = element1_len;
1307 crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
1308 sae->tmp->prime_len);
1309 addr[3] = scalar_b2;
1310 len[3] = sae->tmp->prime_len;
1311 addr[4] = element2;
1312 len[4] = element2_len;
1313 hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
1314 confirm);
1315}
1316
1317
1318static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
1319 const struct crypto_bignum *scalar1,
1320 const struct crypto_ec_point *element1,
1321 const struct crypto_bignum *scalar2,
1322 const struct crypto_ec_point *element2,
1323 u8 *confirm)
1324{
1325 u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
1326 u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
1327
1328 crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
1329 element_b1 + sae->tmp->prime_len);
1330 crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
1331 element_b2 + sae->tmp->prime_len);
1332
1333 sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
1334 scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
1335}
1336
1337
1338static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
1339 const struct crypto_bignum *scalar1,
1340 const struct crypto_bignum *element1,
1341 const struct crypto_bignum *scalar2,
1342 const struct crypto_bignum *element2,
1343 u8 *confirm)
1344{
1345 u8 element_b1[SAE_MAX_PRIME_LEN];
1346 u8 element_b2[SAE_MAX_PRIME_LEN];
1347
1348 crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
1349 sae->tmp->prime_len);
1350 crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
1351 sae->tmp->prime_len);
1352
1353 sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
1354 scalar2, element_b2, sae->tmp->prime_len, confirm);
1355}
1356
1357
1358void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
1359{
1360 const u8 *sc;
1361
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001362 if (sae->tmp == NULL)
1363 return;
1364
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001365 /* Send-Confirm */
1366 sc = wpabuf_put(buf, 0);
1367 wpabuf_put_le16(buf, sae->send_confirm);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001368 if (sae->send_confirm < 0xffff)
1369 sae->send_confirm++;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001370
1371 if (sae->tmp->ec)
1372 sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
1373 sae->tmp->own_commit_element_ecc,
1374 sae->peer_commit_scalar,
1375 sae->tmp->peer_commit_element_ecc,
1376 wpabuf_put(buf, SHA256_MAC_LEN));
1377 else
1378 sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
1379 sae->tmp->own_commit_element_ffc,
1380 sae->peer_commit_scalar,
1381 sae->tmp->peer_commit_element_ffc,
1382 wpabuf_put(buf, SHA256_MAC_LEN));
1383}
1384
1385
1386int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
1387{
1388 u8 verifier[SHA256_MAC_LEN];
1389
1390 if (len < 2 + SHA256_MAC_LEN) {
1391 wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
1392 return -1;
1393 }
1394
1395 wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
1396
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001397 if (sae->tmp == NULL) {
1398 wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
1399 return -1;
1400 }
1401
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001402 if (sae->tmp->ec)
1403 sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
1404 sae->tmp->peer_commit_element_ecc,
1405 sae->tmp->own_commit_scalar,
1406 sae->tmp->own_commit_element_ecc,
1407 verifier);
1408 else
1409 sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
1410 sae->tmp->peer_commit_element_ffc,
1411 sae->tmp->own_commit_scalar,
1412 sae->tmp->own_commit_element_ffc,
1413 verifier);
1414
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001415 if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001416 wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
1417 wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
1418 data + 2, SHA256_MAC_LEN);
1419 wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
1420 verifier, SHA256_MAC_LEN);
1421 return -1;
1422 }
1423
1424 return 0;
1425}
Roshan Pius3a1667e2018-07-03 15:17:14 -07001426
1427
1428const char * sae_state_txt(enum sae_state state)
1429{
1430 switch (state) {
1431 case SAE_NOTHING:
1432 return "Nothing";
1433 case SAE_COMMITTED:
1434 return "Committed";
1435 case SAE_CONFIRMED:
1436 return "Confirmed";
1437 case SAE_ACCEPTED:
1438 return "Accepted";
1439 }
1440 return "?";
1441}