2 * hostapd - PeerKey for Direct Link Setup (DLS)
3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "utils/eloop.h"
19 #include "crypto/sha1.h"
20 #include "crypto/sha256.h"
22 #include "wpa_auth_i.h"
23 #include "wpa_auth_ie.h"
27 static void wpa_stsl_step(void *eloop_ctx
, void *timeout_ctx
)
30 struct wpa_authenticator
*wpa_auth
= eloop_ctx
;
31 struct wpa_stsl_negotiation
*neg
= timeout_ctx
;
38 struct wpa_stsl_search
{
40 struct wpa_state_machine
*sm
;
44 static int wpa_stsl_select_sta(struct wpa_state_machine
*sm
, void *ctx
)
46 struct wpa_stsl_search
*search
= ctx
;
47 if (os_memcmp(search
->addr
, sm
->addr
, ETH_ALEN
) == 0) {
55 static 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
)
59 u8 kde
[2 + RSN_SELECTOR_LEN
+ ETH_ALEN
+
60 2 + RSN_SELECTOR_LEN
+ sizeof(struct rsn_error_kde
)];
62 struct rsn_error_kde error
;
64 wpa_auth_logger(wpa_auth
, sm
->addr
, LOGGER_DEBUG
,
70 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_MAC_ADDR
, peer
, ETH_ALEN
,
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);
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);
86 void wpa_smk_m1(struct wpa_authenticator
*wpa_auth
,
87 struct wpa_state_machine
*sm
, struct wpa_eapol_key
*key
)
89 struct wpa_eapol_ie_parse kde
;
90 struct wpa_stsl_search search
;
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");
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 "
107 /* Initiator = sm->addr; Peer = kde.mac_addr */
109 search
.addr
= kde
.mac_addr
;
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
,
118 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
122 buf_len
= kde
.rsn_ie_len
+ 2 + RSN_SELECTOR_LEN
+ ETH_ALEN
;
123 buf
= os_malloc(buf_len
);
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
,
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)
138 wpa_auth_logger(wpa_auth
, search
.sm
->addr
, LOGGER_DEBUG
,
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);
150 static 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
,
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,
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
);
174 /* Initiator MAC Address */
175 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_MAC_ADDR
, kde
->mac_addr
, ETH_ALEN
,
178 /* Initiator Nonce */
179 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_NONCE
, kde
->nonce
, WPA_NONCE_LEN
,
182 /* SMK with PNonce */
183 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_SMK
, smk
, PMK_LEN
,
184 key
->key_nonce
, WPA_NONCE_LEN
);
187 lifetime
= htonl(43200); /* dot11RSNAConfigSMKLifetime */
188 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_LIFETIME
,
189 (u8
*) &lifetime
, sizeof(lifetime
), NULL
, 0);
191 wpa_auth_logger(sm
->wpa_auth
, sm
->addr
, LOGGER_DEBUG
,
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);
203 static 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
)
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,
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
);
229 os_memcpy(buf
, kde
->rsn_ie
, kde
->rsn_ie_len
);
230 pos
= buf
+ kde
->rsn_ie_len
;
232 /* Peer MAC Address */
233 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_MAC_ADDR
, peer
, ETH_ALEN
, NULL
, 0);
236 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_NONCE
, key
->key_nonce
,
237 WPA_NONCE_LEN
, NULL
, 0);
240 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_SMK
, smk
, PMK_LEN
,
241 kde
->nonce
, WPA_NONCE_LEN
);
244 lifetime
= htonl(43200); /* dot11RSNAConfigSMKLifetime */
245 pos
= wpa_add_kde(pos
, RSN_KEY_DATA_LIFETIME
,
246 (u8
*) &lifetime
, sizeof(lifetime
), NULL
, 0);
248 wpa_auth_logger(sm
->wpa_auth
, sm
->addr
, LOGGER_DEBUG
,
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);
260 void wpa_smk_m3(struct wpa_authenticator
*wpa_auth
,
261 struct wpa_state_machine
*sm
, struct wpa_eapol_key
*key
)
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
;
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");
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");
281 /* Peer = sm->addr; Initiator = kde.mac_addr;
282 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
284 search
.addr
= kde
.mac_addr
;
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
,
293 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
297 if (os_get_random(smk
, PMK_LEN
)) {
298 wpa_printf(MSG_DEBUG
, "RSN: Failed to generate SMK");
302 /* SMK = PRF-256(Random number, "SMK Derivation",
303 * AA || Time || INonce || PNonce)
305 os_memcpy(buf
, wpa_auth
->addr
, ETH_ALEN
);
306 pos
= buf
+ ETH_ALEN
;
307 wpa_get_ntp_timestamp(pos
);
309 os_memcpy(pos
, kde
.nonce
, WPA_NONCE_LEN
);
310 pos
+= WPA_NONCE_LEN
;
311 os_memcpy(pos
, key
->key_nonce
, WPA_NONCE_LEN
);
312 #ifdef CONFIG_IEEE80211W
313 sha256_prf(smk
, PMK_LEN
, "SMK Derivation", buf
, sizeof(buf
),
315 #else /* CONFIG_IEEE80211W */
316 sha1_prf(smk
, PMK_LEN
, "SMK Derivation", buf
, sizeof(buf
),
318 #endif /* CONFIG_IEEE80211W */
320 wpa_hexdump_key(MSG_DEBUG
, "RSN: SMK", smk
, PMK_LEN
);
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
);
325 /* Authenticator does not need SMK anymore and it is required to forget
327 os_memset(smk
, 0, sizeof(*smk
));
331 void wpa_smk_error(struct wpa_authenticator
*wpa_auth
,
332 struct wpa_state_machine
*sm
, struct wpa_eapol_key
*key
)
334 struct wpa_eapol_ie_parse kde
;
335 struct wpa_stsl_search search
;
336 struct rsn_error_kde error
;
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");
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 "
352 search
.addr
= kde
.mac_addr
;
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
));
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
);
370 wpa_smk_send_error(wpa_auth
, search
.sm
, sm
->addr
, mui
, error_type
);
374 int wpa_stsl_remove(struct wpa_authenticator
*wpa_auth
,
375 struct wpa_stsl_negotiation
*neg
)
377 struct wpa_stsl_negotiation
*pos
, *prev
;
379 if (wpa_auth
== NULL
)
381 pos
= wpa_auth
->stsl_negotiations
;
386 prev
->next
= pos
->next
;
388 wpa_auth
->stsl_negotiations
= pos
->next
;
390 eloop_cancel_timeout(wpa_stsl_step
, wpa_auth
, pos
);
401 #endif /* CONFIG_PEERKEY */