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