pmksa_cache_auth.c
Go to the documentation of this file.
00001 /*
00002  * hostapd - PMKSA cache for IEEE 802.11i RSN
00003  * Copyright (c) 2004-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 "utils/includes.h"
00016 
00017 #include "utils/common.h"
00018 #include "utils/eloop.h"
00019 #include "eapol_auth/eapol_auth_sm.h"
00020 #include "eapol_auth/eapol_auth_sm_i.h"
00021 #include "sta_info.h"
00022 #include "ap_config.h"
00023 #include "pmksa_cache_auth.h"
00024 
00025 
00026 static const int pmksa_cache_max_entries = 1024;
00027 static const int dot11RSNAConfigPMKLifetime = 43200;
00028 
00029 struct rsn_pmksa_cache {
00030 #define PMKID_HASH_SIZE 128
00031 #define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
00032         struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
00033         struct rsn_pmksa_cache_entry *pmksa;
00034         int pmksa_count;
00035 
00036         void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
00037         void *ctx;
00038 };
00039 
00040 
00041 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
00042 
00043 
00044 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
00045 {
00046         if (entry == NULL)
00047                 return;
00048         os_free(entry->identity);
00049 #ifndef CONFIG_NO_RADIUS
00050         radius_free_class(&entry->radius_class);
00051 #endif /* CONFIG_NO_RADIUS */
00052         os_free(entry);
00053 }
00054 
00055 
00056 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
00057                                    struct rsn_pmksa_cache_entry *entry)
00058 {
00059         struct rsn_pmksa_cache_entry *pos, *prev;
00060 
00061         pmksa->pmksa_count--;
00062         pmksa->free_cb(entry, pmksa->ctx);
00063         pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
00064         prev = NULL;
00065         while (pos) {
00066                 if (pos == entry) {
00067                         if (prev != NULL) {
00068                                 prev->hnext = pos->hnext;
00069                         } else {
00070                                 pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
00071                                         pos->hnext;
00072                         }
00073                         break;
00074                 }
00075                 prev = pos;
00076                 pos = pos->hnext;
00077         }
00078 
00079         pos = pmksa->pmksa;
00080         prev = NULL;
00081         while (pos) {
00082                 if (pos == entry) {
00083                         if (prev != NULL)
00084                                 prev->next = pos->next;
00085                         else
00086                                 pmksa->pmksa = pos->next;
00087                         break;
00088                 }
00089                 prev = pos;
00090                 pos = pos->next;
00091         }
00092         _pmksa_cache_free_entry(entry);
00093 }
00094 
00095 
00096 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
00097 {
00098         struct rsn_pmksa_cache *pmksa = eloop_ctx;
00099         struct os_time now;
00100 
00101         os_get_time(&now);
00102         while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
00103                 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00104                 pmksa->pmksa = entry->next;
00105                 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
00106                            MACSTR, MAC2STR(entry->spa));
00107                 pmksa_cache_free_entry(pmksa, entry);
00108         }
00109 
00110         pmksa_cache_set_expiration(pmksa);
00111 }
00112 
00113 
00114 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
00115 {
00116         int sec;
00117         struct os_time now;
00118 
00119         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
00120         if (pmksa->pmksa == NULL)
00121                 return;
00122         os_get_time(&now);
00123         sec = pmksa->pmksa->expiration - now.sec;
00124         if (sec < 0)
00125                 sec = 0;
00126         eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
00127 }
00128 
00129 
00130 static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
00131                                         struct eapol_state_machine *eapol)
00132 {
00133         if (eapol == NULL)
00134                 return;
00135 
00136         if (eapol->identity) {
00137                 entry->identity = os_malloc(eapol->identity_len);
00138                 if (entry->identity) {
00139                         entry->identity_len = eapol->identity_len;
00140                         os_memcpy(entry->identity, eapol->identity,
00141                                   eapol->identity_len);
00142                 }
00143         }
00144 
00145 #ifndef CONFIG_NO_RADIUS
00146         radius_copy_class(&entry->radius_class, &eapol->radius_class);
00147 #endif /* CONFIG_NO_RADIUS */
00148 
00149         entry->eap_type_authsrv = eapol->eap_type_authsrv;
00150         entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
00151 }
00152 
00153 
00154 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
00155                                struct eapol_state_machine *eapol)
00156 {
00157         if (entry == NULL || eapol == NULL)
00158                 return;
00159 
00160         if (entry->identity) {
00161                 os_free(eapol->identity);
00162                 eapol->identity = os_malloc(entry->identity_len);
00163                 if (eapol->identity) {
00164                         eapol->identity_len = entry->identity_len;
00165                         os_memcpy(eapol->identity, entry->identity,
00166                                   entry->identity_len);
00167                 }
00168                 wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
00169                                   eapol->identity, eapol->identity_len);
00170         }
00171 
00172 #ifndef CONFIG_NO_RADIUS
00173         radius_free_class(&eapol->radius_class);
00174         radius_copy_class(&eapol->radius_class, &entry->radius_class);
00175 #endif /* CONFIG_NO_RADIUS */
00176         if (eapol->radius_class.attr) {
00177                 wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
00178                            "PMKSA", (unsigned long) eapol->radius_class.count);
00179         }
00180 
00181         eapol->eap_type_authsrv = entry->eap_type_authsrv;
00182         ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
00183 }
00184 
00185 
00186 static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
00187                                    struct rsn_pmksa_cache_entry *entry)
00188 {
00189         struct rsn_pmksa_cache_entry *pos, *prev;
00190 
00191         /* Add the new entry; order by expiration time */
00192         pos = pmksa->pmksa;
00193         prev = NULL;
00194         while (pos) {
00195                 if (pos->expiration > entry->expiration)
00196                         break;
00197                 prev = pos;
00198                 pos = pos->next;
00199         }
00200         if (prev == NULL) {
00201                 entry->next = pmksa->pmksa;
00202                 pmksa->pmksa = entry;
00203         } else {
00204                 entry->next = prev->next;
00205                 prev->next = entry;
00206         }
00207         entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
00208         pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
00209 
00210         pmksa->pmksa_count++;
00211         wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
00212                    MAC2STR(entry->spa));
00213         wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
00214 }
00215 
00216 
00234 struct rsn_pmksa_cache_entry *
00235 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
00236                      const u8 *pmk, size_t pmk_len,
00237                 const u8 *aa, const u8 *spa, int session_timeout,
00238                 struct eapol_state_machine *eapol, int akmp)
00239 {
00240         struct rsn_pmksa_cache_entry *entry, *pos;
00241         struct os_time now;
00242 
00243         if (pmk_len > PMK_LEN)
00244                 return NULL;
00245 
00246         entry = os_zalloc(sizeof(*entry));
00247         if (entry == NULL)
00248                 return NULL;
00249         os_memcpy(entry->pmk, pmk, pmk_len);
00250         entry->pmk_len = pmk_len;
00251         rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
00252                   wpa_key_mgmt_sha256(akmp));
00253         os_get_time(&now);
00254         entry->expiration = now.sec;
00255         if (session_timeout > 0)
00256                 entry->expiration += session_timeout;
00257         else
00258                 entry->expiration += dot11RSNAConfigPMKLifetime;
00259         entry->akmp = akmp;
00260         os_memcpy(entry->spa, spa, ETH_ALEN);
00261         pmksa_cache_from_eapol_data(entry, eapol);
00262 
00263         /* Replace an old entry for the same STA (if found) with the new entry
00264          */
00265         pos = pmksa_cache_auth_get(pmksa, spa, NULL);
00266         if (pos)
00267                 pmksa_cache_free_entry(pmksa, pos);
00268 
00269         if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
00270                 /* Remove the oldest entry to make room for the new entry */
00271                 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
00272                            "entry (for " MACSTR ") to make room for new one",
00273                            MAC2STR(pmksa->pmksa->spa));
00274                 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
00275         }
00276 
00277         pmksa_cache_link_entry(pmksa, entry);
00278 
00279         return entry;
00280 }
00281 
00282 
00283 struct rsn_pmksa_cache_entry *
00284 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
00285                     const struct rsn_pmksa_cache_entry *old_entry,
00286                     const u8 *aa, const u8 *pmkid)
00287 {
00288         struct rsn_pmksa_cache_entry *entry;
00289 
00290         entry = os_zalloc(sizeof(*entry));
00291         if (entry == NULL)
00292                 return NULL;
00293         os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
00294         os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
00295         entry->pmk_len = old_entry->pmk_len;
00296         entry->expiration = old_entry->expiration;
00297         entry->akmp = old_entry->akmp;
00298         os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
00299         entry->opportunistic = 1;
00300         if (old_entry->identity) {
00301                 entry->identity = os_malloc(old_entry->identity_len);
00302                 if (entry->identity) {
00303                         entry->identity_len = old_entry->identity_len;
00304                         os_memcpy(entry->identity, old_entry->identity,
00305                                   old_entry->identity_len);
00306                 }
00307         }
00308 #ifndef CONFIG_NO_RADIUS
00309         radius_copy_class(&entry->radius_class, &old_entry->radius_class);
00310 #endif /* CONFIG_NO_RADIUS */
00311         entry->eap_type_authsrv = old_entry->eap_type_authsrv;
00312         entry->vlan_id = old_entry->vlan_id;
00313         entry->opportunistic = 1;
00314 
00315         pmksa_cache_link_entry(pmksa, entry);
00316 
00317         return entry;
00318 }
00319 
00320 
00325 void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
00326 {
00327         struct rsn_pmksa_cache_entry *entry, *prev;
00328         int i;
00329 
00330         if (pmksa == NULL)
00331                 return;
00332 
00333         entry = pmksa->pmksa;
00334         while (entry) {
00335                 prev = entry;
00336                 entry = entry->next;
00337                 _pmksa_cache_free_entry(prev);
00338         }
00339         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
00340         for (i = 0; i < PMKID_HASH_SIZE; i++)
00341                 pmksa->pmkid[i] = NULL;
00342         os_free(pmksa);
00343 }
00344 
00345 
00353 struct rsn_pmksa_cache_entry *
00354 pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
00355                      const u8 *spa, const u8 *pmkid)
00356 {
00357         struct rsn_pmksa_cache_entry *entry;
00358 
00359         if (pmkid)
00360                 entry = pmksa->pmkid[PMKID_HASH(pmkid)];
00361         else
00362                 entry = pmksa->pmksa;
00363         while (entry) {
00364                 if ((spa == NULL ||
00365                      os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
00366                     (pmkid == NULL ||
00367                      os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
00368                         return entry;
00369                 entry = pmkid ? entry->hnext : entry->next;
00370         }
00371         return NULL;
00372 }
00373 
00374 
00385 struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
00386         struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
00387         const u8 *pmkid)
00388 {
00389         struct rsn_pmksa_cache_entry *entry;
00390         u8 new_pmkid[PMKID_LEN];
00391 
00392         entry = pmksa->pmksa;
00393         while (entry) {
00394                 if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
00395                         continue;
00396                 rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
00397                           wpa_key_mgmt_sha256(entry->akmp));
00398                 if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
00399                         return entry;
00400                 entry = entry->next;
00401         }
00402         return NULL;
00403 }
00404 
00405 
00412 struct rsn_pmksa_cache *
00413 pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
00414                                       void *ctx), void *ctx)
00415 {
00416         struct rsn_pmksa_cache *pmksa;
00417 
00418         pmksa = os_zalloc(sizeof(*pmksa));
00419         if (pmksa) {
00420                 pmksa->free_cb = free_cb;
00421                 pmksa->ctx = ctx;
00422         }
00423 
00424         return pmksa;
00425 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:38