Disconnect hostapd from building in base
[dragonfly.git] / contrib / hostapd / src / ap / peerkey_auth.c
CommitLineData
a875087d
JL
1/*
2 * hostapd - PeerKey for Direct Link Setup (DLS)
4781064b 3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
a875087d 4 *
4781064b
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
a875087d
JL
7 */
8
4781064b 9#include "utils/includes.h"
a875087d 10
4781064b
JM
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"
a875087d
JL
17#include "wpa_auth_i.h"
18#include "wpa_auth_ie.h"
19
20#ifdef CONFIG_PEERKEY
21
22static 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}
31
32
33struct wpa_stsl_search {
34 const u8 *addr;
35 struct wpa_state_machine *sm;
36};
37
38
39static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
40{
41 struct wpa_stsl_search *search = ctx;
42 if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
43 search->sm = sm;
44 return 1;
45 }
46 return 0;
47}
48
49
50static 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 wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
60 "Sending SMK Error");
61
62 pos = kde;
63
64 if (peer) {
65 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
66 NULL, 0);
67 }
68
69 error.mui = host_to_be16(mui);
70 error.error_type = host_to_be16(error_type);
71 pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
72 (u8 *) &error, sizeof(error), NULL, 0);
73
74 __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 NULL, NULL, kde, pos - kde, 0, 0, 0);
78}
79
80
81void 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 if (wpa_parse_kde_ies((const u8 *) (key + 1),
90 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
91 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
92 return;
93 }
94
95 if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
96 kde.mac_addr_len < ETH_ALEN) {
97 wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
98 "SMK M1");
99 return;
100 }
101
102 /* Initiator = sm->addr; Peer = kde.mac_addr */
103
104 search.addr = kde.mac_addr;
105 search.sm = NULL;
106 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
107 0 || search.sm == NULL) {
108 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
109 " aborted - STA not associated anymore",
110 MAC2STR(kde.mac_addr));
111 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 return;
115 }
116
117 buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
118 buf = os_malloc(buf_len);
119 if (buf == NULL)
120 return;
121 /* Initiator RSN IE */
122 os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
123 pos = buf + kde.rsn_ie_len;
124 /* Initiator MAC Address */
125 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 wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
134 "Sending SMK M2");
135
136 __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 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
140
141 os_free(buf);
142}
143
144
145static 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 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 pos = buf = os_malloc(buf_len);
166 if (buf == NULL)
167 return;
168
169 /* Initiator MAC Address */
170 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
171 NULL, 0);
172
173 /* Initiator Nonce */
174 pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
175 NULL, 0);
176
177 /* SMK with PNonce */
178 pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
179 key->key_nonce, WPA_NONCE_LEN);
180
181 /* Lifetime */
182 lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
183 pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
184 (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
185
186 wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
187 "Sending SMK M4");
188
189 __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 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
193
194 os_free(buf);
195}
196
197
198static 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 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 pos = buf = os_malloc(buf_len);
220 if (buf == NULL)
221 return;
222
223 /* Peer RSN IE */
224 os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
225 pos = buf + kde->rsn_ie_len;
226
227 /* Peer MAC Address */
228 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
229
230 /* PNonce */
231 pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
232 WPA_NONCE_LEN, NULL, 0);
233
234 /* SMK and INonce */
235 pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
236 kde->nonce, WPA_NONCE_LEN);
237
238 /* Lifetime */
239 lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
240 pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
241 (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
242
243 wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
244 "Sending SMK M5");
245
246 __wpa_send_eapol(wpa_auth, sm,
247 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
248 WPA_KEY_INFO_SMK_MESSAGE,
249 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
250
251 os_free(buf);
252}
253
254
255void 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 if (wpa_parse_kde_ies((const u8 *) (key + 1),
263 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
264 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
265 return;
266 }
267
268 if (kde.rsn_ie == NULL ||
269 kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
270 kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
271 wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
272 "Nonce KDE in SMK M3");
273 return;
274 }
275
276 /* Peer = sm->addr; Initiator = kde.mac_addr;
277 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
278
279 search.addr = kde.mac_addr;
280 search.sm = NULL;
281 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
282 0 || search.sm == NULL) {
283 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
284 " aborted - STA not associated anymore",
285 MAC2STR(kde.mac_addr));
286 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 return;
290 }
291
4781064b 292 if (random_get_bytes(smk, PMK_LEN)) {
a875087d
JL
293 wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
294 return;
295 }
296
297 /* SMK = PRF-256(Random number, "SMK Derivation",
298 * AA || Time || INonce || PNonce)
299 */
300 os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
301 pos = buf + ETH_ALEN;
302 wpa_get_ntp_timestamp(pos);
303 pos += 8;
304 os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
305 pos += WPA_NONCE_LEN;
306 os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
307#ifdef CONFIG_IEEE80211W
308 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 wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
316
317 wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
318 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 os_memset(smk, 0, sizeof(*smk));
323}
324
325
326void 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 if (wpa_parse_kde_ies((const u8 *) (key + 1),
335 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
336 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
337 return;
338 }
339
340 if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
341 kde.error == NULL || kde.error_len < sizeof(error)) {
342 wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
343 "SMK Error");
344 return;
345 }
346
347 search.addr = kde.mac_addr;
348 search.sm = NULL;
349 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
350 0 || search.sm == NULL) {
351 wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
352 "associated for SMK Error message from " MACSTR,
353 MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
354 return;
355 }
356
357 os_memcpy(&error, kde.error, sizeof(error));
358 mui = be_to_host16(error.mui);
359 error_type = be_to_host16(error.error_type);
360 wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
361 "STA reported SMK Error: Peer " MACSTR
362 " MUI %d Error Type %d",
363 MAC2STR(kde.mac_addr), mui, error_type);
364
365 wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
366}
367
368
369int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
370 struct wpa_stsl_negotiation *neg)
371{
372 struct wpa_stsl_negotiation *pos, *prev;
373
374 if (wpa_auth == NULL)
375 return -1;
376 pos = wpa_auth->stsl_negotiations;
377 prev = NULL;
378 while (pos) {
379 if (pos == neg) {
380 if (prev)
381 prev->next = pos->next;
382 else
383 wpa_auth->stsl_negotiations = pos->next;
384
385 eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
386 os_free(pos);
387 return 0;
388 }
389 prev = pos;
390 pos = pos->next;
391 }
392
393 return -1;
394}
395
396#endif /* CONFIG_PEERKEY */