1 /* 2 * EAP-WSC peer for Wi-Fi Protected Setup 3 * Copyright (c) 2007-2009, 2012, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "uuid.h" 13 #include "eap_i.h" 14 #include "eap_common/eap_wsc_common.h" 15 #include "wps/wps.h" 16 #include "wps/wps_defs.h" 17 18 19 struct eap_wsc_data { 20 enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 21 int registrar; 22 struct wpabuf *in_buf; 23 struct wpabuf *out_buf; 24 enum wsc_op_code in_op_code, out_op_code; 25 size_t out_used; 26 size_t fragment_size; 27 struct wps_data *wps; 28 struct wps_context *wps_ctx; 29 }; 30 31 32 static const char * eap_wsc_state_txt(int state) 33 { 34 switch (state) { 35 case WAIT_START: 36 return "WAIT_START"; 37 case MESG: 38 return "MESG"; 39 case FRAG_ACK: 40 return "FRAG_ACK"; 41 case WAIT_FRAG_ACK: 42 return "WAIT_FRAG_ACK"; 43 case DONE: 44 return "DONE"; 45 case FAIL: 46 return "FAIL"; 47 default: 48 return "?"; 49 } 50 } 51 52 53 static void eap_wsc_state(struct eap_wsc_data *data, int state) 54 { 55 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 56 eap_wsc_state_txt(data->state), 57 eap_wsc_state_txt(state)); 58 data->state = state; 59 } 60 61 62 static int eap_wsc_new_ap_settings(struct wps_credential *cred, 63 const char *params) 64 { 65 const char *pos, *end; 66 size_t len; 67 68 os_memset(cred, 0, sizeof(*cred)); 69 70 pos = os_strstr(params, "new_ssid="); 71 if (pos == NULL) 72 return 0; 73 pos += 9; 74 end = os_strchr(pos, ' '); 75 if (end == NULL) 76 len = os_strlen(pos); 77 else 78 len = end - pos; 79 if ((len & 1) || len > 2 * sizeof(cred->ssid) || 80 hexstr2bin(pos, cred->ssid, len / 2)) { 81 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid"); 82 return -1; 83 } 84 cred->ssid_len = len / 2; 85 86 pos = os_strstr(params, "new_auth="); 87 if (pos == NULL) { 88 wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth"); 89 return -1; 90 } 91 if (os_strncmp(pos + 9, "OPEN", 4) == 0) 92 cred->auth_type = WPS_AUTH_OPEN; 93 else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) 94 cred->auth_type = WPS_AUTH_WPAPSK; 95 else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) 96 cred->auth_type = WPS_AUTH_WPA2PSK; 97 else { 98 wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth"); 99 return -1; 100 } 101 102 pos = os_strstr(params, "new_encr="); 103 if (pos == NULL) { 104 wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr"); 105 return -1; 106 } 107 if (os_strncmp(pos + 9, "NONE", 4) == 0) 108 cred->encr_type = WPS_ENCR_NONE; 109 #ifdef CONFIG_TESTING_OPTIONS 110 else if (os_strncmp(pos + 9, "WEP", 3) == 0) 111 cred->encr_type = WPS_ENCR_WEP; 112 #endif /* CONFIG_TESTING_OPTIONS */ 113 else if (os_strncmp(pos + 9, "TKIP", 4) == 0) 114 cred->encr_type = WPS_ENCR_TKIP; 115 else if (os_strncmp(pos + 9, "CCMP", 4) == 0) 116 cred->encr_type = WPS_ENCR_AES; 117 else { 118 wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr"); 119 return -1; 120 } 121 122 pos = os_strstr(params, "new_key="); 123 if (pos == NULL) 124 return 0; 125 pos += 8; 126 end = os_strchr(pos, ' '); 127 if (end == NULL) 128 len = os_strlen(pos); 129 else 130 len = end - pos; 131 if ((len & 1) || len > 2 * sizeof(cred->key) || 132 hexstr2bin(pos, cred->key, len / 2)) { 133 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key"); 134 return -1; 135 } 136 cred->key_len = len / 2; 137 138 return 1; 139 } 140 141 142 static void * eap_wsc_init(struct eap_sm *sm) 143 { 144 struct eap_wsc_data *data; 145 const u8 *identity; 146 size_t identity_len; 147 int registrar; 148 struct wps_config cfg; 149 const char *pos, *end; 150 const char *phase1; 151 struct wps_context *wps; 152 struct wps_credential new_ap_settings; 153 int res; 154 int nfc = 0; 155 u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN]; 156 157 wps = sm->wps; 158 if (wps == NULL) { 159 wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); 160 return NULL; 161 } 162 163 identity = eap_get_config_identity(sm, &identity_len); 164 165 if (identity && identity_len == WSC_ID_REGISTRAR_LEN && 166 os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) 167 registrar = 1; /* Supplicant is Registrar */ 168 else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && 169 os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) 170 registrar = 0; /* Supplicant is Enrollee */ 171 else { 172 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 173 identity, identity_len); 174 return NULL; 175 } 176 177 data = os_zalloc(sizeof(*data)); 178 if (data == NULL) 179 return NULL; 180 data->state = registrar ? MESG : WAIT_START; 181 data->registrar = registrar; 182 data->wps_ctx = wps; 183 184 os_memset(&cfg, 0, sizeof(cfg)); 185 cfg.wps = wps; 186 cfg.registrar = registrar; 187 188 phase1 = eap_get_config_phase1(sm); 189 if (phase1 == NULL) { 190 wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " 191 "set"); 192 os_free(data); 193 return NULL; 194 } 195 196 pos = os_strstr(phase1, "pin="); 197 if (pos) { 198 pos += 4; 199 cfg.pin = (const u8 *) pos; 200 while (*pos != '\0' && *pos != ' ') 201 pos++; 202 cfg.pin_len = pos - (const char *) cfg.pin; 203 if (cfg.pin_len == 6 && 204 os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) { 205 cfg.pin = NULL; 206 cfg.pin_len = 0; 207 nfc = 1; 208 } 209 } else { 210 pos = os_strstr(phase1, "pbc=1"); 211 if (pos) 212 cfg.pbc = 1; 213 } 214 215 pos = os_strstr(phase1, "dev_pw_id="); 216 if (pos) { 217 u16 id = atoi(pos + 10); 218 if (id == DEV_PW_NFC_CONNECTION_HANDOVER) 219 nfc = 1; 220 if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER) 221 cfg.dev_pw_id = id; 222 } 223 224 if (cfg.pin == NULL && !cfg.pbc && !nfc) { 225 wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " 226 "configuration data"); 227 os_free(data); 228 return NULL; 229 } 230 231 pos = os_strstr(phase1, " pkhash="); 232 if (pos) { 233 size_t len; 234 pos += 8; 235 end = os_strchr(pos, ' '); 236 if (end) 237 len = end - pos; 238 else 239 len = os_strlen(pos); 240 if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN || 241 hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) { 242 wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash"); 243 os_free(data); 244 return NULL; 245 } 246 cfg.peer_pubkey_hash = pkhash; 247 } 248 249 res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); 250 if (res < 0) { 251 os_free(data); 252 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP " 253 "settings"); 254 return NULL; 255 } 256 if (res == 1) { 257 wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " 258 "WPS"); 259 cfg.new_ap_settings = &new_ap_settings; 260 } 261 262 data->wps = wps_init(&cfg); 263 if (data->wps == NULL) { 264 os_free(data); 265 wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed"); 266 return NULL; 267 } 268 res = eap_get_config_fragment_size(sm); 269 if (res > 0) 270 data->fragment_size = res; 271 else 272 data->fragment_size = WSC_FRAGMENT_SIZE; 273 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", 274 (unsigned int) data->fragment_size); 275 276 if (registrar && cfg.pin) { 277 wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, 278 cfg.pin, cfg.pin_len, 0); 279 } 280 281 /* Use reduced client timeout for WPS to avoid long wait */ 282 if (sm->ClientTimeout > 30) 283 sm->ClientTimeout = 30; 284 285 return data; 286 } 287 288 289 static void eap_wsc_deinit(struct eap_sm *sm, void *priv) 290 { 291 struct eap_wsc_data *data = priv; 292 wpabuf_free(data->in_buf); 293 wpabuf_free(data->out_buf); 294 wps_deinit(data->wps); 295 os_free(data->wps_ctx->network_key); 296 data->wps_ctx->network_key = NULL; 297 os_free(data); 298 } 299 300 301 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, 302 struct eap_method_ret *ret, u8 id) 303 { 304 struct wpabuf *resp; 305 u8 flags; 306 size_t send_len, plen; 307 308 ret->ignore = FALSE; 309 wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); 310 ret->allowNotifications = TRUE; 311 312 flags = 0; 313 send_len = wpabuf_len(data->out_buf) - data->out_used; 314 if (2 + send_len > data->fragment_size) { 315 send_len = data->fragment_size - 2; 316 flags |= WSC_FLAGS_MF; 317 if (data->out_used == 0) { 318 flags |= WSC_FLAGS_LF; 319 send_len -= 2; 320 } 321 } 322 plen = 2 + send_len; 323 if (flags & WSC_FLAGS_LF) 324 plen += 2; 325 resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 326 EAP_CODE_RESPONSE, id); 327 if (resp == NULL) 328 return NULL; 329 330 wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ 331 wpabuf_put_u8(resp, flags); /* Flags */ 332 if (flags & WSC_FLAGS_LF) 333 wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); 334 335 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 336 send_len); 337 data->out_used += send_len; 338 339 ret->methodState = METHOD_MAY_CONT; 340 ret->decision = DECISION_FAIL; 341 342 if (data->out_used == wpabuf_len(data->out_buf)) { 343 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 344 "(message sent completely)", 345 (unsigned long) send_len); 346 wpabuf_free(data->out_buf); 347 data->out_buf = NULL; 348 data->out_used = 0; 349 if ((data->state == FAIL && data->out_op_code == WSC_ACK) || 350 data->out_op_code == WSC_NACK || 351 data->out_op_code == WSC_Done) { 352 eap_wsc_state(data, FAIL); 353 ret->methodState = METHOD_DONE; 354 } else 355 eap_wsc_state(data, MESG); 356 } else { 357 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 358 "(%lu more to send)", (unsigned long) send_len, 359 (unsigned long) wpabuf_len(data->out_buf) - 360 data->out_used); 361 eap_wsc_state(data, WAIT_FRAG_ACK); 362 } 363 364 return resp; 365 } 366 367 368 static int eap_wsc_process_cont(struct eap_wsc_data *data, 369 const u8 *buf, size_t len, u8 op_code) 370 { 371 /* Process continuation of a pending message */ 372 if (op_code != data->in_op_code) { 373 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 374 "fragment (expected %d)", 375 op_code, data->in_op_code); 376 return -1; 377 } 378 379 if (len > wpabuf_tailroom(data->in_buf)) { 380 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 381 eap_wsc_state(data, FAIL); 382 return -1; 383 } 384 385 wpabuf_put_data(data->in_buf, buf, len); 386 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " 387 "for %lu bytes more", (unsigned long) len, 388 (unsigned long) wpabuf_tailroom(data->in_buf)); 389 390 return 0; 391 } 392 393 394 static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, 395 struct eap_method_ret *ret, 396 u8 id, u8 flags, u8 op_code, 397 u16 message_length, 398 const u8 *buf, size_t len) 399 { 400 /* Process a fragment that is not the last one of the message */ 401 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 402 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " 403 "fragmented packet"); 404 ret->ignore = TRUE; 405 return NULL; 406 } 407 408 if (data->in_buf == NULL) { 409 /* First fragment of the message */ 410 data->in_buf = wpabuf_alloc(message_length); 411 if (data->in_buf == NULL) { 412 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 413 "message"); 414 ret->ignore = TRUE; 415 return NULL; 416 } 417 data->in_op_code = op_code; 418 wpabuf_put_data(data->in_buf, buf, len); 419 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " 420 "fragment, waiting for %lu bytes more", 421 (unsigned long) len, 422 (unsigned long) wpabuf_tailroom(data->in_buf)); 423 } 424 425 return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); 426 } 427 428 429 static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, 430 struct eap_method_ret *ret, 431 const struct wpabuf *reqData) 432 { 433 struct eap_wsc_data *data = priv; 434 const u8 *start, *pos, *end; 435 size_t len; 436 u8 op_code, flags, id; 437 u16 message_length = 0; 438 enum wps_process_res res; 439 struct wpabuf tmpbuf; 440 struct wpabuf *r; 441 442 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, 443 &len); 444 if (pos == NULL || len < 2) { 445 ret->ignore = TRUE; 446 return NULL; 447 } 448 449 id = eap_get_id(reqData); 450 451 start = pos; 452 end = start + len; 453 454 op_code = *pos++; 455 flags = *pos++; 456 if (flags & WSC_FLAGS_LF) { 457 if (end - pos < 2) { 458 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 459 ret->ignore = TRUE; 460 return NULL; 461 } 462 message_length = WPA_GET_BE16(pos); 463 pos += 2; 464 465 if (message_length < end - pos) { 466 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 467 "Length"); 468 ret->ignore = TRUE; 469 return NULL; 470 } 471 } 472 473 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 474 "Flags 0x%x Message Length %d", 475 op_code, flags, message_length); 476 477 if (data->state == WAIT_FRAG_ACK) { 478 if (op_code != WSC_FRAG_ACK) { 479 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 480 "in WAIT_FRAG_ACK state", op_code); 481 ret->ignore = TRUE; 482 return NULL; 483 } 484 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 485 eap_wsc_state(data, MESG); 486 return eap_wsc_build_msg(data, ret, id); 487 } 488 489 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 490 op_code != WSC_Done && op_code != WSC_Start) { 491 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 492 op_code); 493 ret->ignore = TRUE; 494 return NULL; 495 } 496 497 if (data->state == WAIT_START) { 498 if (op_code != WSC_Start) { 499 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 500 "in WAIT_START state", op_code); 501 ret->ignore = TRUE; 502 return NULL; 503 } 504 wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); 505 eap_wsc_state(data, MESG); 506 /* Start message has empty payload, skip processing */ 507 goto send_msg; 508 } else if (op_code == WSC_Start) { 509 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 510 op_code); 511 ret->ignore = TRUE; 512 return NULL; 513 } 514 515 if (data->in_buf && 516 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 517 ret->ignore = TRUE; 518 return NULL; 519 } 520 521 if (flags & WSC_FLAGS_MF) { 522 return eap_wsc_process_fragment(data, ret, id, flags, op_code, 523 message_length, pos, 524 end - pos); 525 } 526 527 if (data->in_buf == NULL) { 528 /* Wrap unfragmented messages as wpabuf without extra copy */ 529 wpabuf_set(&tmpbuf, pos, end - pos); 530 data->in_buf = &tmpbuf; 531 } 532 533 res = wps_process_msg(data->wps, op_code, data->in_buf); 534 switch (res) { 535 case WPS_DONE: 536 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 537 "successfully - wait for EAP failure"); 538 eap_wsc_state(data, FAIL); 539 break; 540 case WPS_CONTINUE: 541 eap_wsc_state(data, MESG); 542 break; 543 case WPS_FAILURE: 544 case WPS_PENDING: 545 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 546 eap_wsc_state(data, FAIL); 547 break; 548 } 549 550 if (data->in_buf != &tmpbuf) 551 wpabuf_free(data->in_buf); 552 data->in_buf = NULL; 553 554 send_msg: 555 if (data->out_buf == NULL) { 556 data->out_buf = wps_get_msg(data->wps, &data->out_op_code); 557 if (data->out_buf == NULL) { 558 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " 559 "message from WPS"); 560 return NULL; 561 } 562 data->out_used = 0; 563 } 564 565 eap_wsc_state(data, MESG); 566 r = eap_wsc_build_msg(data, ret, id); 567 if (data->state == FAIL && ret->methodState == METHOD_DONE) { 568 /* Use reduced client timeout for WPS to avoid long wait */ 569 if (sm->ClientTimeout > 2) 570 sm->ClientTimeout = 2; 571 } 572 return r; 573 } 574 575 576 int eap_peer_wsc_register(void) 577 { 578 struct eap_method *eap; 579 int ret; 580 581 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 582 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 583 "WSC"); 584 if (eap == NULL) 585 return -1; 586 587 eap->init = eap_wsc_init; 588 eap->deinit = eap_wsc_deinit; 589 eap->process = eap_wsc_process; 590 591 ret = eap_peer_method_register(eap); 592 if (ret) 593 eap_peer_method_free(eap); 594 return ret; 595 } 596