$search
00001 /* 00002 * EAP-WSC server for Wi-Fi Protected Setup 00003 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eloop.h" 00019 #include "eap_i.h" 00020 #include "eap_common/eap_wsc_common.h" 00021 #include "wps/wps.h" 00022 00023 00024 struct eap_wsc_data { 00025 enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 00026 int registrar; 00027 struct wpabuf *in_buf; 00028 struct wpabuf *out_buf; 00029 enum wsc_op_code in_op_code, out_op_code; 00030 size_t out_used; 00031 size_t fragment_size; 00032 struct wps_data *wps; 00033 int ext_reg_timeout; 00034 }; 00035 00036 00037 #ifndef CONFIG_NO_STDOUT_DEBUG 00038 static const char * eap_wsc_state_txt(int state) 00039 { 00040 switch (state) { 00041 case START: 00042 return "START"; 00043 case MESG: 00044 return "MESG"; 00045 case FRAG_ACK: 00046 return "FRAG_ACK"; 00047 case WAIT_FRAG_ACK: 00048 return "WAIT_FRAG_ACK"; 00049 case DONE: 00050 return "DONE"; 00051 case FAIL: 00052 return "FAIL"; 00053 default: 00054 return "?"; 00055 } 00056 } 00057 #endif /* CONFIG_NO_STDOUT_DEBUG */ 00058 00059 00060 static void eap_wsc_state(struct eap_wsc_data *data, int state) 00061 { 00062 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 00063 eap_wsc_state_txt(data->state), 00064 eap_wsc_state_txt(state)); 00065 data->state = state; 00066 } 00067 00068 00069 static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) 00070 { 00071 struct eap_sm *sm = eloop_ctx; 00072 struct eap_wsc_data *data = timeout_ctx; 00073 00074 if (sm->method_pending != METHOD_PENDING_WAIT) 00075 return; 00076 00077 wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " 00078 "Registrar"); 00079 data->ext_reg_timeout = 1; 00080 eap_sm_pending_cb(sm); 00081 } 00082 00083 00084 static void * eap_wsc_init(struct eap_sm *sm) 00085 { 00086 struct eap_wsc_data *data; 00087 int registrar; 00088 struct wps_config cfg; 00089 00090 if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && 00091 os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 00092 0) 00093 registrar = 0; /* Supplicant is Registrar */ 00094 else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN && 00095 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) 00096 == 0) 00097 registrar = 1; /* Supplicant is Enrollee */ 00098 else { 00099 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 00100 sm->identity, sm->identity_len); 00101 return NULL; 00102 } 00103 00104 data = os_zalloc(sizeof(*data)); 00105 if (data == NULL) 00106 return NULL; 00107 data->state = registrar ? START : MESG; 00108 data->registrar = registrar; 00109 00110 os_memset(&cfg, 0, sizeof(cfg)); 00111 cfg.wps = sm->wps; 00112 cfg.registrar = registrar; 00113 if (registrar) { 00114 if (sm->wps == NULL || sm->wps->registrar == NULL) { 00115 wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " 00116 "initialized"); 00117 os_free(data); 00118 return NULL; 00119 } 00120 } else { 00121 if (sm->user == NULL || sm->user->password == NULL) { 00122 wpa_printf(MSG_INFO, "EAP-WSC: No AP PIN (password) " 00123 "configured for Enrollee functionality"); 00124 os_free(data); 00125 return NULL; 00126 } 00127 cfg.pin = sm->user->password; 00128 cfg.pin_len = sm->user->password_len; 00129 } 00130 cfg.assoc_wps_ie = sm->assoc_wps_ie; 00131 cfg.peer_addr = sm->peer_addr; 00132 if (0 /* TODO: could provide option for forcing PSK format */) 00133 cfg.use_psk_key = 1; 00134 data->wps = wps_init(&cfg); 00135 if (data->wps == NULL) { 00136 os_free(data); 00137 return NULL; 00138 } 00139 data->fragment_size = WSC_FRAGMENT_SIZE; 00140 00141 return data; 00142 } 00143 00144 00145 static void eap_wsc_reset(struct eap_sm *sm, void *priv) 00146 { 00147 struct eap_wsc_data *data = priv; 00148 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 00149 wpabuf_free(data->in_buf); 00150 wpabuf_free(data->out_buf); 00151 wps_deinit(data->wps); 00152 os_free(data); 00153 } 00154 00155 00156 static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm, 00157 struct eap_wsc_data *data, u8 id) 00158 { 00159 struct wpabuf *req; 00160 00161 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, 00162 EAP_CODE_REQUEST, id); 00163 if (req == NULL) { 00164 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 00165 "request"); 00166 return NULL; 00167 } 00168 00169 wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start"); 00170 wpabuf_put_u8(req, WSC_Start); /* Op-Code */ 00171 wpabuf_put_u8(req, 0); /* Flags */ 00172 00173 return req; 00174 } 00175 00176 00177 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) 00178 { 00179 struct wpabuf *req; 00180 u8 flags; 00181 size_t send_len, plen; 00182 00183 flags = 0; 00184 send_len = wpabuf_len(data->out_buf) - data->out_used; 00185 if (2 + send_len > data->fragment_size) { 00186 send_len = data->fragment_size - 2; 00187 flags |= WSC_FLAGS_MF; 00188 if (data->out_used == 0) { 00189 flags |= WSC_FLAGS_LF; 00190 send_len -= 2; 00191 } 00192 } 00193 plen = 2 + send_len; 00194 if (flags & WSC_FLAGS_LF) 00195 plen += 2; 00196 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 00197 EAP_CODE_REQUEST, id); 00198 if (req == NULL) { 00199 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 00200 "request"); 00201 return NULL; 00202 } 00203 00204 wpabuf_put_u8(req, data->out_op_code); /* Op-Code */ 00205 wpabuf_put_u8(req, flags); /* Flags */ 00206 if (flags & WSC_FLAGS_LF) 00207 wpabuf_put_be16(req, wpabuf_len(data->out_buf)); 00208 00209 wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 00210 send_len); 00211 data->out_used += send_len; 00212 00213 if (data->out_used == wpabuf_len(data->out_buf)) { 00214 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 00215 "(message sent completely)", 00216 (unsigned long) send_len); 00217 wpabuf_free(data->out_buf); 00218 data->out_buf = NULL; 00219 data->out_used = 0; 00220 eap_wsc_state(data, MESG); 00221 } else { 00222 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 00223 "(%lu more to send)", (unsigned long) send_len, 00224 (unsigned long) wpabuf_len(data->out_buf) - 00225 data->out_used); 00226 eap_wsc_state(data, WAIT_FRAG_ACK); 00227 } 00228 00229 return req; 00230 } 00231 00232 00233 static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) 00234 { 00235 struct eap_wsc_data *data = priv; 00236 00237 switch (data->state) { 00238 case START: 00239 return eap_wsc_build_start(sm, data, id); 00240 case MESG: 00241 if (data->out_buf == NULL) { 00242 data->out_buf = wps_get_msg(data->wps, 00243 &data->out_op_code); 00244 if (data->out_buf == NULL) { 00245 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to " 00246 "receive message from WPS"); 00247 return NULL; 00248 } 00249 data->out_used = 0; 00250 } 00251 /* pass through */ 00252 case WAIT_FRAG_ACK: 00253 return eap_wsc_build_msg(data, id); 00254 case FRAG_ACK: 00255 return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST); 00256 default: 00257 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in " 00258 "buildReq", data->state); 00259 return NULL; 00260 } 00261 } 00262 00263 00264 static Boolean eap_wsc_check(struct eap_sm *sm, void *priv, 00265 struct wpabuf *respData) 00266 { 00267 const u8 *pos; 00268 size_t len; 00269 00270 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 00271 respData, &len); 00272 if (pos == NULL || len < 2) { 00273 wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame"); 00274 return TRUE; 00275 } 00276 00277 return FALSE; 00278 } 00279 00280 00281 static int eap_wsc_process_cont(struct eap_wsc_data *data, 00282 const u8 *buf, size_t len, u8 op_code) 00283 { 00284 /* Process continuation of a pending message */ 00285 if (op_code != data->in_op_code) { 00286 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 00287 "fragment (expected %d)", 00288 op_code, data->in_op_code); 00289 eap_wsc_state(data, FAIL); 00290 return -1; 00291 } 00292 00293 if (len > wpabuf_tailroom(data->in_buf)) { 00294 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 00295 eap_wsc_state(data, FAIL); 00296 return -1; 00297 } 00298 00299 wpabuf_put_data(data->in_buf, buf, len); 00300 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " 00301 "bytes more", (unsigned long) len, 00302 (unsigned long) wpabuf_tailroom(data->in_buf)); 00303 00304 return 0; 00305 } 00306 00307 00308 static int eap_wsc_process_fragment(struct eap_wsc_data *data, 00309 u8 flags, u8 op_code, u16 message_length, 00310 const u8 *buf, size_t len) 00311 { 00312 /* Process a fragment that is not the last one of the message */ 00313 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 00314 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length " 00315 "field in a fragmented packet"); 00316 return -1; 00317 } 00318 00319 if (data->in_buf == NULL) { 00320 /* First fragment of the message */ 00321 data->in_buf = wpabuf_alloc(message_length); 00322 if (data->in_buf == NULL) { 00323 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 00324 "message"); 00325 return -1; 00326 } 00327 data->in_op_code = op_code; 00328 wpabuf_put_data(data->in_buf, buf, len); 00329 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in " 00330 "first fragment, waiting for %lu bytes more", 00331 (unsigned long) len, 00332 (unsigned long) wpabuf_tailroom(data->in_buf)); 00333 } 00334 00335 return 0; 00336 } 00337 00338 00339 static void eap_wsc_process(struct eap_sm *sm, void *priv, 00340 struct wpabuf *respData) 00341 { 00342 struct eap_wsc_data *data = priv; 00343 const u8 *start, *pos, *end; 00344 size_t len; 00345 u8 op_code, flags; 00346 u16 message_length = 0; 00347 enum wps_process_res res; 00348 struct wpabuf tmpbuf; 00349 00350 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 00351 if (data->ext_reg_timeout) { 00352 eap_wsc_state(data, FAIL); 00353 return; 00354 } 00355 00356 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 00357 respData, &len); 00358 if (pos == NULL || len < 2) 00359 return; /* Should not happen; message already verified */ 00360 00361 start = pos; 00362 end = start + len; 00363 00364 op_code = *pos++; 00365 flags = *pos++; 00366 if (flags & WSC_FLAGS_LF) { 00367 if (end - pos < 2) { 00368 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 00369 return; 00370 } 00371 message_length = WPA_GET_BE16(pos); 00372 pos += 2; 00373 00374 if (message_length < end - pos) { 00375 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 00376 "Length"); 00377 return; 00378 } 00379 } 00380 00381 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 00382 "Flags 0x%x Message Length %d", 00383 op_code, flags, message_length); 00384 00385 if (data->state == WAIT_FRAG_ACK) { 00386 if (op_code != WSC_FRAG_ACK) { 00387 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 00388 "in WAIT_FRAG_ACK state", op_code); 00389 eap_wsc_state(data, FAIL); 00390 return; 00391 } 00392 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 00393 eap_wsc_state(data, MESG); 00394 return; 00395 } 00396 00397 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 00398 op_code != WSC_Done) { 00399 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 00400 op_code); 00401 eap_wsc_state(data, FAIL); 00402 return; 00403 } 00404 00405 if (data->in_buf && 00406 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 00407 eap_wsc_state(data, FAIL); 00408 return; 00409 } 00410 00411 if (flags & WSC_FLAGS_MF) { 00412 if (eap_wsc_process_fragment(data, flags, op_code, 00413 message_length, pos, end - pos) < 00414 0) 00415 eap_wsc_state(data, FAIL); 00416 else 00417 eap_wsc_state(data, FRAG_ACK); 00418 return; 00419 } 00420 00421 if (data->in_buf == NULL) { 00422 /* Wrap unfragmented messages as wpabuf without extra copy */ 00423 wpabuf_set(&tmpbuf, pos, end - pos); 00424 data->in_buf = &tmpbuf; 00425 } 00426 00427 res = wps_process_msg(data->wps, op_code, data->in_buf); 00428 switch (res) { 00429 case WPS_DONE: 00430 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 00431 "successfully - report EAP failure"); 00432 eap_wsc_state(data, FAIL); 00433 break; 00434 case WPS_CONTINUE: 00435 eap_wsc_state(data, MESG); 00436 break; 00437 case WPS_FAILURE: 00438 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 00439 eap_wsc_state(data, FAIL); 00440 break; 00441 case WPS_PENDING: 00442 eap_wsc_state(data, MESG); 00443 sm->method_pending = METHOD_PENDING_WAIT; 00444 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 00445 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, 00446 sm, data); 00447 break; 00448 } 00449 00450 if (data->in_buf != &tmpbuf) 00451 wpabuf_free(data->in_buf); 00452 data->in_buf = NULL; 00453 } 00454 00455 00456 static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv) 00457 { 00458 struct eap_wsc_data *data = priv; 00459 return data->state == FAIL; 00460 } 00461 00462 00463 static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv) 00464 { 00465 /* EAP-WSC will always result in EAP-Failure */ 00466 return FALSE; 00467 } 00468 00469 00470 static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv) 00471 { 00472 /* Recommended retransmit times: retransmit timeout 5 seconds, 00473 * per-message timeout 15 seconds, i.e., 3 tries. */ 00474 sm->MaxRetrans = 2; /* total 3 attempts */ 00475 return 5; 00476 } 00477 00478 00479 int eap_server_wsc_register(void) 00480 { 00481 struct eap_method *eap; 00482 int ret; 00483 00484 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 00485 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 00486 "WSC"); 00487 if (eap == NULL) 00488 return -1; 00489 00490 eap->init = eap_wsc_init; 00491 eap->reset = eap_wsc_reset; 00492 eap->buildReq = eap_wsc_buildReq; 00493 eap->check = eap_wsc_check; 00494 eap->process = eap_wsc_process; 00495 eap->isDone = eap_wsc_isDone; 00496 eap->isSuccess = eap_wsc_isSuccess; 00497 eap->getTimeout = eap_wsc_getTimeout; 00498 00499 ret = eap_server_method_register(eap); 00500 if (ret) 00501 eap_server_method_free(eap); 00502 return ret; 00503 }