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 11 : static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
40 : {
41 11 : struct wpa_stsl_search *search = ctx;
42 11 : if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
43 6 : search->sm = sm;
44 6 : return 1;
45 : }
46 5 : return 0;
47 : }
48 :
49 :
50 3 : 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 3 : wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
60 : "Sending SMK Error");
61 :
62 3 : pos = kde;
63 :
64 3 : if (peer) {
65 3 : pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
66 : NULL, 0);
67 : }
68 :
69 3 : error.mui = host_to_be16(mui);
70 3 : error.error_type = host_to_be16(error_type);
71 3 : pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
72 : (u8 *) &error, sizeof(error), NULL, 0);
73 :
74 3 : __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 3 : NULL, NULL, kde, pos - kde, 0, 0, 0);
78 3 : }
79 :
80 :
81 4 : void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
82 : struct wpa_state_machine *sm, struct wpa_eapol_key *key,
83 : const u8 *key_data, size_t key_data_len)
84 : {
85 : struct wpa_eapol_ie_parse kde;
86 : struct wpa_stsl_search search;
87 : u8 *buf, *pos;
88 : size_t buf_len;
89 :
90 4 : if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
91 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
92 0 : return;
93 : }
94 :
95 8 : if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
96 4 : 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 4 : search.addr = kde.mac_addr;
105 4 : search.sm = NULL;
106 4 : if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
107 3 : 0 || search.sm == NULL) {
108 6 : wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
109 : " aborted - STA not associated anymore",
110 6 : MAC2STR(kde.mac_addr));
111 1 : 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 1 : return;
115 : }
116 :
117 3 : buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
118 3 : buf = os_malloc(buf_len);
119 3 : if (buf == NULL)
120 0 : return;
121 : /* Initiator RSN IE */
122 3 : os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
123 3 : pos = buf + kde.rsn_ie_len;
124 : /* Initiator MAC Address */
125 3 : 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 3 : wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
134 : "Sending SMK M2");
135 :
136 6 : __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 6 : NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
140 :
141 3 : 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 2 : __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(pos, kde->rsn_ie, kde->rsn_ie_len);
225 1 : pos += 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 : const u8 *key_data, size_t key_data_len)
258 : {
259 : struct wpa_eapol_ie_parse kde;
260 : struct wpa_stsl_search search;
261 : u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
262 :
263 1 : if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
264 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
265 0 : return;
266 : }
267 :
268 2 : if (kde.rsn_ie == NULL ||
269 3 : kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
270 2 : 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 2 : void wpa_smk_error(struct wpa_authenticator *wpa_auth,
327 : struct wpa_state_machine *sm,
328 : const u8 *key_data, size_t key_data_len)
329 : {
330 : struct wpa_eapol_ie_parse kde;
331 : struct wpa_stsl_search search;
332 : struct rsn_error_kde error;
333 : u16 mui, error_type;
334 :
335 2 : if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
336 0 : wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
337 0 : return;
338 : }
339 :
340 4 : if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
341 4 : 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 2 : search.addr = kde.mac_addr;
348 2 : search.sm = NULL;
349 2 : if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
350 2 : 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 2 : os_memcpy(&error, kde.error, sizeof(error));
358 2 : mui = be_to_host16(error.mui);
359 2 : error_type = be_to_host16(error.error_type);
360 14 : wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
361 : "STA reported SMK Error: Peer " MACSTR
362 : " MUI %d Error Type %d",
363 12 : MAC2STR(kde.mac_addr), mui, error_type);
364 :
365 2 : 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 */
|