eap_server_wsc.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1/* 2 * EAP-WSC server for Wi-Fi Protected Setup 3 * Copyright (c) 2007-2008, 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 "eloop.h" 19#include "eap_i.h" 20#include "eap_common/eap_wsc_common.h" 21#include "p2p/p2p.h" 22#include "wps/wps.h" 23 24 25struct eap_wsc_data { 26 enum { 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 int ext_reg_timeout; 35}; 36 37 38#ifndef CONFIG_NO_STDOUT_DEBUG 39static const char * eap_wsc_state_txt(int state) 40{ 41 switch (state) { 42 case START: 43 return "START"; 44 case MESG: 45 return "MESG"; 46 case FRAG_ACK: 47 return "FRAG_ACK"; 48 case WAIT_FRAG_ACK: 49 return "WAIT_FRAG_ACK"; 50 case DONE: 51 return "DONE"; 52 case FAIL: 53 return "FAIL"; 54 default: 55 return "?"; 56 } 57} 58#endif /* CONFIG_NO_STDOUT_DEBUG */ 59 60 61static void eap_wsc_state(struct eap_wsc_data *data, int state) 62{ 63 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 64 eap_wsc_state_txt(data->state), 65 eap_wsc_state_txt(state)); 66 data->state = state; 67} 68 69 70static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) 71{ 72 struct eap_sm *sm = eloop_ctx; 73 struct eap_wsc_data *data = timeout_ctx; 74 75 if (sm->method_pending != METHOD_PENDING_WAIT) 76 return; 77 78 wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " 79 "Registrar"); 80 data->ext_reg_timeout = 1; 81 eap_sm_pending_cb(sm); 82} 83 84 85static void * eap_wsc_init(struct eap_sm *sm) 86{ 87 struct eap_wsc_data *data; 88 int registrar; 89 struct wps_config cfg; 90 91 if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && 92 os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 93 0) 94 registrar = 0; /* Supplicant is Registrar */ 95 else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN && 96 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) 97 == 0) 98 registrar = 1; /* Supplicant is Enrollee */ 99 else { 100 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 101 sm->identity, sm->identity_len); 102 return NULL; 103 } 104 105 data = os_zalloc(sizeof(*data)); 106 if (data == NULL) 107 return NULL; 108 data->state = registrar ? START : MESG; 109 data->registrar = registrar; 110 111 os_memset(&cfg, 0, sizeof(cfg)); 112 cfg.wps = sm->wps; 113 cfg.registrar = registrar; 114 if (registrar) { 115 if (sm->wps == NULL || sm->wps->registrar == NULL) { 116 wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " 117 "initialized"); 118 os_free(data); 119 return NULL; 120 } 121 } else { 122 if (sm->user == NULL || sm->user->password == NULL) { 123 /* 124 * In theory, this should not really be needed, but 125 * Windows 7 uses Registrar mode to probe AP's WPS 126 * capabilities before trying to use Enrollee and fails 127 * if the AP does not allow that probing to happen.. 128 */ 129 wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " 130 "configured for Enrollee functionality - " 131 "allow for probing capabilities (M1)"); 132 } else { 133 cfg.pin = sm->user->password; 134 cfg.pin_len = sm->user->password_len; 135 } 136 } 137 cfg.assoc_wps_ie = sm->assoc_wps_ie; 138 cfg.peer_addr = sm->peer_addr; 139#ifdef CONFIG_P2P 140 if (sm->assoc_p2p_ie) { 141 wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " 142 "client"); 143 cfg.use_psk_key = 1; 144 cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); 145 } 146#endif /* CONFIG_P2P */ 147 data->wps = wps_init(&cfg); 148 if (data->wps == NULL) { 149 os_free(data); 150 return NULL; 151 } 152 data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : 153 WSC_FRAGMENT_SIZE; 154 155 return data; 156} 157 158 159static void eap_wsc_reset(struct eap_sm *sm, void *priv) 160{ 161 struct eap_wsc_data *data = priv; 162 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 163 wpabuf_free(data->in_buf); 164 wpabuf_free(data->out_buf); 165 wps_deinit(data->wps); 166 os_free(data); 167} 168 169 170static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm, 171 struct eap_wsc_data *data, u8 id) 172{ 173 struct wpabuf *req; 174 175 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, 176 EAP_CODE_REQUEST, id); 177 if (req == NULL) { 178 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 179 "request"); 180 return NULL; 181 } 182 183 wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start"); 184 wpabuf_put_u8(req, WSC_Start); /* Op-Code */ 185 wpabuf_put_u8(req, 0); /* Flags */ 186 187 return req; 188} 189 190 191static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) 192{ 193 struct wpabuf *req; 194 u8 flags; 195 size_t send_len, plen; 196 197 flags = 0; 198 send_len = wpabuf_len(data->out_buf) - data->out_used; 199 if (2 + send_len > data->fragment_size) { 200 send_len = data->fragment_size - 2; 201 flags |= WSC_FLAGS_MF; 202 if (data->out_used == 0) { 203 flags |= WSC_FLAGS_LF; 204 send_len -= 2; 205 } 206 } 207 plen = 2 + send_len; 208 if (flags & WSC_FLAGS_LF) 209 plen += 2; 210 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 211 EAP_CODE_REQUEST, id); 212 if (req == NULL) { 213 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 214 "request"); 215 return NULL; 216 } 217 218 wpabuf_put_u8(req, data->out_op_code); /* Op-Code */ 219 wpabuf_put_u8(req, flags); /* Flags */ 220 if (flags & WSC_FLAGS_LF) 221 wpabuf_put_be16(req, wpabuf_len(data->out_buf)); 222 223 wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 224 send_len); 225 data->out_used += send_len; 226 227 if (data->out_used == wpabuf_len(data->out_buf)) { 228 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 229 "(message sent completely)", 230 (unsigned long) send_len); 231 wpabuf_free(data->out_buf); 232 data->out_buf = NULL; 233 data->out_used = 0; 234 eap_wsc_state(data, MESG); 235 } else { 236 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 237 "(%lu more to send)", (unsigned long) send_len, 238 (unsigned long) wpabuf_len(data->out_buf) - 239 data->out_used); 240 eap_wsc_state(data, WAIT_FRAG_ACK); 241 } 242 243 return req; 244} 245 246 247static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) 248{ 249 struct eap_wsc_data *data = priv; 250 251 switch (data->state) { 252 case START: 253 return eap_wsc_build_start(sm, data, id); 254 case MESG: 255 if (data->out_buf == NULL) { 256 data->out_buf = wps_get_msg(data->wps, 257 &data->out_op_code); 258 if (data->out_buf == NULL) { 259 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to " 260 "receive message from WPS"); 261 return NULL; 262 } 263 data->out_used = 0; 264 } 265 /* pass through */ 266 case WAIT_FRAG_ACK: 267 return eap_wsc_build_msg(data, id); 268 case FRAG_ACK: 269 return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST); 270 default: 271 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in " 272 "buildReq", data->state); 273 return NULL; 274 } 275} 276 277 278static Boolean eap_wsc_check(struct eap_sm *sm, void *priv, 279 struct wpabuf *respData) 280{ 281 const u8 *pos; 282 size_t len; 283 284 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 285 respData, &len); 286 if (pos == NULL || len < 2) { 287 wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame"); 288 return TRUE; 289 } 290 291 return FALSE; 292} 293 294 295static int eap_wsc_process_cont(struct eap_wsc_data *data, 296 const u8 *buf, size_t len, u8 op_code) 297{ 298 /* Process continuation of a pending message */ 299 if (op_code != data->in_op_code) { 300 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 301 "fragment (expected %d)", 302 op_code, data->in_op_code); 303 eap_wsc_state(data, FAIL); 304 return -1; 305 } 306 307 if (len > wpabuf_tailroom(data->in_buf)) { 308 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 309 eap_wsc_state(data, FAIL); 310 return -1; 311 } 312 313 wpabuf_put_data(data->in_buf, buf, len); 314 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " 315 "bytes more", (unsigned long) len, 316 (unsigned long) wpabuf_tailroom(data->in_buf)); 317 318 return 0; 319} 320 321 322static int eap_wsc_process_fragment(struct eap_wsc_data *data, 323 u8 flags, u8 op_code, u16 message_length, 324 const u8 *buf, size_t len) 325{ 326 /* Process a fragment that is not the last one of the message */ 327 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 328 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length " 329 "field in a fragmented packet"); 330 return -1; 331 } 332 333 if (data->in_buf == NULL) { 334 /* First fragment of the message */ 335 data->in_buf = wpabuf_alloc(message_length); 336 if (data->in_buf == NULL) { 337 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 338 "message"); 339 return -1; 340 } 341 data->in_op_code = op_code; 342 wpabuf_put_data(data->in_buf, buf, len); 343 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in " 344 "first fragment, waiting for %lu bytes more", 345 (unsigned long) len, 346 (unsigned long) wpabuf_tailroom(data->in_buf)); 347 } 348 349 return 0; 350} 351 352 353static void eap_wsc_process(struct eap_sm *sm, void *priv, 354 struct wpabuf *respData) 355{ 356 struct eap_wsc_data *data = priv; 357 const u8 *start, *pos, *end; 358 size_t len; 359 u8 op_code, flags; 360 u16 message_length = 0; 361 enum wps_process_res res; 362 struct wpabuf tmpbuf; 363 364 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 365 if (data->ext_reg_timeout) { 366 eap_wsc_state(data, FAIL); 367 return; 368 } 369 370 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 371 respData, &len); 372 if (pos == NULL || len < 2) 373 return; /* Should not happen; message already verified */ 374 375 start = pos; 376 end = start + len; 377 378 op_code = *pos++; 379 flags = *pos++; 380 if (flags & WSC_FLAGS_LF) { 381 if (end - pos < 2) { 382 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 383 return; 384 } 385 message_length = WPA_GET_BE16(pos); 386 pos += 2; 387 388 if (message_length < end - pos) { 389 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 390 "Length"); 391 return; 392 } 393 } 394 395 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 396 "Flags 0x%x Message Length %d", 397 op_code, flags, message_length); 398 399 if (data->state == WAIT_FRAG_ACK) { 400 if (op_code != WSC_FRAG_ACK) { 401 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 402 "in WAIT_FRAG_ACK state", op_code); 403 eap_wsc_state(data, FAIL); 404 return; 405 } 406 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 407 eap_wsc_state(data, MESG); 408 return; 409 } 410 411 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 412 op_code != WSC_Done) { 413 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 414 op_code); 415 eap_wsc_state(data, FAIL); 416 return; 417 } 418 419 if (data->in_buf && 420 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 421 eap_wsc_state(data, FAIL); 422 return; 423 } 424 425 if (flags & WSC_FLAGS_MF) { 426 if (eap_wsc_process_fragment(data, flags, op_code, 427 message_length, pos, end - pos) < 428 0) 429 eap_wsc_state(data, FAIL); 430 else 431 eap_wsc_state(data, FRAG_ACK); 432 return; 433 } 434 435 if (data->in_buf == NULL) { 436 /* Wrap unfragmented messages as wpabuf without extra copy */ 437 wpabuf_set(&tmpbuf, pos, end - pos); 438 data->in_buf = &tmpbuf; 439 } 440 441 res = wps_process_msg(data->wps, op_code, data->in_buf); 442 switch (res) { 443 case WPS_DONE: 444 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 445 "successfully - report EAP failure"); 446 eap_wsc_state(data, FAIL); 447 break; 448 case WPS_CONTINUE: 449 eap_wsc_state(data, MESG); 450 break; 451 case WPS_FAILURE: 452 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 453 eap_wsc_state(data, FAIL); 454 break; 455 case WPS_PENDING: 456 eap_wsc_state(data, MESG); 457 sm->method_pending = METHOD_PENDING_WAIT; 458 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 459 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, 460 sm, data); 461 break; 462 } 463 464 if (data->in_buf != &tmpbuf) 465 wpabuf_free(data->in_buf); 466 data->in_buf = NULL; 467} 468 469 470static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv) 471{ 472 struct eap_wsc_data *data = priv; 473 return data->state == FAIL; 474} 475 476 477static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv) 478{ 479 /* EAP-WSC will always result in EAP-Failure */ 480 return FALSE; 481} 482 483 484static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv) 485{ 486 /* Recommended retransmit times: retransmit timeout 5 seconds, 487 * per-message timeout 15 seconds, i.e., 3 tries. */ 488 sm->MaxRetrans = 2; /* total 3 attempts */ 489 return 5; 490} 491 492 493int eap_server_wsc_register(void) 494{ 495 struct eap_method *eap; 496 int ret; 497 498 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 499 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 500 "WSC"); 501 if (eap == NULL) 502 return -1; 503 504 eap->init = eap_wsc_init; 505 eap->reset = eap_wsc_reset; 506 eap->buildReq = eap_wsc_buildReq; 507 eap->check = eap_wsc_check; 508 eap->process = eap_wsc_process; 509 eap->isDone = eap_wsc_isDone; 510 eap->isSuccess = eap_wsc_isSuccess; 511 eap->getTimeout = eap_wsc_getTimeout; 512 513 ret = eap_server_method_register(eap); 514 if (ret) 515 eap_server_method_free(eap); 516 return ret; 517} 518