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 else if (os_strncmp(pos + 9, "WEP", 3) == 0) 110 cred->encr_type = WPS_ENCR_WEP; 111 else if (os_strncmp(pos + 9, "TKIP", 4) == 0) 112 cred->encr_type = WPS_ENCR_TKIP; 113 else if (os_strncmp(pos + 9, "CCMP", 4) == 0) 114 cred->encr_type = WPS_ENCR_AES; 115 else { 116 wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr"); 117 return -1; 118 } 119 120 pos = os_strstr(params, "new_key="); 121 if (pos == NULL) 122 return 0; 123 pos += 8; 124 end = os_strchr(pos, ' '); 125 if (end == NULL) 126 len = os_strlen(pos); 127 else 128 len = end - pos; 129 if ((len & 1) || len > 2 * sizeof(cred->key) || 130 hexstr2bin(pos, cred->key, len / 2)) { 131 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key"); 132 return -1; 133 } 134 cred->key_len = len / 2; 135 136 return 1; 137 } 138 139 140 static void * eap_wsc_init(struct eap_sm *sm) 141 { 142 struct eap_wsc_data *data; 143 const u8 *identity; 144 size_t identity_len; 145 int registrar; 146 struct wps_config cfg; 147 const char *pos; 148 const char *phase1; 149 struct wps_context *wps; 150 struct wps_credential new_ap_settings; 151 int res; 152 int nfc = 0; 153 154 wps = sm->wps; 155 if (wps == NULL) { 156 wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); 157 return NULL; 158 } 159 160 identity = eap_get_config_identity(sm, &identity_len); 161 162 if (identity && identity_len == WSC_ID_REGISTRAR_LEN && 163 os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) 164 registrar = 1; /* Supplicant is Registrar */ 165 else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && 166 os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) 167 registrar = 0; /* Supplicant is Enrollee */ 168 else { 169 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 170 identity, identity_len); 171 return NULL; 172 } 173 174 data = os_zalloc(sizeof(*data)); 175 if (data == NULL) 176 return NULL; 177 data->state = registrar ? MESG : WAIT_START; 178 data->registrar = registrar; 179 data->wps_ctx = wps; 180 181 os_memset(&cfg, 0, sizeof(cfg)); 182 cfg.wps = wps; 183 cfg.registrar = registrar; 184 185 phase1 = eap_get_config_phase1(sm); 186 if (phase1 == NULL) { 187 wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " 188 "set"); 189 os_free(data); 190 return NULL; 191 } 192 193 pos = os_strstr(phase1, "pin="); 194 if (pos) { 195 pos += 4; 196 cfg.pin = (const u8 *) pos; 197 while (*pos != '\0' && *pos != ' ') 198 pos++; 199 cfg.pin_len = pos - (const char *) cfg.pin; 200 if (cfg.pin_len == 6 && 201 os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) { 202 cfg.pin = NULL; 203 cfg.pin_len = 0; 204 nfc = 1; 205 } 206 } else { 207 pos = os_strstr(phase1, "pbc=1"); 208 if (pos) 209 cfg.pbc = 1; 210 } 211 212 if (cfg.pin == NULL && !cfg.pbc && !nfc) { 213 wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " 214 "configuration data"); 215 os_free(data); 216 return NULL; 217 } 218 219 pos = os_strstr(phase1, "dev_pw_id="); 220 if (pos && cfg.pin) 221 cfg.dev_pw_id = atoi(pos + 10); 222 223 res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); 224 if (res < 0) { 225 os_free(data); 226 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP " 227 "settings"); 228 return NULL; 229 } 230 if (res == 1) { 231 wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " 232 "WPS"); 233 cfg.new_ap_settings = &new_ap_settings; 234 } 235 236 data->wps = wps_init(&cfg); 237 if (data->wps == NULL) { 238 os_free(data); 239 wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed"); 240 return NULL; 241 } 242 res = eap_get_config_fragment_size(sm); 243 if (res > 0) 244 data->fragment_size = res; 245 else 246 data->fragment_size = WSC_FRAGMENT_SIZE; 247 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", 248 (unsigned int) data->fragment_size); 249 250 if (registrar && cfg.pin) { 251 wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, 252 cfg.pin, cfg.pin_len, 0); 253 } 254 255 /* Use reduced client timeout for WPS to avoid long wait */ 256 if (sm->ClientTimeout > 30) 257 sm->ClientTimeout = 30; 258 259 return data; 260 } 261 262 263 static void eap_wsc_deinit(struct eap_sm *sm, void *priv) 264 { 265 struct eap_wsc_data *data = priv; 266 wpabuf_free(data->in_buf); 267 wpabuf_free(data->out_buf); 268 wps_deinit(data->wps); 269 os_free(data->wps_ctx->network_key); 270 data->wps_ctx->network_key = NULL; 271 os_free(data); 272 } 273 274 275 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, 276 struct eap_method_ret *ret, u8 id) 277 { 278 struct wpabuf *resp; 279 u8 flags; 280 size_t send_len, plen; 281 282 ret->ignore = FALSE; 283 wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); 284 ret->allowNotifications = TRUE; 285 286 flags = 0; 287 send_len = wpabuf_len(data->out_buf) - data->out_used; 288 if (2 + send_len > data->fragment_size) { 289 send_len = data->fragment_size - 2; 290 flags |= WSC_FLAGS_MF; 291 if (data->out_used == 0) { 292 flags |= WSC_FLAGS_LF; 293 send_len -= 2; 294 } 295 } 296 plen = 2 + send_len; 297 if (flags & WSC_FLAGS_LF) 298 plen += 2; 299 resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 300 EAP_CODE_RESPONSE, id); 301 if (resp == NULL) 302 return NULL; 303 304 wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ 305 wpabuf_put_u8(resp, flags); /* Flags */ 306 if (flags & WSC_FLAGS_LF) 307 wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); 308 309 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 310 send_len); 311 data->out_used += send_len; 312 313 ret->methodState = METHOD_MAY_CONT; 314 ret->decision = DECISION_FAIL; 315 316 if (data->out_used == wpabuf_len(data->out_buf)) { 317 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 318 "(message sent completely)", 319 (unsigned long) send_len); 320 wpabuf_free(data->out_buf); 321 data->out_buf = NULL; 322 data->out_used = 0; 323 if ((data->state == FAIL && data->out_op_code == WSC_ACK) || 324 data->out_op_code == WSC_NACK || 325 data->out_op_code == WSC_Done) { 326 eap_wsc_state(data, FAIL); 327 ret->methodState = METHOD_DONE; 328 } else 329 eap_wsc_state(data, MESG); 330 } else { 331 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 332 "(%lu more to send)", (unsigned long) send_len, 333 (unsigned long) wpabuf_len(data->out_buf) - 334 data->out_used); 335 eap_wsc_state(data, WAIT_FRAG_ACK); 336 } 337 338 return resp; 339 } 340 341 342 static int eap_wsc_process_cont(struct eap_wsc_data *data, 343 const u8 *buf, size_t len, u8 op_code) 344 { 345 /* Process continuation of a pending message */ 346 if (op_code != data->in_op_code) { 347 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 348 "fragment (expected %d)", 349 op_code, data->in_op_code); 350 return -1; 351 } 352 353 if (len > wpabuf_tailroom(data->in_buf)) { 354 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 355 eap_wsc_state(data, FAIL); 356 return -1; 357 } 358 359 wpabuf_put_data(data->in_buf, buf, len); 360 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " 361 "for %lu bytes more", (unsigned long) len, 362 (unsigned long) wpabuf_tailroom(data->in_buf)); 363 364 return 0; 365 } 366 367 368 static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, 369 struct eap_method_ret *ret, 370 u8 id, u8 flags, u8 op_code, 371 u16 message_length, 372 const u8 *buf, size_t len) 373 { 374 /* Process a fragment that is not the last one of the message */ 375 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 376 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " 377 "fragmented packet"); 378 ret->ignore = TRUE; 379 return NULL; 380 } 381 382 if (data->in_buf == NULL) { 383 /* First fragment of the message */ 384 data->in_buf = wpabuf_alloc(message_length); 385 if (data->in_buf == NULL) { 386 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 387 "message"); 388 ret->ignore = TRUE; 389 return NULL; 390 } 391 data->in_op_code = op_code; 392 wpabuf_put_data(data->in_buf, buf, len); 393 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " 394 "fragment, waiting for %lu bytes more", 395 (unsigned long) len, 396 (unsigned long) wpabuf_tailroom(data->in_buf)); 397 } 398 399 return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); 400 } 401 402 403 static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, 404 struct eap_method_ret *ret, 405 const struct wpabuf *reqData) 406 { 407 struct eap_wsc_data *data = priv; 408 const u8 *start, *pos, *end; 409 size_t len; 410 u8 op_code, flags, id; 411 u16 message_length = 0; 412 enum wps_process_res res; 413 struct wpabuf tmpbuf; 414 struct wpabuf *r; 415 416 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, 417 &len); 418 if (pos == NULL || len < 2) { 419 ret->ignore = TRUE; 420 return NULL; 421 } 422 423 id = eap_get_id(reqData); 424 425 start = pos; 426 end = start + len; 427 428 op_code = *pos++; 429 flags = *pos++; 430 if (flags & WSC_FLAGS_LF) { 431 if (end - pos < 2) { 432 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 433 ret->ignore = TRUE; 434 return NULL; 435 } 436 message_length = WPA_GET_BE16(pos); 437 pos += 2; 438 439 if (message_length < end - pos) { 440 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 441 "Length"); 442 ret->ignore = TRUE; 443 return NULL; 444 } 445 } 446 447 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 448 "Flags 0x%x Message Length %d", 449 op_code, flags, message_length); 450 451 if (data->state == WAIT_FRAG_ACK) { 452 if (op_code != WSC_FRAG_ACK) { 453 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 454 "in WAIT_FRAG_ACK state", op_code); 455 ret->ignore = TRUE; 456 return NULL; 457 } 458 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 459 eap_wsc_state(data, MESG); 460 return eap_wsc_build_msg(data, ret, id); 461 } 462 463 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 464 op_code != WSC_Done && op_code != WSC_Start) { 465 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 466 op_code); 467 ret->ignore = TRUE; 468 return NULL; 469 } 470 471 if (data->state == WAIT_START) { 472 if (op_code != WSC_Start) { 473 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 474 "in WAIT_START state", op_code); 475 ret->ignore = TRUE; 476 return NULL; 477 } 478 wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); 479 eap_wsc_state(data, MESG); 480 /* Start message has empty payload, skip processing */ 481 goto send_msg; 482 } else if (op_code == WSC_Start) { 483 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 484 op_code); 485 ret->ignore = TRUE; 486 return NULL; 487 } 488 489 if (data->in_buf && 490 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 491 ret->ignore = TRUE; 492 return NULL; 493 } 494 495 if (flags & WSC_FLAGS_MF) { 496 return eap_wsc_process_fragment(data, ret, id, flags, op_code, 497 message_length, pos, 498 end - pos); 499 } 500 501 if (data->in_buf == NULL) { 502 /* Wrap unfragmented messages as wpabuf without extra copy */ 503 wpabuf_set(&tmpbuf, pos, end - pos); 504 data->in_buf = &tmpbuf; 505 } 506 507 res = wps_process_msg(data->wps, op_code, data->in_buf); 508 switch (res) { 509 case WPS_DONE: 510 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 511 "successfully - wait for EAP failure"); 512 eap_wsc_state(data, FAIL); 513 break; 514 case WPS_CONTINUE: 515 eap_wsc_state(data, MESG); 516 break; 517 case WPS_FAILURE: 518 case WPS_PENDING: 519 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 520 eap_wsc_state(data, FAIL); 521 break; 522 } 523 524 if (data->in_buf != &tmpbuf) 525 wpabuf_free(data->in_buf); 526 data->in_buf = NULL; 527 528 send_msg: 529 if (data->out_buf == NULL) { 530 data->out_buf = wps_get_msg(data->wps, &data->out_op_code); 531 if (data->out_buf == NULL) { 532 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " 533 "message from WPS"); 534 return NULL; 535 } 536 data->out_used = 0; 537 } 538 539 eap_wsc_state(data, MESG); 540 r = eap_wsc_build_msg(data, ret, id); 541 if (data->state == FAIL && ret->methodState == METHOD_DONE) { 542 /* Use reduced client timeout for WPS to avoid long wait */ 543 if (sm->ClientTimeout > 2) 544 sm->ClientTimeout = 2; 545 } 546 return r; 547 } 548 549 550 int eap_peer_wsc_register(void) 551 { 552 struct eap_method *eap; 553 int ret; 554 555 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 556 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 557 "WSC"); 558 if (eap == NULL) 559 return -1; 560 561 eap->init = eap_wsc_init; 562 eap->deinit = eap_wsc_deinit; 563 eap->process = eap_wsc_process; 564 565 ret = eap_peer_method_register(eap); 566 if (ret) 567 eap_peer_method_free(eap); 568 return ret; 569 } 570