preauth.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "wpa.h"
00020 #include "drivers/driver.h"
00021 #include "eloop.h"
00022 #include "l2_packet/l2_packet.h"
00023 #include "eapol_supp/eapol_supp_sm.h"
00024 #include "preauth.h"
00025 #include "pmksa_cache.h"
00026 #include "wpa_i.h"
00027 #include "ieee802_11_defs.h"
00028 
00029 
00030 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
00031 
00032 #define PMKID_CANDIDATE_PRIO_SCAN 1000
00033 
00034 
00035 struct rsn_pmksa_candidate {
00036         struct rsn_pmksa_candidate *next;
00037         u8 bssid[ETH_ALEN];
00038         int priority;
00039 };
00040 
00041 
00047 void pmksa_candidate_free(struct wpa_sm *sm)
00048 {
00049         struct rsn_pmksa_candidate *entry, *prev;
00050 
00051         if (sm == NULL)
00052                 return;
00053 
00054         entry = sm->pmksa_candidates;
00055         sm->pmksa_candidates = NULL;
00056         while (entry) {
00057                 prev = entry;
00058                 entry = entry->next;
00059                 os_free(prev);
00060         }
00061 }
00062 
00063 
00064 static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
00065                                 const u8 *buf, size_t len)
00066 {
00067         struct wpa_sm *sm = ctx;
00068 
00069         wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
00070         wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
00071 
00072         if (sm->preauth_eapol == NULL ||
00073             is_zero_ether_addr(sm->preauth_bssid) ||
00074             os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
00075                 wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
00076                            "unexpected source " MACSTR " - dropped",
00077                            MAC2STR(src_addr));
00078                 return;
00079         }
00080 
00081         eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
00082 }
00083 
00084 
00085 static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
00086                                  void *ctx)
00087 {
00088         struct wpa_sm *sm = ctx;
00089         u8 pmk[PMK_LEN];
00090 
00091         if (success) {
00092                 int res, pmk_len;
00093                 pmk_len = PMK_LEN;
00094                 res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
00095                 if (res) {
00096                         /*
00097                          * EAP-LEAP is an exception from other EAP methods: it
00098                          * uses only 16-byte PMK.
00099                          */
00100                         res = eapol_sm_get_key(eapol, pmk, 16);
00101                         pmk_len = 16;
00102                 }
00103                 if (res == 0) {
00104                         wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
00105                                         pmk, pmk_len);
00106                         sm->pmk_len = pmk_len;
00107                         pmksa_cache_add(sm->pmksa, pmk, pmk_len,
00108                                         sm->preauth_bssid, sm->own_addr,
00109                                         sm->network_ctx,
00110                                         WPA_KEY_MGMT_IEEE8021X);
00111                 } else {
00112                         wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
00113                                 "RSN: failed to get master session key from "
00114                                 "pre-auth EAPOL state machines");
00115                         success = 0;
00116                 }
00117         }
00118 
00119         wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
00120                 MACSTR " %s", MAC2STR(sm->preauth_bssid),
00121                 success ? "completed successfully" : "failed");
00122 
00123         rsn_preauth_deinit(sm);
00124         rsn_preauth_candidate_process(sm);
00125 }
00126 
00127 
00128 static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
00129 {
00130         struct wpa_sm *sm = eloop_ctx;
00131 
00132         wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
00133                 MACSTR " timed out", MAC2STR(sm->preauth_bssid));
00134         rsn_preauth_deinit(sm);
00135         rsn_preauth_candidate_process(sm);
00136 }
00137 
00138 
00139 static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
00140                                   size_t len)
00141 {
00142         struct wpa_sm *sm = ctx;
00143         u8 *msg;
00144         size_t msglen;
00145         int res;
00146 
00147         /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
00148          * extra copy here */
00149 
00150         if (sm->l2_preauth == NULL)
00151                 return -1;
00152 
00153         msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
00154         if (msg == NULL)
00155                 return -1;
00156 
00157         wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
00158         res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
00159                              ETH_P_RSN_PREAUTH, msg, msglen);
00160         os_free(msg);
00161         return res;
00162 }
00163 
00164 
00180 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
00181                      struct eap_peer_config *eap_conf)
00182 {
00183         struct eapol_config eapol_conf;
00184         struct eapol_ctx *ctx;
00185 
00186         if (sm->preauth_eapol)
00187                 return -1;
00188 
00189         wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
00190                 "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
00191 
00192         sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
00193                                         ETH_P_RSN_PREAUTH,
00194                                         rsn_preauth_receive, sm, 0);
00195         if (sm->l2_preauth == NULL) {
00196                 wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
00197                            "processing for pre-authentication");
00198                 return -2;
00199         }
00200 
00201         if (sm->bridge_ifname) {
00202                 sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
00203                                                    sm->own_addr,
00204                                                    ETH_P_RSN_PREAUTH,
00205                                                    rsn_preauth_receive, sm, 0);
00206                 if (sm->l2_preauth_br == NULL) {
00207                         wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
00208                                    "packet processing (bridge) for "
00209                                    "pre-authentication");
00210                         return -2;
00211                 }
00212         }
00213 
00214         ctx = os_zalloc(sizeof(*ctx));
00215         if (ctx == NULL) {
00216                 wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
00217                 return -4;
00218         }
00219         ctx->ctx = sm->ctx->ctx;
00220         ctx->msg_ctx = sm->ctx->ctx;
00221         ctx->preauth = 1;
00222         ctx->cb = rsn_preauth_eapol_cb;
00223         ctx->cb_ctx = sm;
00224         ctx->scard_ctx = sm->scard_ctx;
00225         ctx->eapol_send = rsn_preauth_eapol_send;
00226         ctx->eapol_send_ctx = sm;
00227         ctx->set_config_blob = sm->ctx->set_config_blob;
00228         ctx->get_config_blob = sm->ctx->get_config_blob;
00229 
00230         sm->preauth_eapol = eapol_sm_init(ctx);
00231         if (sm->preauth_eapol == NULL) {
00232                 os_free(ctx);
00233                 wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
00234                            "state machines for pre-authentication");
00235                 return -3;
00236         }
00237         os_memset(&eapol_conf, 0, sizeof(eapol_conf));
00238         eapol_conf.accept_802_1x_keys = 0;
00239         eapol_conf.required_keys = 0;
00240         eapol_conf.fast_reauth = sm->fast_reauth;
00241         eapol_conf.workaround = sm->eap_workaround;
00242         eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
00243         /*
00244          * Use a shorter startPeriod with preauthentication since the first
00245          * preauth EAPOL-Start frame may end up being dropped due to race
00246          * condition in the AP between the data receive and key configuration
00247          * after the 4-Way Handshake.
00248          */
00249         eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
00250         os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
00251 
00252         eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
00253         /* 802.1X::portControl = Auto */
00254         eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
00255 
00256         eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
00257                                rsn_preauth_timeout, sm, NULL);
00258 
00259         return 0;
00260 }
00261 
00262 
00271 void rsn_preauth_deinit(struct wpa_sm *sm)
00272 {
00273         if (sm == NULL || !sm->preauth_eapol)
00274                 return;
00275 
00276         eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
00277         eapol_sm_deinit(sm->preauth_eapol);
00278         sm->preauth_eapol = NULL;
00279         os_memset(sm->preauth_bssid, 0, ETH_ALEN);
00280 
00281         l2_packet_deinit(sm->l2_preauth);
00282         sm->l2_preauth = NULL;
00283         if (sm->l2_preauth_br) {
00284                 l2_packet_deinit(sm->l2_preauth_br);
00285                 sm->l2_preauth_br = NULL;
00286         }
00287 }
00288 
00289 
00299 void rsn_preauth_candidate_process(struct wpa_sm *sm)
00300 {
00301         struct rsn_pmksa_candidate *candidate;
00302 
00303         if (sm->pmksa_candidates == NULL)
00304                 return;
00305 
00306         /* TODO: drop priority for old candidate entries */
00307 
00308         wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
00309                 "list");
00310         if (sm->preauth_eapol ||
00311             sm->proto != WPA_PROTO_RSN ||
00312             wpa_sm_get_state(sm) != WPA_COMPLETED ||
00313             (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
00314              sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
00315                 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
00316                         "state for new pre-authentication");
00317                 return; /* invalid state for new pre-auth */
00318         }
00319 
00320         while (sm->pmksa_candidates) {
00321                 struct rsn_pmksa_cache_entry *p = NULL;
00322                 candidate = sm->pmksa_candidates;
00323                 p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
00324                 if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
00325                     (p == NULL || p->opportunistic)) {
00326                         wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
00327                                 "candidate " MACSTR
00328                                 " selected for pre-authentication",
00329                                 MAC2STR(candidate->bssid));
00330                         sm->pmksa_candidates = candidate->next;
00331                         rsn_preauth_init(sm, candidate->bssid,
00332                                          sm->eap_conf_ctx);
00333                         os_free(candidate);
00334                         return;
00335                 }
00336                 wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
00337                         MACSTR " does not need pre-authentication anymore",
00338                         MAC2STR(candidate->bssid));
00339                 /* Some drivers (e.g., NDIS) expect to get notified about the
00340                  * PMKIDs again, so report the existing data now. */
00341                 if (p) {
00342                         wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
00343                 }
00344 
00345                 sm->pmksa_candidates = candidate->next;
00346                 os_free(candidate);
00347         }
00348         wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
00349                 "candidates");
00350 }
00351 
00352 
00365 void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
00366                          int prio, int preauth)
00367 {
00368         struct rsn_pmksa_candidate *cand, *prev, *pos;
00369 
00370         if (sm->network_ctx && sm->proactive_key_caching)
00371                 pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
00372                                               bssid);
00373 
00374         if (!preauth) {
00375                 wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
00376                            "preauth flag");
00377                 return;
00378         }
00379 
00380         /* If BSSID already on candidate list, update the priority of the old
00381          * entry. Do not override priority based on normal scan results. */
00382         prev = NULL;
00383         cand = sm->pmksa_candidates;
00384         while (cand) {
00385                 if (os_memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
00386                         if (prev)
00387                                 prev->next = cand->next;
00388                         else
00389                                 sm->pmksa_candidates = cand->next;
00390                         break;
00391                 }
00392                 prev = cand;
00393                 cand = cand->next;
00394         }
00395 
00396         if (cand) {
00397                 if (prio < PMKID_CANDIDATE_PRIO_SCAN)
00398                         cand->priority = prio;
00399         } else {
00400                 cand = os_zalloc(sizeof(*cand));
00401                 if (cand == NULL)
00402                         return;
00403                 os_memcpy(cand->bssid, bssid, ETH_ALEN);
00404                 cand->priority = prio;
00405         }
00406 
00407         /* Add candidate to the list; order by increasing priority value. i.e.,
00408          * highest priority (smallest value) first. */
00409         prev = NULL;
00410         pos = sm->pmksa_candidates;
00411         while (pos) {
00412                 if (cand->priority <= pos->priority)
00413                         break;
00414                 prev = pos;
00415                 pos = pos->next;
00416         }
00417         cand->next = pos;
00418         if (prev)
00419                 prev->next = cand;
00420         else
00421                 sm->pmksa_candidates = cand;
00422 
00423         wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
00424                 "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
00425         rsn_preauth_candidate_process(sm);
00426 }
00427 
00428 
00429 /* TODO: schedule periodic scans if current AP supports preauth */
00430 
00440 void rsn_preauth_scan_results(struct wpa_sm *sm,
00441                               struct wpa_scan_results *results)
00442 {
00443         struct wpa_scan_res *r;
00444         struct wpa_ie_data ie;
00445         int i;
00446         struct rsn_pmksa_cache_entry *pmksa;
00447 
00448         if (sm->ssid_len == 0)
00449                 return;
00450 
00451         /*
00452          * TODO: is it ok to free all candidates? What about the entries
00453          * received from EVENT_PMKID_CANDIDATE?
00454          */
00455         pmksa_candidate_free(sm);
00456 
00457         for (i = results->num - 1; i >= 0; i--) {
00458                 const u8 *ssid, *rsn;
00459 
00460                 r = results->res[i];
00461 
00462                 ssid = wpa_scan_get_ie(r, WLAN_EID_SSID);
00463                 if (ssid == NULL || ssid[1] != sm->ssid_len ||
00464                     os_memcmp(ssid + 2, sm->ssid, ssid[1]) != 0)
00465                         continue;
00466 
00467                 if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0)
00468                         continue;
00469 
00470                 rsn = wpa_scan_get_ie(r, WLAN_EID_RSN);
00471                 if (rsn == NULL || wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
00472                         continue;
00473 
00474                 pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL);
00475                 if (pmksa &&
00476                     (!pmksa->opportunistic ||
00477                      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
00478                         continue;
00479 
00480                 /*
00481                  * Give less priority to candidates found from normal
00482                  * scan results.
00483                  */
00484                 pmksa_candidate_add(sm, r->bssid,
00485                                     PMKID_CANDIDATE_PRIO_SCAN,
00486                                     ie.capabilities & WPA_CAPABILITY_PREAUTH);
00487         }
00488 }
00489 
00490 
00491 #ifdef CONFIG_CTRL_IFACE
00492 
00505 int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
00506                            int verbose)
00507 {
00508         char *pos = buf, *end = buf + buflen;
00509         int res, ret;
00510 
00511         if (sm->preauth_eapol) {
00512                 ret = os_snprintf(pos, end - pos, "Pre-authentication "
00513                                   "EAPOL state machines:\n");
00514                 if (ret < 0 || ret >= end - pos)
00515                         return pos - buf;
00516                 pos += ret;
00517                 res = eapol_sm_get_status(sm->preauth_eapol,
00518                                           pos, end - pos, verbose);
00519                 if (res >= 0)
00520                         pos += res;
00521         }
00522 
00523         return pos - buf;
00524 }
00525 #endif /* CONFIG_CTRL_IFACE */
00526 
00527 
00533 int rsn_preauth_in_progress(struct wpa_sm *sm)
00534 {
00535         return sm->preauth_eapol != NULL;
00536 }
00537 
00538 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
00539 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:48 2009 for hostapd by  doxygen 1.6.1