2 * hostapd - PeerKey for Direct Link Setup (DLS)
3 * Copyright (c) 2006-2008, 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.
23 #include "wpa_auth_i.h"
24 #include "wpa_auth_ie.h"
28 static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
31 struct wpa_authenticator *wpa_auth = eloop_ctx;
32 struct wpa_stsl_negotiation *neg = timeout_ctx;
39 struct wpa_stsl_search {
41 struct wpa_state_machine *sm;
45 static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
47 struct wpa_stsl_search *search = ctx;
48 if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
56 static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
57 struct wpa_state_machine *sm, const u8 *peer,
58 u16 mui, u16 error_type)
60 u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
61 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
63 struct rsn_error_kde error;
65 wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
71 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
75 error.mui = host_to_be16(mui);
76 error.error_type = host_to_be16(error_type);
77 pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
78 (u8 *) &error, sizeof(error), NULL, 0);
80 __wpa_send_eapol(wpa_auth, sm,
81 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
82 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
83 NULL, NULL, kde, pos - kde, 0, 0, 0);
87 void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
88 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
90 struct wpa_eapol_ie_parse kde;
91 struct wpa_stsl_search search;
95 if (wpa_parse_kde_ies((const u8 *) (key + 1),
96 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
97 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
101 if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
102 kde.mac_addr_len < ETH_ALEN) {
103 wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
108 /* Initiator = sm->addr; Peer = kde.mac_addr */
110 search.addr = kde.mac_addr;
112 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
113 0 || search.sm == NULL) {
114 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
115 " aborted - STA not associated anymore",
116 MAC2STR(kde.mac_addr));
117 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
119 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
123 buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
124 buf = os_malloc(buf_len);
127 /* Initiator RSN IE */
128 os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
129 pos = buf + kde.rsn_ie_len;
130 /* Initiator MAC Address */
131 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
135 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
136 * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
139 wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
142 __wpa_send_eapol(wpa_auth, search.sm,
143 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
144 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
145 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
151 static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
152 struct wpa_state_machine *sm,
153 struct wpa_eapol_key *key,
154 struct wpa_eapol_ie_parse *kde,
162 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
163 * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
167 buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
168 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
169 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
170 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
171 pos = buf = os_malloc(buf_len);
175 /* Initiator MAC Address */
176 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
179 /* Initiator Nonce */
180 pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
183 /* SMK with PNonce */
184 pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
185 key->key_nonce, WPA_NONCE_LEN);
188 lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
189 pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
190 (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
192 wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
195 __wpa_send_eapol(wpa_auth, sm,
196 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
197 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
198 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
204 static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
205 struct wpa_state_machine *sm,
206 struct wpa_eapol_key *key,
207 struct wpa_eapol_ie_parse *kde,
208 const u8 *smk, const u8 *peer)
215 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
216 * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
220 buf_len = kde->rsn_ie_len +
221 2 + RSN_SELECTOR_LEN + ETH_ALEN +
222 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
223 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
224 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
225 pos = buf = os_malloc(buf_len);
230 os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
231 pos = buf + kde->rsn_ie_len;
233 /* Peer MAC Address */
234 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
237 pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
238 WPA_NONCE_LEN, NULL, 0);
241 pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
242 kde->nonce, WPA_NONCE_LEN);
245 lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
246 pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
247 (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
249 wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
252 __wpa_send_eapol(wpa_auth, sm,
253 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
254 WPA_KEY_INFO_SMK_MESSAGE,
255 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
261 void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
262 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
264 struct wpa_eapol_ie_parse kde;
265 struct wpa_stsl_search search;
266 u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
268 if (wpa_parse_kde_ies((const u8 *) (key + 1),
269 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
270 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
274 if (kde.rsn_ie == NULL ||
275 kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
276 kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
277 wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
278 "Nonce KDE in SMK M3");
282 /* Peer = sm->addr; Initiator = kde.mac_addr;
283 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
285 search.addr = kde.mac_addr;
287 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
288 0 || search.sm == NULL) {
289 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
290 " aborted - STA not associated anymore",
291 MAC2STR(kde.mac_addr));
292 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
294 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
298 if (os_get_random(smk, PMK_LEN)) {
299 wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
303 /* SMK = PRF-256(Random number, "SMK Derivation",
304 * AA || Time || INonce || PNonce)
306 os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
307 pos = buf + ETH_ALEN;
308 wpa_get_ntp_timestamp(pos);
310 os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
311 pos += WPA_NONCE_LEN;
312 os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
313 #ifdef CONFIG_IEEE80211W
314 sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
316 #else /* CONFIG_IEEE80211W */
317 sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
319 #endif /* CONFIG_IEEE80211W */
321 wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
323 wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
324 wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
326 /* Authenticator does not need SMK anymore and it is required to forget
328 os_memset(smk, 0, sizeof(*smk));
332 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
333 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
335 struct wpa_eapol_ie_parse kde;
336 struct wpa_stsl_search search;
337 struct rsn_error_kde error;
340 if (wpa_parse_kde_ies((const u8 *) (key + 1),
341 WPA_GET_BE16(key->key_data_length), &kde) < 0) {
342 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
346 if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
347 kde.error == NULL || kde.error_len < sizeof(error)) {
348 wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
353 search.addr = kde.mac_addr;
355 if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
356 0 || search.sm == NULL) {
357 wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
358 "associated for SMK Error message from " MACSTR,
359 MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
363 os_memcpy(&error, kde.error, sizeof(error));
364 mui = be_to_host16(error.mui);
365 error_type = be_to_host16(error.error_type);
366 wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
367 "STA reported SMK Error: Peer " MACSTR
368 " MUI %d Error Type %d",
369 MAC2STR(kde.mac_addr), mui, error_type);
371 wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
375 int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
376 struct wpa_stsl_negotiation *neg)
378 struct wpa_stsl_negotiation *pos, *prev;
380 if (wpa_auth == NULL)
382 pos = wpa_auth->stsl_negotiations;
387 prev->next = pos->next;
389 wpa_auth->stsl_negotiations = pos->next;
391 eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
402 #endif /* CONFIG_PEERKEY */