Branch data Line data Source code
1 : : /*
2 : : * hostapd - PeerKey for Direct Link Setup (DLS)
3 : : * Copyright (c) 2006-2009, 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 "crypto/sha1.h"
14 : : #include "crypto/sha256.h"
15 : : #include "crypto/random.h"
16 : : #include "wpa_auth.h"
17 : : #include "wpa_auth_i.h"
18 : : #include "wpa_auth_ie.h"
19 : :
20 : : #ifdef CONFIG_PEERKEY
21 : :
22 : 0 : static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
23 : : {
24 : : #if 0
25 : : struct wpa_authenticator *wpa_auth = eloop_ctx;
26 : : struct wpa_stsl_negotiation *neg = timeout_ctx;
27 : : #endif
28 : :
29 : : /* TODO: ? */
30 : 0 : }
31 : :
32 : :
33 : : struct wpa_stsl_search {
34 : : const u8 *addr;
35 : : struct wpa_state_machine *sm;
36 : : };
37 : :
38 : :
39 : 3 : static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
40 : : {
41 : 3 : struct wpa_stsl_search *search = ctx;
42 [ + + ]: 3 : if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
43 : 2 : search->sm = sm;
44 : 2 : return 1;
45 : : }
46 : 3 : return 0;
47 : : }
48 : :
49 : :
50 : 0 : static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
51 : : struct wpa_state_machine *sm, const u8 *peer,
52 : : u16 mui, u16 error_type)
53 : : {
54 : : u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
55 : : 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
56 : : u8 *pos;
57 : : struct rsn_error_kde error;
58 : :
59 : 0 : wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
60 : : "Sending SMK Error");
61 : :
62 : 0 : pos = kde;
63 : :
64 [ # # ]: 0 : if (peer) {
65 : 0 : pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
66 : : NULL, 0);
67 : : }
68 : :
69 : 0 : error.mui = host_to_be16(mui);
70 : 0 : error.error_type = host_to_be16(error_type);
71 : 0 : pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
72 : : (u8 *) &error, sizeof(error), NULL, 0);
73 : :
74 : 0 : __wpa_send_eapol(wpa_auth, sm,
75 : : WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
76 : : WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
77 : 0 : NULL, NULL, kde, pos - kde, 0, 0, 0);
78 : 0 : }
79 : :
80 : :
81 : 1 : void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
82 : : struct wpa_state_machine *sm, struct wpa_eapol_key *key)
83 : : {
84 : : struct wpa_eapol_ie_parse kde;
85 : : struct wpa_stsl_search search;
86 : : u8 *buf, *pos;
87 : : size_t buf_len;
88 : :
89 [ - + ]: 1 : if (wpa_parse_kde_ies((const u8 *) (key + 1),
90 : 1 : WPA_GET_BE16(key->key_data_length), &kde) < 0) {
91 : 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
92 : 0 : return;
93 : : }
94 : :
95 [ + - ][ + - ]: 1 : if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
[ - + ]
96 : 1 : kde.mac_addr_len < ETH_ALEN) {
97 : 0 : wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
98 : : "SMK M1");
99 : 0 : return;
100 : : }
101 : :
102 : : /* Initiator = sm->addr; Peer = kde.mac_addr */
103 : :
104 : 1 : search.addr = kde.mac_addr;
105 : 1 : search.sm = NULL;
106 [ + - ]: 1 : if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
107 [ - + ]: 1 : 0 || search.sm == NULL) {
108 : 0 : wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
109 : : " aborted - STA not associated anymore",
110 : 0 : MAC2STR(kde.mac_addr));
111 : 0 : wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
112 : : STK_ERR_STA_NR);
113 : : /* FIX: wpa_stsl_remove(wpa_auth, neg); */
114 : 0 : return;
115 : : }
116 : :
117 : 1 : buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
118 : 1 : buf = os_malloc(buf_len);
119 [ - + ]: 1 : if (buf == NULL)
120 : 0 : return;
121 : : /* Initiator RSN IE */
122 : 1 : os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
123 : 1 : pos = buf + kde.rsn_ie_len;
124 : : /* Initiator MAC Address */
125 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
126 : : NULL, 0);
127 : :
128 : : /* SMK M2:
129 : : * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
130 : : * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
131 : : */
132 : :
133 : 1 : wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
134 : : "Sending SMK M2");
135 : :
136 : 1 : __wpa_send_eapol(wpa_auth, search.sm,
137 : : WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
138 : : WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
139 : 2 : NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
140 : :
141 : 1 : os_free(buf);
142 : : }
143 : :
144 : :
145 : 1 : static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
146 : : struct wpa_state_machine *sm,
147 : : struct wpa_eapol_key *key,
148 : : struct wpa_eapol_ie_parse *kde,
149 : : const u8 *smk)
150 : : {
151 : : u8 *buf, *pos;
152 : : size_t buf_len;
153 : : u32 lifetime;
154 : :
155 : : /* SMK M4:
156 : : * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
157 : : * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
158 : : * Lifetime KDE)
159 : : */
160 : :
161 : 1 : buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
162 : : 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
163 : : 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
164 : : 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
165 : 1 : pos = buf = os_malloc(buf_len);
166 [ - + ]: 1 : if (buf == NULL)
167 : 1 : return;
168 : :
169 : : /* Initiator MAC Address */
170 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
171 : : NULL, 0);
172 : :
173 : : /* Initiator Nonce */
174 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
175 : : NULL, 0);
176 : :
177 : : /* SMK with PNonce */
178 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
179 : 1 : key->key_nonce, WPA_NONCE_LEN);
180 : :
181 : : /* Lifetime */
182 : 1 : lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
183 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
184 : : (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
185 : :
186 : 1 : wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
187 : : "Sending SMK M4");
188 : :
189 : 1 : __wpa_send_eapol(wpa_auth, sm,
190 : : WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
191 : : WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
192 : 2 : NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
193 : :
194 : 1 : os_free(buf);
195 : : }
196 : :
197 : :
198 : 1 : static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
199 : : struct wpa_state_machine *sm,
200 : : struct wpa_eapol_key *key,
201 : : struct wpa_eapol_ie_parse *kde,
202 : : const u8 *smk, const u8 *peer)
203 : : {
204 : : u8 *buf, *pos;
205 : : size_t buf_len;
206 : : u32 lifetime;
207 : :
208 : : /* SMK M5:
209 : : * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
210 : : * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
211 : : * Lifetime KDE))
212 : : */
213 : :
214 : 1 : buf_len = kde->rsn_ie_len +
215 : : 2 + RSN_SELECTOR_LEN + ETH_ALEN +
216 : : 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
217 : : 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
218 : : 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
219 : 1 : pos = buf = os_malloc(buf_len);
220 [ - + ]: 1 : if (buf == NULL)
221 : 1 : return;
222 : :
223 : : /* Peer RSN IE */
224 : 1 : os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
225 : 1 : pos = buf + kde->rsn_ie_len;
226 : :
227 : : /* Peer MAC Address */
228 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
229 : :
230 : : /* PNonce */
231 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
232 : : WPA_NONCE_LEN, NULL, 0);
233 : :
234 : : /* SMK and INonce */
235 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
236 : : kde->nonce, WPA_NONCE_LEN);
237 : :
238 : : /* Lifetime */
239 : 1 : lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
240 : 1 : pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
241 : : (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
242 : :
243 : 1 : wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
244 : : "Sending SMK M5");
245 : :
246 : 1 : __wpa_send_eapol(wpa_auth, sm,
247 : : WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
248 : : WPA_KEY_INFO_SMK_MESSAGE,
249 : 1 : NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
250 : :
251 : 1 : os_free(buf);
252 : : }
253 : :
254 : :
255 : 1 : void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
256 : : struct wpa_state_machine *sm, struct wpa_eapol_key *key)
257 : : {
258 : : struct wpa_eapol_ie_parse kde;
259 : : struct wpa_stsl_search search;
260 : : u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
261 : :
262 [ - + ]: 1 : if (wpa_parse_kde_ies((const u8 *) (key + 1),
263 : 1 : WPA_GET_BE16(key->key_data_length), &kde) < 0) {
264 : 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
265 : 0 : return;
266 : : }
267 : :
268 [ + - ][ + - ]: 1 : if (kde.rsn_ie == NULL ||
269 [ + - ][ + - ]: 1 : kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
270 [ - + ]: 1 : kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
271 : 0 : wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
272 : : "Nonce KDE in SMK M3");
273 : 0 : return;
274 : : }
275 : :
276 : : /* Peer = sm->addr; Initiator = kde.mac_addr;
277 : : * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
278 : :
279 : 1 : search.addr = kde.mac_addr;
280 : 1 : search.sm = NULL;
281 [ + - ]: 1 : if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
282 [ - + ]: 1 : 0 || search.sm == NULL) {
283 : 0 : wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
284 : : " aborted - STA not associated anymore",
285 : 0 : MAC2STR(kde.mac_addr));
286 : 0 : wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
287 : : STK_ERR_STA_NR);
288 : : /* FIX: wpa_stsl_remove(wpa_auth, neg); */
289 : 0 : return;
290 : : }
291 : :
292 [ - + ]: 1 : if (random_get_bytes(smk, PMK_LEN)) {
293 : 0 : wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
294 : 0 : return;
295 : : }
296 : :
297 : : /* SMK = PRF-256(Random number, "SMK Derivation",
298 : : * AA || Time || INonce || PNonce)
299 : : */
300 : 1 : os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
301 : 1 : pos = buf + ETH_ALEN;
302 : 1 : wpa_get_ntp_timestamp(pos);
303 : 1 : pos += 8;
304 : 1 : os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
305 : 1 : pos += WPA_NONCE_LEN;
306 : 1 : os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
307 : : #ifdef CONFIG_IEEE80211W
308 : 1 : sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
309 : : smk, PMK_LEN);
310 : : #else /* CONFIG_IEEE80211W */
311 : : sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
312 : : smk, PMK_LEN);
313 : : #endif /* CONFIG_IEEE80211W */
314 : :
315 : 1 : wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
316 : :
317 : 1 : wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
318 : 1 : wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
319 : :
320 : : /* Authenticator does not need SMK anymore and it is required to forget
321 : : * it. */
322 : 1 : os_memset(smk, 0, sizeof(*smk));
323 : : }
324 : :
325 : :
326 : 0 : void wpa_smk_error(struct wpa_authenticator *wpa_auth,
327 : : struct wpa_state_machine *sm, struct wpa_eapol_key *key)
328 : : {
329 : : struct wpa_eapol_ie_parse kde;
330 : : struct wpa_stsl_search search;
331 : : struct rsn_error_kde error;
332 : : u16 mui, error_type;
333 : :
334 [ # # ]: 0 : if (wpa_parse_kde_ies((const u8 *) (key + 1),
335 : 0 : WPA_GET_BE16(key->key_data_length), &kde) < 0) {
336 : 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
337 : 0 : return;
338 : : }
339 : :
340 [ # # ][ # # ]: 0 : if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
[ # # ]
341 [ # # ]: 0 : kde.error == NULL || kde.error_len < sizeof(error)) {
342 : 0 : wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
343 : : "SMK Error");
344 : 0 : return;
345 : : }
346 : :
347 : 0 : search.addr = kde.mac_addr;
348 : 0 : search.sm = NULL;
349 [ # # ]: 0 : if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
350 [ # # ]: 0 : 0 || search.sm == NULL) {
351 : 0 : wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
352 : : "associated for SMK Error message from " MACSTR,
353 : 0 : MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
354 : 0 : return;
355 : : }
356 : :
357 : 0 : os_memcpy(&error, kde.error, sizeof(error));
358 : 0 : mui = be_to_host16(error.mui);
359 : 0 : error_type = be_to_host16(error.error_type);
360 : 0 : wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
361 : : "STA reported SMK Error: Peer " MACSTR
362 : : " MUI %d Error Type %d",
363 : 0 : MAC2STR(kde.mac_addr), mui, error_type);
364 : :
365 : 0 : wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
366 : : }
367 : :
368 : :
369 : 0 : int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
370 : : struct wpa_stsl_negotiation *neg)
371 : : {
372 : : struct wpa_stsl_negotiation *pos, *prev;
373 : :
374 [ # # ]: 0 : if (wpa_auth == NULL)
375 : 0 : return -1;
376 : 0 : pos = wpa_auth->stsl_negotiations;
377 : 0 : prev = NULL;
378 [ # # ]: 0 : while (pos) {
379 [ # # ]: 0 : if (pos == neg) {
380 [ # # ]: 0 : if (prev)
381 : 0 : prev->next = pos->next;
382 : : else
383 : 0 : wpa_auth->stsl_negotiations = pos->next;
384 : :
385 : 0 : eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
386 : 0 : os_free(pos);
387 : 0 : return 0;
388 : : }
389 : 0 : prev = pos;
390 : 0 : pos = pos->next;
391 : : }
392 : :
393 : 0 : return -1;
394 : : }
395 : :
396 : : #endif /* CONFIG_PEERKEY */
|