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