00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
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
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
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
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
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
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 }