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