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