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