1 /*
2 * SAE-PK
3 * Copyright (c) 2020, The Linux Foundation
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10 #include <stdint.h>
11
12 #include "utils/common.h"
13 #include "utils/base64.h"
14 #include "common/ieee802_11_defs.h"
15 #include "common/ieee802_11_common.h"
16 #include "crypto/crypto.h"
17 #include "crypto/aes.h"
18 #include "crypto/aes_siv.h"
19 #include "sae.h"
20
21
22 /* RFC 4648 base 32 alphabet with lowercase characters */
23 static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
24
25
26 static const u8 d_mult_table[] = {
27 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
28 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
29 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
30 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
31 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
32 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
33 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
34 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
35 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
36 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
37 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
38 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
39 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
40 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
41 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
42 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
43 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
44 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
45 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
46 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
47 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
48 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
49 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
50 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
51 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
52 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
53 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
54 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
55 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
56 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
57 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
58 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
59 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
60 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
61 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
62 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
63 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
64 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
65 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
66 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
67 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
68 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
69 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
70 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
71 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
72 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
73 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
74 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
75 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
76 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
77 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
78 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
79 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
80 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
81 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
82 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
83 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
84 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
85 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
86 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
87 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
88 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
89 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
90 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
91 };
92
93 static const u8 d_perm_table[] = {
94 7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
95 22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
96 };
97
98
d_permute(u8 val,unsigned int iter)99 static u8 d_permute(u8 val, unsigned int iter)
100 {
101 if (iter == 0)
102 return val;
103 return d_permute(d_perm_table[val], iter - 1);
104 }
105
106
d_invert(u8 val)107 static u8 d_invert(u8 val)
108 {
109 if (val > 0 && val < 16)
110 return 16 - val;
111 return val;
112 }
113
114
d_check_char(const char * str,size_t len)115 static char d_check_char(const char *str, size_t len)
116 {
117 size_t i;
118 u8 val = 0;
119 u8 dtable[256];
120 unsigned int iter = 1;
121 int j;
122
123 os_memset(dtable, 0x80, 256);
124 for (i = 0; sae_pk_base32_table[i]; i++)
125 dtable[(u8) sae_pk_base32_table[i]] = i;
126
127 for (j = len - 1; j >= 0; j--) {
128 u8 c, p;
129
130 c = dtable[(u8) str[j]];
131 if (c == 0x80)
132 continue;
133 p = d_permute(c, iter);
134 iter++;
135 val = d_mult_table[val * 32 + p];
136 }
137
138 return sae_pk_base32_table[d_invert(val)];
139 }
140
141
sae_pk_valid_password(const char * pw)142 bool sae_pk_valid_password(const char *pw)
143 {
144 int pos;
145 size_t i, pw_len = os_strlen(pw);
146 u8 sec_1b;
147 u8 dtable[256];
148
149 os_memset(dtable, 0x80, 256);
150 for (i = 0; sae_pk_base32_table[i]; i++)
151 dtable[(u8) sae_pk_base32_table[i]] = i;
152
153 /* SAE-PK password has at least three four character components
154 * separated by hyphens. */
155 if (pw_len < 14 || pw_len % 5 != 4) {
156 wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
157 return false;
158 }
159
160 for (pos = 0; pw[pos]; pos++) {
161 if (pos && pos % 5 == 4) {
162 if (pw[pos] != '-') {
163 wpa_printf(MSG_DEBUG,
164 "SAE-PK: Not a valid password (separator)");
165 return false;
166 }
167 continue;
168 }
169 if (dtable[(u8) pw[pos]] == 0x80) {
170 wpa_printf(MSG_DEBUG,
171 "SAE-PK: Not a valid password (character)");
172 return false;
173 }
174 }
175
176 /* Verify that the checksum character is valid */
177 if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
178 wpa_printf(MSG_DEBUG,
179 "SAE-PK: Not a valid password (checksum)");
180 return false;
181 }
182
183 /* Verify that Sec_1b bits match */
184 sec_1b = dtable[(u8) pw[0]] & BIT(4);
185 for (i = 5; i < pw_len; i += 5) {
186 if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
187 wpa_printf(MSG_DEBUG,
188 "SAE-PK: Not a valid password (Sec_1b)");
189 return false;
190 }
191 }
192 return true;
193 }
194
195
add_char(const char * start,char * pos,u8 idx,size_t * bits)196 static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
197 {
198 if (*bits == 0)
199 return pos;
200 if (*bits > 5)
201 *bits -= 5;
202 else
203 *bits = 0;
204
205 if ((pos - start) % 5 == 4)
206 *pos++ = '-';
207 *pos++ = sae_pk_base32_table[idx];
208 return pos;
209 }
210
211
212 /* Base32 encode a password and add hyper separators and checksum */
sae_pk_base32_encode(const u8 * src,size_t len_bits)213 char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
214 {
215 char *out, *pos;
216 size_t olen, extra_pad, i;
217 u64 block = 0;
218 u8 val;
219 size_t len = (len_bits + 7) / 8;
220 size_t left = len_bits;
221 int j;
222
223 if (len == 0 || len >= SIZE_MAX / 8)
224 return NULL;
225 olen = len * 8 / 5 + 1;
226 olen += olen / 4; /* hyphen separators */
227 pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
228 if (!out)
229 return NULL;
230
231 extra_pad = (5 - len % 5) % 5;
232 for (i = 0; i < len + extra_pad; i++) {
233 val = i < len ? src[i] : 0;
234 block <<= 8;
235 block |= val;
236 if (i % 5 == 4) {
237 for (j = 7; j >= 0; j--)
238 pos = add_char(out, pos,
239 (block >> j * 5) & 0x1f, &left);
240 block = 0;
241 }
242 }
243
244 *pos = d_check_char(out, os_strlen(out));
245
246 return out;
247 }
248
249
sae_pk_base32_decode(const char * src,size_t len,size_t * out_len)250 u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
251 {
252 u8 dtable[256], *out, *pos, tmp;
253 u64 block = 0;
254 size_t i, count, olen;
255 int pad = 0;
256 size_t extra_pad;
257
258 os_memset(dtable, 0x80, 256);
259 for (i = 0; sae_pk_base32_table[i]; i++)
260 dtable[(u8) sae_pk_base32_table[i]] = i;
261 dtable['='] = 0;
262
263 count = 0;
264 for (i = 0; i < len; i++) {
265 if (dtable[(u8) src[i]] != 0x80)
266 count++;
267 }
268
269 if (count == 0)
270 return NULL;
271 extra_pad = (8 - count % 8) % 8;
272
273 olen = (count + extra_pad) / 8 * 5;
274 pos = out = os_malloc(olen);
275 if (!out)
276 return NULL;
277
278 count = 0;
279 for (i = 0; i < len + extra_pad; i++) {
280 u8 val;
281
282 if (i >= len)
283 val = '=';
284 else
285 val = src[i];
286 tmp = dtable[val];
287 if (tmp == 0x80)
288 continue;
289
290 if (val == '=')
291 pad++;
292 block <<= 5;
293 block |= tmp;
294 count++;
295 if (count == 8) {
296 *pos++ = (block >> 32) & 0xff;
297 *pos++ = (block >> 24) & 0xff;
298 *pos++ = (block >> 16) & 0xff;
299 *pos++ = (block >> 8) & 0xff;
300 *pos++ = block & 0xff;
301 count = 0;
302 block = 0;
303 if (pad) {
304 /* Leave in all the available bits with zero
305 * padding to full octets from right. */
306 pos -= pad * 5 / 8;
307 break;
308 }
309 }
310 }
311
312 *out_len = pos - out;
313 return out;
314 }
315
316
sae_pk_get_be19(const u8 * buf)317 u32 sae_pk_get_be19(const u8 *buf)
318 {
319 return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
320 }
321
322
323 /* shift left by two octets and three bits; fill in zeros from right;
324 * len must be at least three */
sae_pk_buf_shift_left_19(u8 * buf,size_t len)325 void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
326 {
327 u8 *dst, *src, *end;
328
329 dst = buf;
330 src = buf + 2;
331 end = buf + len;
332
333 while (src + 1 < end) {
334 *dst++ = (src[0] << 3) | (src[1] >> 5);
335 src++;
336 }
337 *dst++ = *src << 3;
338 *dst++ = 0;
339 *dst++ = 0;
340 }
341
342
sae_pk_buf_shift_left_1(u8 * buf,size_t len)343 static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
344 {
345 u8 *dst, *src, *end;
346
347 dst = buf;
348 src = buf;
349 end = buf + len;
350
351 while (src + 1 < end) {
352 *dst++ = (src[0] << 1) | (src[1] >> 7);
353 src++;
354 }
355 *dst++ = *src << 1;
356 }
357
358
sae_pk_set_password(struct sae_data * sae,const char * password)359 int sae_pk_set_password(struct sae_data *sae, const char *password)
360 {
361 struct sae_temporary_data *tmp = sae->tmp;
362 size_t len, pw_len;
363 u8 *pw, *pos;
364 int bits;
365 u32 val = 0, val19;
366 unsigned int val_bits = 0;
367
368 if (!tmp)
369 return -1;
370
371 os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
372 tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
373
374 len = os_strlen(password);
375 if (len < 1 || !sae_pk_valid_password(password))
376 return -1;
377
378 pw = sae_pk_base32_decode(password, len, &pw_len);
379 if (!pw)
380 return -1;
381
382 tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
383 tmp->lambda = len - len / 5;
384 tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
385 wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
386 tmp->sec, tmp->lambda, tmp->fingerprint_bits);
387
388 /* Construct Fingerprint from PasswordBase by prefixing with Sec zero
389 * octets and skipping the Sec_1b bits */
390 pos = &tmp->fingerprint[tmp->sec];
391 bits = tmp->fingerprint_bits - 8 * tmp->sec;
392 wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
393 while (bits > 0) {
394 if (val_bits < 8) {
395 sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
396 val19 = sae_pk_get_be19(pw);
397 sae_pk_buf_shift_left_19(pw, pw_len);
398 val = (val << 19) | val19;
399 val_bits += 19;
400 }
401 if (val_bits >= 8) {
402 if (bits < 8)
403 break;
404 *pos++ = (val >> (val_bits - 8)) & 0xff;
405 val_bits -= 8;
406 bits -= 8;
407 }
408 }
409 if (bits > 0) {
410 val >>= val_bits - bits;
411 *pos++ = val << (8 - bits);
412 }
413 tmp->fingerprint_bytes = pos - tmp->fingerprint;
414 wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
415 tmp->fingerprint, tmp->fingerprint_bytes);
416 bin_clear_free(pw, pw_len);
417 return 0;
418 }
419
420
sae_group_2_hash_len(int group)421 static size_t sae_group_2_hash_len(int group)
422 {
423 switch (group) {
424 case 19:
425 return 32;
426 case 20:
427 return 48;
428 case 21:
429 return 64;
430 }
431
432 return 0;
433 }
434
435
sae_deinit_pk(struct sae_pk * pk)436 void sae_deinit_pk(struct sae_pk *pk)
437 {
438 if (pk) {
439 wpabuf_free(pk->m);
440 crypto_ec_key_deinit(pk->key);
441 #ifdef CONFIG_TESTING_OPTIONS
442 crypto_ec_key_deinit(pk->sign_key_override);
443 #endif /* CONFIG_TESTING_OPTIONS */
444 wpabuf_free(pk->pubkey);
445 os_free(pk);
446 }
447 }
448
449
sae_parse_pk(const char * val)450 struct sae_pk * sae_parse_pk(const char *val)
451 {
452 struct sae_pk *pk;
453 const char *pos;
454 #ifdef CONFIG_TESTING_OPTIONS
455 const char *pos2;
456 #endif /* CONFIG_TESTING_OPTIONS */
457 size_t len;
458 unsigned char *der;
459 size_t der_len, b_len;
460
461 /* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
462
463 pos = os_strchr(val, ':');
464 if (!pos || (pos - val) & 0x01)
465 return NULL;
466 len = (pos - val) / 2;
467 if (len != SAE_PK_M_LEN) {
468 wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
469 len);
470 return NULL;
471 }
472
473 pk = os_zalloc(sizeof(*pk));
474 if (!pk)
475 return NULL;
476 pk->m = wpabuf_alloc(len);
477 if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
478 wpa_printf(MSG_INFO, "SAE: Failed to parse m");
479 goto fail;
480 }
481
482 pos++;
483 b_len = os_strlen(pos);
484 #ifdef CONFIG_TESTING_OPTIONS
485 pos2 = os_strchr(pos, ':');
486 if (pos2) {
487 b_len = pos2 - pos;
488 pos2++;
489 }
490 #endif /* CONFIG_TESTING_OPTIONS */
491 der = base64_decode(pos, b_len, &der_len);
492 if (!der) {
493 wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
494 goto fail;
495 }
496
497 pk->key = crypto_ec_key_parse_priv(der, der_len);
498 bin_clear_free(der, der_len);
499 if (!pk->key)
500 goto fail;
501 pk->group = crypto_ec_key_group(pk->key);
502 pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
503 if (!pk->pubkey)
504 goto fail;
505
506 #ifdef CONFIG_TESTING_OPTIONS
507 if (pos2) {
508 der = base64_decode(pos2, os_strlen(pos2), &der_len);
509 if (!der) {
510 wpa_printf(MSG_INFO,
511 "SAE: Failed to base64 decode PK key");
512 goto fail;
513 }
514
515 pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
516 bin_clear_free(der, der_len);
517 if (!pk->sign_key_override)
518 goto fail;
519 }
520 #endif /* CONFIG_TESTING_OPTIONS */
521
522 return pk;
523 fail:
524 sae_deinit_pk(pk);
525 return NULL;
526 }
527
528
sae_hash(size_t hash_len,const u8 * data,size_t len,u8 * hash)529 int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
530 {
531 if (hash_len == 32)
532 return sha256_vector(1, &data, &len, hash);
533 #ifdef CONFIG_SHA384
534 if (hash_len == 48)
535 return sha384_vector(1, &data, &len, hash);
536 #endif /* CONFIG_SHA384 */
537 #ifdef CONFIG_SHA512
538 if (hash_len == 64)
539 return sha512_vector(1, &data, &len, hash);
540 #endif /* CONFIG_SHA512 */
541 return -1;
542 }
543
544
sae_pk_hash_sig_data(struct sae_data * sae,size_t hash_len,bool ap,const u8 * m,size_t m_len,const u8 * pubkey,size_t pubkey_len,u8 * hash)545 static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
546 bool ap, const u8 *m, size_t m_len,
547 const u8 *pubkey, size_t pubkey_len, u8 *hash)
548 {
549 struct sae_temporary_data *tmp = sae->tmp;
550 struct wpabuf *sig_data;
551 u8 *pos;
552 int ret = -1;
553
554 /* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
555 * M || K_AP || AP-BSSID || STA-MAC */
556 sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
557 2 * ETH_ALEN);
558 if (!sig_data)
559 goto fail;
560 pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
561 if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
562 tmp->peer_commit_element_ecc,
563 pos, pos + tmp->prime_len) < 0)
564 goto fail;
565 pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
566 if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
567 tmp->own_commit_element_ecc,
568 pos, pos + tmp->prime_len) < 0)
569 goto fail;
570 if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
571 sae->peer_commit_scalar,
572 wpabuf_put(sig_data, tmp->prime_len),
573 tmp->prime_len, tmp->prime_len) < 0 ||
574 crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
575 tmp->own_commit_scalar,
576 wpabuf_put(sig_data, tmp->prime_len),
577 tmp->prime_len, tmp->prime_len) < 0)
578 goto fail;
579 wpabuf_put_data(sig_data, m, m_len);
580 wpabuf_put_data(sig_data, pubkey, pubkey_len);
581 wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
582 ETH_ALEN);
583 wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
584 ETH_ALEN);
585 wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
586 sig_data);
587 if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
588 hash) < 0)
589 goto fail;
590 wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
591 hash, hash_len);
592 ret = 0;
593 fail:
594 wpabuf_free(sig_data);
595 return ret;
596 }
597
598
sae_write_confirm_pk(struct sae_data * sae,struct wpabuf * buf)599 int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
600 {
601 struct sae_temporary_data *tmp = sae->tmp;
602 struct wpabuf *sig = NULL;
603 size_t need;
604 int ret = -1;
605 u8 *encr_mod;
606 size_t encr_mod_len;
607 const struct sae_pk *pk;
608 u8 hash[SAE_MAX_HASH_LEN];
609 size_t hash_len;
610 struct crypto_ec_key *key;
611
612 if (!tmp)
613 return -1;
614
615 pk = tmp->ap_pk;
616 if (!sae->pk || !pk)
617 return 0;
618
619 key = pk->key;
620 #ifdef CONFIG_TESTING_OPTIONS
621 if (tmp->omit_pk_elem)
622 return 0;
623 if (pk->sign_key_override) {
624 wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
625 key = pk->sign_key_override;
626 }
627 #endif /* CONFIG_TESTING_OPTIONS */
628
629 if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
630 wpa_printf(MSG_INFO,
631 "SAE-PK: No KEK available for writing confirm");
632 return -1;
633 }
634
635 if (!tmp->ec) {
636 /* Only ECC groups are supported for SAE-PK in the current
637 * implementation. */
638 wpa_printf(MSG_INFO,
639 "SAE-PK: SAE commit did not use an ECC group");
640 return -1;
641 }
642
643 hash_len = sae_group_2_hash_len(pk->group);
644 if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
645 wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
646 wpabuf_len(pk->pubkey), hash) < 0)
647 goto fail;
648 sig = crypto_ec_key_sign(key, hash, hash_len);
649 if (!sig)
650 goto fail;
651 wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
652
653 /* TODO: fragmentation if any of the elements needs it for a group
654 * using sufficiently large primes (none of the currently supported
655 * ones do) */
656
657 encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
658 need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
659 6 + encr_mod_len;
660 if (wpabuf_tailroom(buf) < need) {
661 wpa_printf(MSG_INFO,
662 "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
663 wpabuf_tailroom(buf), need);
664 goto fail;
665 }
666
667 /* FILS Public Key element */
668 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
669 wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
670 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
671 wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
672 wpabuf_put_buf(buf, pk->pubkey);
673
674 /* FILS Key Confirmation element (KeyAuth) */
675 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
676 wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
677 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
678 /* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
679 * AP-BSSID || STA-MAC) */
680 wpabuf_put_buf(buf, sig);
681
682 /* SAE-PK element */
683 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
684 wpabuf_put_u8(buf, 4 + encr_mod_len);
685 wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
686 /* EncryptedModifier = AES-SIV-Q(M); no AAD */
687 encr_mod = wpabuf_put(buf, encr_mod_len);
688 if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
689 wpabuf_head(pk->m), wpabuf_len(pk->m),
690 0, NULL, NULL, encr_mod) < 0)
691 goto fail;
692 wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
693 encr_mod, encr_mod_len);
694
695 ret = 0;
696 fail:
697 wpabuf_free(sig);
698 return ret;
699
700 }
701
702
sae_pk_valid_fingerprint(struct sae_data * sae,const u8 * m,size_t m_len,const u8 * k_ap,size_t k_ap_len,int group)703 static bool sae_pk_valid_fingerprint(struct sae_data *sae,
704 const u8 *m, size_t m_len,
705 const u8 *k_ap, size_t k_ap_len, int group)
706 {
707 struct sae_temporary_data *tmp = sae->tmp;
708 u8 *hash_data, *pos;
709 size_t hash_len, hash_data_len;
710 u8 hash[SAE_MAX_HASH_LEN];
711 int res;
712
713 if (!tmp->fingerprint_bytes) {
714 wpa_printf(MSG_DEBUG,
715 "SAE-PK: No PW available for K_AP fingerprint check");
716 return false;
717 }
718
719 /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
720 */
721
722 hash_len = sae_group_2_hash_len(group);
723 hash_data_len = tmp->ssid_len + m_len + k_ap_len;
724 hash_data = os_malloc(hash_data_len);
725 if (!hash_data)
726 return false;
727 pos = hash_data;
728 os_memcpy(pos, tmp->ssid, tmp->ssid_len);
729 pos += tmp->ssid_len;
730 os_memcpy(pos, m, m_len);
731 pos += m_len;
732 os_memcpy(pos, k_ap, k_ap_len);
733
734 wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
735 hash_data, hash_data_len);
736 res = sae_hash(hash_len, hash_data, hash_data_len, hash);
737 bin_clear_free(hash_data, hash_data_len);
738 if (res < 0)
739 return false;
740 wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
741 hash, hash_len);
742
743 if (tmp->fingerprint_bits > hash_len * 8) {
744 wpa_printf(MSG_INFO,
745 "SAE-PK: Not enough hash output bits for the fingerprint");
746 return false;
747 }
748 if (tmp->fingerprint_bits % 8) {
749 size_t extra;
750
751 /* Zero out the extra bits in the last octet */
752 extra = 8 - tmp->fingerprint_bits % 8;
753 pos = &hash[tmp->fingerprint_bits / 8];
754 *pos = (*pos >> extra) << extra;
755 }
756 wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
757 tmp->fingerprint_bytes);
758 res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
759 if (res) {
760 wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
761 wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
762 tmp->fingerprint, tmp->fingerprint_bytes);
763 return false;
764 }
765
766 wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
767 return true;
768 }
769
770
sae_check_confirm_pk(struct sae_data * sae,const u8 * ies,size_t ies_len)771 int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
772 {
773 struct sae_temporary_data *tmp = sae->tmp;
774 const u8 *k_ap;
775 u8 m[SAE_PK_M_LEN];
776 size_t k_ap_len;
777 struct crypto_ec_key *key;
778 int res;
779 u8 hash[SAE_MAX_HASH_LEN];
780 size_t hash_len;
781 int group;
782 struct ieee802_11_elems elems;
783
784 if (!tmp)
785 return -1;
786 if (!sae->pk || tmp->ap_pk)
787 return 0;
788
789 if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
790 wpa_printf(MSG_INFO,
791 "SAE-PK: No KEK available for checking confirm");
792 return -1;
793 }
794
795 if (!tmp->ec) {
796 /* Only ECC groups are supported for SAE-PK in the current
797 * implementation. */
798 wpa_printf(MSG_INFO,
799 "SAE-PK: SAE commit did not use an ECC group");
800 return -1;
801 }
802
803 wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
804 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
805 wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
806 return -1;
807 }
808 if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
809 wpa_printf(MSG_INFO,
810 "SAE-PK: Not all mandatory IEs included in confirm");
811 return -1;
812 }
813
814 /* TODO: Fragment reassembly */
815
816 if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
817 wpa_printf(MSG_INFO,
818 "SAE-PK: No room for EncryptedModifier in SAE-PK element");
819 return -1;
820 }
821
822 wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
823 elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
824
825 if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
826 elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
827 0, NULL, NULL, m) < 0) {
828 wpa_printf(MSG_INFO,
829 "SAE-PK: Failed to decrypt EncryptedModifier");
830 return -1;
831 }
832 wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
833
834 if (elems.fils_pk[0] != 2) {
835 wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
836 elems.fils_pk[0]);
837 return -1;
838 }
839 k_ap_len = elems.fils_pk_len - 1;
840 k_ap = elems.fils_pk + 1;
841 wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
842 /* TODO: Check against the public key, if one is stored in the network
843 * profile */
844
845 key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
846 if (!key) {
847 wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
848 return -1;
849 }
850
851 group = crypto_ec_key_group(key);
852 if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
853 group)) {
854 crypto_ec_key_deinit(key);
855 return -1;
856 }
857
858 wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
859 elems.fils_key_confirm, elems.fils_key_confirm_len);
860
861 hash_len = sae_group_2_hash_len(group);
862 if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
863 k_ap, k_ap_len, hash) < 0) {
864 crypto_ec_key_deinit(key);
865 return -1;
866 }
867
868 res = crypto_ec_key_verify_signature(key, hash, hash_len,
869 elems.fils_key_confirm,
870 elems.fils_key_confirm_len);
871 crypto_ec_key_deinit(key);
872
873 if (res != 1) {
874 wpa_printf(MSG_INFO,
875 "SAE-PK: Invalid or incorrect signature in KeyAuth");
876 return -1;
877 }
878
879 wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
880
881 /* TODO: Store validated public key into network profile */
882
883 return 0;
884 }
885