$search
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 }