$search
00001 /* 00002 * EAP-WSC peer for Wi-Fi Protected Setup 00003 * Copyright (c) 2007-2009, 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 "uuid.h" 00019 #include "eap_i.h" 00020 #include "eap_common/eap_wsc_common.h" 00021 #include "wps/wps.h" 00022 #include "wps/wps_defs.h" 00023 00024 00025 struct eap_wsc_data { 00026 enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 00027 int registrar; 00028 struct wpabuf *in_buf; 00029 struct wpabuf *out_buf; 00030 enum wsc_op_code in_op_code, out_op_code; 00031 size_t out_used; 00032 size_t fragment_size; 00033 struct wps_data *wps; 00034 struct wps_context *wps_ctx; 00035 }; 00036 00037 00038 static const char * eap_wsc_state_txt(int state) 00039 { 00040 switch (state) { 00041 case WAIT_START: 00042 return "WAIT_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 00058 00059 static void eap_wsc_state(struct eap_wsc_data *data, int state) 00060 { 00061 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 00062 eap_wsc_state_txt(data->state), 00063 eap_wsc_state_txt(state)); 00064 data->state = state; 00065 } 00066 00067 00068 static int eap_wsc_new_ap_settings(struct wps_credential *cred, 00069 const char *params) 00070 { 00071 const char *pos, *end; 00072 size_t len; 00073 00074 os_memset(cred, 0, sizeof(*cred)); 00075 00076 pos = os_strstr(params, "new_ssid="); 00077 if (pos == NULL) 00078 return 0; 00079 pos += 9; 00080 end = os_strchr(pos, ' '); 00081 if (end == NULL) 00082 len = os_strlen(pos); 00083 else 00084 len = end - pos; 00085 if ((len & 1) || len > 2 * sizeof(cred->ssid) || 00086 hexstr2bin(pos, cred->ssid, len / 2)) 00087 return -1; 00088 cred->ssid_len = len / 2; 00089 00090 pos = os_strstr(params, "new_auth="); 00091 if (pos == NULL) 00092 return -1; 00093 if (os_strncmp(pos + 9, "OPEN", 4) == 0) 00094 cred->auth_type = WPS_AUTH_OPEN; 00095 else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) 00096 cred->auth_type = WPS_AUTH_WPAPSK; 00097 else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) 00098 cred->auth_type = WPS_AUTH_WPA2PSK; 00099 else 00100 return -1; 00101 00102 pos = os_strstr(params, "new_encr="); 00103 if (pos == NULL) 00104 return -1; 00105 if (os_strncmp(pos + 9, "NONE", 4) == 0) 00106 cred->encr_type = WPS_ENCR_NONE; 00107 else if (os_strncmp(pos + 9, "WEP", 3) == 0) 00108 cred->encr_type = WPS_ENCR_WEP; 00109 else if (os_strncmp(pos + 9, "TKIP", 4) == 0) 00110 cred->encr_type = WPS_ENCR_TKIP; 00111 else if (os_strncmp(pos + 9, "CCMP", 4) == 0) 00112 cred->encr_type = WPS_ENCR_AES; 00113 else 00114 return -1; 00115 00116 pos = os_strstr(params, "new_key="); 00117 if (pos == NULL) 00118 return 0; 00119 pos += 8; 00120 end = os_strchr(pos, ' '); 00121 if (end == NULL) 00122 len = os_strlen(pos); 00123 else 00124 len = end - pos; 00125 if ((len & 1) || len > 2 * sizeof(cred->key) || 00126 hexstr2bin(pos, cred->key, len / 2)) 00127 return -1; 00128 cred->key_len = len / 2; 00129 00130 return 1; 00131 } 00132 00133 00134 static void * eap_wsc_init(struct eap_sm *sm) 00135 { 00136 struct eap_wsc_data *data; 00137 const u8 *identity; 00138 size_t identity_len; 00139 int registrar; 00140 struct wps_config cfg; 00141 const char *pos; 00142 const char *phase1; 00143 struct wps_context *wps; 00144 struct wps_credential new_ap_settings; 00145 int res; 00146 00147 wps = sm->wps; 00148 if (wps == NULL) { 00149 wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); 00150 return NULL; 00151 } 00152 00153 identity = eap_get_config_identity(sm, &identity_len); 00154 00155 if (identity && identity_len == WSC_ID_REGISTRAR_LEN && 00156 os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) 00157 registrar = 1; /* Supplicant is Registrar */ 00158 else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && 00159 os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) 00160 registrar = 0; /* Supplicant is Enrollee */ 00161 else { 00162 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 00163 identity, identity_len); 00164 return NULL; 00165 } 00166 00167 data = os_zalloc(sizeof(*data)); 00168 if (data == NULL) 00169 return NULL; 00170 data->state = registrar ? MESG : WAIT_START; 00171 data->registrar = registrar; 00172 data->wps_ctx = wps; 00173 00174 os_memset(&cfg, 0, sizeof(cfg)); 00175 cfg.wps = wps; 00176 cfg.registrar = registrar; 00177 00178 phase1 = eap_get_config_phase1(sm); 00179 if (phase1 == NULL) { 00180 wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " 00181 "set"); 00182 os_free(data); 00183 return NULL; 00184 } 00185 00186 pos = os_strstr(phase1, "pin="); 00187 if (pos) { 00188 pos += 4; 00189 cfg.pin = (const u8 *) pos; 00190 while (*pos != '\0' && *pos != ' ') 00191 pos++; 00192 cfg.pin_len = pos - (const char *) cfg.pin; 00193 } else { 00194 pos = os_strstr(phase1, "pbc=1"); 00195 if (pos) 00196 cfg.pbc = 1; 00197 } 00198 00199 if (cfg.pin == NULL && !cfg.pbc) { 00200 wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " 00201 "configuration data"); 00202 os_free(data); 00203 return NULL; 00204 } 00205 00206 res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); 00207 if (res < 0) { 00208 os_free(data); 00209 return NULL; 00210 } 00211 if (res == 1) { 00212 wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " 00213 "WPS"); 00214 cfg.new_ap_settings = &new_ap_settings; 00215 } 00216 00217 data->wps = wps_init(&cfg); 00218 if (data->wps == NULL) { 00219 os_free(data); 00220 return NULL; 00221 } 00222 data->fragment_size = WSC_FRAGMENT_SIZE; 00223 00224 if (registrar && cfg.pin) { 00225 wps_registrar_add_pin(data->wps_ctx->registrar, NULL, 00226 cfg.pin, cfg.pin_len, 0); 00227 } 00228 00229 return data; 00230 } 00231 00232 00233 static void eap_wsc_deinit(struct eap_sm *sm, void *priv) 00234 { 00235 struct eap_wsc_data *data = priv; 00236 wpabuf_free(data->in_buf); 00237 wpabuf_free(data->out_buf); 00238 wps_deinit(data->wps); 00239 os_free(data->wps_ctx->network_key); 00240 data->wps_ctx->network_key = NULL; 00241 os_free(data); 00242 } 00243 00244 00245 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, 00246 struct eap_method_ret *ret, u8 id) 00247 { 00248 struct wpabuf *resp; 00249 u8 flags; 00250 size_t send_len, plen; 00251 00252 ret->ignore = FALSE; 00253 wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); 00254 ret->allowNotifications = TRUE; 00255 00256 flags = 0; 00257 send_len = wpabuf_len(data->out_buf) - data->out_used; 00258 if (2 + send_len > data->fragment_size) { 00259 send_len = data->fragment_size - 2; 00260 flags |= WSC_FLAGS_MF; 00261 if (data->out_used == 0) { 00262 flags |= WSC_FLAGS_LF; 00263 send_len -= 2; 00264 } 00265 } 00266 plen = 2 + send_len; 00267 if (flags & WSC_FLAGS_LF) 00268 plen += 2; 00269 resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 00270 EAP_CODE_RESPONSE, id); 00271 if (resp == NULL) 00272 return NULL; 00273 00274 wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ 00275 wpabuf_put_u8(resp, flags); /* Flags */ 00276 if (flags & WSC_FLAGS_LF) 00277 wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); 00278 00279 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 00280 send_len); 00281 data->out_used += send_len; 00282 00283 ret->methodState = METHOD_MAY_CONT; 00284 ret->decision = DECISION_FAIL; 00285 00286 if (data->out_used == wpabuf_len(data->out_buf)) { 00287 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 00288 "(message sent completely)", 00289 (unsigned long) send_len); 00290 wpabuf_free(data->out_buf); 00291 data->out_buf = NULL; 00292 data->out_used = 0; 00293 if ((data->state == FAIL && data->out_op_code == WSC_ACK) || 00294 data->out_op_code == WSC_NACK || 00295 data->out_op_code == WSC_Done) { 00296 eap_wsc_state(data, FAIL); 00297 ret->methodState = METHOD_DONE; 00298 } else 00299 eap_wsc_state(data, MESG); 00300 } else { 00301 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 00302 "(%lu more to send)", (unsigned long) send_len, 00303 (unsigned long) wpabuf_len(data->out_buf) - 00304 data->out_used); 00305 eap_wsc_state(data, WAIT_FRAG_ACK); 00306 } 00307 00308 return resp; 00309 } 00310 00311 00312 static int eap_wsc_process_cont(struct eap_wsc_data *data, 00313 const u8 *buf, size_t len, u8 op_code) 00314 { 00315 /* Process continuation of a pending message */ 00316 if (op_code != data->in_op_code) { 00317 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 00318 "fragment (expected %d)", 00319 op_code, data->in_op_code); 00320 return -1; 00321 } 00322 00323 if (len > wpabuf_tailroom(data->in_buf)) { 00324 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 00325 eap_wsc_state(data, FAIL); 00326 return -1; 00327 } 00328 00329 wpabuf_put_data(data->in_buf, buf, len); 00330 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " 00331 "for %lu bytes more", (unsigned long) len, 00332 (unsigned long) wpabuf_tailroom(data->in_buf)); 00333 00334 return 0; 00335 } 00336 00337 00338 static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, 00339 struct eap_method_ret *ret, 00340 u8 id, u8 flags, u8 op_code, 00341 u16 message_length, 00342 const u8 *buf, size_t len) 00343 { 00344 /* Process a fragment that is not the last one of the message */ 00345 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 00346 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " 00347 "fragmented packet"); 00348 ret->ignore = TRUE; 00349 return NULL; 00350 } 00351 00352 if (data->in_buf == NULL) { 00353 /* First fragment of the message */ 00354 data->in_buf = wpabuf_alloc(message_length); 00355 if (data->in_buf == NULL) { 00356 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 00357 "message"); 00358 ret->ignore = TRUE; 00359 return NULL; 00360 } 00361 data->in_op_code = op_code; 00362 wpabuf_put_data(data->in_buf, buf, len); 00363 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " 00364 "fragment, waiting for %lu bytes more", 00365 (unsigned long) len, 00366 (unsigned long) wpabuf_tailroom(data->in_buf)); 00367 } 00368 00369 return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); 00370 } 00371 00372 00373 static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, 00374 struct eap_method_ret *ret, 00375 const struct wpabuf *reqData) 00376 { 00377 struct eap_wsc_data *data = priv; 00378 const u8 *start, *pos, *end; 00379 size_t len; 00380 u8 op_code, flags, id; 00381 u16 message_length = 0; 00382 enum wps_process_res res; 00383 struct wpabuf tmpbuf; 00384 00385 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, 00386 &len); 00387 if (pos == NULL || len < 2) { 00388 ret->ignore = TRUE; 00389 return NULL; 00390 } 00391 00392 id = eap_get_id(reqData); 00393 00394 start = pos; 00395 end = start + len; 00396 00397 op_code = *pos++; 00398 flags = *pos++; 00399 if (flags & WSC_FLAGS_LF) { 00400 if (end - pos < 2) { 00401 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 00402 ret->ignore = TRUE; 00403 return NULL; 00404 } 00405 message_length = WPA_GET_BE16(pos); 00406 pos += 2; 00407 00408 if (message_length < end - pos) { 00409 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 00410 "Length"); 00411 ret->ignore = TRUE; 00412 return NULL; 00413 } 00414 } 00415 00416 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 00417 "Flags 0x%x Message Length %d", 00418 op_code, flags, message_length); 00419 00420 if (data->state == WAIT_FRAG_ACK) { 00421 if (op_code != WSC_FRAG_ACK) { 00422 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 00423 "in WAIT_FRAG_ACK state", op_code); 00424 ret->ignore = TRUE; 00425 return NULL; 00426 } 00427 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 00428 eap_wsc_state(data, MESG); 00429 return eap_wsc_build_msg(data, ret, id); 00430 } 00431 00432 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 00433 op_code != WSC_Done && op_code != WSC_Start) { 00434 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 00435 op_code); 00436 ret->ignore = TRUE; 00437 return NULL; 00438 } 00439 00440 if (data->state == WAIT_START) { 00441 if (op_code != WSC_Start) { 00442 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 00443 "in WAIT_START state", op_code); 00444 ret->ignore = TRUE; 00445 return NULL; 00446 } 00447 wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); 00448 eap_wsc_state(data, MESG); 00449 /* Start message has empty payload, skip processing */ 00450 goto send_msg; 00451 } else if (op_code == WSC_Start) { 00452 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 00453 op_code); 00454 ret->ignore = TRUE; 00455 return NULL; 00456 } 00457 00458 if (data->in_buf && 00459 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 00460 ret->ignore = TRUE; 00461 return NULL; 00462 } 00463 00464 if (flags & WSC_FLAGS_MF) { 00465 return eap_wsc_process_fragment(data, ret, id, flags, op_code, 00466 message_length, pos, 00467 end - pos); 00468 } 00469 00470 if (data->in_buf == NULL) { 00471 /* Wrap unfragmented messages as wpabuf without extra copy */ 00472 wpabuf_set(&tmpbuf, pos, end - pos); 00473 data->in_buf = &tmpbuf; 00474 } 00475 00476 res = wps_process_msg(data->wps, op_code, data->in_buf); 00477 switch (res) { 00478 case WPS_DONE: 00479 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 00480 "successfully - wait for EAP failure"); 00481 eap_wsc_state(data, FAIL); 00482 break; 00483 case WPS_CONTINUE: 00484 eap_wsc_state(data, MESG); 00485 break; 00486 case WPS_FAILURE: 00487 case WPS_PENDING: 00488 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 00489 eap_wsc_state(data, FAIL); 00490 break; 00491 } 00492 00493 if (data->in_buf != &tmpbuf) 00494 wpabuf_free(data->in_buf); 00495 data->in_buf = NULL; 00496 00497 send_msg: 00498 if (data->out_buf == NULL) { 00499 data->out_buf = wps_get_msg(data->wps, &data->out_op_code); 00500 if (data->out_buf == NULL) { 00501 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " 00502 "message from WPS"); 00503 return NULL; 00504 } 00505 data->out_used = 0; 00506 } 00507 00508 eap_wsc_state(data, MESG); 00509 return eap_wsc_build_msg(data, ret, id); 00510 } 00511 00512 00513 int eap_peer_wsc_register(void) 00514 { 00515 struct eap_method *eap; 00516 int ret; 00517 00518 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 00519 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 00520 "WSC"); 00521 if (eap == NULL) 00522 return -1; 00523 00524 eap->init = eap_wsc_init; 00525 eap->deinit = eap_wsc_deinit; 00526 eap->process = eap_wsc_process; 00527 00528 ret = eap_peer_method_register(eap); 00529 if (ret) 00530 eap_peer_method_free(eap); 00531 return ret; 00532 }