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


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