1 /*
2 * hostapd - PMKSA cache for IEEE 802.11i RSN
3 * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "eapol_auth/eapol_auth_sm.h"
14 #include "eapol_auth/eapol_auth_sm_i.h"
15 #include "sta_info.h"
16 #include "ap_config.h"
17 #include "pmksa_cache_auth.h"
18
19
20 static const int pmksa_cache_max_entries = 1024;
21 static const int dot11RSNAConfigPMKLifetime = 43200;
22
23 struct rsn_pmksa_cache {
24 #define PMKID_HASH_SIZE 128
25 #define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
26 struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
27 struct rsn_pmksa_cache_entry *pmksa;
28 int pmksa_count;
29
30 void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
31 void *ctx;
32 };
33
34
35 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
36
37
_pmksa_cache_free_entry(struct rsn_pmksa_cache_entry * entry)38 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
39 {
40 os_free(entry->identity);
41 wpabuf_free(entry->cui);
42 #ifndef CONFIG_NO_RADIUS
43 radius_free_class(&entry->radius_class);
44 #endif /* CONFIG_NO_RADIUS */
45 bin_clear_free(entry, sizeof(*entry));
46 }
47
48
pmksa_cache_free_entry(struct rsn_pmksa_cache * pmksa,struct rsn_pmksa_cache_entry * entry)49 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
50 struct rsn_pmksa_cache_entry *entry)
51 {
52 struct rsn_pmksa_cache_entry *pos, *prev;
53 unsigned int hash;
54
55 pmksa->pmksa_count--;
56 pmksa->free_cb(entry, pmksa->ctx);
57
58 /* unlink from hash list */
59 hash = PMKID_HASH(entry->pmkid);
60 pos = pmksa->pmkid[hash];
61 prev = NULL;
62 while (pos) {
63 if (pos == entry) {
64 if (prev != NULL)
65 prev->hnext = entry->hnext;
66 else
67 pmksa->pmkid[hash] = entry->hnext;
68 break;
69 }
70 prev = pos;
71 pos = pos->hnext;
72 }
73
74 /* unlink from entry list */
75 pos = pmksa->pmksa;
76 prev = NULL;
77 while (pos) {
78 if (pos == entry) {
79 if (prev != NULL)
80 prev->next = entry->next;
81 else
82 pmksa->pmksa = entry->next;
83 break;
84 }
85 prev = pos;
86 pos = pos->next;
87 }
88
89 _pmksa_cache_free_entry(entry);
90 }
91
92
pmksa_cache_expire(void * eloop_ctx,void * timeout_ctx)93 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
94 {
95 struct rsn_pmksa_cache *pmksa = eloop_ctx;
96 struct os_reltime now;
97
98 os_get_reltime(&now);
99 while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
100 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
101 MACSTR, MAC2STR(pmksa->pmksa->spa));
102 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
103 }
104
105 pmksa_cache_set_expiration(pmksa);
106 }
107
108
pmksa_cache_set_expiration(struct rsn_pmksa_cache * pmksa)109 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
110 {
111 int sec;
112 struct os_reltime now;
113
114 eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
115 if (pmksa->pmksa == NULL)
116 return;
117 os_get_reltime(&now);
118 sec = pmksa->pmksa->expiration - now.sec;
119 if (sec < 0)
120 sec = 0;
121 eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
122 }
123
124
pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry * entry,struct eapol_state_machine * eapol)125 static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
126 struct eapol_state_machine *eapol)
127 {
128 if (eapol == NULL)
129 return;
130
131 if (eapol->identity) {
132 entry->identity = os_malloc(eapol->identity_len);
133 if (entry->identity) {
134 entry->identity_len = eapol->identity_len;
135 os_memcpy(entry->identity, eapol->identity,
136 eapol->identity_len);
137 }
138 }
139
140 if (eapol->radius_cui)
141 entry->cui = wpabuf_dup(eapol->radius_cui);
142
143 #ifndef CONFIG_NO_RADIUS
144 radius_copy_class(&entry->radius_class, &eapol->radius_class);
145 #endif /* CONFIG_NO_RADIUS */
146
147 entry->eap_type_authsrv = eapol->eap_type_authsrv;
148 entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
149 }
150
151
pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry * entry,struct eapol_state_machine * eapol)152 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
153 struct eapol_state_machine *eapol)
154 {
155 if (entry == NULL || eapol == NULL)
156 return;
157
158 if (entry->identity) {
159 os_free(eapol->identity);
160 eapol->identity = os_malloc(entry->identity_len);
161 if (eapol->identity) {
162 eapol->identity_len = entry->identity_len;
163 os_memcpy(eapol->identity, entry->identity,
164 entry->identity_len);
165 }
166 wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
167 eapol->identity, eapol->identity_len);
168 }
169
170 if (entry->cui) {
171 wpabuf_free(eapol->radius_cui);
172 eapol->radius_cui = wpabuf_dup(entry->cui);
173 }
174
175 #ifndef CONFIG_NO_RADIUS
176 radius_free_class(&eapol->radius_class);
177 radius_copy_class(&eapol->radius_class, &entry->radius_class);
178 #endif /* CONFIG_NO_RADIUS */
179 if (eapol->radius_class.attr) {
180 wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
181 "PMKSA", (unsigned long) eapol->radius_class.count);
182 }
183
184 eapol->eap_type_authsrv = entry->eap_type_authsrv;
185 ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
186 }
187
188
pmksa_cache_link_entry(struct rsn_pmksa_cache * pmksa,struct rsn_pmksa_cache_entry * entry)189 static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
190 struct rsn_pmksa_cache_entry *entry)
191 {
192 struct rsn_pmksa_cache_entry *pos, *prev;
193 int hash;
194
195 /* Add the new entry; order by expiration time */
196 pos = pmksa->pmksa;
197 prev = NULL;
198 while (pos) {
199 if (pos->expiration > entry->expiration)
200 break;
201 prev = pos;
202 pos = pos->next;
203 }
204 if (prev == NULL) {
205 entry->next = pmksa->pmksa;
206 pmksa->pmksa = entry;
207 } else {
208 entry->next = prev->next;
209 prev->next = entry;
210 }
211
212 hash = PMKID_HASH(entry->pmkid);
213 entry->hnext = pmksa->pmkid[hash];
214 pmksa->pmkid[hash] = entry;
215
216 pmksa->pmksa_count++;
217 if (prev == NULL)
218 pmksa_cache_set_expiration(pmksa);
219 wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
220 MAC2STR(entry->spa));
221 wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
222 }
223
224
225 /**
226 * pmksa_cache_auth_add - Add a PMKSA cache entry
227 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
228 * @pmk: The new pairwise master key
229 * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
230 * @aa: Authenticator address
231 * @spa: Supplicant address
232 * @session_timeout: Session timeout
233 * @eapol: Pointer to EAPOL state machine data
234 * @akmp: WPA_KEY_MGMT_* used in key derivation
235 * Returns: Pointer to the added PMKSA cache entry or %NULL on error
236 *
237 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
238 * cache. If an old entry is already in the cache for the same Supplicant,
239 * this entry will be replaced with the new entry. PMKID will be calculated
240 * based on the PMK.
241 */
242 struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache * pmksa,const u8 * pmk,size_t pmk_len,const u8 * aa,const u8 * spa,int session_timeout,struct eapol_state_machine * eapol,int akmp)243 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
244 const u8 *pmk, size_t pmk_len,
245 const u8 *aa, const u8 *spa, int session_timeout,
246 struct eapol_state_machine *eapol, int akmp)
247 {
248 struct rsn_pmksa_cache_entry *entry, *pos;
249 struct os_reltime now;
250
251 if (pmk_len > PMK_LEN)
252 return NULL;
253
254 entry = os_zalloc(sizeof(*entry));
255 if (entry == NULL)
256 return NULL;
257 os_memcpy(entry->pmk, pmk, pmk_len);
258 entry->pmk_len = pmk_len;
259 rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
260 wpa_key_mgmt_sha256(akmp));
261 os_get_reltime(&now);
262 entry->expiration = now.sec;
263 if (session_timeout > 0)
264 entry->expiration += session_timeout;
265 else
266 entry->expiration += dot11RSNAConfigPMKLifetime;
267 entry->akmp = akmp;
268 os_memcpy(entry->spa, spa, ETH_ALEN);
269 pmksa_cache_from_eapol_data(entry, eapol);
270
271 /* Replace an old entry for the same STA (if found) with the new entry
272 */
273 pos = pmksa_cache_auth_get(pmksa, spa, NULL);
274 if (pos)
275 pmksa_cache_free_entry(pmksa, pos);
276
277 if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
278 /* Remove the oldest entry to make room for the new entry */
279 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
280 "entry (for " MACSTR ") to make room for new one",
281 MAC2STR(pmksa->pmksa->spa));
282 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
283 }
284
285 pmksa_cache_link_entry(pmksa, entry);
286
287 return entry;
288 }
289
290
291 struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache * pmksa,const struct rsn_pmksa_cache_entry * old_entry,const u8 * aa,const u8 * pmkid)292 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
293 const struct rsn_pmksa_cache_entry *old_entry,
294 const u8 *aa, const u8 *pmkid)
295 {
296 struct rsn_pmksa_cache_entry *entry;
297
298 entry = os_zalloc(sizeof(*entry));
299 if (entry == NULL)
300 return NULL;
301 os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
302 os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
303 entry->pmk_len = old_entry->pmk_len;
304 entry->expiration = old_entry->expiration;
305 entry->akmp = old_entry->akmp;
306 os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
307 entry->opportunistic = 1;
308 if (old_entry->identity) {
309 entry->identity = os_malloc(old_entry->identity_len);
310 if (entry->identity) {
311 entry->identity_len = old_entry->identity_len;
312 os_memcpy(entry->identity, old_entry->identity,
313 old_entry->identity_len);
314 }
315 }
316 if (old_entry->cui)
317 entry->cui = wpabuf_dup(old_entry->cui);
318 #ifndef CONFIG_NO_RADIUS
319 radius_copy_class(&entry->radius_class, &old_entry->radius_class);
320 #endif /* CONFIG_NO_RADIUS */
321 entry->eap_type_authsrv = old_entry->eap_type_authsrv;
322 entry->vlan_id = old_entry->vlan_id;
323 entry->opportunistic = 1;
324
325 pmksa_cache_link_entry(pmksa, entry);
326
327 return entry;
328 }
329
330
331 /**
332 * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
333 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
334 */
pmksa_cache_auth_deinit(struct rsn_pmksa_cache * pmksa)335 void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
336 {
337 struct rsn_pmksa_cache_entry *entry, *prev;
338 int i;
339
340 if (pmksa == NULL)
341 return;
342
343 entry = pmksa->pmksa;
344 while (entry) {
345 prev = entry;
346 entry = entry->next;
347 _pmksa_cache_free_entry(prev);
348 }
349 eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
350 pmksa->pmksa_count = 0;
351 pmksa->pmksa = NULL;
352 for (i = 0; i < PMKID_HASH_SIZE; i++)
353 pmksa->pmkid[i] = NULL;
354 os_free(pmksa);
355 }
356
357
358 /**
359 * pmksa_cache_auth_get - Fetch a PMKSA cache entry
360 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
361 * @spa: Supplicant address or %NULL to match any
362 * @pmkid: PMKID or %NULL to match any
363 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
364 */
365 struct rsn_pmksa_cache_entry *
pmksa_cache_auth_get(struct rsn_pmksa_cache * pmksa,const u8 * spa,const u8 * pmkid)366 pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
367 const u8 *spa, const u8 *pmkid)
368 {
369 struct rsn_pmksa_cache_entry *entry;
370
371 if (pmkid) {
372 for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
373 entry = entry->hnext) {
374 if ((spa == NULL ||
375 os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
376 os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
377 return entry;
378 }
379 } else {
380 for (entry = pmksa->pmksa; entry; entry = entry->next) {
381 if (spa == NULL ||
382 os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
383 return entry;
384 }
385 }
386
387 return NULL;
388 }
389
390
391 /**
392 * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
393 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
394 * @aa: Authenticator address
395 * @spa: Supplicant address
396 * @pmkid: PMKID
397 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
398 *
399 * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
400 */
pmksa_cache_get_okc(struct rsn_pmksa_cache * pmksa,const u8 * aa,const u8 * spa,const u8 * pmkid)401 struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
402 struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
403 const u8 *pmkid)
404 {
405 struct rsn_pmksa_cache_entry *entry;
406 u8 new_pmkid[PMKID_LEN];
407
408 for (entry = pmksa->pmksa; entry; entry = entry->next) {
409 if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
410 continue;
411 rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
412 wpa_key_mgmt_sha256(entry->akmp));
413 if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
414 return entry;
415 }
416 return NULL;
417 }
418
419
420 /**
421 * pmksa_cache_auth_init - Initialize PMKSA cache
422 * @free_cb: Callback function to be called when a PMKSA cache entry is freed
423 * @ctx: Context pointer for free_cb function
424 * Returns: Pointer to PMKSA cache data or %NULL on failure
425 */
426 struct rsn_pmksa_cache *
pmksa_cache_auth_init(void (* free_cb)(struct rsn_pmksa_cache_entry * entry,void * ctx),void * ctx)427 pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
428 void *ctx), void *ctx)
429 {
430 struct rsn_pmksa_cache *pmksa;
431
432 pmksa = os_zalloc(sizeof(*pmksa));
433 if (pmksa) {
434 pmksa->free_cb = free_cb;
435 pmksa->ctx = ctx;
436 }
437
438 return pmksa;
439 }
440