00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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;
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;
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);
00275 wpabuf_put_u8(resp, 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
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
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
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
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
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 }