xref: /freebsd/contrib/wpa/src/common/sae_pk.c (revision 177034c44ed18d99e6cc85dfddd2bb04b41d38ac)
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 
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 
107 static u8 d_invert(u8 val)
108 {
109 	if (val > 0 && val < 16)
110 		return 16 - val;
111 	return val;
112 }
113 
114 
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 
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 
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 */
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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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