Home | History | Annotate | Line # | Download | only in common
      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