xref: /freebsd/contrib/wpa/src/ap/wpa_auth_kay.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1206b73d0SCy Schubert /*
2206b73d0SCy Schubert  * IEEE 802.1X-2010 KaY Interface
3206b73d0SCy Schubert  * Copyright (c) 2019, The Linux Foundation
4206b73d0SCy Schubert  *
5206b73d0SCy Schubert  * This software may be distributed under the terms of the BSD license.
6206b73d0SCy Schubert  * See README for more details.
7206b73d0SCy Schubert  */
8206b73d0SCy Schubert 
9206b73d0SCy Schubert #include "utils/includes.h"
10206b73d0SCy Schubert 
11206b73d0SCy Schubert #include "utils/common.h"
12206b73d0SCy Schubert #include "pae/ieee802_1x_key.h"
13206b73d0SCy Schubert #include "pae/ieee802_1x_kay.h"
14206b73d0SCy Schubert #include "hostapd.h"
15206b73d0SCy Schubert #include "sta_info.h"
16206b73d0SCy Schubert #include "wpa_auth_kay.h"
17206b73d0SCy Schubert #include "ieee802_1x.h"
18206b73d0SCy Schubert 
19206b73d0SCy Schubert 
20206b73d0SCy Schubert #define DEFAULT_KEY_LEN		16
21206b73d0SCy Schubert /* secure Connectivity Association Key Name (CKN) */
22206b73d0SCy Schubert #define DEFAULT_CKN_LEN		16
23206b73d0SCy Schubert 
24206b73d0SCy Schubert 
hapd_macsec_init(void * priv,struct macsec_init_params * params)25206b73d0SCy Schubert static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
26206b73d0SCy Schubert {
27206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
28206b73d0SCy Schubert 
29206b73d0SCy Schubert 	if (!hapd->driver->macsec_init)
30206b73d0SCy Schubert 		return -1;
31206b73d0SCy Schubert 	return hapd->driver->macsec_init(hapd->drv_priv, params);
32206b73d0SCy Schubert }
33206b73d0SCy Schubert 
34206b73d0SCy Schubert 
hapd_macsec_deinit(void * priv)35206b73d0SCy Schubert static int hapd_macsec_deinit(void *priv)
36206b73d0SCy Schubert {
37206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
38206b73d0SCy Schubert 
39206b73d0SCy Schubert 	if (!hapd->driver->macsec_deinit)
40206b73d0SCy Schubert 		return -1;
41206b73d0SCy Schubert 	return hapd->driver->macsec_deinit(hapd->drv_priv);
42206b73d0SCy Schubert }
43206b73d0SCy Schubert 
44206b73d0SCy Schubert 
hapd_macsec_get_capability(void * priv,enum macsec_cap * cap)45206b73d0SCy Schubert static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
46206b73d0SCy Schubert {
47206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
48206b73d0SCy Schubert 
49206b73d0SCy Schubert 	if (!hapd->driver->macsec_get_capability)
50206b73d0SCy Schubert 		return -1;
51206b73d0SCy Schubert 	return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
52206b73d0SCy Schubert }
53206b73d0SCy Schubert 
54206b73d0SCy Schubert 
hapd_enable_protect_frames(void * priv,bool enabled)55c1d255d3SCy Schubert static int hapd_enable_protect_frames(void *priv, bool enabled)
56206b73d0SCy Schubert {
57206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
58206b73d0SCy Schubert 
59206b73d0SCy Schubert 	if (!hapd->driver->enable_protect_frames)
60206b73d0SCy Schubert 		return -1;
61206b73d0SCy Schubert 	return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
62206b73d0SCy Schubert }
63206b73d0SCy Schubert 
64206b73d0SCy Schubert 
hapd_enable_encrypt(void * priv,bool enabled)65c1d255d3SCy Schubert static int hapd_enable_encrypt(void *priv, bool enabled)
66206b73d0SCy Schubert {
67206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
68206b73d0SCy Schubert 
69206b73d0SCy Schubert 	if (!hapd->driver->enable_encrypt)
70206b73d0SCy Schubert 		return -1;
71206b73d0SCy Schubert 	return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
72206b73d0SCy Schubert }
73206b73d0SCy Schubert 
74206b73d0SCy Schubert 
hapd_set_replay_protect(void * priv,bool enabled,u32 window)75c1d255d3SCy Schubert static int hapd_set_replay_protect(void *priv, bool enabled, u32 window)
76206b73d0SCy Schubert {
77206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
78206b73d0SCy Schubert 
79206b73d0SCy Schubert 	if (!hapd->driver->set_replay_protect)
80206b73d0SCy Schubert 		return -1;
81206b73d0SCy Schubert 	return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
82206b73d0SCy Schubert 						 window);
83206b73d0SCy Schubert }
84206b73d0SCy Schubert 
85206b73d0SCy Schubert 
hapd_set_current_cipher_suite(void * priv,u64 cs)86206b73d0SCy Schubert static int hapd_set_current_cipher_suite(void *priv, u64 cs)
87206b73d0SCy Schubert {
88206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
89206b73d0SCy Schubert 
90206b73d0SCy Schubert 	if (!hapd->driver->set_current_cipher_suite)
91206b73d0SCy Schubert 		return -1;
92206b73d0SCy Schubert 	return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
93206b73d0SCy Schubert }
94206b73d0SCy Schubert 
95206b73d0SCy Schubert 
hapd_enable_controlled_port(void * priv,bool enabled)96c1d255d3SCy Schubert static int hapd_enable_controlled_port(void *priv, bool enabled)
97206b73d0SCy Schubert {
98206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
99206b73d0SCy Schubert 
100206b73d0SCy Schubert 	if (!hapd->driver->enable_controlled_port)
101206b73d0SCy Schubert 		return -1;
102206b73d0SCy Schubert 	return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
103206b73d0SCy Schubert }
104206b73d0SCy Schubert 
105206b73d0SCy Schubert 
hapd_get_receive_lowest_pn(void * priv,struct receive_sa * sa)106206b73d0SCy Schubert static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
107206b73d0SCy Schubert {
108206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
109206b73d0SCy Schubert 
110206b73d0SCy Schubert 	if (!hapd->driver->get_receive_lowest_pn)
111206b73d0SCy Schubert 		return -1;
112206b73d0SCy Schubert 	return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
113206b73d0SCy Schubert }
114206b73d0SCy Schubert 
115206b73d0SCy Schubert 
hapd_get_transmit_next_pn(void * priv,struct transmit_sa * sa)116206b73d0SCy Schubert static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
117206b73d0SCy Schubert {
118206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
119206b73d0SCy Schubert 
120206b73d0SCy Schubert 	if (!hapd->driver->get_transmit_next_pn)
121206b73d0SCy Schubert 		return -1;
122206b73d0SCy Schubert 	return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
123206b73d0SCy Schubert }
124206b73d0SCy Schubert 
125206b73d0SCy Schubert 
hapd_set_transmit_next_pn(void * priv,struct transmit_sa * sa)126206b73d0SCy Schubert static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
127206b73d0SCy Schubert {
128206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
129206b73d0SCy Schubert 
130206b73d0SCy Schubert 	if (!hapd->driver->set_transmit_next_pn)
131206b73d0SCy Schubert 		return -1;
132206b73d0SCy Schubert 	return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
133206b73d0SCy Schubert }
134206b73d0SCy Schubert 
135206b73d0SCy Schubert 
conf_offset_val(enum confidentiality_offset co)136206b73d0SCy Schubert static unsigned int conf_offset_val(enum confidentiality_offset co)
137206b73d0SCy Schubert {
138206b73d0SCy Schubert 	switch (co) {
139206b73d0SCy Schubert 	case CONFIDENTIALITY_OFFSET_30:
140206b73d0SCy Schubert 		return 30;
141206b73d0SCy Schubert 	case CONFIDENTIALITY_OFFSET_50:
142206b73d0SCy Schubert 		return 50;
143206b73d0SCy Schubert 	default:
144206b73d0SCy Schubert 		return 0;
145206b73d0SCy Schubert 	}
146206b73d0SCy Schubert }
147206b73d0SCy Schubert 
148206b73d0SCy Schubert 
hapd_create_receive_sc(void * priv,struct receive_sc * sc,enum validate_frames vf,enum confidentiality_offset co)149206b73d0SCy Schubert static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
150206b73d0SCy Schubert 				  enum validate_frames vf,
151206b73d0SCy Schubert 				  enum confidentiality_offset co)
152206b73d0SCy Schubert {
153206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
154206b73d0SCy Schubert 
155206b73d0SCy Schubert 	if (!hapd->driver->create_receive_sc)
156206b73d0SCy Schubert 		return -1;
157206b73d0SCy Schubert 	return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
158206b73d0SCy Schubert 					       conf_offset_val(co), vf);
159206b73d0SCy Schubert }
160206b73d0SCy Schubert 
161206b73d0SCy Schubert 
hapd_delete_receive_sc(void * priv,struct receive_sc * sc)162206b73d0SCy Schubert static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
163206b73d0SCy Schubert {
164206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
165206b73d0SCy Schubert 
166206b73d0SCy Schubert 	if (!hapd->driver->delete_receive_sc)
167206b73d0SCy Schubert 		return -1;
168206b73d0SCy Schubert 	return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
169206b73d0SCy Schubert }
170206b73d0SCy Schubert 
171206b73d0SCy Schubert 
hapd_create_receive_sa(void * priv,struct receive_sa * sa)172206b73d0SCy Schubert static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
173206b73d0SCy Schubert {
174206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
175206b73d0SCy Schubert 
176206b73d0SCy Schubert 	if (!hapd->driver->create_receive_sa)
177206b73d0SCy Schubert 		return -1;
178206b73d0SCy Schubert 	return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
179206b73d0SCy Schubert }
180206b73d0SCy Schubert 
181206b73d0SCy Schubert 
hapd_delete_receive_sa(void * priv,struct receive_sa * sa)182206b73d0SCy Schubert static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
183206b73d0SCy Schubert {
184206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
185206b73d0SCy Schubert 
186206b73d0SCy Schubert 	if (!hapd->driver->delete_receive_sa)
187206b73d0SCy Schubert 		return -1;
188206b73d0SCy Schubert 	return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
189206b73d0SCy Schubert }
190206b73d0SCy Schubert 
191206b73d0SCy Schubert 
hapd_enable_receive_sa(void * priv,struct receive_sa * sa)192206b73d0SCy Schubert static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
193206b73d0SCy Schubert {
194206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
195206b73d0SCy Schubert 
196206b73d0SCy Schubert 	if (!hapd->driver->enable_receive_sa)
197206b73d0SCy Schubert 		return -1;
198206b73d0SCy Schubert 	return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
199206b73d0SCy Schubert }
200206b73d0SCy Schubert 
201206b73d0SCy Schubert 
hapd_disable_receive_sa(void * priv,struct receive_sa * sa)202206b73d0SCy Schubert static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
203206b73d0SCy Schubert {
204206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
205206b73d0SCy Schubert 
206206b73d0SCy Schubert 	if (!hapd->driver->disable_receive_sa)
207206b73d0SCy Schubert 		return -1;
208206b73d0SCy Schubert 	return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
209206b73d0SCy Schubert }
210206b73d0SCy Schubert 
211206b73d0SCy Schubert 
212206b73d0SCy Schubert static int
hapd_create_transmit_sc(void * priv,struct transmit_sc * sc,enum confidentiality_offset co)213206b73d0SCy Schubert hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
214206b73d0SCy Schubert 			enum confidentiality_offset co)
215206b73d0SCy Schubert {
216206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
217206b73d0SCy Schubert 
218206b73d0SCy Schubert 	if (!hapd->driver->create_transmit_sc)
219206b73d0SCy Schubert 		return -1;
220206b73d0SCy Schubert 	return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
221206b73d0SCy Schubert 						conf_offset_val(co));
222206b73d0SCy Schubert }
223206b73d0SCy Schubert 
224206b73d0SCy Schubert 
hapd_delete_transmit_sc(void * priv,struct transmit_sc * sc)225206b73d0SCy Schubert static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
226206b73d0SCy Schubert {
227206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
228206b73d0SCy Schubert 
229206b73d0SCy Schubert 	if (!hapd->driver->delete_transmit_sc)
230206b73d0SCy Schubert 		return -1;
231206b73d0SCy Schubert 	return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
232206b73d0SCy Schubert }
233206b73d0SCy Schubert 
234206b73d0SCy Schubert 
hapd_create_transmit_sa(void * priv,struct transmit_sa * sa)235206b73d0SCy Schubert static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
236206b73d0SCy Schubert {
237206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
238206b73d0SCy Schubert 
239206b73d0SCy Schubert 	if (!hapd->driver->create_transmit_sa)
240206b73d0SCy Schubert 		return -1;
241206b73d0SCy Schubert 	return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
242206b73d0SCy Schubert }
243206b73d0SCy Schubert 
244206b73d0SCy Schubert 
hapd_delete_transmit_sa(void * priv,struct transmit_sa * sa)245206b73d0SCy Schubert static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
246206b73d0SCy Schubert {
247206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
248206b73d0SCy Schubert 
249206b73d0SCy Schubert 	if (!hapd->driver->delete_transmit_sa)
250206b73d0SCy Schubert 		return -1;
251206b73d0SCy Schubert 	return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
252206b73d0SCy Schubert }
253206b73d0SCy Schubert 
254206b73d0SCy Schubert 
hapd_enable_transmit_sa(void * priv,struct transmit_sa * sa)255206b73d0SCy Schubert static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
256206b73d0SCy Schubert {
257206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
258206b73d0SCy Schubert 
259206b73d0SCy Schubert 	if (!hapd->driver->enable_transmit_sa)
260206b73d0SCy Schubert 		return -1;
261206b73d0SCy Schubert 	return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
262206b73d0SCy Schubert }
263206b73d0SCy Schubert 
264206b73d0SCy Schubert 
hapd_disable_transmit_sa(void * priv,struct transmit_sa * sa)265206b73d0SCy Schubert static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
266206b73d0SCy Schubert {
267206b73d0SCy Schubert 	struct hostapd_data *hapd = priv;
268206b73d0SCy Schubert 
269206b73d0SCy Schubert 	if (!hapd->driver->disable_transmit_sa)
270206b73d0SCy Schubert 		return -1;
271206b73d0SCy Schubert 	return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
272206b73d0SCy Schubert }
273206b73d0SCy Schubert 
274206b73d0SCy Schubert 
ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data * hapd,struct sta_info * sta)275206b73d0SCy Schubert int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
276206b73d0SCy Schubert 				 struct sta_info *sta)
277206b73d0SCy Schubert {
278206b73d0SCy Schubert 	struct ieee802_1x_kay_ctx *kay_ctx;
279206b73d0SCy Schubert 	struct ieee802_1x_kay *res = NULL;
280206b73d0SCy Schubert 	enum macsec_policy policy;
281206b73d0SCy Schubert 
282206b73d0SCy Schubert 	ieee802_1x_dealloc_kay_sm_hapd(hapd);
283206b73d0SCy Schubert 
284206b73d0SCy Schubert 	if (!hapd->conf || hapd->conf->macsec_policy == 0)
285206b73d0SCy Schubert 		return 0;
286206b73d0SCy Schubert 
287206b73d0SCy Schubert 	if (hapd->conf->macsec_policy == 1) {
288206b73d0SCy Schubert 		if (hapd->conf->macsec_integ_only == 1)
289206b73d0SCy Schubert 			policy = SHOULD_SECURE;
290206b73d0SCy Schubert 		else
291206b73d0SCy Schubert 			policy = SHOULD_ENCRYPT;
292206b73d0SCy Schubert 	} else {
293206b73d0SCy Schubert 		policy = DO_NOT_SECURE;
294206b73d0SCy Schubert 	}
295206b73d0SCy Schubert 
296206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
297206b73d0SCy Schubert 	kay_ctx = os_zalloc(sizeof(*kay_ctx));
298206b73d0SCy Schubert 	if (!kay_ctx)
299206b73d0SCy Schubert 		return -1;
300206b73d0SCy Schubert 
301206b73d0SCy Schubert 	kay_ctx->ctx = hapd;
302206b73d0SCy Schubert 
303206b73d0SCy Schubert 	kay_ctx->macsec_init = hapd_macsec_init;
304206b73d0SCy Schubert 	kay_ctx->macsec_deinit = hapd_macsec_deinit;
305206b73d0SCy Schubert 	kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
306206b73d0SCy Schubert 	kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
307206b73d0SCy Schubert 	kay_ctx->enable_encrypt = hapd_enable_encrypt;
308206b73d0SCy Schubert 	kay_ctx->set_replay_protect = hapd_set_replay_protect;
309206b73d0SCy Schubert 	kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
310206b73d0SCy Schubert 	kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
311206b73d0SCy Schubert 	kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
312206b73d0SCy Schubert 	kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
313206b73d0SCy Schubert 	kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
314206b73d0SCy Schubert 	kay_ctx->create_receive_sc = hapd_create_receive_sc;
315206b73d0SCy Schubert 	kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
316206b73d0SCy Schubert 	kay_ctx->create_receive_sa = hapd_create_receive_sa;
317206b73d0SCy Schubert 	kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
318206b73d0SCy Schubert 	kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
319206b73d0SCy Schubert 	kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
320206b73d0SCy Schubert 	kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
321206b73d0SCy Schubert 	kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
322206b73d0SCy Schubert 	kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
323206b73d0SCy Schubert 	kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
324206b73d0SCy Schubert 	kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
325206b73d0SCy Schubert 	kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
326206b73d0SCy Schubert 
327206b73d0SCy Schubert 	res = ieee802_1x_kay_init(kay_ctx, policy,
328206b73d0SCy Schubert 				  hapd->conf->macsec_replay_protect,
329206b73d0SCy Schubert 				  hapd->conf->macsec_replay_window,
330*a90b9d01SCy Schubert 				  hapd->conf->macsec_offload,
331206b73d0SCy Schubert 				  hapd->conf->macsec_port,
332*a90b9d01SCy Schubert 				  hapd->conf->mka_priority,
333*a90b9d01SCy Schubert 				  hapd->conf->macsec_csindex,
334*a90b9d01SCy Schubert 				  hapd->conf->iface,
335206b73d0SCy Schubert 				  hapd->own_addr);
336206b73d0SCy Schubert 	/* ieee802_1x_kay_init() frees kay_ctx on failure */
337206b73d0SCy Schubert 	if (!res)
338206b73d0SCy Schubert 		return -1;
339206b73d0SCy Schubert 
340206b73d0SCy Schubert 	hapd->kay = res;
341206b73d0SCy Schubert 
342206b73d0SCy Schubert 	return 0;
343206b73d0SCy Schubert }
344206b73d0SCy Schubert 
345206b73d0SCy Schubert 
ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data * hapd)346206b73d0SCy Schubert void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
347206b73d0SCy Schubert {
348206b73d0SCy Schubert 	if (!hapd->kay)
349206b73d0SCy Schubert 		return;
350206b73d0SCy Schubert 
351206b73d0SCy Schubert 	ieee802_1x_kay_deinit(hapd->kay);
352206b73d0SCy Schubert 	hapd->kay = NULL;
353206b73d0SCy Schubert }
354206b73d0SCy Schubert 
355206b73d0SCy Schubert 
ieee802_1x_auth_get_msk(struct hostapd_data * hapd,struct sta_info * sta,u8 * msk,size_t * len)356206b73d0SCy Schubert static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
357206b73d0SCy Schubert 				   struct sta_info *sta, u8 *msk, size_t *len)
358206b73d0SCy Schubert {
359206b73d0SCy Schubert 	const u8 *key;
360206b73d0SCy Schubert 	size_t keylen;
361206b73d0SCy Schubert 
362206b73d0SCy Schubert 	if (!sta->eapol_sm)
363206b73d0SCy Schubert 		return -1;
364206b73d0SCy Schubert 
365206b73d0SCy Schubert 	key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
366206b73d0SCy Schubert 	if (key == NULL) {
367206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG,
368206b73d0SCy Schubert 			   "MACsec: Failed to get MSK from EAPOL state machines");
369206b73d0SCy Schubert 		return -1;
370206b73d0SCy Schubert 	}
371206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
372206b73d0SCy Schubert 		   (unsigned long) keylen);
373206b73d0SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
374206b73d0SCy Schubert 
375206b73d0SCy Schubert 	if (keylen > *len)
376206b73d0SCy Schubert 		keylen = *len;
377206b73d0SCy Schubert 	os_memcpy(msk, key, keylen);
378206b73d0SCy Schubert 	*len = keylen;
379206b73d0SCy Schubert 
380206b73d0SCy Schubert 	return 0;
381206b73d0SCy Schubert }
382206b73d0SCy Schubert 
383206b73d0SCy Schubert 
ieee802_1x_notify_create_actor_hapd(struct hostapd_data * hapd,struct sta_info * sta)384206b73d0SCy Schubert void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
385206b73d0SCy Schubert 					   struct sta_info *sta)
386206b73d0SCy Schubert {
387*a90b9d01SCy Schubert 	const u8 *sid;
388*a90b9d01SCy Schubert 	size_t sid_len;
389206b73d0SCy Schubert 	struct mka_key_name *ckn;
390206b73d0SCy Schubert 	struct mka_key *cak;
391206b73d0SCy Schubert 	struct mka_key *msk;
392206b73d0SCy Schubert 	void *res = NULL;
393206b73d0SCy Schubert 
394206b73d0SCy Schubert 	if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
395206b73d0SCy Schubert 		return NULL;
396206b73d0SCy Schubert 
397206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG,
398206b73d0SCy Schubert 		   "IEEE 802.1X: External notification - Create MKA for "
399206b73d0SCy Schubert 		   MACSTR, MAC2STR(sta->addr));
400206b73d0SCy Schubert 
401206b73d0SCy Schubert 	msk = os_zalloc(sizeof(*msk));
402206b73d0SCy Schubert 	ckn = os_zalloc(sizeof(*ckn));
403206b73d0SCy Schubert 	cak = os_zalloc(sizeof(*cak));
404*a90b9d01SCy Schubert 	if (!msk || !ckn || !cak)
405206b73d0SCy Schubert 		goto fail;
406206b73d0SCy Schubert 
407206b73d0SCy Schubert 	msk->len = DEFAULT_KEY_LEN;
408206b73d0SCy Schubert 	if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
409206b73d0SCy Schubert 		wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
410206b73d0SCy Schubert 		goto fail;
411206b73d0SCy Schubert 	}
412206b73d0SCy Schubert 
413*a90b9d01SCy Schubert 	sid = ieee802_1x_get_session_id(sta->eapol_sm, &sid_len);
414*a90b9d01SCy Schubert 	if (!sid) {
415206b73d0SCy Schubert 		wpa_printf(MSG_ERROR,
416206b73d0SCy Schubert 			   "IEEE 802.1X: Could not get EAP Session Id");
417206b73d0SCy Schubert 		goto fail;
418206b73d0SCy Schubert 	}
419206b73d0SCy Schubert 
420206b73d0SCy Schubert 	wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
421206b73d0SCy Schubert 	wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
422206b73d0SCy Schubert 
423206b73d0SCy Schubert 	/* Derive CAK from MSK */
424206b73d0SCy Schubert 	cak->len = DEFAULT_KEY_LEN;
425206b73d0SCy Schubert 	if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
426206b73d0SCy Schubert 				    sta->addr, cak->key, cak->len)) {
427206b73d0SCy Schubert 		wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
428206b73d0SCy Schubert 		goto fail;
429206b73d0SCy Schubert 	}
430206b73d0SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
431206b73d0SCy Schubert 
432206b73d0SCy Schubert 	/* Derive CKN from MSK */
433206b73d0SCy Schubert 	ckn->len = DEFAULT_CKN_LEN;
434206b73d0SCy Schubert 	if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
435206b73d0SCy Schubert 				    sta->addr, sid, sid_len, ckn->name)) {
436206b73d0SCy Schubert 		wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
437206b73d0SCy Schubert 		goto fail;
438206b73d0SCy Schubert 	}
439206b73d0SCy Schubert 	wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
440206b73d0SCy Schubert 
441206b73d0SCy Schubert 	res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
442c1d255d3SCy Schubert 					true);
443206b73d0SCy Schubert 
444206b73d0SCy Schubert fail:
445206b73d0SCy Schubert 	bin_clear_free(msk, sizeof(*msk));
446206b73d0SCy Schubert 	os_free(ckn);
447206b73d0SCy Schubert 	bin_clear_free(cak, sizeof(*cak));
448206b73d0SCy Schubert 
449206b73d0SCy Schubert 	return res;
450206b73d0SCy Schubert }
451206b73d0SCy Schubert 
452206b73d0SCy Schubert 
ieee802_1x_create_preshared_mka_hapd(struct hostapd_data * hapd,struct sta_info * sta)453206b73d0SCy Schubert void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
454206b73d0SCy Schubert 					    struct sta_info *sta)
455206b73d0SCy Schubert {
456206b73d0SCy Schubert 	struct mka_key *cak;
457206b73d0SCy Schubert 	struct mka_key_name *ckn;
458206b73d0SCy Schubert 	void *res = NULL;
459206b73d0SCy Schubert 
460206b73d0SCy Schubert 	if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
461206b73d0SCy Schubert 		goto end;
462206b73d0SCy Schubert 
463206b73d0SCy Schubert 	ckn = os_zalloc(sizeof(*ckn));
464206b73d0SCy Schubert 	if (!ckn)
465206b73d0SCy Schubert 		goto end;
466206b73d0SCy Schubert 
467206b73d0SCy Schubert 	cak = os_zalloc(sizeof(*cak));
468206b73d0SCy Schubert 	if (!cak)
469206b73d0SCy Schubert 		goto free_ckn;
470206b73d0SCy Schubert 
471206b73d0SCy Schubert 	if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
472206b73d0SCy Schubert 		goto free_cak;
473206b73d0SCy Schubert 
474206b73d0SCy Schubert 	if (hapd->kay->policy == DO_NOT_SECURE)
475206b73d0SCy Schubert 		goto dealloc;
476206b73d0SCy Schubert 
477206b73d0SCy Schubert 	cak->len = hapd->conf->mka_cak_len;
478206b73d0SCy Schubert 	os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
479206b73d0SCy Schubert 
480206b73d0SCy Schubert 	ckn->len = hapd->conf->mka_ckn_len;;
481206b73d0SCy Schubert 	os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
482206b73d0SCy Schubert 
483c1d255d3SCy Schubert 	res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
484206b73d0SCy Schubert 	if (res)
485206b73d0SCy Schubert 		goto free_cak;
486206b73d0SCy Schubert 
487206b73d0SCy Schubert dealloc:
488206b73d0SCy Schubert 	/* Failed to create MKA */
489206b73d0SCy Schubert 	ieee802_1x_dealloc_kay_sm_hapd(hapd);
490206b73d0SCy Schubert free_cak:
491206b73d0SCy Schubert 	os_free(cak);
492206b73d0SCy Schubert free_ckn:
493206b73d0SCy Schubert 	os_free(ckn);
494206b73d0SCy Schubert end:
495206b73d0SCy Schubert 	return res;
496206b73d0SCy Schubert }
497