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