xref: /dragonfly/contrib/wpa_supplicant/src/common/sae.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * Simultaneous authentication of equals
3  * Copyright (c) 2012-2016, 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 "utils/const_time.h"
13 #include "crypto/crypto.h"
14 #include "crypto/sha256.h"
15 #include "crypto/random.h"
16 #include "crypto/dh_groups.h"
17 #include "ieee802_11_defs.h"
18 #include "dragonfly.h"
19 #include "sae.h"
20 
21 
sae_set_group(struct sae_data * sae,int group)22 int sae_set_group(struct sae_data *sae, int group)
23 {
24           struct sae_temporary_data *tmp;
25 
26 #ifdef CONFIG_TESTING_OPTIONS
27           /* Allow all groups for testing purposes in non-production builds. */
28 #else /* CONFIG_TESTING_OPTIONS */
29           if (!dragonfly_suitable_group(group, 0)) {
30                     wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
31                     return -1;
32           }
33 #endif /* CONFIG_TESTING_OPTIONS */
34 
35           sae_clear_data(sae);
36           tmp = sae->tmp = os_zalloc(sizeof(*tmp));
37           if (tmp == NULL)
38                     return -1;
39 
40           /* First, check if this is an ECC group */
41           tmp->ec = crypto_ec_init(group);
42           if (tmp->ec) {
43                     wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
44                                  group);
45                     sae->group = group;
46                     tmp->prime_len = crypto_ec_prime_len(tmp->ec);
47                     tmp->prime = crypto_ec_get_prime(tmp->ec);
48                     tmp->order_len = crypto_ec_order_len(tmp->ec);
49                     tmp->order = crypto_ec_get_order(tmp->ec);
50                     return 0;
51           }
52 
53           /* Not an ECC group, check FFC */
54           tmp->dh = dh_groups_get(group);
55           if (tmp->dh) {
56                     wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
57                                  group);
58                     sae->group = group;
59                     tmp->prime_len = tmp->dh->prime_len;
60                     if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
61                               sae_clear_data(sae);
62                               return -1;
63                     }
64 
65                     tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
66                                                                       tmp->prime_len);
67                     if (tmp->prime_buf == NULL) {
68                               sae_clear_data(sae);
69                               return -1;
70                     }
71                     tmp->prime = tmp->prime_buf;
72 
73                     tmp->order_len = tmp->dh->order_len;
74                     tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
75                                                                       tmp->dh->order_len);
76                     if (tmp->order_buf == NULL) {
77                               sae_clear_data(sae);
78                               return -1;
79                     }
80                     tmp->order = tmp->order_buf;
81 
82                     return 0;
83           }
84 
85           /* Unsupported group */
86           wpa_printf(MSG_DEBUG,
87                        "SAE: Group %d not supported by the crypto library", group);
88           return -1;
89 }
90 
91 
sae_clear_temp_data(struct sae_data * sae)92 void sae_clear_temp_data(struct sae_data *sae)
93 {
94           struct sae_temporary_data *tmp;
95           if (sae == NULL || sae->tmp == NULL)
96                     return;
97           tmp = sae->tmp;
98           crypto_ec_deinit(tmp->ec);
99           crypto_bignum_deinit(tmp->prime_buf, 0);
100           crypto_bignum_deinit(tmp->order_buf, 0);
101           crypto_bignum_deinit(tmp->sae_rand, 1);
102           crypto_bignum_deinit(tmp->pwe_ffc, 1);
103           crypto_bignum_deinit(tmp->own_commit_scalar, 0);
104           crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
105           crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
106           crypto_ec_point_deinit(tmp->pwe_ecc, 1);
107           crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
108           crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
109           wpabuf_free(tmp->anti_clogging_token);
110           os_free(tmp->pw_id);
111           bin_clear_free(tmp, sizeof(*tmp));
112           sae->tmp = NULL;
113 }
114 
115 
sae_clear_data(struct sae_data * sae)116 void sae_clear_data(struct sae_data *sae)
117 {
118           if (sae == NULL)
119                     return;
120           sae_clear_temp_data(sae);
121           crypto_bignum_deinit(sae->peer_commit_scalar, 0);
122           os_memset(sae, 0, sizeof(*sae));
123 }
124 
125 
sae_pwd_seed_key(const u8 * addr1,const u8 * addr2,u8 * key)126 static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
127 {
128           wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
129                        " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
130           if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
131                     os_memcpy(key, addr1, ETH_ALEN);
132                     os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
133           } else {
134                     os_memcpy(key, addr2, ETH_ALEN);
135                     os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
136           }
137 }
138 
139 
sae_test_pwd_seed_ecc(struct sae_data * sae,const u8 * pwd_seed,const u8 * prime,const u8 * qr,const u8 * qnr,u8 * pwd_value)140 static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
141                                          const u8 *prime, const u8 *qr, const u8 *qnr,
142                                          u8 *pwd_value)
143 {
144           struct crypto_bignum *y_sqr, *x_cand;
145           int res;
146           size_t bits;
147           int cmp_prime;
148           unsigned int in_range;
149 
150           wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
151 
152           /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
153           bits = crypto_ec_prime_len_bits(sae->tmp->ec);
154           if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
155                                   prime, sae->tmp->prime_len, pwd_value, bits) < 0)
156                     return -1;
157           if (bits % 8)
158                     buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
159           wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
160                               pwd_value, sae->tmp->prime_len);
161 
162           cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
163           /* Create a const_time mask for selection based on prf result
164            * being smaller than prime. */
165           in_range = const_time_fill_msb((unsigned int) cmp_prime);
166           /* The algorithm description would skip the next steps if
167            * cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
168            * minimize externally observable differences in behavior. */
169 
170           x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
171           if (!x_cand)
172                     return -1;
173           y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
174           crypto_bignum_deinit(x_cand, 1);
175           if (!y_sqr)
176                     return -1;
177 
178           res = dragonfly_is_quadratic_residue_blind(sae->tmp->ec, qr, qnr,
179                                                                y_sqr);
180           crypto_bignum_deinit(y_sqr, 1);
181           if (res < 0)
182                     return res;
183           return const_time_select_int(in_range, res, 0);
184 }
185 
186 
187 /* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
188  * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
sae_test_pwd_seed_ffc(struct sae_data * sae,const u8 * pwd_seed,struct crypto_bignum * pwe)189 static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
190                                          struct crypto_bignum *pwe)
191 {
192           u8 pwd_value[SAE_MAX_PRIME_LEN];
193           size_t bits = sae->tmp->prime_len * 8;
194           u8 exp[1];
195           struct crypto_bignum *a, *b = NULL;
196           int res, is_val;
197           u8 pwd_value_valid;
198 
199           wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
200 
201           /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
202           if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
203                                   sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
204                                   bits) < 0)
205                     return -1;
206           wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
207                               sae->tmp->prime_len);
208 
209           /* Check whether pwd-value < p */
210           res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
211                                         sae->tmp->prime_len);
212           /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
213            * the negative sign can be used to fill the mask for constant time
214            * selection */
215           pwd_value_valid = const_time_fill_msb(res);
216 
217           /* If pwd-value >= p, force pwd-value to be < p and perform the
218            * calculations anyway to hide timing difference. The derived PWE will
219            * be ignored in that case. */
220           pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
221 
222           /* PWE = pwd-value^((p-1)/r) modulo p */
223 
224           res = -1;
225           a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
226           if (!a)
227                     goto fail;
228 
229           /* This is an optimization based on the used group that does not depend
230            * on the password in any way, so it is fine to use separate branches
231            * for this step without constant time operations. */
232           if (sae->tmp->dh->safe_prime) {
233                     /*
234                      * r = (p-1)/2 for the group used here, so this becomes:
235                      * PWE = pwd-value^2 modulo p
236                      */
237                     exp[0] = 2;
238                     b = crypto_bignum_init_set(exp, sizeof(exp));
239           } else {
240                     /* Calculate exponent: (p-1)/r */
241                     exp[0] = 1;
242                     b = crypto_bignum_init_set(exp, sizeof(exp));
243                     if (b == NULL ||
244                         crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
245                         crypto_bignum_div(b, sae->tmp->order, b) < 0)
246                               goto fail;
247           }
248 
249           if (!b)
250                     goto fail;
251 
252           res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
253           if (res < 0)
254                     goto fail;
255 
256           /* There were no fatal errors in calculations, so determine the return
257            * value using constant time operations. We get here for number of
258            * invalid cases which are cleared here after having performed all the
259            * computation. PWE is valid if pwd-value was less than prime and
260            * PWE > 1. Start with pwd-value check first and then use constant time
261            * operations to clear res to 0 if PWE is 0 or 1.
262            */
263           res = const_time_select_u8(pwd_value_valid, 1, 0);
264           is_val = crypto_bignum_is_zero(pwe);
265           res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
266           is_val = crypto_bignum_is_one(pwe);
267           res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
268 
269 fail:
270           crypto_bignum_deinit(a, 1);
271           crypto_bignum_deinit(b, 1);
272           return res;
273 }
274 
275 
sae_derive_pwe_ecc(struct sae_data * sae,const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len,const char * identifier)276 static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
277                                     const u8 *addr2, const u8 *password,
278                                     size_t password_len, const char *identifier)
279 {
280           u8 counter, k;
281           u8 addrs[2 * ETH_ALEN];
282           const u8 *addr[3];
283           size_t len[3];
284           size_t num_elem;
285           u8 *dummy_password, *tmp_password;
286           int pwd_seed_odd = 0;
287           u8 prime[SAE_MAX_ECC_PRIME_LEN];
288           size_t prime_len;
289           struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
290           u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
291           u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
292           u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
293           u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
294           int res = -1;
295           u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
296                            * mask */
297 
298           os_memset(x_bin, 0, sizeof(x_bin));
299 
300           dummy_password = os_malloc(password_len);
301           tmp_password = os_malloc(password_len);
302           if (!dummy_password || !tmp_password ||
303               random_get_bytes(dummy_password, password_len) < 0)
304                     goto fail;
305 
306           prime_len = sae->tmp->prime_len;
307           if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
308                                          prime_len) < 0)
309                     goto fail;
310 
311           /*
312            * Create a random quadratic residue (qr) and quadratic non-residue
313            * (qnr) modulo p for blinding purposes during the loop.
314            */
315           if (dragonfly_get_random_qr_qnr(sae->tmp->prime, &qr, &qnr) < 0 ||
316               crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
317               crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
318                     goto fail;
319 
320           wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
321                                     password, password_len);
322           if (identifier)
323                     wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
324                                  identifier);
325 
326           /*
327            * H(salt, ikm) = HMAC-SHA256(salt, ikm)
328            * base = password [|| identifier]
329            * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
330            *              base || counter)
331            */
332           sae_pwd_seed_key(addr1, addr2, addrs);
333 
334           addr[0] = tmp_password;
335           len[0] = password_len;
336           num_elem = 1;
337           if (identifier) {
338                     addr[num_elem] = (const u8 *) identifier;
339                     len[num_elem] = os_strlen(identifier);
340                     num_elem++;
341           }
342           addr[num_elem] = &counter;
343           len[num_elem] = sizeof(counter);
344           num_elem++;
345 
346           /*
347            * Continue for at least k iterations to protect against side-channel
348            * attacks that attempt to determine the number of iterations required
349            * in the loop.
350            */
351           k = dragonfly_min_pwe_loop_iter(sae->group);
352 
353           for (counter = 1; counter <= k || !found; counter++) {
354                     u8 pwd_seed[SHA256_MAC_LEN];
355 
356                     if (counter > 200) {
357                               /* This should not happen in practice */
358                               wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
359                               break;
360                     }
361 
362                     wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
363                     const_time_select_bin(found, dummy_password, password,
364                                               password_len, tmp_password);
365                     if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
366                                                addr, len, pwd_seed) < 0)
367                               break;
368 
369                     res = sae_test_pwd_seed_ecc(sae, pwd_seed,
370                                                       prime, qr_bin, qnr_bin, x_cand_bin);
371                     const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
372                                               x_bin);
373                     pwd_seed_odd = const_time_select_u8(
374                               found, pwd_seed_odd,
375                               pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
376                     os_memset(pwd_seed, 0, sizeof(pwd_seed));
377                     if (res < 0)
378                               goto fail;
379                     /* Need to minimize differences in handling res == 0 and 1 here
380                      * to avoid differences in timing and instruction cache access,
381                      * so use const_time_select_*() to make local copies of the
382                      * values based on whether this loop iteration was the one that
383                      * found the pwd-seed/x. */
384 
385                     /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
386                      * (with res converted to 0/0xff) handles this in constant time.
387                      */
388                     found |= res * 0xff;
389                     wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x",
390                                  res, found);
391           }
392 
393           if (!found) {
394                     wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
395                     res = -1;
396                     goto fail;
397           }
398 
399           x = crypto_bignum_init_set(x_bin, prime_len);
400           if (!x) {
401                     res = -1;
402                     goto fail;
403           }
404 
405           if (!sae->tmp->pwe_ecc)
406                     sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
407           if (!sae->tmp->pwe_ecc)
408                     res = -1;
409           else
410                     res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
411                                                                 sae->tmp->pwe_ecc, x,
412                                                                 pwd_seed_odd);
413           if (res < 0) {
414                     /*
415                      * This should not happen since we already checked that there
416                      * is a result.
417                      */
418                     wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
419           }
420 
421 fail:
422           crypto_bignum_deinit(qr, 0);
423           crypto_bignum_deinit(qnr, 0);
424           os_free(dummy_password);
425           bin_clear_free(tmp_password, password_len);
426           crypto_bignum_deinit(x, 1);
427           os_memset(x_bin, 0, sizeof(x_bin));
428           os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
429 
430           return res;
431 }
432 
433 
sae_derive_pwe_ffc(struct sae_data * sae,const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len,const char * identifier)434 static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
435                                     const u8 *addr2, const u8 *password,
436                                     size_t password_len, const char *identifier)
437 {
438           u8 counter, k, sel_counter = 0;
439           u8 addrs[2 * ETH_ALEN];
440           const u8 *addr[3];
441           size_t len[3];
442           size_t num_elem;
443           u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
444                            * mask */
445           u8 mask;
446           struct crypto_bignum *pwe;
447           size_t prime_len = sae->tmp->prime_len * 8;
448           u8 *pwe_buf;
449 
450           crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
451           sae->tmp->pwe_ffc = NULL;
452 
453           /* Allocate a buffer to maintain selected and candidate PWE for constant
454            * time selection. */
455           pwe_buf = os_zalloc(prime_len * 2);
456           pwe = crypto_bignum_init();
457           if (!pwe_buf || !pwe)
458                     goto fail;
459 
460           wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
461                                     password, password_len);
462 
463           /*
464            * H(salt, ikm) = HMAC-SHA256(salt, ikm)
465            * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
466            *              password [|| identifier] || counter)
467            */
468           sae_pwd_seed_key(addr1, addr2, addrs);
469 
470           addr[0] = password;
471           len[0] = password_len;
472           num_elem = 1;
473           if (identifier) {
474                     addr[num_elem] = (const u8 *) identifier;
475                     len[num_elem] = os_strlen(identifier);
476                     num_elem++;
477           }
478           addr[num_elem] = &counter;
479           len[num_elem] = sizeof(counter);
480           num_elem++;
481 
482           k = dragonfly_min_pwe_loop_iter(sae->group);
483 
484           for (counter = 1; counter <= k || !found; counter++) {
485                     u8 pwd_seed[SHA256_MAC_LEN];
486                     int res;
487 
488                     if (counter > 200) {
489                               /* This should not happen in practice */
490                               wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
491                               break;
492                     }
493 
494                     wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
495                     if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
496                                                addr, len, pwd_seed) < 0)
497                               break;
498                     res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
499                     /* res is -1 for fatal failure, 0 if a valid PWE was not found,
500                      * or 1 if a valid PWE was found. */
501                     if (res < 0)
502                               break;
503                     /* Store the candidate PWE into the second half of pwe_buf and
504                      * the selected PWE in the beginning of pwe_buf using constant
505                      * time selection. */
506                     if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
507                                                    prime_len) < 0)
508                               break;
509                     const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
510                                               prime_len, pwe_buf);
511                     sel_counter = const_time_select_u8(found, sel_counter, counter);
512                     mask = const_time_eq_u8(res, 1);
513                     found = const_time_select_u8(found, found, mask);
514           }
515 
516           if (!found)
517                     goto fail;
518 
519           wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
520           sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
521 fail:
522           crypto_bignum_deinit(pwe, 1);
523           bin_clear_free(pwe_buf, prime_len * 2);
524           return sae->tmp->pwe_ffc ? 0 : -1;
525 }
526 
527 
sae_derive_commit_element_ecc(struct sae_data * sae,struct crypto_bignum * mask)528 static int sae_derive_commit_element_ecc(struct sae_data *sae,
529                                                    struct crypto_bignum *mask)
530 {
531           /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
532           if (!sae->tmp->own_commit_element_ecc) {
533                     sae->tmp->own_commit_element_ecc =
534                               crypto_ec_point_init(sae->tmp->ec);
535                     if (!sae->tmp->own_commit_element_ecc)
536                               return -1;
537           }
538 
539           if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
540                                         sae->tmp->own_commit_element_ecc) < 0 ||
541               crypto_ec_point_invert(sae->tmp->ec,
542                                            sae->tmp->own_commit_element_ecc) < 0) {
543                     wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
544                     return -1;
545           }
546 
547           return 0;
548 }
549 
550 
sae_derive_commit_element_ffc(struct sae_data * sae,struct crypto_bignum * mask)551 static int sae_derive_commit_element_ffc(struct sae_data *sae,
552                                                    struct crypto_bignum *mask)
553 {
554           /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
555           if (!sae->tmp->own_commit_element_ffc) {
556                     sae->tmp->own_commit_element_ffc = crypto_bignum_init();
557                     if (!sae->tmp->own_commit_element_ffc)
558                               return -1;
559           }
560 
561           if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
562                                           sae->tmp->own_commit_element_ffc) < 0 ||
563               crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
564                                           sae->tmp->prime,
565                                           sae->tmp->own_commit_element_ffc) < 0) {
566                     wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
567                     return -1;
568           }
569 
570           return 0;
571 }
572 
573 
sae_derive_commit(struct sae_data * sae)574 static int sae_derive_commit(struct sae_data *sae)
575 {
576           struct crypto_bignum *mask;
577           int ret;
578 
579           mask = crypto_bignum_init();
580           if (!sae->tmp->sae_rand)
581                     sae->tmp->sae_rand = crypto_bignum_init();
582           if (!sae->tmp->own_commit_scalar)
583                     sae->tmp->own_commit_scalar = crypto_bignum_init();
584           ret = !mask || !sae->tmp->sae_rand || !sae->tmp->own_commit_scalar ||
585                     dragonfly_generate_scalar(sae->tmp->order, sae->tmp->sae_rand,
586                                                     mask,
587                                                     sae->tmp->own_commit_scalar) < 0 ||
588                     (sae->tmp->ec &&
589                      sae_derive_commit_element_ecc(sae, mask) < 0) ||
590                     (sae->tmp->dh &&
591                      sae_derive_commit_element_ffc(sae, mask) < 0);
592           crypto_bignum_deinit(mask, 1);
593           return ret ? -1 : 0;
594 }
595 
596 
sae_prepare_commit(const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len,const char * identifier,struct sae_data * sae)597 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
598                            const u8 *password, size_t password_len,
599                            const char *identifier, struct sae_data *sae)
600 {
601           if (sae->tmp == NULL ||
602               (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
603                                                             password_len,
604                                                             identifier) < 0) ||
605               (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
606                                                             password_len,
607                                                             identifier) < 0) ||
608               sae_derive_commit(sae) < 0)
609                     return -1;
610           return 0;
611 }
612 
613 
sae_derive_k_ecc(struct sae_data * sae,u8 * k)614 static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
615 {
616           struct crypto_ec_point *K;
617           int ret = -1;
618 
619           K = crypto_ec_point_init(sae->tmp->ec);
620           if (K == NULL)
621                     goto fail;
622 
623           /*
624            * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
625            *                                        PEER-COMMIT-ELEMENT)))
626            * If K is identity element (point-at-infinity), reject
627            * k = F(K) (= x coordinate)
628            */
629 
630           if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
631                                         sae->peer_commit_scalar, K) < 0 ||
632               crypto_ec_point_add(sae->tmp->ec, K,
633                                         sae->tmp->peer_commit_element_ecc, K) < 0 ||
634               crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
635               crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
636               crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
637                     wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
638                     goto fail;
639           }
640 
641           wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
642 
643           ret = 0;
644 fail:
645           crypto_ec_point_deinit(K, 1);
646           return ret;
647 }
648 
649 
sae_derive_k_ffc(struct sae_data * sae,u8 * k)650 static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
651 {
652           struct crypto_bignum *K;
653           int ret = -1;
654 
655           K = crypto_bignum_init();
656           if (K == NULL)
657                     goto fail;
658 
659           /*
660            * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
661            *                                        PEER-COMMIT-ELEMENT)))
662            * If K is identity element (one), reject.
663            * k = F(K) (= x coordinate)
664            */
665 
666           if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
667                                           sae->tmp->prime, K) < 0 ||
668               crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
669                                          sae->tmp->prime, K) < 0 ||
670               crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
671               ||
672               crypto_bignum_is_one(K) ||
673               crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
674               0) {
675                     wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
676                     goto fail;
677           }
678 
679           wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
680 
681           ret = 0;
682 fail:
683           crypto_bignum_deinit(K, 1);
684           return ret;
685 }
686 
687 
sae_derive_keys(struct sae_data * sae,const u8 * k)688 static int sae_derive_keys(struct sae_data *sae, const u8 *k)
689 {
690           u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
691           u8 keyseed[SHA256_MAC_LEN];
692           u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
693           struct crypto_bignum *tmp;
694           int ret = -1;
695 
696           tmp = crypto_bignum_init();
697           if (tmp == NULL)
698                     goto fail;
699 
700           /* keyseed = H(<0>32, k)
701            * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
702            *                      (commit-scalar + peer-commit-scalar) modulo r)
703            * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
704            */
705 
706           os_memset(null_key, 0, sizeof(null_key));
707           hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
708                         keyseed);
709           wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
710 
711           crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
712                                 tmp);
713           crypto_bignum_mod(tmp, sae->tmp->order, tmp);
714           /* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
715            * string that is needed for KCK, PMK, and PMKID derivation, but it
716            * seems to make most sense to encode the
717            * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
718            * zero padding it from left to the length of the order (in full
719            * octets). */
720           crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
721           wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
722           if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
723                            val, sae->tmp->order_len, keys, sizeof(keys)) < 0)
724                     goto fail;
725           os_memset(keyseed, 0, sizeof(keyseed));
726           os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
727           os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
728           os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
729           os_memset(keys, 0, sizeof(keys));
730           wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
731           wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
732 
733           ret = 0;
734 fail:
735           crypto_bignum_deinit(tmp, 0);
736           return ret;
737 }
738 
739 
sae_process_commit(struct sae_data * sae)740 int sae_process_commit(struct sae_data *sae)
741 {
742           u8 k[SAE_MAX_PRIME_LEN];
743           if (sae->tmp == NULL ||
744               (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
745               (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
746               sae_derive_keys(sae, k) < 0)
747                     return -1;
748           return 0;
749 }
750 
751 
sae_write_commit(struct sae_data * sae,struct wpabuf * buf,const struct wpabuf * token,const char * identifier)752 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
753                           const struct wpabuf *token, const char *identifier)
754 {
755           u8 *pos;
756 
757           if (sae->tmp == NULL)
758                     return;
759 
760           wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
761           if (token) {
762                     wpabuf_put_buf(buf, token);
763                     wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
764                                   wpabuf_head(token), wpabuf_len(token));
765           }
766           pos = wpabuf_put(buf, sae->tmp->prime_len);
767           crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
768                                    sae->tmp->prime_len, sae->tmp->prime_len);
769           wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
770                         pos, sae->tmp->prime_len);
771           if (sae->tmp->ec) {
772                     pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
773                     crypto_ec_point_to_bin(sae->tmp->ec,
774                                                sae->tmp->own_commit_element_ecc,
775                                                pos, pos + sae->tmp->prime_len);
776                     wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
777                                   pos, sae->tmp->prime_len);
778                     wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
779                                   pos + sae->tmp->prime_len, sae->tmp->prime_len);
780           } else {
781                     pos = wpabuf_put(buf, sae->tmp->prime_len);
782                     crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
783                                              sae->tmp->prime_len, sae->tmp->prime_len);
784                     wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
785                                   pos, sae->tmp->prime_len);
786           }
787 
788           if (identifier) {
789                     /* Password Identifier element */
790                     wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
791                     wpabuf_put_u8(buf, 1 + os_strlen(identifier));
792                     wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
793                     wpabuf_put_str(buf, identifier);
794                     wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
795                                  identifier);
796           }
797 }
798 
799 
sae_group_allowed(struct sae_data * sae,int * allowed_groups,u16 group)800 u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
801 {
802           if (allowed_groups) {
803                     int i;
804                     for (i = 0; allowed_groups[i] > 0; i++) {
805                               if (allowed_groups[i] == group)
806                                         break;
807                     }
808                     if (allowed_groups[i] != group) {
809                               wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
810                                            "enabled in the current configuration",
811                                            group);
812                               return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
813                     }
814           }
815 
816           if (sae->state == SAE_COMMITTED && group != sae->group) {
817                     wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
818                     return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
819           }
820 
821           if (group != sae->group && sae_set_group(sae, group) < 0) {
822                     wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
823                                  group);
824                     return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
825           }
826 
827           if (sae->tmp == NULL) {
828                     wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
829                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
830           }
831 
832           if (sae->tmp->dh && !allowed_groups) {
833                     wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
834                                  "explicit configuration enabling it", group);
835                     return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
836           }
837 
838           return WLAN_STATUS_SUCCESS;
839 }
840 
841 
sae_is_password_id_elem(const u8 * pos,const u8 * end)842 static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
843 {
844           return end - pos >= 3 &&
845                     pos[0] == WLAN_EID_EXTENSION &&
846                     pos[1] >= 1 &&
847                     end - pos - 2 >= pos[1] &&
848                     pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
849 }
850 
851 
sae_parse_commit_token(struct sae_data * sae,const u8 ** pos,const u8 * end,const u8 ** token,size_t * token_len)852 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
853                                            const u8 *end, const u8 **token,
854                                            size_t *token_len)
855 {
856           size_t scalar_elem_len, tlen;
857           const u8 *elem;
858 
859           if (token)
860                     *token = NULL;
861           if (token_len)
862                     *token_len = 0;
863 
864           scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
865           if (scalar_elem_len >= (size_t) (end - *pos))
866                     return; /* No extra data beyond peer scalar and element */
867 
868           /* It is a bit difficult to parse this now that there is an
869            * optional variable length Anti-Clogging Token field and
870            * optional variable length Password Identifier element in the
871            * frame. We are sending out fixed length Anti-Clogging Token
872            * fields, so use that length as a requirement for the received
873            * token and check for the presence of possible Password
874            * Identifier element based on the element header information.
875            */
876           tlen = end - (*pos + scalar_elem_len);
877 
878           if (tlen < SHA256_MAC_LEN) {
879                     wpa_printf(MSG_DEBUG,
880                                  "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
881                                  (unsigned int) tlen);
882                     return;
883           }
884 
885           elem = *pos + scalar_elem_len;
886           if (sae_is_password_id_elem(elem, end)) {
887                      /* Password Identifier element takes out all available
888                       * extra octets, so there can be no Anti-Clogging token in
889                       * this frame. */
890                     return;
891           }
892 
893           elem += SHA256_MAC_LEN;
894           if (sae_is_password_id_elem(elem, end)) {
895                      /* Password Identifier element is included in the end, so
896                       * remove its length from the Anti-Clogging token field. */
897                     tlen -= 2 + elem[1];
898           }
899 
900           wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
901           if (token)
902                     *token = *pos;
903           if (token_len)
904                     *token_len = tlen;
905           *pos += tlen;
906 }
907 
908 
sae_parse_commit_scalar(struct sae_data * sae,const u8 ** pos,const u8 * end)909 static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
910                                            const u8 *end)
911 {
912           struct crypto_bignum *peer_scalar;
913 
914           if (sae->tmp->prime_len > end - *pos) {
915                     wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
916                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
917           }
918 
919           peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
920           if (peer_scalar == NULL)
921                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
922 
923           /*
924            * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
925            * the peer and it is in Authenticated state, the new Commit Message
926            * shall be dropped if the peer-scalar is identical to the one used in
927            * the existing protocol instance.
928            */
929           if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
930               crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
931                     wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
932                                  "peer-commit-scalar");
933                     crypto_bignum_deinit(peer_scalar, 0);
934                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
935           }
936 
937           /* 1 < scalar < r */
938           if (crypto_bignum_is_zero(peer_scalar) ||
939               crypto_bignum_is_one(peer_scalar) ||
940               crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
941                     wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
942                     crypto_bignum_deinit(peer_scalar, 0);
943                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
944           }
945 
946 
947           crypto_bignum_deinit(sae->peer_commit_scalar, 0);
948           sae->peer_commit_scalar = peer_scalar;
949           wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
950                         *pos, sae->tmp->prime_len);
951           *pos += sae->tmp->prime_len;
952 
953           return WLAN_STATUS_SUCCESS;
954 }
955 
956 
sae_parse_commit_element_ecc(struct sae_data * sae,const u8 ** pos,const u8 * end)957 static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
958                                                   const u8 *end)
959 {
960           u8 prime[SAE_MAX_ECC_PRIME_LEN];
961 
962           if (2 * sae->tmp->prime_len > end - *pos) {
963                     wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
964                                  "commit-element");
965                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
966           }
967 
968           if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
969                                          sae->tmp->prime_len) < 0)
970                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
971 
972           /* element x and y coordinates < p */
973           if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
974               os_memcmp(*pos + sae->tmp->prime_len, prime,
975                           sae->tmp->prime_len) >= 0) {
976                     wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
977                                  "element");
978                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
979           }
980 
981           wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
982                         *pos, sae->tmp->prime_len);
983           wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
984                         *pos + sae->tmp->prime_len, sae->tmp->prime_len);
985 
986           crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
987           sae->tmp->peer_commit_element_ecc =
988                     crypto_ec_point_from_bin(sae->tmp->ec, *pos);
989           if (sae->tmp->peer_commit_element_ecc == NULL)
990                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
991 
992           if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
993                                                    sae->tmp->peer_commit_element_ecc)) {
994                     wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
995                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
996           }
997 
998           *pos += 2 * sae->tmp->prime_len;
999 
1000           return WLAN_STATUS_SUCCESS;
1001 }
1002 
1003 
sae_parse_commit_element_ffc(struct sae_data * sae,const u8 ** pos,const u8 * end)1004 static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
1005                                                   const u8 *end)
1006 {
1007           struct crypto_bignum *res, *one;
1008           const u8 one_bin[1] = { 0x01 };
1009 
1010           if (sae->tmp->prime_len > end - *pos) {
1011                     wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1012                                  "commit-element");
1013                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1014           }
1015           wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
1016                         sae->tmp->prime_len);
1017 
1018           crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
1019           sae->tmp->peer_commit_element_ffc =
1020                     crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1021           if (sae->tmp->peer_commit_element_ffc == NULL)
1022                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1023           /* 1 < element < p - 1 */
1024           res = crypto_bignum_init();
1025           one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
1026           if (!res || !one ||
1027               crypto_bignum_sub(sae->tmp->prime, one, res) ||
1028               crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
1029               crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
1030               crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
1031                     crypto_bignum_deinit(res, 0);
1032                     crypto_bignum_deinit(one, 0);
1033                     wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
1034                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1035           }
1036           crypto_bignum_deinit(one, 0);
1037 
1038           /* scalar-op(r, ELEMENT) = 1 modulo p */
1039           if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
1040                                           sae->tmp->order, sae->tmp->prime, res) < 0 ||
1041               !crypto_bignum_is_one(res)) {
1042                     wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
1043                     crypto_bignum_deinit(res, 0);
1044                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1045           }
1046           crypto_bignum_deinit(res, 0);
1047 
1048           *pos += sae->tmp->prime_len;
1049 
1050           return WLAN_STATUS_SUCCESS;
1051 }
1052 
1053 
sae_parse_commit_element(struct sae_data * sae,const u8 ** pos,const u8 * end)1054 static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
1055                                             const u8 *end)
1056 {
1057           if (sae->tmp->dh)
1058                     return sae_parse_commit_element_ffc(sae, pos, end);
1059           return sae_parse_commit_element_ecc(sae, pos, end);
1060 }
1061 
1062 
sae_parse_password_identifier(struct sae_data * sae,const u8 * pos,const u8 * end)1063 static int sae_parse_password_identifier(struct sae_data *sae,
1064                                                    const u8 *pos, const u8 *end)
1065 {
1066           wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
1067                         pos, end - pos);
1068           if (!sae_is_password_id_elem(pos, end)) {
1069                     if (sae->tmp->pw_id) {
1070                               wpa_printf(MSG_DEBUG,
1071                                            "SAE: No Password Identifier included, but expected one (%s)",
1072                                            sae->tmp->pw_id);
1073                               return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1074                     }
1075                     os_free(sae->tmp->pw_id);
1076                     sae->tmp->pw_id = NULL;
1077                     return WLAN_STATUS_SUCCESS; /* No Password Identifier */
1078           }
1079 
1080           if (sae->tmp->pw_id &&
1081               (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
1082                os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
1083                     wpa_printf(MSG_DEBUG,
1084                                  "SAE: The included Password Identifier does not match the expected one (%s)",
1085                                  sae->tmp->pw_id);
1086                     return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1087           }
1088 
1089           os_free(sae->tmp->pw_id);
1090           sae->tmp->pw_id = os_malloc(pos[1]);
1091           if (!sae->tmp->pw_id)
1092                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1093           os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
1094           sae->tmp->pw_id[pos[1] - 1] = '\0';
1095           wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
1096                                 sae->tmp->pw_id, pos[1] -  1);
1097           return WLAN_STATUS_SUCCESS;
1098 }
1099 
1100 
sae_parse_commit(struct sae_data * sae,const u8 * data,size_t len,const u8 ** token,size_t * token_len,int * allowed_groups)1101 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
1102                          const u8 **token, size_t *token_len, int *allowed_groups)
1103 {
1104           const u8 *pos = data, *end = data + len;
1105           u16 res;
1106 
1107           /* Check Finite Cyclic Group */
1108           if (end - pos < 2)
1109                     return WLAN_STATUS_UNSPECIFIED_FAILURE;
1110           res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
1111           if (res != WLAN_STATUS_SUCCESS)
1112                     return res;
1113           pos += 2;
1114 
1115           /* Optional Anti-Clogging Token */
1116           sae_parse_commit_token(sae, &pos, end, token, token_len);
1117 
1118           /* commit-scalar */
1119           res = sae_parse_commit_scalar(sae, &pos, end);
1120           if (res != WLAN_STATUS_SUCCESS)
1121                     return res;
1122 
1123           /* commit-element */
1124           res = sae_parse_commit_element(sae, &pos, end);
1125           if (res != WLAN_STATUS_SUCCESS)
1126                     return res;
1127 
1128           /* Optional Password Identifier element */
1129           res = sae_parse_password_identifier(sae, pos, end);
1130           if (res != WLAN_STATUS_SUCCESS)
1131                     return res;
1132 
1133           /*
1134            * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
1135            * the values we sent which would be evidence of a reflection attack.
1136            */
1137           if (!sae->tmp->own_commit_scalar ||
1138               crypto_bignum_cmp(sae->tmp->own_commit_scalar,
1139                                     sae->peer_commit_scalar) != 0 ||
1140               (sae->tmp->dh &&
1141                (!sae->tmp->own_commit_element_ffc ||
1142                 crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
1143                                         sae->tmp->peer_commit_element_ffc) != 0)) ||
1144               (sae->tmp->ec &&
1145                (!sae->tmp->own_commit_element_ecc ||
1146                 crypto_ec_point_cmp(sae->tmp->ec,
1147                                           sae->tmp->own_commit_element_ecc,
1148                                           sae->tmp->peer_commit_element_ecc) != 0)))
1149                     return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
1150 
1151           /*
1152            * This is a reflection attack - return special value to trigger caller
1153            * to silently discard the frame instead of replying with a specific
1154            * status code.
1155            */
1156           return SAE_SILENTLY_DISCARD;
1157 }
1158 
1159 
sae_cn_confirm(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const u8 * element1,size_t element1_len,const struct crypto_bignum * scalar2,const u8 * element2,size_t element2_len,u8 * confirm)1160 static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
1161                                  const struct crypto_bignum *scalar1,
1162                                  const u8 *element1, size_t element1_len,
1163                                  const struct crypto_bignum *scalar2,
1164                                  const u8 *element2, size_t element2_len,
1165                                  u8 *confirm)
1166 {
1167           const u8 *addr[5];
1168           size_t len[5];
1169           u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
1170 
1171           /* Confirm
1172            * CN(key, X, Y, Z, ...) =
1173            *    HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
1174            * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
1175            *              peer-commit-scalar, PEER-COMMIT-ELEMENT)
1176            * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
1177            *               PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
1178            */
1179           addr[0] = sc;
1180           len[0] = 2;
1181           crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
1182                                    sae->tmp->prime_len);
1183           addr[1] = scalar_b1;
1184           len[1] = sae->tmp->prime_len;
1185           addr[2] = element1;
1186           len[2] = element1_len;
1187           crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
1188                                    sae->tmp->prime_len);
1189           addr[3] = scalar_b2;
1190           len[3] = sae->tmp->prime_len;
1191           addr[4] = element2;
1192           len[4] = element2_len;
1193           hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
1194                                  confirm);
1195 }
1196 
1197 
sae_cn_confirm_ecc(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const struct crypto_ec_point * element1,const struct crypto_bignum * scalar2,const struct crypto_ec_point * element2,u8 * confirm)1198 static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
1199                                      const struct crypto_bignum *scalar1,
1200                                      const struct crypto_ec_point *element1,
1201                                      const struct crypto_bignum *scalar2,
1202                                      const struct crypto_ec_point *element2,
1203                                      u8 *confirm)
1204 {
1205           u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
1206           u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
1207 
1208           crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
1209                                      element_b1 + sae->tmp->prime_len);
1210           crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
1211                                      element_b2 + sae->tmp->prime_len);
1212 
1213           sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
1214                            scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
1215 }
1216 
1217 
sae_cn_confirm_ffc(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const struct crypto_bignum * element1,const struct crypto_bignum * scalar2,const struct crypto_bignum * element2,u8 * confirm)1218 static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
1219                                      const struct crypto_bignum *scalar1,
1220                                      const struct crypto_bignum *element1,
1221                                      const struct crypto_bignum *scalar2,
1222                                      const struct crypto_bignum *element2,
1223                                      u8 *confirm)
1224 {
1225           u8 element_b1[SAE_MAX_PRIME_LEN];
1226           u8 element_b2[SAE_MAX_PRIME_LEN];
1227 
1228           crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
1229                                    sae->tmp->prime_len);
1230           crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
1231                                    sae->tmp->prime_len);
1232 
1233           sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
1234                            scalar2, element_b2, sae->tmp->prime_len, confirm);
1235 }
1236 
1237 
sae_write_confirm(struct sae_data * sae,struct wpabuf * buf)1238 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
1239 {
1240           const u8 *sc;
1241 
1242           if (sae->tmp == NULL)
1243                     return;
1244 
1245           /* Send-Confirm */
1246           sc = wpabuf_put(buf, 0);
1247           wpabuf_put_le16(buf, sae->send_confirm);
1248           if (sae->send_confirm < 0xffff)
1249                     sae->send_confirm++;
1250 
1251           if (sae->tmp->ec)
1252                     sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
1253                                            sae->tmp->own_commit_element_ecc,
1254                                            sae->peer_commit_scalar,
1255                                            sae->tmp->peer_commit_element_ecc,
1256                                            wpabuf_put(buf, SHA256_MAC_LEN));
1257           else
1258                     sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
1259                                            sae->tmp->own_commit_element_ffc,
1260                                            sae->peer_commit_scalar,
1261                                            sae->tmp->peer_commit_element_ffc,
1262                                            wpabuf_put(buf, SHA256_MAC_LEN));
1263 }
1264 
1265 
sae_check_confirm(struct sae_data * sae,const u8 * data,size_t len)1266 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
1267 {
1268           u8 verifier[SHA256_MAC_LEN];
1269 
1270           if (len < 2 + SHA256_MAC_LEN) {
1271                     wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
1272                     return -1;
1273           }
1274 
1275           wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
1276 
1277           if (!sae->tmp || !sae->peer_commit_scalar ||
1278               !sae->tmp->own_commit_scalar) {
1279                     wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
1280                     return -1;
1281           }
1282 
1283           if (sae->tmp->ec) {
1284                     if (!sae->tmp->peer_commit_element_ecc ||
1285                         !sae->tmp->own_commit_element_ecc)
1286                               return -1;
1287                     sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
1288                                            sae->tmp->peer_commit_element_ecc,
1289                                            sae->tmp->own_commit_scalar,
1290                                            sae->tmp->own_commit_element_ecc,
1291                                            verifier);
1292           } else {
1293                     if (!sae->tmp->peer_commit_element_ffc ||
1294                         !sae->tmp->own_commit_element_ffc)
1295                               return -1;
1296                     sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
1297                                            sae->tmp->peer_commit_element_ffc,
1298                                            sae->tmp->own_commit_scalar,
1299                                            sae->tmp->own_commit_element_ffc,
1300                                            verifier);
1301           }
1302 
1303           if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
1304                     wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
1305                     wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
1306                                   data + 2, SHA256_MAC_LEN);
1307                     wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
1308                                   verifier, SHA256_MAC_LEN);
1309                     return -1;
1310           }
1311 
1312           return 0;
1313 }
1314 
1315 
sae_state_txt(enum sae_state state)1316 const char * sae_state_txt(enum sae_state state)
1317 {
1318           switch (state) {
1319           case SAE_NOTHING:
1320                     return "Nothing";
1321           case SAE_COMMITTED:
1322                     return "Committed";
1323           case SAE_CONFIRMED:
1324                     return "Confirmed";
1325           case SAE_ACCEPTED:
1326                     return "Accepted";
1327           }
1328           return "?";
1329 }
1330