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