wlantest: Derive PMK to existing BSSes when a new passphrase is added
[mech_eap.git] / wlantest / bss.c
1 /*
2  * BSS list
3  * Copyright (c) 2010, 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 "utils/includes.h"
16
17 #include "utils/common.h"
18 #include "common/defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "crypto/sha1.h"
21 #include "wlantest.h"
22
23
24 struct wlantest_bss * bss_find(struct wlantest *wt, const u8 *bssid)
25 {
26         struct wlantest_bss *bss;
27
28         dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
29                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
30                         return bss;
31         }
32
33         return NULL;
34 }
35
36
37 struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid)
38 {
39         struct wlantest_bss *bss;
40
41         if (bssid[0] & 0x01)
42                 return NULL; /* Skip group addressed frames */
43
44         bss = bss_find(wt, bssid);
45         if (bss)
46                 return bss;
47
48         bss = os_zalloc(sizeof(*bss));
49         if (bss == NULL)
50                 return NULL;
51         dl_list_init(&bss->sta);
52         dl_list_init(&bss->pmk);
53         os_memcpy(bss->bssid, bssid, ETH_ALEN);
54         dl_list_add(&wt->bss, &bss->list);
55         wpa_printf(MSG_DEBUG, "Discovered new BSS - " MACSTR,
56                    MAC2STR(bss->bssid));
57         return bss;
58 }
59
60
61 void pmk_deinit(struct wlantest_pmk *pmk)
62 {
63         dl_list_del(&pmk->list);
64         os_free(pmk);
65 }
66
67
68 void bss_deinit(struct wlantest_bss *bss)
69 {
70         struct wlantest_sta *sta, *n;
71         struct wlantest_pmk *pmk, *np;
72         dl_list_for_each_safe(sta, n, &bss->sta, struct wlantest_sta, list)
73                 sta_deinit(sta);
74         dl_list_for_each_safe(pmk, np, &bss->pmk, struct wlantest_pmk, list)
75                 pmk_deinit(pmk);
76         dl_list_del(&bss->list);
77         os_free(bss);
78 }
79
80
81 int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
82                                 const char *passphrase)
83 {
84         struct wlantest_pmk *pmk;
85
86         pmk = os_zalloc(sizeof(*pmk));
87         if (pmk == NULL)
88                 return -1;
89         if (pbkdf2_sha1(passphrase, (char *) bss->ssid, bss->ssid_len, 4096,
90                         pmk->pmk, sizeof(pmk->pmk)) < 0) {
91                 os_free(pmk);
92                 return -1;
93         }
94
95         wpa_printf(MSG_INFO, "Add possible PMK for BSSID " MACSTR
96                    " based on passphrase '%s'",
97                    MAC2STR(bss->bssid), passphrase);
98         wpa_hexdump(MSG_DEBUG, "Possible PMK", pmk->pmk, sizeof(pmk->pmk));
99         dl_list_add(&bss->pmk, &pmk->list);
100
101         return 0;
102 }
103
104
105 static void bss_add_pmk(struct wlantest *wt, struct wlantest_bss *bss)
106 {
107         struct wlantest_passphrase *p;
108
109         dl_list_for_each(p, &wt->passphrase, struct wlantest_passphrase, list)
110         {
111                 if (!is_zero_ether_addr(p->bssid) &&
112                     os_memcmp(p->bssid, bss->bssid, ETH_ALEN) != 0)
113                         continue;
114                 if (p->ssid_len &&
115                     (p->ssid_len != bss->ssid_len ||
116                      os_memcmp(p->ssid, bss->ssid, p->ssid_len) != 0))
117                         continue;
118
119                 if (bss_add_pmk_from_passphrase(bss, p->passphrase) < 0)
120                         break;
121         }
122 }
123
124
125 void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
126                 struct ieee802_11_elems *elems)
127 {
128         struct wpa_ie_data data;
129         int update = 0;
130
131         if (elems->ssid == NULL || elems->ssid_len > 32) {
132                 wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon "
133                            "frame for " MACSTR, MAC2STR(bss->bssid));
134                 bss->parse_error_reported = 1;
135                 return;
136         }
137
138         if (bss->ssid_len != elems->ssid_len ||
139             os_memcmp(bss->ssid, elems->ssid, bss->ssid_len) != 0) {
140                 wpa_printf(MSG_DEBUG, "Store SSID '%s' for BSSID " MACSTR,
141                            wpa_ssid_txt(elems->ssid, elems->ssid_len),
142                            MAC2STR(bss->bssid));
143                 os_memcpy(bss->ssid, elems->ssid, elems->ssid_len);
144                 bss->ssid_len = elems->ssid_len;
145                 bss_add_pmk(wt, bss);
146         }
147
148
149         if (elems->rsn_ie == NULL) {
150                 if (bss->rsnie[0]) {
151                         wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
152                                    MAC2STR(bss->bssid));
153                         bss->rsnie[0] = 0;
154                         update = 1;
155                 }
156         } else {
157                 if (bss->rsnie[0] == 0 ||
158                     os_memcmp(bss->rsnie, elems->rsn_ie - 2,
159                               elems->rsn_ie_len + 2) != 0) {
160                         wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE "
161                                    "stored", MAC2STR(bss->bssid));
162                         wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
163                                     elems->rsn_ie_len + 2);
164                         update = 1;
165                 }
166                 os_memcpy(bss->rsnie, elems->rsn_ie - 2,
167                           elems->rsn_ie_len + 2);
168         }
169
170         if (elems->wpa_ie == NULL) {
171                 if (bss->wpaie[0]) {
172                         wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
173                                    MAC2STR(bss->bssid));
174                         bss->wpaie[0] = 0;
175                         update = 1;
176                 }
177         } else {
178                 if (bss->wpaie[0] == 0 ||
179                     os_memcmp(bss->wpaie, elems->wpa_ie - 2,
180                               elems->wpa_ie_len + 2) != 0) {
181                         wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE "
182                                    "stored", MAC2STR(bss->bssid));
183                         wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
184                                     elems->wpa_ie_len + 2);
185                         update = 1;
186                 }
187                 os_memcpy(bss->wpaie, elems->wpa_ie - 2,
188                           elems->wpa_ie_len + 2);
189         }
190
191         if (!update)
192                 return;
193
194         bss->proto = 0;
195         bss->pairwise_cipher = 0;
196         bss->group_cipher = 0;
197         bss->key_mgmt = 0;
198         bss->rsn_capab = 0;
199         bss->mgmt_group_cipher = 0;
200
201         if (bss->wpaie[0]) {
202                 if (wpa_parse_wpa_ie_wpa(bss->wpaie, 2 + bss->wpaie[1], &data)
203                     < 0) {
204                         wpa_printf(MSG_INFO, "Failed to parse WPA IE from "
205                                    MACSTR, MAC2STR(bss->bssid));
206                 } else {
207                         bss->proto |= data.proto;
208                         bss->pairwise_cipher |= data.pairwise_cipher;
209                         bss->group_cipher |= data.group_cipher;
210                         bss->key_mgmt |= data.key_mgmt;
211                         bss->rsn_capab = data.capabilities;
212                         bss->mgmt_group_cipher |= data.mgmt_group_cipher;
213                 }
214         }
215
216         if (bss->rsnie[0]) {
217                 if (wpa_parse_wpa_ie_rsn(bss->rsnie, 2 + bss->rsnie[1], &data)
218                     < 0) {
219                         wpa_printf(MSG_INFO, "Failed to parse RSN IE from "
220                                    MACSTR, MAC2STR(bss->bssid));
221                 } else {
222                         bss->proto |= data.proto;
223                         bss->pairwise_cipher |= data.pairwise_cipher;
224                         bss->group_cipher |= data.group_cipher;
225                         bss->key_mgmt |= data.key_mgmt;
226                         bss->rsn_capab = data.capabilities;
227                         bss->mgmt_group_cipher |= data.mgmt_group_cipher;
228                 }
229         }
230
231         if (!(bss->proto & WPA_PROTO_RSN) ||
232             !(bss->rsn_capab & WPA_CAPABILITY_MFPC))
233                 bss->mgmt_group_cipher = 0;
234
235         wpa_printf(MSG_INFO, "BSS " MACSTR
236                    " proto=%s%s%s"
237                    "pairwise=%s%s%s%s"
238                    "group=%s%s%s%s%s%s"
239                    "mgmt_group_cipher=%s"
240                    "key_mgmt=%s%s%s%s%s%s%s%s"
241                    "rsn_capab=%s%s%s%s%s",
242                    MAC2STR(bss->bssid),
243                    bss->proto == 0 ? "OPEN " : "",
244                    bss->proto & WPA_PROTO_WPA ? "WPA " : "",
245                    bss->proto & WPA_PROTO_RSN ? "WPA2 " : "",
246                    bss->pairwise_cipher == 0 ? "N/A " : "",
247                    bss->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "",
248                    bss->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
249                    bss->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
250                    bss->group_cipher == 0 ? "N/A " : "",
251                    bss->group_cipher & WPA_CIPHER_NONE ? "NONE " : "",
252                    bss->group_cipher & WPA_CIPHER_WEP40 ? "WEP40 " : "",
253                    bss->group_cipher & WPA_CIPHER_WEP104 ? "WEP104 " : "",
254                    bss->group_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
255                    bss->group_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
256                    bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ? "BIP " :
257                    "N/A ",
258                    bss->key_mgmt == 0 ? "N/A " : "",
259                    bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "",
260                    bss->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "",
261                    bss->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "",
262                    bss->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "",
263                    bss->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "",
264                    bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ?
265                    "EAP-SHA256 " : "",
266                    bss->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
267                    "PSK-SHA256 " : "",
268                    bss->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
269                    bss->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
270                    "NO_PAIRWISE " : "",
271                    bss->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "",
272                    bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
273                    bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
274                    "PEERKEY " : "");
275 }
276
277
278 void bss_flush(struct wlantest *wt)
279 {
280         struct wlantest_bss *bss, *n;
281         dl_list_for_each_safe(bss, n, &wt->bss, struct wlantest_bss, list)
282                 bss_deinit(bss);
283 }