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