eap_wsc.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35