1214501Srpaulo/*
2214501Srpaulo * hostapd - PeerKey for Direct Link Setup (DLS)
3214501Srpaulo * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#include "utils/common.h"
12214501Srpaulo#include "utils/eloop.h"
13214501Srpaulo#include "crypto/sha1.h"
14214501Srpaulo#include "crypto/sha256.h"
15252726Srpaulo#include "crypto/random.h"
16214501Srpaulo#include "wpa_auth.h"
17214501Srpaulo#include "wpa_auth_i.h"
18214501Srpaulo#include "wpa_auth_ie.h"
19214501Srpaulo
20214501Srpaulo#ifdef CONFIG_PEERKEY
21214501Srpaulo
22214501Srpaulostatic void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
23214501Srpaulo{
24214501Srpaulo#if 0
25214501Srpaulo	struct wpa_authenticator *wpa_auth = eloop_ctx;
26214501Srpaulo	struct wpa_stsl_negotiation *neg = timeout_ctx;
27214501Srpaulo#endif
28214501Srpaulo
29214501Srpaulo	/* TODO: ? */
30214501Srpaulo}
31214501Srpaulo
32214501Srpaulo
33214501Srpaulostruct wpa_stsl_search {
34214501Srpaulo	const u8 *addr;
35214501Srpaulo	struct wpa_state_machine *sm;
36214501Srpaulo};
37214501Srpaulo
38214501Srpaulo
39214501Srpaulostatic int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
40214501Srpaulo{
41214501Srpaulo	struct wpa_stsl_search *search = ctx;
42214501Srpaulo	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
43214501Srpaulo		search->sm = sm;
44214501Srpaulo		return 1;
45214501Srpaulo	}
46214501Srpaulo	return 0;
47214501Srpaulo}
48214501Srpaulo
49214501Srpaulo
50214501Srpaulostatic void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
51214501Srpaulo			       struct wpa_state_machine *sm, const u8 *peer,
52214501Srpaulo			       u16 mui, u16 error_type)
53214501Srpaulo{
54214501Srpaulo	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
55214501Srpaulo	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
56214501Srpaulo	u8 *pos;
57214501Srpaulo	struct rsn_error_kde error;
58214501Srpaulo
59214501Srpaulo	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
60214501Srpaulo			"Sending SMK Error");
61214501Srpaulo
62214501Srpaulo	pos = kde;
63214501Srpaulo
64214501Srpaulo	if (peer) {
65214501Srpaulo		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
66214501Srpaulo				  NULL, 0);
67214501Srpaulo	}
68214501Srpaulo
69214501Srpaulo	error.mui = host_to_be16(mui);
70214501Srpaulo	error.error_type = host_to_be16(error_type);
71214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
72214501Srpaulo			  (u8 *) &error, sizeof(error), NULL, 0);
73214501Srpaulo
74214501Srpaulo	__wpa_send_eapol(wpa_auth, sm,
75214501Srpaulo			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
76214501Srpaulo			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
77214501Srpaulo			 NULL, NULL, kde, pos - kde, 0, 0, 0);
78214501Srpaulo}
79214501Srpaulo
80214501Srpaulo
81214501Srpaulovoid wpa_smk_m1(struct wpa_authenticator *wpa_auth,
82214501Srpaulo		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
83214501Srpaulo{
84214501Srpaulo	struct wpa_eapol_ie_parse kde;
85214501Srpaulo	struct wpa_stsl_search search;
86214501Srpaulo	u8 *buf, *pos;
87214501Srpaulo	size_t buf_len;
88214501Srpaulo
89214501Srpaulo	if (wpa_parse_kde_ies((const u8 *) (key + 1),
90214501Srpaulo			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
91214501Srpaulo		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
92214501Srpaulo		return;
93214501Srpaulo	}
94214501Srpaulo
95214501Srpaulo	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
96214501Srpaulo	    kde.mac_addr_len < ETH_ALEN) {
97214501Srpaulo		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
98214501Srpaulo			   "SMK M1");
99214501Srpaulo		return;
100214501Srpaulo	}
101214501Srpaulo
102214501Srpaulo	/* Initiator = sm->addr; Peer = kde.mac_addr */
103214501Srpaulo
104214501Srpaulo	search.addr = kde.mac_addr;
105214501Srpaulo	search.sm = NULL;
106214501Srpaulo	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
107214501Srpaulo	    0 || search.sm == NULL) {
108214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
109214501Srpaulo			   " aborted - STA not associated anymore",
110214501Srpaulo			   MAC2STR(kde.mac_addr));
111214501Srpaulo		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
112214501Srpaulo				   STK_ERR_STA_NR);
113214501Srpaulo		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
114214501Srpaulo		return;
115214501Srpaulo	}
116214501Srpaulo
117214501Srpaulo	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
118214501Srpaulo	buf = os_malloc(buf_len);
119214501Srpaulo	if (buf == NULL)
120214501Srpaulo		return;
121214501Srpaulo	/* Initiator RSN IE */
122214501Srpaulo	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
123214501Srpaulo	pos = buf + kde.rsn_ie_len;
124214501Srpaulo	/* Initiator MAC Address */
125214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
126214501Srpaulo			  NULL, 0);
127214501Srpaulo
128214501Srpaulo	/* SMK M2:
129214501Srpaulo	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
130214501Srpaulo	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
131214501Srpaulo	 */
132214501Srpaulo
133214501Srpaulo	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
134214501Srpaulo			"Sending SMK M2");
135214501Srpaulo
136214501Srpaulo	__wpa_send_eapol(wpa_auth, search.sm,
137214501Srpaulo			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
138214501Srpaulo			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
139214501Srpaulo			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
140214501Srpaulo
141214501Srpaulo	os_free(buf);
142214501Srpaulo}
143214501Srpaulo
144214501Srpaulo
145214501Srpaulostatic void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
146214501Srpaulo			    struct wpa_state_machine *sm,
147214501Srpaulo			    struct wpa_eapol_key *key,
148214501Srpaulo			    struct wpa_eapol_ie_parse *kde,
149214501Srpaulo			    const u8 *smk)
150214501Srpaulo{
151214501Srpaulo	u8 *buf, *pos;
152214501Srpaulo	size_t buf_len;
153214501Srpaulo	u32 lifetime;
154214501Srpaulo
155214501Srpaulo	/* SMK M4:
156214501Srpaulo	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
157214501Srpaulo	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
158214501Srpaulo	 *           Lifetime KDE)
159214501Srpaulo	 */
160214501Srpaulo
161214501Srpaulo	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
162214501Srpaulo		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
163214501Srpaulo		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
164214501Srpaulo		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
165214501Srpaulo	pos = buf = os_malloc(buf_len);
166214501Srpaulo	if (buf == NULL)
167214501Srpaulo		return;
168214501Srpaulo
169214501Srpaulo	/* Initiator MAC Address */
170214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
171214501Srpaulo			  NULL, 0);
172214501Srpaulo
173214501Srpaulo	/* Initiator Nonce */
174214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
175214501Srpaulo			  NULL, 0);
176214501Srpaulo
177214501Srpaulo	/* SMK with PNonce */
178214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
179214501Srpaulo			  key->key_nonce, WPA_NONCE_LEN);
180214501Srpaulo
181214501Srpaulo	/* Lifetime */
182214501Srpaulo	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
183214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
184214501Srpaulo			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
185214501Srpaulo
186214501Srpaulo	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
187214501Srpaulo			"Sending SMK M4");
188214501Srpaulo
189214501Srpaulo	__wpa_send_eapol(wpa_auth, sm,
190214501Srpaulo			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
191214501Srpaulo			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
192214501Srpaulo			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
193214501Srpaulo
194214501Srpaulo	os_free(buf);
195214501Srpaulo}
196214501Srpaulo
197214501Srpaulo
198214501Srpaulostatic void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
199214501Srpaulo			    struct wpa_state_machine *sm,
200214501Srpaulo			    struct wpa_eapol_key *key,
201214501Srpaulo			    struct wpa_eapol_ie_parse *kde,
202214501Srpaulo			    const u8 *smk, const u8 *peer)
203214501Srpaulo{
204214501Srpaulo	u8 *buf, *pos;
205214501Srpaulo	size_t buf_len;
206214501Srpaulo	u32 lifetime;
207214501Srpaulo
208214501Srpaulo	/* SMK M5:
209214501Srpaulo	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
210214501Srpaulo	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
211214501Srpaulo	 *                             Lifetime KDE))
212214501Srpaulo	 */
213214501Srpaulo
214214501Srpaulo	buf_len = kde->rsn_ie_len +
215214501Srpaulo		2 + RSN_SELECTOR_LEN + ETH_ALEN +
216214501Srpaulo		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
217214501Srpaulo		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
218214501Srpaulo		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
219214501Srpaulo	pos = buf = os_malloc(buf_len);
220214501Srpaulo	if (buf == NULL)
221214501Srpaulo		return;
222214501Srpaulo
223214501Srpaulo	/* Peer RSN IE */
224214501Srpaulo	os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
225214501Srpaulo	pos = buf + kde->rsn_ie_len;
226214501Srpaulo
227214501Srpaulo	/* Peer MAC Address */
228214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
229214501Srpaulo
230214501Srpaulo	/* PNonce */
231214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
232214501Srpaulo			  WPA_NONCE_LEN, NULL, 0);
233214501Srpaulo
234214501Srpaulo	/* SMK and INonce */
235214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
236214501Srpaulo			  kde->nonce, WPA_NONCE_LEN);
237214501Srpaulo
238214501Srpaulo	/* Lifetime */
239214501Srpaulo	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
240214501Srpaulo	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
241214501Srpaulo			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
242214501Srpaulo
243214501Srpaulo	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
244214501Srpaulo			"Sending SMK M5");
245214501Srpaulo
246214501Srpaulo	__wpa_send_eapol(wpa_auth, sm,
247214501Srpaulo			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
248214501Srpaulo			 WPA_KEY_INFO_SMK_MESSAGE,
249214501Srpaulo			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
250214501Srpaulo
251214501Srpaulo	os_free(buf);
252214501Srpaulo}
253214501Srpaulo
254214501Srpaulo
255214501Srpaulovoid wpa_smk_m3(struct wpa_authenticator *wpa_auth,
256214501Srpaulo		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
257214501Srpaulo{
258214501Srpaulo	struct wpa_eapol_ie_parse kde;
259214501Srpaulo	struct wpa_stsl_search search;
260214501Srpaulo	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
261214501Srpaulo
262214501Srpaulo	if (wpa_parse_kde_ies((const u8 *) (key + 1),
263214501Srpaulo			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
264214501Srpaulo		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
265214501Srpaulo		return;
266214501Srpaulo	}
267214501Srpaulo
268214501Srpaulo	if (kde.rsn_ie == NULL ||
269214501Srpaulo	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
270214501Srpaulo	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
271214501Srpaulo		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
272214501Srpaulo			   "Nonce KDE in SMK M3");
273214501Srpaulo		return;
274214501Srpaulo	}
275214501Srpaulo
276214501Srpaulo	/* Peer = sm->addr; Initiator = kde.mac_addr;
277214501Srpaulo	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
278214501Srpaulo
279214501Srpaulo	search.addr = kde.mac_addr;
280214501Srpaulo	search.sm = NULL;
281214501Srpaulo	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
282214501Srpaulo	    0 || search.sm == NULL) {
283214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
284214501Srpaulo			   " aborted - STA not associated anymore",
285214501Srpaulo			   MAC2STR(kde.mac_addr));
286214501Srpaulo		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
287214501Srpaulo				   STK_ERR_STA_NR);
288214501Srpaulo		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
289214501Srpaulo		return;
290214501Srpaulo	}
291214501Srpaulo
292252726Srpaulo	if (random_get_bytes(smk, PMK_LEN)) {
293214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
294214501Srpaulo		return;
295214501Srpaulo	}
296214501Srpaulo
297214501Srpaulo	/* SMK = PRF-256(Random number, "SMK Derivation",
298214501Srpaulo	 *               AA || Time || INonce || PNonce)
299214501Srpaulo	 */
300214501Srpaulo	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
301214501Srpaulo	pos = buf + ETH_ALEN;
302214501Srpaulo	wpa_get_ntp_timestamp(pos);
303214501Srpaulo	pos += 8;
304214501Srpaulo	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
305214501Srpaulo	pos += WPA_NONCE_LEN;
306214501Srpaulo	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
307214501Srpaulo#ifdef CONFIG_IEEE80211W
308214501Srpaulo	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
309214501Srpaulo		   smk, PMK_LEN);
310214501Srpaulo#else /* CONFIG_IEEE80211W */
311214501Srpaulo	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
312214501Srpaulo		 smk, PMK_LEN);
313214501Srpaulo#endif /* CONFIG_IEEE80211W */
314214501Srpaulo
315214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
316214501Srpaulo
317214501Srpaulo	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
318214501Srpaulo	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
319214501Srpaulo
320214501Srpaulo	/* Authenticator does not need SMK anymore and it is required to forget
321214501Srpaulo	 * it. */
322214501Srpaulo	os_memset(smk, 0, sizeof(*smk));
323214501Srpaulo}
324214501Srpaulo
325214501Srpaulo
326214501Srpaulovoid wpa_smk_error(struct wpa_authenticator *wpa_auth,
327214501Srpaulo		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
328214501Srpaulo{
329214501Srpaulo	struct wpa_eapol_ie_parse kde;
330214501Srpaulo	struct wpa_stsl_search search;
331214501Srpaulo	struct rsn_error_kde error;
332214501Srpaulo	u16 mui, error_type;
333214501Srpaulo
334214501Srpaulo	if (wpa_parse_kde_ies((const u8 *) (key + 1),
335214501Srpaulo			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
336214501Srpaulo		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
337214501Srpaulo		return;
338214501Srpaulo	}
339214501Srpaulo
340214501Srpaulo	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
341214501Srpaulo	    kde.error == NULL || kde.error_len < sizeof(error)) {
342214501Srpaulo		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
343214501Srpaulo			   "SMK Error");
344214501Srpaulo		return;
345214501Srpaulo	}
346214501Srpaulo
347214501Srpaulo	search.addr = kde.mac_addr;
348214501Srpaulo	search.sm = NULL;
349214501Srpaulo	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
350214501Srpaulo	    0 || search.sm == NULL) {
351214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
352214501Srpaulo			   "associated for SMK Error message from " MACSTR,
353214501Srpaulo			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
354214501Srpaulo		return;
355214501Srpaulo	}
356214501Srpaulo
357214501Srpaulo	os_memcpy(&error, kde.error, sizeof(error));
358214501Srpaulo	mui = be_to_host16(error.mui);
359214501Srpaulo	error_type = be_to_host16(error.error_type);
360214501Srpaulo	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
361214501Srpaulo			 "STA reported SMK Error: Peer " MACSTR
362214501Srpaulo			 " MUI %d Error Type %d",
363214501Srpaulo			 MAC2STR(kde.mac_addr), mui, error_type);
364214501Srpaulo
365214501Srpaulo	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
366214501Srpaulo}
367214501Srpaulo
368214501Srpaulo
369214501Srpauloint wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
370214501Srpaulo		    struct wpa_stsl_negotiation *neg)
371214501Srpaulo{
372214501Srpaulo	struct wpa_stsl_negotiation *pos, *prev;
373214501Srpaulo
374214501Srpaulo	if (wpa_auth == NULL)
375214501Srpaulo		return -1;
376214501Srpaulo	pos = wpa_auth->stsl_negotiations;
377214501Srpaulo	prev = NULL;
378214501Srpaulo	while (pos) {
379214501Srpaulo		if (pos == neg) {
380214501Srpaulo			if (prev)
381214501Srpaulo				prev->next = pos->next;
382214501Srpaulo			else
383214501Srpaulo				wpa_auth->stsl_negotiations = pos->next;
384214501Srpaulo
385214501Srpaulo			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
386214501Srpaulo			os_free(pos);
387214501Srpaulo			return 0;
388214501Srpaulo		}
389214501Srpaulo		prev = pos;
390214501Srpaulo		pos = pos->next;
391214501Srpaulo	}
392214501Srpaulo
393214501Srpaulo	return -1;
394214501Srpaulo}
395214501Srpaulo
396214501Srpaulo#endif /* CONFIG_PEERKEY */
397