00001
00016 #include "includes.h"
00017
00018 #include "common.h"
00019 #include "wpa.h"
00020 #include "eloop.h"
00021 #include "sha1.h"
00022 #include "sha256.h"
00023 #include "wpa_i.h"
00024 #include "eapol_supp/eapol_supp_sm.h"
00025 #include "pmksa_cache.h"
00026
00027 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
00028
00029 static const int pmksa_cache_max_entries = 32;
00030
00031 struct rsn_pmksa_cache {
00032 struct rsn_pmksa_cache_entry *pmksa;
00033 int pmksa_count;
00034 struct wpa_sm *sm;
00035
00036 void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
00037 int replace);
00038 void *ctx;
00039 };
00040
00041
00042 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
00043
00044
00045 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
00046 {
00047 os_free(entry);
00048 }
00049
00050
00051 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
00052 struct rsn_pmksa_cache_entry *entry,
00053 int replace)
00054 {
00055 pmksa->pmksa_count--;
00056 pmksa->free_cb(entry, pmksa->ctx, replace);
00057 _pmksa_cache_free_entry(entry);
00058 }
00059
00060
00061 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
00062 {
00063 struct rsn_pmksa_cache *pmksa = eloop_ctx;
00064 struct os_time now;
00065
00066 os_get_time(&now);
00067 while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
00068 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00069 pmksa->pmksa = entry->next;
00070 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
00071 MACSTR, MAC2STR(entry->aa));
00072 pmksa_cache_free_entry(pmksa, entry, 0);
00073 }
00074
00075 pmksa_cache_set_expiration(pmksa);
00076 }
00077
00078
00079 static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
00080 {
00081 struct rsn_pmksa_cache *pmksa = eloop_ctx;
00082 pmksa->sm->cur_pmksa = NULL;
00083 eapol_sm_request_reauth(pmksa->sm->eapol);
00084 }
00085
00086
00087 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
00088 {
00089 int sec;
00090 struct rsn_pmksa_cache_entry *entry;
00091 struct os_time now;
00092
00093 eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
00094 eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
00095 if (pmksa->pmksa == NULL)
00096 return;
00097 os_get_time(&now);
00098 sec = pmksa->pmksa->expiration - now.sec;
00099 if (sec < 0)
00100 sec = 0;
00101 eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
00102
00103 entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
00104 pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL);
00105 if (entry) {
00106 sec = pmksa->pmksa->reauth_time - now.sec;
00107 if (sec < 0)
00108 sec = 0;
00109 eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
00110 NULL);
00111 }
00112 }
00113
00114
00132 struct rsn_pmksa_cache_entry *
00133 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
00134 const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
00135 {
00136 struct rsn_pmksa_cache_entry *entry, *pos, *prev;
00137 struct os_time now;
00138
00139 if (pmk_len > PMK_LEN)
00140 return NULL;
00141
00142 entry = os_zalloc(sizeof(*entry));
00143 if (entry == NULL)
00144 return NULL;
00145 os_memcpy(entry->pmk, pmk, pmk_len);
00146 entry->pmk_len = pmk_len;
00147 rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
00148 wpa_key_mgmt_sha256(akmp));
00149 os_get_time(&now);
00150 entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
00151 entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
00152 pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
00153 entry->akmp = akmp;
00154 os_memcpy(entry->aa, aa, ETH_ALEN);
00155 entry->network_ctx = network_ctx;
00156
00157
00158
00159 pos = pmksa->pmksa;
00160 prev = NULL;
00161 while (pos) {
00162 if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
00163 if (pos->pmk_len == pmk_len &&
00164 os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
00165 os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
00166 0) {
00167 wpa_printf(MSG_DEBUG, "WPA: reusing previous "
00168 "PMKSA entry");
00169 os_free(entry);
00170 return pos;
00171 }
00172 if (prev == NULL)
00173 pmksa->pmksa = pos->next;
00174 else
00175 prev->next = pos->next;
00176 if (pos == pmksa->sm->cur_pmksa) {
00177
00178
00179
00180
00181
00182
00183
00184
00185 wpa_printf(MSG_DEBUG, "RSN: replacing current "
00186 "PMKSA entry");
00187 pmksa->sm->cur_pmksa = NULL;
00188 }
00189 wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
00190 "the current AP");
00191 pmksa_cache_free_entry(pmksa, pos, 1);
00192 break;
00193 }
00194 prev = pos;
00195 pos = pos->next;
00196 }
00197
00198 if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
00199
00200 pos = pmksa->pmksa;
00201 pmksa->pmksa = pos->next;
00202 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
00203 "entry (for " MACSTR ") to make room for new one",
00204 MAC2STR(pos->aa));
00205 wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
00206 pmksa_cache_free_entry(pmksa, pos, 0);
00207 }
00208
00209
00210 pos = pmksa->pmksa;
00211 prev = NULL;
00212 while (pos) {
00213 if (pos->expiration > entry->expiration)
00214 break;
00215 prev = pos;
00216 pos = pos->next;
00217 }
00218 if (prev == NULL) {
00219 entry->next = pmksa->pmksa;
00220 pmksa->pmksa = entry;
00221 pmksa_cache_set_expiration(pmksa);
00222 } else {
00223 entry->next = prev->next;
00224 prev->next = entry;
00225 }
00226 pmksa->pmksa_count++;
00227 wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
00228 MAC2STR(entry->aa));
00229 wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
00230
00231 return entry;
00232 }
00233
00234
00240 void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
00241 {
00242 struct rsn_pmksa_cache_entry *entry, *prev;
00243
00244 if (pmksa == NULL)
00245 return;
00246
00247 entry = pmksa->pmksa;
00248 pmksa->pmksa = NULL;
00249 while (entry) {
00250 prev = entry;
00251 entry = entry->next;
00252 os_free(prev);
00253 }
00254 pmksa_cache_set_expiration(pmksa);
00255 os_free(pmksa);
00256 }
00257
00258
00267 struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
00268 const u8 *aa, const u8 *pmkid)
00269 {
00270 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00271 while (entry) {
00272 if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
00273 (pmkid == NULL ||
00274 os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
00275 return entry;
00276 entry = entry->next;
00277 }
00278 return NULL;
00279 }
00280
00281
00289 void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
00290 {
00291 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00292 while (entry) {
00293 entry->network_ctx = NULL;
00294 entry = entry->next;
00295 }
00296 }
00297
00298
00299 static struct rsn_pmksa_cache_entry *
00300 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
00301 const struct rsn_pmksa_cache_entry *old_entry,
00302 const u8 *aa)
00303 {
00304 struct rsn_pmksa_cache_entry *new_entry;
00305
00306 new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
00307 aa, pmksa->sm->own_addr,
00308 old_entry->network_ctx, old_entry->akmp);
00309 if (new_entry == NULL)
00310 return NULL;
00311
00312
00313 new_entry->expiration = old_entry->expiration;
00314 new_entry->opportunistic = 1;
00315
00316 return new_entry;
00317 }
00318
00319
00332 struct rsn_pmksa_cache_entry *
00333 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
00334 const u8 *aa)
00335 {
00336 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00337
00338 if (network_ctx == NULL)
00339 return NULL;
00340 while (entry) {
00341 if (entry->network_ctx == network_ctx) {
00342 entry = pmksa_cache_clone_entry(pmksa, entry, aa);
00343 if (entry) {
00344 wpa_printf(MSG_DEBUG, "RSN: added "
00345 "opportunistic PMKSA cache entry "
00346 "for " MACSTR, MAC2STR(aa));
00347 }
00348 return entry;
00349 }
00350 entry = entry->next;
00351 }
00352 return NULL;
00353 }
00354
00355
00362 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
00363 {
00364 if (sm == NULL)
00365 return NULL;
00366 return sm->cur_pmksa;
00367 }
00368
00369
00375 void pmksa_cache_clear_current(struct wpa_sm *sm)
00376 {
00377 if (sm == NULL)
00378 return;
00379 sm->cur_pmksa = NULL;
00380 }
00381
00382
00393 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
00394 const u8 *bssid, void *network_ctx,
00395 int try_opportunistic)
00396 {
00397 struct rsn_pmksa_cache *pmksa = sm->pmksa;
00398 sm->cur_pmksa = NULL;
00399 if (pmkid)
00400 sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid);
00401 if (sm->cur_pmksa == NULL && bssid)
00402 sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL);
00403 if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
00404 sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
00405 network_ctx,
00406 bssid);
00407 if (sm->cur_pmksa) {
00408 wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
00409 sm->cur_pmksa->pmkid, PMKID_LEN);
00410 return 0;
00411 }
00412 return -1;
00413 }
00414
00415
00427 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
00428 {
00429 int i, ret;
00430 char *pos = buf;
00431 struct rsn_pmksa_cache_entry *entry;
00432 struct os_time now;
00433
00434 os_get_time(&now);
00435 ret = os_snprintf(pos, buf + len - pos,
00436 "Index / AA / PMKID / expiration (in seconds) / "
00437 "opportunistic\n");
00438 if (ret < 0 || ret >= buf + len - pos)
00439 return pos - buf;
00440 pos += ret;
00441 i = 0;
00442 entry = pmksa->pmksa;
00443 while (entry) {
00444 i++;
00445 ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
00446 i, MAC2STR(entry->aa));
00447 if (ret < 0 || ret >= buf + len - pos)
00448 return pos - buf;
00449 pos += ret;
00450 pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
00451 PMKID_LEN);
00452 ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
00453 (int) (entry->expiration - now.sec),
00454 entry->opportunistic);
00455 if (ret < 0 || ret >= buf + len - pos)
00456 return pos - buf;
00457 pos += ret;
00458 entry = entry->next;
00459 }
00460 return pos - buf;
00461 }
00462
00463
00472 struct rsn_pmksa_cache *
00473 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
00474 void *ctx, int replace),
00475 void *ctx, struct wpa_sm *sm)
00476 {
00477 struct rsn_pmksa_cache *pmksa;
00478
00479 pmksa = os_zalloc(sizeof(*pmksa));
00480 if (pmksa) {
00481 pmksa->free_cb = free_cb;
00482 pmksa->ctx = ctx;
00483 pmksa->sm = sm;
00484 }
00485
00486 return pmksa;
00487 }
00488
00489 #endif
00490