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