xref: /freebsd/contrib/wpa/src/ap/preauth_auth.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
3e28a4053SRui Paulo  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "utils/includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #ifdef CONFIG_RSN_PREAUTH
12e28a4053SRui Paulo 
13e28a4053SRui Paulo #include "utils/common.h"
14e28a4053SRui Paulo #include "utils/eloop.h"
15e28a4053SRui Paulo #include "l2_packet/l2_packet.h"
16e28a4053SRui Paulo #include "common/wpa_common.h"
17e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h"
18e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h"
19e28a4053SRui Paulo #include "hostapd.h"
20e28a4053SRui Paulo #include "ap_config.h"
21e28a4053SRui Paulo #include "ieee802_1x.h"
22e28a4053SRui Paulo #include "sta_info.h"
23e28a4053SRui Paulo #include "wpa_auth.h"
24e28a4053SRui Paulo #include "preauth_auth.h"
25e28a4053SRui Paulo 
26e28a4053SRui Paulo #ifndef ETH_P_PREAUTH
27e28a4053SRui Paulo #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
28e28a4053SRui Paulo #endif /* ETH_P_PREAUTH */
29e28a4053SRui Paulo 
30e28a4053SRui Paulo static const int dot11RSNAConfigPMKLifetime = 43200;
31e28a4053SRui Paulo 
32e28a4053SRui Paulo struct rsn_preauth_interface {
33e28a4053SRui Paulo 	struct rsn_preauth_interface *next;
34e28a4053SRui Paulo 	struct hostapd_data *hapd;
35e28a4053SRui Paulo 	struct l2_packet_data *l2;
36e28a4053SRui Paulo 	char *ifname;
37e28a4053SRui Paulo 	int ifindex;
38e28a4053SRui Paulo };
39e28a4053SRui Paulo 
40e28a4053SRui Paulo 
rsn_preauth_receive(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)41e28a4053SRui Paulo static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
42e28a4053SRui Paulo 				const u8 *buf, size_t len)
43e28a4053SRui Paulo {
44e28a4053SRui Paulo 	struct rsn_preauth_interface *piface = ctx;
45e28a4053SRui Paulo 	struct hostapd_data *hapd = piface->hapd;
46e28a4053SRui Paulo 	struct ieee802_1x_hdr *hdr;
47e28a4053SRui Paulo 	struct sta_info *sta;
48e28a4053SRui Paulo 	struct l2_ethhdr *ethhdr;
49e28a4053SRui Paulo 
50e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
51e28a4053SRui Paulo 		   "from interface '%s'", piface->ifname);
52e28a4053SRui Paulo 	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
53e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
54e28a4053SRui Paulo 			   "(len=%lu)", (unsigned long) len);
55e28a4053SRui Paulo 		return;
56e28a4053SRui Paulo 	}
57e28a4053SRui Paulo 
58e28a4053SRui Paulo 	ethhdr = (struct l2_ethhdr *) buf;
59e28a4053SRui Paulo 	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
60e28a4053SRui Paulo 
61*a90b9d01SCy Schubert 	if (!ether_addr_equal(ethhdr->h_dest, hapd->own_addr)) {
62e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
63e28a4053SRui Paulo 			   MACSTR, MAC2STR(ethhdr->h_dest));
64e28a4053SRui Paulo 		return;
65e28a4053SRui Paulo 	}
66e28a4053SRui Paulo 
67e28a4053SRui Paulo 	sta = ap_get_sta(hapd, ethhdr->h_source);
68e28a4053SRui Paulo 	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
69e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
70e28a4053SRui Paulo 			   "STA " MACSTR, MAC2STR(sta->addr));
71e28a4053SRui Paulo 		return;
72e28a4053SRui Paulo 	}
73e28a4053SRui Paulo 	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
74e28a4053SRui Paulo 		sta = ap_sta_add(hapd, ethhdr->h_source);
75e28a4053SRui Paulo 		if (sta == NULL)
76e28a4053SRui Paulo 			return;
77e28a4053SRui Paulo 		sta->flags = WLAN_STA_PREAUTH;
78e28a4053SRui Paulo 
79e28a4053SRui Paulo 		ieee802_1x_new_station(hapd, sta);
80e28a4053SRui Paulo 		if (sta->eapol_sm == NULL) {
81e28a4053SRui Paulo 			ap_free_sta(hapd, sta);
82e28a4053SRui Paulo 			sta = NULL;
83e28a4053SRui Paulo 		} else {
84e28a4053SRui Paulo 			sta->eapol_sm->radius_identifier = -1;
85c1d255d3SCy Schubert 			sta->eapol_sm->portValid = true;
86e28a4053SRui Paulo 			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
87e28a4053SRui Paulo 		}
88e28a4053SRui Paulo 	}
89e28a4053SRui Paulo 	if (sta == NULL)
90e28a4053SRui Paulo 		return;
91e28a4053SRui Paulo 	sta->preauth_iface = piface;
92e28a4053SRui Paulo 	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
93*a90b9d01SCy Schubert 			   len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN);
94e28a4053SRui Paulo }
95e28a4053SRui Paulo 
96e28a4053SRui Paulo 
rsn_preauth_iface_add(struct hostapd_data * hapd,const char * ifname)97e28a4053SRui Paulo static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
98e28a4053SRui Paulo {
99e28a4053SRui Paulo 	struct rsn_preauth_interface *piface;
100e28a4053SRui Paulo 
101e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
102e28a4053SRui Paulo 
103e28a4053SRui Paulo 	piface = os_zalloc(sizeof(*piface));
104e28a4053SRui Paulo 	if (piface == NULL)
105e28a4053SRui Paulo 		return -1;
106e28a4053SRui Paulo 	piface->hapd = hapd;
107e28a4053SRui Paulo 
108e28a4053SRui Paulo 	piface->ifname = os_strdup(ifname);
109e28a4053SRui Paulo 	if (piface->ifname == NULL) {
110e28a4053SRui Paulo 		goto fail1;
111e28a4053SRui Paulo 	}
112e28a4053SRui Paulo 
113e28a4053SRui Paulo 	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
114e28a4053SRui Paulo 				    rsn_preauth_receive, piface, 1);
115e28a4053SRui Paulo 	if (piface->l2 == NULL) {
116e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
117e28a4053SRui Paulo 			   "to ETH_P_PREAUTH");
118e28a4053SRui Paulo 		goto fail2;
119e28a4053SRui Paulo 	}
120e28a4053SRui Paulo 
121e28a4053SRui Paulo 	piface->next = hapd->preauth_iface;
122e28a4053SRui Paulo 	hapd->preauth_iface = piface;
123e28a4053SRui Paulo 	return 0;
124e28a4053SRui Paulo 
125e28a4053SRui Paulo fail2:
126e28a4053SRui Paulo 	os_free(piface->ifname);
127e28a4053SRui Paulo fail1:
128e28a4053SRui Paulo 	os_free(piface);
129e28a4053SRui Paulo 	return -1;
130e28a4053SRui Paulo }
131e28a4053SRui Paulo 
132e28a4053SRui Paulo 
rsn_preauth_iface_deinit(struct hostapd_data * hapd)133e28a4053SRui Paulo void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
134e28a4053SRui Paulo {
135e28a4053SRui Paulo 	struct rsn_preauth_interface *piface, *prev;
136e28a4053SRui Paulo 
137e28a4053SRui Paulo 	piface = hapd->preauth_iface;
138e28a4053SRui Paulo 	hapd->preauth_iface = NULL;
139e28a4053SRui Paulo 	while (piface) {
140e28a4053SRui Paulo 		prev = piface;
141e28a4053SRui Paulo 		piface = piface->next;
142e28a4053SRui Paulo 		l2_packet_deinit(prev->l2);
143e28a4053SRui Paulo 		os_free(prev->ifname);
144e28a4053SRui Paulo 		os_free(prev);
145e28a4053SRui Paulo 	}
146e28a4053SRui Paulo }
147e28a4053SRui Paulo 
148e28a4053SRui Paulo 
rsn_preauth_iface_init(struct hostapd_data * hapd)149e28a4053SRui Paulo int rsn_preauth_iface_init(struct hostapd_data *hapd)
150e28a4053SRui Paulo {
151e28a4053SRui Paulo 	char *tmp, *start, *end;
152e28a4053SRui Paulo 
153e28a4053SRui Paulo 	if (hapd->conf->rsn_preauth_interfaces == NULL)
154e28a4053SRui Paulo 		return 0;
155e28a4053SRui Paulo 
156e28a4053SRui Paulo 	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
157e28a4053SRui Paulo 	if (tmp == NULL)
158e28a4053SRui Paulo 		return -1;
159e28a4053SRui Paulo 	start = tmp;
160e28a4053SRui Paulo 	for (;;) {
161e28a4053SRui Paulo 		while (*start == ' ')
162e28a4053SRui Paulo 			start++;
163e28a4053SRui Paulo 		if (*start == '\0')
164e28a4053SRui Paulo 			break;
165e28a4053SRui Paulo 		end = os_strchr(start, ' ');
166e28a4053SRui Paulo 		if (end)
167e28a4053SRui Paulo 			*end = '\0';
168e28a4053SRui Paulo 
169e28a4053SRui Paulo 		if (rsn_preauth_iface_add(hapd, start)) {
170e28a4053SRui Paulo 			rsn_preauth_iface_deinit(hapd);
171e28a4053SRui Paulo 			os_free(tmp);
172e28a4053SRui Paulo 			return -1;
173e28a4053SRui Paulo 		}
174e28a4053SRui Paulo 
175e28a4053SRui Paulo 		if (end)
176e28a4053SRui Paulo 			start = end + 1;
177e28a4053SRui Paulo 		else
178e28a4053SRui Paulo 			break;
179e28a4053SRui Paulo 	}
180e28a4053SRui Paulo 	os_free(tmp);
181e28a4053SRui Paulo 	return 0;
182e28a4053SRui Paulo }
183e28a4053SRui Paulo 
184e28a4053SRui Paulo 
rsn_preauth_finished_cb(void * eloop_ctx,void * timeout_ctx)185e28a4053SRui Paulo static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
186e28a4053SRui Paulo {
187e28a4053SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
188e28a4053SRui Paulo 	struct sta_info *sta = timeout_ctx;
189e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
190e28a4053SRui Paulo 		   MACSTR, MAC2STR(sta->addr));
191e28a4053SRui Paulo 	ap_free_sta(hapd, sta);
192e28a4053SRui Paulo }
193e28a4053SRui Paulo 
194e28a4053SRui Paulo 
rsn_preauth_finished(struct hostapd_data * hapd,struct sta_info * sta,int success)195e28a4053SRui Paulo void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
196e28a4053SRui Paulo 			  int success)
197e28a4053SRui Paulo {
198e28a4053SRui Paulo 	const u8 *key;
199e28a4053SRui Paulo 	size_t len;
200e28a4053SRui Paulo 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
201e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
202e28a4053SRui Paulo 		       success ? "succeeded" : "failed");
203e28a4053SRui Paulo 
204e28a4053SRui Paulo 	key = ieee802_1x_get_key(sta->eapol_sm, &len);
205e28a4053SRui Paulo 	if (len > PMK_LEN)
206e28a4053SRui Paulo 		len = PMK_LEN;
207e28a4053SRui Paulo 	if (success && key) {
208e28a4053SRui Paulo 		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
209e28a4053SRui Paulo 					       sta->addr,
210e28a4053SRui Paulo 					       dot11RSNAConfigPMKLifetime,
211e28a4053SRui Paulo 					       sta->eapol_sm) == 0) {
212e28a4053SRui Paulo 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
213e28a4053SRui Paulo 				       HOSTAPD_LEVEL_DEBUG,
214e28a4053SRui Paulo 				       "added PMKSA cache entry (pre-auth)");
215e28a4053SRui Paulo 		} else {
216e28a4053SRui Paulo 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
217e28a4053SRui Paulo 				       HOSTAPD_LEVEL_DEBUG,
218e28a4053SRui Paulo 				       "failed to add PMKSA cache entry "
219e28a4053SRui Paulo 				       "(pre-auth)");
220e28a4053SRui Paulo 		}
221e28a4053SRui Paulo 	}
222e28a4053SRui Paulo 
223e28a4053SRui Paulo 	/*
224e28a4053SRui Paulo 	 * Finish STA entry removal from timeout in order to avoid freeing
225e28a4053SRui Paulo 	 * STA data before the caller has finished processing.
226e28a4053SRui Paulo 	 */
227e28a4053SRui Paulo 	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
228e28a4053SRui Paulo }
229e28a4053SRui Paulo 
230e28a4053SRui Paulo 
rsn_preauth_send(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len)231e28a4053SRui Paulo void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
232e28a4053SRui Paulo 		      u8 *buf, size_t len)
233e28a4053SRui Paulo {
234e28a4053SRui Paulo 	struct rsn_preauth_interface *piface;
235e28a4053SRui Paulo 	struct l2_ethhdr *ethhdr;
236e28a4053SRui Paulo 
237e28a4053SRui Paulo 	piface = hapd->preauth_iface;
238e28a4053SRui Paulo 	while (piface) {
239e28a4053SRui Paulo 		if (piface == sta->preauth_iface)
240e28a4053SRui Paulo 			break;
241e28a4053SRui Paulo 		piface = piface->next;
242e28a4053SRui Paulo 	}
243e28a4053SRui Paulo 
244e28a4053SRui Paulo 	if (piface == NULL) {
245e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
246e28a4053SRui Paulo 			   "interface for " MACSTR, MAC2STR(sta->addr));
247e28a4053SRui Paulo 		return;
248e28a4053SRui Paulo 	}
249e28a4053SRui Paulo 
250e28a4053SRui Paulo 	ethhdr = os_malloc(sizeof(*ethhdr) + len);
251e28a4053SRui Paulo 	if (ethhdr == NULL)
252e28a4053SRui Paulo 		return;
253e28a4053SRui Paulo 
254e28a4053SRui Paulo 	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
255e28a4053SRui Paulo 	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
256e28a4053SRui Paulo 	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
257e28a4053SRui Paulo 	os_memcpy(ethhdr + 1, buf, len);
258e28a4053SRui Paulo 
259e28a4053SRui Paulo 	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
260e28a4053SRui Paulo 			   sizeof(*ethhdr) + len) < 0) {
261e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
262e28a4053SRui Paulo 			   "l2_packet_send\n");
263e28a4053SRui Paulo 	}
264e28a4053SRui Paulo 	os_free(ethhdr);
265e28a4053SRui Paulo }
266e28a4053SRui Paulo 
267e28a4053SRui Paulo 
rsn_preauth_free_station(struct hostapd_data * hapd,struct sta_info * sta)268e28a4053SRui Paulo void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
269e28a4053SRui Paulo {
270e28a4053SRui Paulo 	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
271e28a4053SRui Paulo }
272e28a4053SRui Paulo 
273e28a4053SRui Paulo #endif /* CONFIG_RSN_PREAUTH */
274