xref: /freebsd/contrib/wpa/src/pae/ieee802_1x_kay.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
1*5b9c547cSRui Paulo /*
2*5b9c547cSRui Paulo  * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
3*5b9c547cSRui Paulo  * Copyright (c) 2013, Qualcomm Atheros, Inc.
4*5b9c547cSRui Paulo  *
5*5b9c547cSRui Paulo  * This software may be distributed under the terms of the BSD license.
6*5b9c547cSRui Paulo  * See README for more details.
7*5b9c547cSRui Paulo  */
8*5b9c547cSRui Paulo 
9*5b9c547cSRui Paulo #include <time.h>
10*5b9c547cSRui Paulo #include "includes.h"
11*5b9c547cSRui Paulo #include "common.h"
12*5b9c547cSRui Paulo #include "list.h"
13*5b9c547cSRui Paulo #include "eloop.h"
14*5b9c547cSRui Paulo #include "wpabuf.h"
15*5b9c547cSRui Paulo #include "state_machine.h"
16*5b9c547cSRui Paulo #include "l2_packet/l2_packet.h"
17*5b9c547cSRui Paulo #include "common/eapol_common.h"
18*5b9c547cSRui Paulo #include "crypto/aes_wrap.h"
19*5b9c547cSRui Paulo #include "ieee802_1x_cp.h"
20*5b9c547cSRui Paulo #include "ieee802_1x_key.h"
21*5b9c547cSRui Paulo #include "ieee802_1x_kay.h"
22*5b9c547cSRui Paulo #include "ieee802_1x_kay_i.h"
23*5b9c547cSRui Paulo #include "ieee802_1x_secy_ops.h"
24*5b9c547cSRui Paulo 
25*5b9c547cSRui Paulo 
26*5b9c547cSRui Paulo #define DEFAULT_SA_KEY_LEN	16
27*5b9c547cSRui Paulo #define DEFAULT_ICV_LEN		16
28*5b9c547cSRui Paulo #define MAX_ICV_LEN		32  /* 32 bytes, 256 bits */
29*5b9c547cSRui Paulo 
30*5b9c547cSRui Paulo #define PENDING_PN_EXHAUSTION 0xC0000000
31*5b9c547cSRui Paulo 
32*5b9c547cSRui Paulo /* IEEE Std 802.1X-2010, Table 9-1 - MKA Algorithm Agility */
33*5b9c547cSRui Paulo #define MKA_ALGO_AGILITY_2009 { 0x00, 0x80, 0xC2, 0x01 }
34*5b9c547cSRui Paulo static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
35*5b9c547cSRui Paulo 
36*5b9c547cSRui Paulo /* IEEE802.1AE-2006 Table 14-1 MACsec Cipher Suites */
37*5b9c547cSRui Paulo static struct macsec_ciphersuite cipher_suite_tbl[] = {
38*5b9c547cSRui Paulo 	/* GCM-AES-128 */
39*5b9c547cSRui Paulo 	{
40*5b9c547cSRui Paulo 		CS_ID_GCM_AES_128,
41*5b9c547cSRui Paulo 		CS_NAME_GCM_AES_128,
42*5b9c547cSRui Paulo 		MACSEC_CAP_INTEG_AND_CONF_0_30_50,
43*5b9c547cSRui Paulo 		16,
44*5b9c547cSRui Paulo 
45*5b9c547cSRui Paulo 		0 /* index */
46*5b9c547cSRui Paulo 	},
47*5b9c547cSRui Paulo };
48*5b9c547cSRui Paulo #define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
49*5b9c547cSRui Paulo #define DEFAULT_CS_INDEX  0
50*5b9c547cSRui Paulo 
51*5b9c547cSRui Paulo static struct mka_alg mka_alg_tbl[] = {
52*5b9c547cSRui Paulo 	{
53*5b9c547cSRui Paulo 		MKA_ALGO_AGILITY_2009,
54*5b9c547cSRui Paulo 		/* 128-bit CAK, KEK, ICK, ICV */
55*5b9c547cSRui Paulo 		16, 16,	16, 16,
56*5b9c547cSRui Paulo 		ieee802_1x_cak_128bits_aes_cmac,
57*5b9c547cSRui Paulo 		ieee802_1x_ckn_128bits_aes_cmac,
58*5b9c547cSRui Paulo 		ieee802_1x_kek_128bits_aes_cmac,
59*5b9c547cSRui Paulo 		ieee802_1x_ick_128bits_aes_cmac,
60*5b9c547cSRui Paulo 		ieee802_1x_icv_128bits_aes_cmac,
61*5b9c547cSRui Paulo 
62*5b9c547cSRui Paulo 		1, /* index */
63*5b9c547cSRui Paulo 	},
64*5b9c547cSRui Paulo };
65*5b9c547cSRui Paulo #define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
66*5b9c547cSRui Paulo 
67*5b9c547cSRui Paulo 
68*5b9c547cSRui Paulo static int is_ki_equal(struct ieee802_1x_mka_ki *ki1,
69*5b9c547cSRui Paulo 		       struct ieee802_1x_mka_ki *ki2)
70*5b9c547cSRui Paulo {
71*5b9c547cSRui Paulo 	return os_memcmp(ki1->mi, ki2->mi, MI_LEN) == 0 &&
72*5b9c547cSRui Paulo 		ki1->kn == ki2->kn;
73*5b9c547cSRui Paulo }
74*5b9c547cSRui Paulo 
75*5b9c547cSRui Paulo 
76*5b9c547cSRui Paulo struct mka_param_body_handler {
77*5b9c547cSRui Paulo 	int (*body_tx)(struct ieee802_1x_mka_participant *participant,
78*5b9c547cSRui Paulo 		       struct wpabuf *buf);
79*5b9c547cSRui Paulo 	int (*body_rx)(struct ieee802_1x_mka_participant *participant,
80*5b9c547cSRui Paulo 		       const u8 *mka_msg, size_t msg_len);
81*5b9c547cSRui Paulo 	int (*body_length)(struct ieee802_1x_mka_participant *participant);
82*5b9c547cSRui Paulo 	Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
83*5b9c547cSRui Paulo };
84*5b9c547cSRui Paulo 
85*5b9c547cSRui Paulo 
86*5b9c547cSRui Paulo static void set_mka_param_body_len(void *body, unsigned int len)
87*5b9c547cSRui Paulo {
88*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr = body;
89*5b9c547cSRui Paulo 	hdr->length = (len >> 8) & 0x0f;
90*5b9c547cSRui Paulo 	hdr->length1 = len & 0xff;
91*5b9c547cSRui Paulo }
92*5b9c547cSRui Paulo 
93*5b9c547cSRui Paulo 
94*5b9c547cSRui Paulo static unsigned int get_mka_param_body_len(const void *body)
95*5b9c547cSRui Paulo {
96*5b9c547cSRui Paulo 	const struct ieee802_1x_mka_hdr *hdr = body;
97*5b9c547cSRui Paulo 	return (hdr->length << 8) | hdr->length1;
98*5b9c547cSRui Paulo }
99*5b9c547cSRui Paulo 
100*5b9c547cSRui Paulo 
101*5b9c547cSRui Paulo static int get_mka_param_body_type(const void *body)
102*5b9c547cSRui Paulo {
103*5b9c547cSRui Paulo 	const struct ieee802_1x_mka_hdr *hdr = body;
104*5b9c547cSRui Paulo 	return hdr->type;
105*5b9c547cSRui Paulo }
106*5b9c547cSRui Paulo 
107*5b9c547cSRui Paulo 
108*5b9c547cSRui Paulo /**
109*5b9c547cSRui Paulo  * ieee802_1x_mka_dump_basic_body -
110*5b9c547cSRui Paulo  */
111*5b9c547cSRui Paulo static void
112*5b9c547cSRui Paulo ieee802_1x_mka_dump_basic_body(struct ieee802_1x_mka_basic_body *body)
113*5b9c547cSRui Paulo {
114*5b9c547cSRui Paulo 	size_t body_len;
115*5b9c547cSRui Paulo 
116*5b9c547cSRui Paulo 	if (!body)
117*5b9c547cSRui Paulo 		return;
118*5b9c547cSRui Paulo 
119*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(body);
120*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "*** MKA Basic Parameter set ***");
121*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tVersion.......: %d", body->version);
122*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPriority......: %d", body->priority);
123*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tKeySvr........: %d", body->key_server);
124*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMACSecDesired.: %d", body->macsec_desired);
125*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capbility);
126*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
127*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tSCI MAC.......: " MACSTR,
128*5b9c547cSRui Paulo 		   MAC2STR(body->actor_sci.addr));
129*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tSCI Port .....: %d",
130*5b9c547cSRui Paulo 		   be_to_host16(body->actor_sci.port));
131*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tMember Id.....:",
132*5b9c547cSRui Paulo 		    body->actor_mi, sizeof(body->actor_mi));
133*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMessage Number: %d",
134*5b9c547cSRui Paulo 		   be_to_host32(body->actor_mn));
135*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tAlgo Agility..:",
136*5b9c547cSRui Paulo 		    body->algo_agility, sizeof(body->algo_agility));
137*5b9c547cSRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "\tCAK Name......:", body->ckn,
138*5b9c547cSRui Paulo 			  body_len + MKA_HDR_LEN - sizeof(*body));
139*5b9c547cSRui Paulo }
140*5b9c547cSRui Paulo 
141*5b9c547cSRui Paulo 
142*5b9c547cSRui Paulo /**
143*5b9c547cSRui Paulo  * ieee802_1x_mka_dump_peer_body -
144*5b9c547cSRui Paulo  */
145*5b9c547cSRui Paulo static void
146*5b9c547cSRui Paulo ieee802_1x_mka_dump_peer_body(struct ieee802_1x_mka_peer_body *body)
147*5b9c547cSRui Paulo {
148*5b9c547cSRui Paulo 	size_t body_len;
149*5b9c547cSRui Paulo 	size_t i;
150*5b9c547cSRui Paulo 	u8 *mi;
151*5b9c547cSRui Paulo 	u32 mn;
152*5b9c547cSRui Paulo 
153*5b9c547cSRui Paulo 	if (body == NULL)
154*5b9c547cSRui Paulo 		return;
155*5b9c547cSRui Paulo 
156*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(body);
157*5b9c547cSRui Paulo 	if (body->type == MKA_LIVE_PEER_LIST) {
158*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "*** Live Peer List ***");
159*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
160*5b9c547cSRui Paulo 	} else if (body->type == MKA_POTENTIAL_PEER_LIST) {
161*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "*** Potential Live Peer List ***");
162*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
163*5b9c547cSRui Paulo 	}
164*5b9c547cSRui Paulo 
165*5b9c547cSRui Paulo 	for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
166*5b9c547cSRui Paulo 		mi = body->peer + i;
167*5b9c547cSRui Paulo 		os_memcpy(&mn, mi + MI_LEN, sizeof(mn));
168*5b9c547cSRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG, "\tMember Id.....:", mi, MI_LEN);
169*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "\tMessage Number: %d", be_to_host32(mn));
170*5b9c547cSRui Paulo 	}
171*5b9c547cSRui Paulo }
172*5b9c547cSRui Paulo 
173*5b9c547cSRui Paulo 
174*5b9c547cSRui Paulo /**
175*5b9c547cSRui Paulo  * ieee802_1x_mka_dump_dist_sak_body -
176*5b9c547cSRui Paulo  */
177*5b9c547cSRui Paulo static void
178*5b9c547cSRui Paulo ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body)
179*5b9c547cSRui Paulo {
180*5b9c547cSRui Paulo 	size_t body_len;
181*5b9c547cSRui Paulo 
182*5b9c547cSRui Paulo 	if (body == NULL)
183*5b9c547cSRui Paulo 		return;
184*5b9c547cSRui Paulo 
185*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(body);
186*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "*** Distributed SAK ***");
187*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
188*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
189*5b9c547cSRui Paulo 		   body->confid_offset);
190*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "\tBody Length...........: %d", (int) body_len);
191*5b9c547cSRui Paulo 	if (!body_len)
192*5b9c547cSRui Paulo 		return;
193*5b9c547cSRui Paulo 
194*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "\tKey Number............: %d",
195*5b9c547cSRui Paulo 		   be_to_host32(body->kn));
196*5b9c547cSRui Paulo 	wpa_hexdump(MSG_INFO, "\tAES Key Wrap of SAK...:", body->sak, 24);
197*5b9c547cSRui Paulo }
198*5b9c547cSRui Paulo 
199*5b9c547cSRui Paulo 
200*5b9c547cSRui Paulo static const char * yes_no(int val)
201*5b9c547cSRui Paulo {
202*5b9c547cSRui Paulo 	return val ? "Yes" : "No";
203*5b9c547cSRui Paulo }
204*5b9c547cSRui Paulo 
205*5b9c547cSRui Paulo 
206*5b9c547cSRui Paulo /**
207*5b9c547cSRui Paulo  * ieee802_1x_mka_dump_sak_use_body -
208*5b9c547cSRui Paulo  */
209*5b9c547cSRui Paulo static void
210*5b9c547cSRui Paulo ieee802_1x_mka_dump_sak_use_body(struct ieee802_1x_mka_sak_use_body *body)
211*5b9c547cSRui Paulo {
212*5b9c547cSRui Paulo 	int body_len;
213*5b9c547cSRui Paulo 
214*5b9c547cSRui Paulo 	if (body == NULL)
215*5b9c547cSRui Paulo 		return;
216*5b9c547cSRui Paulo 
217*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(body);
218*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "*** MACsec SAK Use ***");
219*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tLatest Key AN....: %d", body->lan);
220*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tLatest Key Tx....: %s", yes_no(body->ltx));
221*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tLatest Key Rx....: %s", yes_no(body->lrx));
222*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tOld Key AN....: %d", body->oan);
223*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tOld Key Tx....: %s", yes_no(body->otx));
224*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tOld Key Rx....: %s", yes_no(body->orx));
225*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPlain Key Tx....: %s", yes_no(body->ptx));
226*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPlain Key Rx....: %s", yes_no(body->prx));
227*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tDelay Protect....: %s",
228*5b9c547cSRui Paulo 		   yes_no(body->delay_protect));
229*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tBody Length......: %d", body_len);
230*5b9c547cSRui Paulo 	if (!body_len)
231*5b9c547cSRui Paulo 		return;
232*5b9c547cSRui Paulo 
233*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tKey Server MI....:",
234*5b9c547cSRui Paulo 		    body->lsrv_mi, sizeof(body->lsrv_mi));
235*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tKey Number.......: %u",
236*5b9c547cSRui Paulo 		   be_to_host32(body->lkn));
237*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tLowest PN........: %u",
238*5b9c547cSRui Paulo 		   be_to_host32(body->llpn));
239*5b9c547cSRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "\tOld Key Server MI....:",
240*5b9c547cSRui Paulo 			  body->osrv_mi, sizeof(body->osrv_mi));
241*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tOld Key Number.......: %u",
242*5b9c547cSRui Paulo 		   be_to_host32(body->okn));
243*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tOld Lowest PN........: %u",
244*5b9c547cSRui Paulo 		   be_to_host32(body->olpn));
245*5b9c547cSRui Paulo }
246*5b9c547cSRui Paulo 
247*5b9c547cSRui Paulo 
248*5b9c547cSRui Paulo /**
249*5b9c547cSRui Paulo  * ieee802_1x_kay_get_participant -
250*5b9c547cSRui Paulo  */
251*5b9c547cSRui Paulo static struct ieee802_1x_mka_participant *
252*5b9c547cSRui Paulo ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn)
253*5b9c547cSRui Paulo {
254*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
255*5b9c547cSRui Paulo 
256*5b9c547cSRui Paulo 	dl_list_for_each(participant, &kay->participant_list,
257*5b9c547cSRui Paulo 			 struct ieee802_1x_mka_participant, list) {
258*5b9c547cSRui Paulo 		if (os_memcmp(participant->ckn.name, ckn,
259*5b9c547cSRui Paulo 			      participant->ckn.len) == 0)
260*5b9c547cSRui Paulo 			return participant;
261*5b9c547cSRui Paulo 	}
262*5b9c547cSRui Paulo 
263*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: participant is not found");
264*5b9c547cSRui Paulo 
265*5b9c547cSRui Paulo 	return NULL;
266*5b9c547cSRui Paulo }
267*5b9c547cSRui Paulo 
268*5b9c547cSRui Paulo 
269*5b9c547cSRui Paulo /**
270*5b9c547cSRui Paulo  * ieee802_1x_kay_get_principal_participant -
271*5b9c547cSRui Paulo  */
272*5b9c547cSRui Paulo static struct ieee802_1x_mka_participant *
273*5b9c547cSRui Paulo ieee802_1x_kay_get_principal_participant(struct ieee802_1x_kay *kay)
274*5b9c547cSRui Paulo {
275*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
276*5b9c547cSRui Paulo 
277*5b9c547cSRui Paulo 	dl_list_for_each(participant, &kay->participant_list,
278*5b9c547cSRui Paulo 			 struct ieee802_1x_mka_participant, list) {
279*5b9c547cSRui Paulo 		if (participant->principal)
280*5b9c547cSRui Paulo 			return participant;
281*5b9c547cSRui Paulo 	}
282*5b9c547cSRui Paulo 
283*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: principal participant is not founded");
284*5b9c547cSRui Paulo 	return NULL;
285*5b9c547cSRui Paulo }
286*5b9c547cSRui Paulo 
287*5b9c547cSRui Paulo 
288*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer * get_peer_mi(struct dl_list *peers,
289*5b9c547cSRui Paulo 						const u8 *mi)
290*5b9c547cSRui Paulo {
291*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
292*5b9c547cSRui Paulo 
293*5b9c547cSRui Paulo 	dl_list_for_each(peer, peers, struct ieee802_1x_kay_peer, list) {
294*5b9c547cSRui Paulo 		if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
295*5b9c547cSRui Paulo 			return peer;
296*5b9c547cSRui Paulo 	}
297*5b9c547cSRui Paulo 
298*5b9c547cSRui Paulo 	return NULL;
299*5b9c547cSRui Paulo }
300*5b9c547cSRui Paulo 
301*5b9c547cSRui Paulo 
302*5b9c547cSRui Paulo /**
303*5b9c547cSRui Paulo  * ieee802_1x_kay_is_in_potential_peer
304*5b9c547cSRui Paulo  */
305*5b9c547cSRui Paulo static Boolean
306*5b9c547cSRui Paulo ieee802_1x_kay_is_in_potential_peer(
307*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant, const u8 *mi)
308*5b9c547cSRui Paulo {
309*5b9c547cSRui Paulo 	return get_peer_mi(&participant->potential_peers, mi) != NULL;
310*5b9c547cSRui Paulo }
311*5b9c547cSRui Paulo 
312*5b9c547cSRui Paulo 
313*5b9c547cSRui Paulo /**
314*5b9c547cSRui Paulo  * ieee802_1x_kay_is_in_live_peer
315*5b9c547cSRui Paulo  */
316*5b9c547cSRui Paulo static Boolean
317*5b9c547cSRui Paulo ieee802_1x_kay_is_in_live_peer(
318*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant, const u8 *mi)
319*5b9c547cSRui Paulo {
320*5b9c547cSRui Paulo 	return get_peer_mi(&participant->live_peers, mi) != NULL;
321*5b9c547cSRui Paulo }
322*5b9c547cSRui Paulo 
323*5b9c547cSRui Paulo 
324*5b9c547cSRui Paulo /**
325*5b9c547cSRui Paulo  * ieee802_1x_kay_is_in_peer
326*5b9c547cSRui Paulo  */
327*5b9c547cSRui Paulo static Boolean
328*5b9c547cSRui Paulo ieee802_1x_kay_is_in_peer(struct ieee802_1x_mka_participant *participant,
329*5b9c547cSRui Paulo 			  const u8 *mi)
330*5b9c547cSRui Paulo {
331*5b9c547cSRui Paulo 	return ieee802_1x_kay_is_in_live_peer(participant, mi) ||
332*5b9c547cSRui Paulo 		ieee802_1x_kay_is_in_potential_peer(participant, mi);
333*5b9c547cSRui Paulo }
334*5b9c547cSRui Paulo 
335*5b9c547cSRui Paulo 
336*5b9c547cSRui Paulo /**
337*5b9c547cSRui Paulo  * ieee802_1x_kay_get_peer
338*5b9c547cSRui Paulo  */
339*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
340*5b9c547cSRui Paulo ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
341*5b9c547cSRui Paulo 			const u8 *mi)
342*5b9c547cSRui Paulo {
343*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
344*5b9c547cSRui Paulo 
345*5b9c547cSRui Paulo 	peer = get_peer_mi(&participant->live_peers, mi);
346*5b9c547cSRui Paulo 	if (peer)
347*5b9c547cSRui Paulo 		return peer;
348*5b9c547cSRui Paulo 
349*5b9c547cSRui Paulo 	return get_peer_mi(&participant->potential_peers, mi);
350*5b9c547cSRui Paulo }
351*5b9c547cSRui Paulo 
352*5b9c547cSRui Paulo 
353*5b9c547cSRui Paulo /**
354*5b9c547cSRui Paulo  * ieee802_1x_kay_get_live_peer
355*5b9c547cSRui Paulo  */
356*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
357*5b9c547cSRui Paulo ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
358*5b9c547cSRui Paulo 			     const u8 *mi)
359*5b9c547cSRui Paulo {
360*5b9c547cSRui Paulo 	return get_peer_mi(&participant->live_peers, mi);
361*5b9c547cSRui Paulo }
362*5b9c547cSRui Paulo 
363*5b9c547cSRui Paulo 
364*5b9c547cSRui Paulo /**
365*5b9c547cSRui Paulo  * ieee802_1x_kay_get_cipher_suite
366*5b9c547cSRui Paulo  */
367*5b9c547cSRui Paulo static struct macsec_ciphersuite *
368*5b9c547cSRui Paulo ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
369*5b9c547cSRui Paulo 				u8 *cs_id)
370*5b9c547cSRui Paulo {
371*5b9c547cSRui Paulo 	unsigned int i;
372*5b9c547cSRui Paulo 
373*5b9c547cSRui Paulo 	for (i = 0; i < CS_TABLE_SIZE; i++) {
374*5b9c547cSRui Paulo 		if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
375*5b9c547cSRui Paulo 			break;
376*5b9c547cSRui Paulo 	}
377*5b9c547cSRui Paulo 	if (i >= CS_TABLE_SIZE)
378*5b9c547cSRui Paulo 		return NULL;
379*5b9c547cSRui Paulo 
380*5b9c547cSRui Paulo 	return &cipher_suite_tbl[i];
381*5b9c547cSRui Paulo }
382*5b9c547cSRui Paulo 
383*5b9c547cSRui Paulo 
384*5b9c547cSRui Paulo /**
385*5b9c547cSRui Paulo  * ieee802_1x_kay_get_peer_sci
386*5b9c547cSRui Paulo  */
387*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
388*5b9c547cSRui Paulo ieee802_1x_kay_get_peer_sci(struct ieee802_1x_mka_participant *participant,
389*5b9c547cSRui Paulo 			    const struct ieee802_1x_mka_sci *sci)
390*5b9c547cSRui Paulo {
391*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
392*5b9c547cSRui Paulo 
393*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
394*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
395*5b9c547cSRui Paulo 		if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
396*5b9c547cSRui Paulo 			return peer;
397*5b9c547cSRui Paulo 	}
398*5b9c547cSRui Paulo 
399*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->potential_peers,
400*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
401*5b9c547cSRui Paulo 		if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
402*5b9c547cSRui Paulo 			return peer;
403*5b9c547cSRui Paulo 	}
404*5b9c547cSRui Paulo 
405*5b9c547cSRui Paulo 	return NULL;
406*5b9c547cSRui Paulo }
407*5b9c547cSRui Paulo 
408*5b9c547cSRui Paulo 
409*5b9c547cSRui Paulo /**
410*5b9c547cSRui Paulo  * ieee802_1x_kay_init_receive_sa -
411*5b9c547cSRui Paulo  */
412*5b9c547cSRui Paulo static struct receive_sa *
413*5b9c547cSRui Paulo ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
414*5b9c547cSRui Paulo 			       struct data_key *key)
415*5b9c547cSRui Paulo {
416*5b9c547cSRui Paulo 	struct receive_sa *psa;
417*5b9c547cSRui Paulo 
418*5b9c547cSRui Paulo 	if (!psc || !key)
419*5b9c547cSRui Paulo 		return NULL;
420*5b9c547cSRui Paulo 
421*5b9c547cSRui Paulo 	psa = os_zalloc(sizeof(*psa));
422*5b9c547cSRui Paulo 	if (!psa) {
423*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
424*5b9c547cSRui Paulo 		return NULL;
425*5b9c547cSRui Paulo 	}
426*5b9c547cSRui Paulo 
427*5b9c547cSRui Paulo 	psa->pkey = key;
428*5b9c547cSRui Paulo 	psa->lowest_pn = lowest_pn;
429*5b9c547cSRui Paulo 	psa->next_pn = lowest_pn;
430*5b9c547cSRui Paulo 	psa->an = an;
431*5b9c547cSRui Paulo 	psa->sc = psc;
432*5b9c547cSRui Paulo 
433*5b9c547cSRui Paulo 	os_get_time(&psa->created_time);
434*5b9c547cSRui Paulo 	psa->in_use = FALSE;
435*5b9c547cSRui Paulo 
436*5b9c547cSRui Paulo 	dl_list_add(&psc->sa_list, &psa->list);
437*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
438*5b9c547cSRui Paulo 		   "KaY: Create receive SA(AN: %d lowest_pn: %u of SC(channel: %d)",
439*5b9c547cSRui Paulo 		   (int) an, lowest_pn, psc->channel);
440*5b9c547cSRui Paulo 
441*5b9c547cSRui Paulo 	return psa;
442*5b9c547cSRui Paulo }
443*5b9c547cSRui Paulo 
444*5b9c547cSRui Paulo 
445*5b9c547cSRui Paulo /**
446*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit_receive_sa -
447*5b9c547cSRui Paulo  */
448*5b9c547cSRui Paulo static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
449*5b9c547cSRui Paulo {
450*5b9c547cSRui Paulo 	psa->pkey = NULL;
451*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
452*5b9c547cSRui Paulo 		   "KaY: Delete receive SA(an: %d) of SC(channel: %d)",
453*5b9c547cSRui Paulo 		   psa->an, psa->sc->channel);
454*5b9c547cSRui Paulo 	dl_list_del(&psa->list);
455*5b9c547cSRui Paulo 	os_free(psa);
456*5b9c547cSRui Paulo }
457*5b9c547cSRui Paulo 
458*5b9c547cSRui Paulo 
459*5b9c547cSRui Paulo /**
460*5b9c547cSRui Paulo  * ieee802_1x_kay_init_receive_sc -
461*5b9c547cSRui Paulo  */
462*5b9c547cSRui Paulo static struct receive_sc *
463*5b9c547cSRui Paulo ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci,
464*5b9c547cSRui Paulo 			       int channel)
465*5b9c547cSRui Paulo {
466*5b9c547cSRui Paulo 	struct receive_sc *psc;
467*5b9c547cSRui Paulo 
468*5b9c547cSRui Paulo 	if (!psci)
469*5b9c547cSRui Paulo 		return NULL;
470*5b9c547cSRui Paulo 
471*5b9c547cSRui Paulo 	psc = os_zalloc(sizeof(*psc));
472*5b9c547cSRui Paulo 	if (!psc) {
473*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
474*5b9c547cSRui Paulo 		return NULL;
475*5b9c547cSRui Paulo 	}
476*5b9c547cSRui Paulo 
477*5b9c547cSRui Paulo 	os_memcpy(&psc->sci, psci, sizeof(psc->sci));
478*5b9c547cSRui Paulo 	psc->channel = channel;
479*5b9c547cSRui Paulo 
480*5b9c547cSRui Paulo 	os_get_time(&psc->created_time);
481*5b9c547cSRui Paulo 	psc->receiving = FALSE;
482*5b9c547cSRui Paulo 
483*5b9c547cSRui Paulo 	dl_list_init(&psc->sa_list);
484*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Create receive SC(channel: %d)", channel);
485*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)psci, sizeof(*psci));
486*5b9c547cSRui Paulo 
487*5b9c547cSRui Paulo 	return psc;
488*5b9c547cSRui Paulo }
489*5b9c547cSRui Paulo 
490*5b9c547cSRui Paulo 
491*5b9c547cSRui Paulo /**
492*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit_receive_sc -
493*5b9c547cSRui Paulo  **/
494*5b9c547cSRui Paulo static void
495*5b9c547cSRui Paulo ieee802_1x_kay_deinit_receive_sc(
496*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant, struct receive_sc *psc)
497*5b9c547cSRui Paulo {
498*5b9c547cSRui Paulo 	struct receive_sa *psa, *pre_sa;
499*5b9c547cSRui Paulo 
500*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Delete receive SC(channel: %d)",
501*5b9c547cSRui Paulo 		   psc->channel);
502*5b9c547cSRui Paulo 	dl_list_for_each_safe(psa, pre_sa, &psc->sa_list, struct receive_sa,
503*5b9c547cSRui Paulo 			      list)  {
504*5b9c547cSRui Paulo 		secy_disable_receive_sa(participant->kay, psa);
505*5b9c547cSRui Paulo 		ieee802_1x_kay_deinit_receive_sa(psa);
506*5b9c547cSRui Paulo 	}
507*5b9c547cSRui Paulo 	dl_list_del(&psc->list);
508*5b9c547cSRui Paulo 	os_free(psc);
509*5b9c547cSRui Paulo }
510*5b9c547cSRui Paulo 
511*5b9c547cSRui Paulo 
512*5b9c547cSRui Paulo /**
513*5b9c547cSRui Paulo  * ieee802_1x_kay_create_live_peer
514*5b9c547cSRui Paulo  */
515*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
516*5b9c547cSRui Paulo ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
517*5b9c547cSRui Paulo 				u8 *mi, u32 mn)
518*5b9c547cSRui Paulo {
519*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
520*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
521*5b9c547cSRui Paulo 	u32 sc_ch = 0;
522*5b9c547cSRui Paulo 
523*5b9c547cSRui Paulo 	peer = os_zalloc(sizeof(*peer));
524*5b9c547cSRui Paulo 	if (peer == NULL) {
525*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
526*5b9c547cSRui Paulo 		return NULL;
527*5b9c547cSRui Paulo 	}
528*5b9c547cSRui Paulo 
529*5b9c547cSRui Paulo 	os_memcpy(peer->mi, mi, MI_LEN);
530*5b9c547cSRui Paulo 	peer->mn = mn;
531*5b9c547cSRui Paulo 	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
532*5b9c547cSRui Paulo 	peer->sak_used = FALSE;
533*5b9c547cSRui Paulo 	os_memcpy(&peer->sci, &participant->current_peer_sci,
534*5b9c547cSRui Paulo 		  sizeof(peer->sci));
535*5b9c547cSRui Paulo 	dl_list_add(&participant->live_peers, &peer->list);
536*5b9c547cSRui Paulo 
537*5b9c547cSRui Paulo 	secy_get_available_receive_sc(participant->kay, &sc_ch);
538*5b9c547cSRui Paulo 
539*5b9c547cSRui Paulo 	rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
540*5b9c547cSRui Paulo 	if (!rxsc)
541*5b9c547cSRui Paulo 		return NULL;
542*5b9c547cSRui Paulo 
543*5b9c547cSRui Paulo 	dl_list_add(&participant->rxsc_list, &rxsc->list);
544*5b9c547cSRui Paulo 	secy_create_receive_sc(participant->kay, rxsc);
545*5b9c547cSRui Paulo 
546*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Live peer created");
547*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
548*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
549*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
550*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
551*5b9c547cSRui Paulo 
552*5b9c547cSRui Paulo 	return peer;
553*5b9c547cSRui Paulo }
554*5b9c547cSRui Paulo 
555*5b9c547cSRui Paulo 
556*5b9c547cSRui Paulo /**
557*5b9c547cSRui Paulo  * ieee802_1x_kay_create_potential_peer
558*5b9c547cSRui Paulo  */
559*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
560*5b9c547cSRui Paulo ieee802_1x_kay_create_potential_peer(
561*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant, const u8 *mi, u32 mn)
562*5b9c547cSRui Paulo {
563*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
564*5b9c547cSRui Paulo 
565*5b9c547cSRui Paulo 	peer = os_zalloc(sizeof(*peer));
566*5b9c547cSRui Paulo 	if (peer == NULL) {
567*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
568*5b9c547cSRui Paulo 		return NULL;
569*5b9c547cSRui Paulo 	}
570*5b9c547cSRui Paulo 
571*5b9c547cSRui Paulo 	os_memcpy(peer->mi, mi, MI_LEN);
572*5b9c547cSRui Paulo 	peer->mn = mn;
573*5b9c547cSRui Paulo 	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
574*5b9c547cSRui Paulo 	peer->sak_used = FALSE;
575*5b9c547cSRui Paulo 
576*5b9c547cSRui Paulo 	dl_list_add(&participant->potential_peers, &peer->list);
577*5b9c547cSRui Paulo 
578*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: potential peer created");
579*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
580*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
581*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
582*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
583*5b9c547cSRui Paulo 
584*5b9c547cSRui Paulo 	return peer;
585*5b9c547cSRui Paulo }
586*5b9c547cSRui Paulo 
587*5b9c547cSRui Paulo 
588*5b9c547cSRui Paulo /**
589*5b9c547cSRui Paulo  * ieee802_1x_kay_move_live_peer
590*5b9c547cSRui Paulo  */
591*5b9c547cSRui Paulo static struct ieee802_1x_kay_peer *
592*5b9c547cSRui Paulo ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
593*5b9c547cSRui Paulo 			      u8 *mi, u32 mn)
594*5b9c547cSRui Paulo {
595*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
596*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
597*5b9c547cSRui Paulo 	u32 sc_ch = 0;
598*5b9c547cSRui Paulo 
599*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->potential_peers,
600*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
601*5b9c547cSRui Paulo 		if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
602*5b9c547cSRui Paulo 			break;
603*5b9c547cSRui Paulo 	}
604*5b9c547cSRui Paulo 
605*5b9c547cSRui Paulo 	os_memcpy(&peer->sci, &participant->current_peer_sci,
606*5b9c547cSRui Paulo 		  sizeof(peer->sci));
607*5b9c547cSRui Paulo 	peer->mn = mn;
608*5b9c547cSRui Paulo 	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
609*5b9c547cSRui Paulo 
610*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: move potential peer to live peer");
611*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
612*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
613*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
614*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
615*5b9c547cSRui Paulo 
616*5b9c547cSRui Paulo 	dl_list_del(&peer->list);
617*5b9c547cSRui Paulo 	dl_list_add_tail(&participant->live_peers, &peer->list);
618*5b9c547cSRui Paulo 
619*5b9c547cSRui Paulo 	secy_get_available_receive_sc(participant->kay, &sc_ch);
620*5b9c547cSRui Paulo 
621*5b9c547cSRui Paulo 	rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
622*5b9c547cSRui Paulo 	if (!rxsc)
623*5b9c547cSRui Paulo 		return NULL;
624*5b9c547cSRui Paulo 
625*5b9c547cSRui Paulo 	dl_list_add(&participant->rxsc_list, &rxsc->list);
626*5b9c547cSRui Paulo 	secy_create_receive_sc(participant->kay, rxsc);
627*5b9c547cSRui Paulo 
628*5b9c547cSRui Paulo 	return peer;
629*5b9c547cSRui Paulo }
630*5b9c547cSRui Paulo 
631*5b9c547cSRui Paulo 
632*5b9c547cSRui Paulo 
633*5b9c547cSRui Paulo /**
634*5b9c547cSRui Paulo  *  ieee802_1x_mka_basic_body_present -
635*5b9c547cSRui Paulo  */
636*5b9c547cSRui Paulo static Boolean
637*5b9c547cSRui Paulo ieee802_1x_mka_basic_body_present(
638*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
639*5b9c547cSRui Paulo {
640*5b9c547cSRui Paulo 	return TRUE;
641*5b9c547cSRui Paulo }
642*5b9c547cSRui Paulo 
643*5b9c547cSRui Paulo 
644*5b9c547cSRui Paulo /**
645*5b9c547cSRui Paulo  * ieee802_1x_mka_basic_body_length -
646*5b9c547cSRui Paulo  */
647*5b9c547cSRui Paulo static int
648*5b9c547cSRui Paulo ieee802_1x_mka_basic_body_length(struct ieee802_1x_mka_participant *participant)
649*5b9c547cSRui Paulo {
650*5b9c547cSRui Paulo 	int length;
651*5b9c547cSRui Paulo 
652*5b9c547cSRui Paulo 	length = sizeof(struct ieee802_1x_mka_basic_body);
653*5b9c547cSRui Paulo 	length += participant->ckn.len;
654*5b9c547cSRui Paulo 	return (length + 0x3) & ~0x3;
655*5b9c547cSRui Paulo }
656*5b9c547cSRui Paulo 
657*5b9c547cSRui Paulo 
658*5b9c547cSRui Paulo /**
659*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_basic_body
660*5b9c547cSRui Paulo  */
661*5b9c547cSRui Paulo static int
662*5b9c547cSRui Paulo ieee802_1x_mka_encode_basic_body(
663*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
664*5b9c547cSRui Paulo 	struct wpabuf *buf)
665*5b9c547cSRui Paulo {
666*5b9c547cSRui Paulo 	struct ieee802_1x_mka_basic_body *body;
667*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = participant->kay;
668*5b9c547cSRui Paulo 	unsigned int length = ieee802_1x_mka_basic_body_length(participant);
669*5b9c547cSRui Paulo 
670*5b9c547cSRui Paulo 	body = wpabuf_put(buf, length);
671*5b9c547cSRui Paulo 
672*5b9c547cSRui Paulo 	body->version = kay->mka_version;
673*5b9c547cSRui Paulo 	body->priority = kay->actor_priority;
674*5b9c547cSRui Paulo 	if (participant->is_elected)
675*5b9c547cSRui Paulo 		body->key_server = participant->is_key_server;
676*5b9c547cSRui Paulo 	else
677*5b9c547cSRui Paulo 		body->key_server = participant->can_be_key_server;
678*5b9c547cSRui Paulo 
679*5b9c547cSRui Paulo 	body->macsec_desired = kay->macsec_desired;
680*5b9c547cSRui Paulo 	body->macsec_capbility = kay->macsec_capable;
681*5b9c547cSRui Paulo 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
682*5b9c547cSRui Paulo 
683*5b9c547cSRui Paulo 	os_memcpy(body->actor_sci.addr, kay->actor_sci.addr,
684*5b9c547cSRui Paulo 		  sizeof(kay->actor_sci.addr));
685*5b9c547cSRui Paulo 	body->actor_sci.port = host_to_be16(kay->actor_sci.port);
686*5b9c547cSRui Paulo 
687*5b9c547cSRui Paulo 	os_memcpy(body->actor_mi, participant->mi, sizeof(body->actor_mi));
688*5b9c547cSRui Paulo 	participant->mn = participant->mn + 1;
689*5b9c547cSRui Paulo 	body->actor_mn = host_to_be32(participant->mn);
690*5b9c547cSRui Paulo 	os_memcpy(body->algo_agility, participant->kay->algo_agility,
691*5b9c547cSRui Paulo 		  sizeof(body->algo_agility));
692*5b9c547cSRui Paulo 
693*5b9c547cSRui Paulo 	os_memcpy(body->ckn, participant->ckn.name, participant->ckn.len);
694*5b9c547cSRui Paulo 
695*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_basic_body(body);
696*5b9c547cSRui Paulo 
697*5b9c547cSRui Paulo 	return 0;
698*5b9c547cSRui Paulo }
699*5b9c547cSRui Paulo 
700*5b9c547cSRui Paulo 
701*5b9c547cSRui Paulo /**
702*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_basic_body -
703*5b9c547cSRui Paulo  */
704*5b9c547cSRui Paulo static struct ieee802_1x_mka_participant *
705*5b9c547cSRui Paulo ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
706*5b9c547cSRui Paulo 				 size_t msg_len)
707*5b9c547cSRui Paulo {
708*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
709*5b9c547cSRui Paulo 	const struct ieee802_1x_mka_basic_body *body;
710*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
711*5b9c547cSRui Paulo 
712*5b9c547cSRui Paulo 	body = (const struct ieee802_1x_mka_basic_body *) mka_msg;
713*5b9c547cSRui Paulo 
714*5b9c547cSRui Paulo 	if (body->version > MKA_VERSION_ID) {
715*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
716*5b9c547cSRui Paulo 			   "KaY: peer's version(%d) greater than mka current version(%d)",
717*5b9c547cSRui Paulo 			   body->version, MKA_VERSION_ID);
718*5b9c547cSRui Paulo 	}
719*5b9c547cSRui Paulo 	if (kay->is_obliged_key_server && body->key_server) {
720*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "I must be as key server");
721*5b9c547cSRui Paulo 		return NULL;
722*5b9c547cSRui Paulo 	}
723*5b9c547cSRui Paulo 
724*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_participant(kay, body->ckn);
725*5b9c547cSRui Paulo 	if (!participant) {
726*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
727*5b9c547cSRui Paulo 		return NULL;
728*5b9c547cSRui Paulo 	}
729*5b9c547cSRui Paulo 
730*5b9c547cSRui Paulo 	/* If the peer's MI is my MI, I will choose new MI */
731*5b9c547cSRui Paulo 	if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
732*5b9c547cSRui Paulo 		if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
733*5b9c547cSRui Paulo 			return NULL;
734*5b9c547cSRui Paulo 		participant->mn = 0;
735*5b9c547cSRui Paulo 	}
736*5b9c547cSRui Paulo 
737*5b9c547cSRui Paulo 	os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
738*5b9c547cSRui Paulo 	participant->current_peer_id.mn =  be_to_host32(body->actor_mn);
739*5b9c547cSRui Paulo 	os_memcpy(participant->current_peer_sci.addr, body->actor_sci.addr,
740*5b9c547cSRui Paulo 		  sizeof(participant->current_peer_sci.addr));
741*5b9c547cSRui Paulo 	participant->current_peer_sci.port = be_to_host16(body->actor_sci.port);
742*5b9c547cSRui Paulo 
743*5b9c547cSRui Paulo 	/* handler peer */
744*5b9c547cSRui Paulo 	peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
745*5b9c547cSRui Paulo 	if (!peer) {
746*5b9c547cSRui Paulo 		/* Check duplicated SCI */
747*5b9c547cSRui Paulo 		/* TODO: What policy should be applied to detect duplicated SCI
748*5b9c547cSRui Paulo 		 * is active attacker or a valid peer whose MI is be changed?
749*5b9c547cSRui Paulo 		 */
750*5b9c547cSRui Paulo 		peer = ieee802_1x_kay_get_peer_sci(participant,
751*5b9c547cSRui Paulo 						   &body->actor_sci);
752*5b9c547cSRui Paulo 		if (peer) {
753*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING,
754*5b9c547cSRui Paulo 				   "KaY: duplicated SCI detected, Maybe active attacker");
755*5b9c547cSRui Paulo 			dl_list_del(&peer->list);
756*5b9c547cSRui Paulo 			os_free(peer);
757*5b9c547cSRui Paulo 		}
758*5b9c547cSRui Paulo 
759*5b9c547cSRui Paulo 		peer = ieee802_1x_kay_create_potential_peer(
760*5b9c547cSRui Paulo 			participant, body->actor_mi,
761*5b9c547cSRui Paulo 			be_to_host32(body->actor_mn));
762*5b9c547cSRui Paulo 		if (!peer)
763*5b9c547cSRui Paulo 			return NULL;
764*5b9c547cSRui Paulo 
765*5b9c547cSRui Paulo 		peer->macsec_desired = body->macsec_desired;
766*5b9c547cSRui Paulo 		peer->macsec_capbility = body->macsec_capbility;
767*5b9c547cSRui Paulo 		peer->is_key_server = (Boolean) body->key_server;
768*5b9c547cSRui Paulo 		peer->key_server_priority = body->priority;
769*5b9c547cSRui Paulo 	} else if (peer->mn < be_to_host32(body->actor_mn)) {
770*5b9c547cSRui Paulo 		peer->mn = be_to_host32(body->actor_mn);
771*5b9c547cSRui Paulo 		peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
772*5b9c547cSRui Paulo 		peer->macsec_desired = body->macsec_desired;
773*5b9c547cSRui Paulo 		peer->macsec_capbility = body->macsec_capbility;
774*5b9c547cSRui Paulo 		peer->is_key_server = (Boolean) body->key_server;
775*5b9c547cSRui Paulo 		peer->key_server_priority = body->priority;
776*5b9c547cSRui Paulo 	} else {
777*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: The peer MN have received");
778*5b9c547cSRui Paulo 		return NULL;
779*5b9c547cSRui Paulo 	}
780*5b9c547cSRui Paulo 
781*5b9c547cSRui Paulo 	return participant;
782*5b9c547cSRui Paulo }
783*5b9c547cSRui Paulo 
784*5b9c547cSRui Paulo 
785*5b9c547cSRui Paulo /**
786*5b9c547cSRui Paulo  * ieee802_1x_mka_live_peer_body_present
787*5b9c547cSRui Paulo  */
788*5b9c547cSRui Paulo static Boolean
789*5b9c547cSRui Paulo ieee802_1x_mka_live_peer_body_present(
790*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
791*5b9c547cSRui Paulo {
792*5b9c547cSRui Paulo 	return !dl_list_empty(&participant->live_peers);
793*5b9c547cSRui Paulo }
794*5b9c547cSRui Paulo 
795*5b9c547cSRui Paulo 
796*5b9c547cSRui Paulo /**
797*5b9c547cSRui Paulo  * ieee802_1x_kay_get_live_peer_length
798*5b9c547cSRui Paulo  */
799*5b9c547cSRui Paulo static int
800*5b9c547cSRui Paulo ieee802_1x_mka_get_live_peer_length(
801*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
802*5b9c547cSRui Paulo {
803*5b9c547cSRui Paulo 	int len = MKA_HDR_LEN;
804*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
805*5b9c547cSRui Paulo 
806*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
807*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list)
808*5b9c547cSRui Paulo 		len += sizeof(struct ieee802_1x_mka_peer_id);
809*5b9c547cSRui Paulo 
810*5b9c547cSRui Paulo 	return (len + 0x3) & ~0x3;
811*5b9c547cSRui Paulo }
812*5b9c547cSRui Paulo 
813*5b9c547cSRui Paulo 
814*5b9c547cSRui Paulo /**
815*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_live_peer_body -
816*5b9c547cSRui Paulo  */
817*5b9c547cSRui Paulo static int
818*5b9c547cSRui Paulo ieee802_1x_mka_encode_live_peer_body(
819*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
820*5b9c547cSRui Paulo 	struct wpabuf *buf)
821*5b9c547cSRui Paulo {
822*5b9c547cSRui Paulo 	struct ieee802_1x_mka_peer_body *body;
823*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
824*5b9c547cSRui Paulo 	unsigned int length;
825*5b9c547cSRui Paulo 	struct ieee802_1x_mka_peer_id *body_peer;
826*5b9c547cSRui Paulo 
827*5b9c547cSRui Paulo 	length = ieee802_1x_mka_get_live_peer_length(participant);
828*5b9c547cSRui Paulo 	body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_peer_body));
829*5b9c547cSRui Paulo 
830*5b9c547cSRui Paulo 	body->type = MKA_LIVE_PEER_LIST;
831*5b9c547cSRui Paulo 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
832*5b9c547cSRui Paulo 
833*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
834*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
835*5b9c547cSRui Paulo 		body_peer = wpabuf_put(buf,
836*5b9c547cSRui Paulo 				       sizeof(struct ieee802_1x_mka_peer_id));
837*5b9c547cSRui Paulo 		os_memcpy(body_peer->mi, peer->mi, MI_LEN);
838*5b9c547cSRui Paulo 		body_peer->mn = host_to_be32(peer->mn);
839*5b9c547cSRui Paulo 		body_peer++;
840*5b9c547cSRui Paulo 	}
841*5b9c547cSRui Paulo 
842*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_peer_body(body);
843*5b9c547cSRui Paulo 	return 0;
844*5b9c547cSRui Paulo }
845*5b9c547cSRui Paulo 
846*5b9c547cSRui Paulo /**
847*5b9c547cSRui Paulo  * ieee802_1x_mka_potential_peer_body_present
848*5b9c547cSRui Paulo  */
849*5b9c547cSRui Paulo static Boolean
850*5b9c547cSRui Paulo ieee802_1x_mka_potential_peer_body_present(
851*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
852*5b9c547cSRui Paulo {
853*5b9c547cSRui Paulo 	return !dl_list_empty(&participant->potential_peers);
854*5b9c547cSRui Paulo }
855*5b9c547cSRui Paulo 
856*5b9c547cSRui Paulo 
857*5b9c547cSRui Paulo /**
858*5b9c547cSRui Paulo  * ieee802_1x_kay_get_potential_peer_length
859*5b9c547cSRui Paulo  */
860*5b9c547cSRui Paulo static int
861*5b9c547cSRui Paulo ieee802_1x_mka_get_potential_peer_length(
862*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
863*5b9c547cSRui Paulo {
864*5b9c547cSRui Paulo 	int len = MKA_HDR_LEN;
865*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
866*5b9c547cSRui Paulo 
867*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->potential_peers,
868*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list)
869*5b9c547cSRui Paulo 		len += sizeof(struct ieee802_1x_mka_peer_id);
870*5b9c547cSRui Paulo 
871*5b9c547cSRui Paulo 	return (len + 0x3) & ~0x3;
872*5b9c547cSRui Paulo }
873*5b9c547cSRui Paulo 
874*5b9c547cSRui Paulo 
875*5b9c547cSRui Paulo /**
876*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_potential_peer_body -
877*5b9c547cSRui Paulo  */
878*5b9c547cSRui Paulo static int
879*5b9c547cSRui Paulo ieee802_1x_mka_encode_potential_peer_body(
880*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
881*5b9c547cSRui Paulo 	struct wpabuf *buf)
882*5b9c547cSRui Paulo {
883*5b9c547cSRui Paulo 	struct ieee802_1x_mka_peer_body *body;
884*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
885*5b9c547cSRui Paulo 	unsigned int length;
886*5b9c547cSRui Paulo 	struct ieee802_1x_mka_peer_id *body_peer;
887*5b9c547cSRui Paulo 
888*5b9c547cSRui Paulo 	length = ieee802_1x_mka_get_potential_peer_length(participant);
889*5b9c547cSRui Paulo 	body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_peer_body));
890*5b9c547cSRui Paulo 
891*5b9c547cSRui Paulo 	body->type = MKA_POTENTIAL_PEER_LIST;
892*5b9c547cSRui Paulo 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
893*5b9c547cSRui Paulo 
894*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->potential_peers,
895*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
896*5b9c547cSRui Paulo 		body_peer = wpabuf_put(buf,
897*5b9c547cSRui Paulo 				       sizeof(struct ieee802_1x_mka_peer_id));
898*5b9c547cSRui Paulo 		os_memcpy(body_peer->mi, peer->mi, MI_LEN);
899*5b9c547cSRui Paulo 		body_peer->mn = host_to_be32(peer->mn);
900*5b9c547cSRui Paulo 		body_peer++;
901*5b9c547cSRui Paulo 	}
902*5b9c547cSRui Paulo 
903*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_peer_body(body);
904*5b9c547cSRui Paulo 	return 0;
905*5b9c547cSRui Paulo }
906*5b9c547cSRui Paulo 
907*5b9c547cSRui Paulo 
908*5b9c547cSRui Paulo /**
909*5b9c547cSRui Paulo  * ieee802_1x_mka_i_in_peerlist -
910*5b9c547cSRui Paulo  */
911*5b9c547cSRui Paulo static Boolean
912*5b9c547cSRui Paulo ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
913*5b9c547cSRui Paulo 			     const u8 *mka_msg, size_t msg_len)
914*5b9c547cSRui Paulo {
915*5b9c547cSRui Paulo 	Boolean included = FALSE;
916*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
917*5b9c547cSRui Paulo 	size_t body_len;
918*5b9c547cSRui Paulo 	size_t left_len;
919*5b9c547cSRui Paulo 	int body_type;
920*5b9c547cSRui Paulo 	u32 peer_mn;
921*5b9c547cSRui Paulo 	const u8 *peer_mi;
922*5b9c547cSRui Paulo 	const u8 *pos;
923*5b9c547cSRui Paulo 	size_t i;
924*5b9c547cSRui Paulo 
925*5b9c547cSRui Paulo 	pos = mka_msg;
926*5b9c547cSRui Paulo 	left_len = msg_len;
927*5b9c547cSRui Paulo 	while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
928*5b9c547cSRui Paulo 		hdr = (struct ieee802_1x_mka_hdr *) pos;
929*5b9c547cSRui Paulo 		body_len = get_mka_param_body_len(hdr);
930*5b9c547cSRui Paulo 		body_type = get_mka_param_body_type(hdr);
931*5b9c547cSRui Paulo 
932*5b9c547cSRui Paulo 		if (body_type != MKA_LIVE_PEER_LIST &&
933*5b9c547cSRui Paulo 		    body_type != MKA_POTENTIAL_PEER_LIST)
934*5b9c547cSRui Paulo 			goto SKIP_PEER;
935*5b9c547cSRui Paulo 
936*5b9c547cSRui Paulo 		ieee802_1x_mka_dump_peer_body(
937*5b9c547cSRui Paulo 			(struct ieee802_1x_mka_peer_body *)pos);
938*5b9c547cSRui Paulo 
939*5b9c547cSRui Paulo 		if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
940*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
941*5b9c547cSRui Paulo 				   "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
942*5b9c547cSRui Paulo 				   (int) left_len, (int) MKA_HDR_LEN,
943*5b9c547cSRui Paulo 				   (int) body_len, DEFAULT_ICV_LEN);
944*5b9c547cSRui Paulo 			goto SKIP_PEER;
945*5b9c547cSRui Paulo 		}
946*5b9c547cSRui Paulo 
947*5b9c547cSRui Paulo 		if ((body_len % 16) != 0) {
948*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
949*5b9c547cSRui Paulo 				   "KaY: MKA Peer Packet Body Length (%d bytes) should multiple of 16 octets",
950*5b9c547cSRui Paulo 				   (int) body_len);
951*5b9c547cSRui Paulo 			goto SKIP_PEER;
952*5b9c547cSRui Paulo 		}
953*5b9c547cSRui Paulo 
954*5b9c547cSRui Paulo 		for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
955*5b9c547cSRui Paulo 			peer_mi = MKA_HDR_LEN + pos + i;
956*5b9c547cSRui Paulo 			os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
957*5b9c547cSRui Paulo 			peer_mn = be_to_host32(peer_mn);
958*5b9c547cSRui Paulo 			if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0 &&
959*5b9c547cSRui Paulo 			    peer_mn == participant->mn) {
960*5b9c547cSRui Paulo 				included = TRUE;
961*5b9c547cSRui Paulo 				break;
962*5b9c547cSRui Paulo 			}
963*5b9c547cSRui Paulo 		}
964*5b9c547cSRui Paulo 
965*5b9c547cSRui Paulo 		if (included)
966*5b9c547cSRui Paulo 			return TRUE;
967*5b9c547cSRui Paulo 
968*5b9c547cSRui Paulo SKIP_PEER:
969*5b9c547cSRui Paulo 		left_len -= body_len + MKA_HDR_LEN;
970*5b9c547cSRui Paulo 		pos += body_len + MKA_HDR_LEN;
971*5b9c547cSRui Paulo 	}
972*5b9c547cSRui Paulo 
973*5b9c547cSRui Paulo 	return FALSE;
974*5b9c547cSRui Paulo }
975*5b9c547cSRui Paulo 
976*5b9c547cSRui Paulo 
977*5b9c547cSRui Paulo /**
978*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_live_peer_body -
979*5b9c547cSRui Paulo  */
980*5b9c547cSRui Paulo static int ieee802_1x_mka_decode_live_peer_body(
981*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
982*5b9c547cSRui Paulo 	const u8 *peer_msg, size_t msg_len)
983*5b9c547cSRui Paulo {
984*5b9c547cSRui Paulo 	const struct ieee802_1x_mka_hdr *hdr;
985*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
986*5b9c547cSRui Paulo 	size_t body_len;
987*5b9c547cSRui Paulo 	u32 peer_mn;
988*5b9c547cSRui Paulo 	const u8 *peer_mi;
989*5b9c547cSRui Paulo 	size_t i;
990*5b9c547cSRui Paulo 	Boolean is_included;
991*5b9c547cSRui Paulo 
992*5b9c547cSRui Paulo 	is_included = ieee802_1x_kay_is_in_live_peer(
993*5b9c547cSRui Paulo 		participant, participant->current_peer_id.mi);
994*5b9c547cSRui Paulo 
995*5b9c547cSRui Paulo 	hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
996*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
997*5b9c547cSRui Paulo 
998*5b9c547cSRui Paulo 	for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
999*5b9c547cSRui Paulo 		peer_mi = MKA_HDR_LEN + peer_msg + i;
1000*5b9c547cSRui Paulo 		os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
1001*5b9c547cSRui Paulo 		peer_mn = be_to_host32(peer_mn);
1002*5b9c547cSRui Paulo 
1003*5b9c547cSRui Paulo 		/* it is myself */
1004*5b9c547cSRui Paulo 		if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
1005*5b9c547cSRui Paulo 			/* My message id is used by other participant */
1006*5b9c547cSRui Paulo 			if (peer_mn > participant->mn) {
1007*5b9c547cSRui Paulo 				if (os_get_random(participant->mi,
1008*5b9c547cSRui Paulo 						  sizeof(participant->mi)) < 0)
1009*5b9c547cSRui Paulo 					wpa_printf(MSG_DEBUG,
1010*5b9c547cSRui Paulo 						   "KaY: Could not update mi");
1011*5b9c547cSRui Paulo 				participant->mn = 0;
1012*5b9c547cSRui Paulo 			}
1013*5b9c547cSRui Paulo 			continue;
1014*5b9c547cSRui Paulo 		}
1015*5b9c547cSRui Paulo 		if (!is_included)
1016*5b9c547cSRui Paulo 			continue;
1017*5b9c547cSRui Paulo 
1018*5b9c547cSRui Paulo 		peer = ieee802_1x_kay_get_peer(participant, peer_mi);
1019*5b9c547cSRui Paulo 		if (NULL != peer) {
1020*5b9c547cSRui Paulo 			peer->mn = peer_mn;
1021*5b9c547cSRui Paulo 			peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
1022*5b9c547cSRui Paulo 		} else {
1023*5b9c547cSRui Paulo 			if (!ieee802_1x_kay_create_potential_peer(
1024*5b9c547cSRui Paulo 				participant, peer_mi, peer_mn)) {
1025*5b9c547cSRui Paulo 				return -1;
1026*5b9c547cSRui Paulo 			}
1027*5b9c547cSRui Paulo 		}
1028*5b9c547cSRui Paulo 	}
1029*5b9c547cSRui Paulo 
1030*5b9c547cSRui Paulo 	return 0;
1031*5b9c547cSRui Paulo }
1032*5b9c547cSRui Paulo 
1033*5b9c547cSRui Paulo 
1034*5b9c547cSRui Paulo /**
1035*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_potential_peer_body -
1036*5b9c547cSRui Paulo  */
1037*5b9c547cSRui Paulo static int
1038*5b9c547cSRui Paulo ieee802_1x_mka_decode_potential_peer_body(
1039*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1040*5b9c547cSRui Paulo 	const u8 *peer_msg, size_t msg_len)
1041*5b9c547cSRui Paulo {
1042*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1043*5b9c547cSRui Paulo 	size_t body_len;
1044*5b9c547cSRui Paulo 	u32 peer_mn;
1045*5b9c547cSRui Paulo 	const u8 *peer_mi;
1046*5b9c547cSRui Paulo 	size_t i;
1047*5b9c547cSRui Paulo 
1048*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
1049*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
1050*5b9c547cSRui Paulo 
1051*5b9c547cSRui Paulo 	for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
1052*5b9c547cSRui Paulo 		peer_mi = MKA_HDR_LEN + peer_msg + i;
1053*5b9c547cSRui Paulo 		os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
1054*5b9c547cSRui Paulo 		peer_mn = be_to_host32(peer_mn);
1055*5b9c547cSRui Paulo 
1056*5b9c547cSRui Paulo 		/* it is myself */
1057*5b9c547cSRui Paulo 		if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
1058*5b9c547cSRui Paulo 			/* My message id is used by other participant */
1059*5b9c547cSRui Paulo 			if (peer_mn > participant->mn) {
1060*5b9c547cSRui Paulo 				if (os_get_random(participant->mi,
1061*5b9c547cSRui Paulo 						  sizeof(participant->mi)) < 0)
1062*5b9c547cSRui Paulo 					wpa_printf(MSG_DEBUG,
1063*5b9c547cSRui Paulo 						   "KaY: Could not update mi");
1064*5b9c547cSRui Paulo 				participant->mn = 0;
1065*5b9c547cSRui Paulo 			}
1066*5b9c547cSRui Paulo 			continue;
1067*5b9c547cSRui Paulo 		}
1068*5b9c547cSRui Paulo 	}
1069*5b9c547cSRui Paulo 
1070*5b9c547cSRui Paulo 	return 0;
1071*5b9c547cSRui Paulo }
1072*5b9c547cSRui Paulo 
1073*5b9c547cSRui Paulo 
1074*5b9c547cSRui Paulo /**
1075*5b9c547cSRui Paulo  * ieee802_1x_mka_sak_use_body_present
1076*5b9c547cSRui Paulo  */
1077*5b9c547cSRui Paulo static Boolean
1078*5b9c547cSRui Paulo ieee802_1x_mka_sak_use_body_present(
1079*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
1080*5b9c547cSRui Paulo {
1081*5b9c547cSRui Paulo 	if (participant->to_use_sak)
1082*5b9c547cSRui Paulo 		return TRUE;
1083*5b9c547cSRui Paulo 	else
1084*5b9c547cSRui Paulo 		return FALSE;
1085*5b9c547cSRui Paulo }
1086*5b9c547cSRui Paulo 
1087*5b9c547cSRui Paulo 
1088*5b9c547cSRui Paulo /**
1089*5b9c547cSRui Paulo  * ieee802_1x_mka_get_sak_use_length
1090*5b9c547cSRui Paulo  */
1091*5b9c547cSRui Paulo static int
1092*5b9c547cSRui Paulo ieee802_1x_mka_get_sak_use_length(
1093*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
1094*5b9c547cSRui Paulo {
1095*5b9c547cSRui Paulo 	int length = MKA_HDR_LEN;
1096*5b9c547cSRui Paulo 
1097*5b9c547cSRui Paulo 	if (participant->kay->macsec_desired && participant->advised_desired)
1098*5b9c547cSRui Paulo 		length = sizeof(struct ieee802_1x_mka_sak_use_body);
1099*5b9c547cSRui Paulo 	else
1100*5b9c547cSRui Paulo 		length = MKA_HDR_LEN;
1101*5b9c547cSRui Paulo 
1102*5b9c547cSRui Paulo 	length = (length + 0x3) & ~0x3;
1103*5b9c547cSRui Paulo 
1104*5b9c547cSRui Paulo 	return length;
1105*5b9c547cSRui Paulo }
1106*5b9c547cSRui Paulo 
1107*5b9c547cSRui Paulo 
1108*5b9c547cSRui Paulo /**
1109*5b9c547cSRui Paulo  *
1110*5b9c547cSRui Paulo  */
1111*5b9c547cSRui Paulo static u32
1112*5b9c547cSRui Paulo ieee802_1x_mka_get_lpn(struct ieee802_1x_mka_participant *principal,
1113*5b9c547cSRui Paulo 		       struct ieee802_1x_mka_ki *ki)
1114*5b9c547cSRui Paulo {
1115*5b9c547cSRui Paulo 	struct receive_sa *rxsa;
1116*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
1117*5b9c547cSRui Paulo 	u32 lpn = 0;
1118*5b9c547cSRui Paulo 
1119*5b9c547cSRui Paulo 	dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
1120*5b9c547cSRui Paulo 		dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
1121*5b9c547cSRui Paulo 		{
1122*5b9c547cSRui Paulo 			if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
1123*5b9c547cSRui Paulo 				secy_get_receive_lowest_pn(principal->kay,
1124*5b9c547cSRui Paulo 							   rxsa);
1125*5b9c547cSRui Paulo 
1126*5b9c547cSRui Paulo 				lpn = lpn > rxsa->lowest_pn ?
1127*5b9c547cSRui Paulo 					lpn : rxsa->lowest_pn;
1128*5b9c547cSRui Paulo 				break;
1129*5b9c547cSRui Paulo 			}
1130*5b9c547cSRui Paulo 		}
1131*5b9c547cSRui Paulo 	}
1132*5b9c547cSRui Paulo 
1133*5b9c547cSRui Paulo 	if (lpn == 0)
1134*5b9c547cSRui Paulo 		lpn = 1;
1135*5b9c547cSRui Paulo 
1136*5b9c547cSRui Paulo 	return lpn;
1137*5b9c547cSRui Paulo }
1138*5b9c547cSRui Paulo 
1139*5b9c547cSRui Paulo 
1140*5b9c547cSRui Paulo /**
1141*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_sak_use_body -
1142*5b9c547cSRui Paulo  */
1143*5b9c547cSRui Paulo static int
1144*5b9c547cSRui Paulo ieee802_1x_mka_encode_sak_use_body(
1145*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1146*5b9c547cSRui Paulo 	struct wpabuf *buf)
1147*5b9c547cSRui Paulo {
1148*5b9c547cSRui Paulo 	struct ieee802_1x_mka_sak_use_body *body;
1149*5b9c547cSRui Paulo 	unsigned int length;
1150*5b9c547cSRui Paulo 	u32 pn = 1;
1151*5b9c547cSRui Paulo 
1152*5b9c547cSRui Paulo 	length = ieee802_1x_mka_get_sak_use_length(participant);
1153*5b9c547cSRui Paulo 	body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_sak_use_body));
1154*5b9c547cSRui Paulo 
1155*5b9c547cSRui Paulo 	body->type = MKA_SAK_USE;
1156*5b9c547cSRui Paulo 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
1157*5b9c547cSRui Paulo 
1158*5b9c547cSRui Paulo 	if (length == MKA_HDR_LEN) {
1159*5b9c547cSRui Paulo 		body->ptx = TRUE;
1160*5b9c547cSRui Paulo 		body->prx = TRUE;
1161*5b9c547cSRui Paulo 		body->lan = 0;
1162*5b9c547cSRui Paulo 		body->lrx = FALSE;
1163*5b9c547cSRui Paulo 		body->ltx = FALSE;
1164*5b9c547cSRui Paulo 		body->delay_protect = FALSE;
1165*5b9c547cSRui Paulo 		return 0;
1166*5b9c547cSRui Paulo 	}
1167*5b9c547cSRui Paulo 
1168*5b9c547cSRui Paulo 	/* data protect, lowest accept packet number */
1169*5b9c547cSRui Paulo 	body->delay_protect = participant->kay->macsec_replay_protect;
1170*5b9c547cSRui Paulo 	pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
1171*5b9c547cSRui Paulo 	if (pn > participant->kay->pn_exhaustion) {
1172*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
1173*5b9c547cSRui Paulo 		if (participant->is_key_server)
1174*5b9c547cSRui Paulo 			participant->new_sak = TRUE;
1175*5b9c547cSRui Paulo 	}
1176*5b9c547cSRui Paulo 
1177*5b9c547cSRui Paulo 	body->llpn = host_to_be32(pn);
1178*5b9c547cSRui Paulo 	pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
1179*5b9c547cSRui Paulo 	body->olpn = host_to_be32(pn);
1180*5b9c547cSRui Paulo 
1181*5b9c547cSRui Paulo 	/* plain tx, plain rx */
1182*5b9c547cSRui Paulo 	if (participant->kay->macsec_protect)
1183*5b9c547cSRui Paulo 		body->ptx = FALSE;
1184*5b9c547cSRui Paulo 	else
1185*5b9c547cSRui Paulo 		body->ptx = TRUE;
1186*5b9c547cSRui Paulo 
1187*5b9c547cSRui Paulo 	if (participant->kay->macsec_validate == Strict)
1188*5b9c547cSRui Paulo 		body->prx = FALSE;
1189*5b9c547cSRui Paulo 	else
1190*5b9c547cSRui Paulo 		body->prx = TRUE;
1191*5b9c547cSRui Paulo 
1192*5b9c547cSRui Paulo 	/* latest key: rx, tx, key server member identifier key number */
1193*5b9c547cSRui Paulo 	body->lan = participant->lan;
1194*5b9c547cSRui Paulo 	os_memcpy(body->lsrv_mi, participant->lki.mi,
1195*5b9c547cSRui Paulo 		  sizeof(body->lsrv_mi));
1196*5b9c547cSRui Paulo 	body->lkn = host_to_be32(participant->lki.kn);
1197*5b9c547cSRui Paulo 	body->lrx = participant->lrx;
1198*5b9c547cSRui Paulo 	body->ltx = participant->ltx;
1199*5b9c547cSRui Paulo 
1200*5b9c547cSRui Paulo 	/* old key: rx, tx, key server member identifier key number */
1201*5b9c547cSRui Paulo 	body->oan = participant->oan;
1202*5b9c547cSRui Paulo 	if (participant->oki.kn != participant->lki.kn &&
1203*5b9c547cSRui Paulo 	    participant->oki.kn != 0) {
1204*5b9c547cSRui Paulo 		body->otx = TRUE;
1205*5b9c547cSRui Paulo 		body->orx = TRUE;
1206*5b9c547cSRui Paulo 		os_memcpy(body->osrv_mi, participant->oki.mi,
1207*5b9c547cSRui Paulo 			  sizeof(body->osrv_mi));
1208*5b9c547cSRui Paulo 		body->okn = host_to_be32(participant->oki.kn);
1209*5b9c547cSRui Paulo 	} else {
1210*5b9c547cSRui Paulo 		body->otx = FALSE;
1211*5b9c547cSRui Paulo 		body->orx = FALSE;
1212*5b9c547cSRui Paulo 	}
1213*5b9c547cSRui Paulo 
1214*5b9c547cSRui Paulo 	/* set CP's variable */
1215*5b9c547cSRui Paulo 	if (body->ltx) {
1216*5b9c547cSRui Paulo 		if (!participant->kay->tx_enable)
1217*5b9c547cSRui Paulo 			participant->kay->tx_enable = TRUE;
1218*5b9c547cSRui Paulo 
1219*5b9c547cSRui Paulo 		if (!participant->kay->port_enable)
1220*5b9c547cSRui Paulo 			participant->kay->port_enable = TRUE;
1221*5b9c547cSRui Paulo 	}
1222*5b9c547cSRui Paulo 	if (body->lrx) {
1223*5b9c547cSRui Paulo 		if (!participant->kay->rx_enable)
1224*5b9c547cSRui Paulo 			participant->kay->rx_enable = TRUE;
1225*5b9c547cSRui Paulo 	}
1226*5b9c547cSRui Paulo 
1227*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_sak_use_body(body);
1228*5b9c547cSRui Paulo 	return 0;
1229*5b9c547cSRui Paulo }
1230*5b9c547cSRui Paulo 
1231*5b9c547cSRui Paulo 
1232*5b9c547cSRui Paulo /**
1233*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_sak_use_body -
1234*5b9c547cSRui Paulo  */
1235*5b9c547cSRui Paulo static int
1236*5b9c547cSRui Paulo ieee802_1x_mka_decode_sak_use_body(
1237*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1238*5b9c547cSRui Paulo 	const u8 *mka_msg, size_t msg_len)
1239*5b9c547cSRui Paulo {
1240*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1241*5b9c547cSRui Paulo 	struct ieee802_1x_mka_sak_use_body *body;
1242*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
1243*5b9c547cSRui Paulo 	struct transmit_sa *txsa;
1244*5b9c547cSRui Paulo 	struct data_key *sa_key = NULL;
1245*5b9c547cSRui Paulo 	size_t body_len;
1246*5b9c547cSRui Paulo 	struct ieee802_1x_mka_ki ki;
1247*5b9c547cSRui Paulo 	u32 lpn;
1248*5b9c547cSRui Paulo 	Boolean all_receiving;
1249*5b9c547cSRui Paulo 	Boolean founded;
1250*5b9c547cSRui Paulo 
1251*5b9c547cSRui Paulo 	if (!participant->principal) {
1252*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
1253*5b9c547cSRui Paulo 		return -1;
1254*5b9c547cSRui Paulo 	}
1255*5b9c547cSRui Paulo 	peer = ieee802_1x_kay_get_live_peer(participant,
1256*5b9c547cSRui Paulo 					    participant->current_peer_id.mi);
1257*5b9c547cSRui Paulo 	if (!peer) {
1258*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: the peer is not my live peer");
1259*5b9c547cSRui Paulo 		return -1;
1260*5b9c547cSRui Paulo 	}
1261*5b9c547cSRui Paulo 
1262*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
1263*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
1264*5b9c547cSRui Paulo 	body = (struct ieee802_1x_mka_sak_use_body *) mka_msg;
1265*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_sak_use_body(body);
1266*5b9c547cSRui Paulo 
1267*5b9c547cSRui Paulo 	if ((body_len != 0) && (body_len < 40)) {
1268*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1269*5b9c547cSRui Paulo 			   "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 40, or more octets",
1270*5b9c547cSRui Paulo 			   (int) body_len);
1271*5b9c547cSRui Paulo 		return -1;
1272*5b9c547cSRui Paulo 	}
1273*5b9c547cSRui Paulo 
1274*5b9c547cSRui Paulo 	/* TODO: what action should I take when peer does not support MACsec */
1275*5b9c547cSRui Paulo 	if (body_len == 0) {
1276*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: Peer does not support MACsec");
1277*5b9c547cSRui Paulo 		return 0;
1278*5b9c547cSRui Paulo 	}
1279*5b9c547cSRui Paulo 
1280*5b9c547cSRui Paulo 	/* TODO: when the plain tx or rx of peer is true, should I change
1281*5b9c547cSRui Paulo 	 * the attribute of controlled port
1282*5b9c547cSRui Paulo 	 */
1283*5b9c547cSRui Paulo 	if (body->prx)
1284*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: peer's plain rx are TRUE");
1285*5b9c547cSRui Paulo 
1286*5b9c547cSRui Paulo 	if (body->ptx)
1287*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
1288*5b9c547cSRui Paulo 
1289*5b9c547cSRui Paulo 	/* check latest key is valid */
1290*5b9c547cSRui Paulo 	if (body->ltx || body->lrx) {
1291*5b9c547cSRui Paulo 		founded = FALSE;
1292*5b9c547cSRui Paulo 		os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
1293*5b9c547cSRui Paulo 		ki.kn = ntohl(body->lkn);
1294*5b9c547cSRui Paulo 		dl_list_for_each(sa_key, &participant->sak_list,
1295*5b9c547cSRui Paulo 				 struct data_key, list) {
1296*5b9c547cSRui Paulo 			if (is_ki_equal(&sa_key->key_identifier, &ki)) {
1297*5b9c547cSRui Paulo 				founded = TRUE;
1298*5b9c547cSRui Paulo 				break;
1299*5b9c547cSRui Paulo 			}
1300*5b9c547cSRui Paulo 		}
1301*5b9c547cSRui Paulo 		if (!founded) {
1302*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
1303*5b9c547cSRui Paulo 			return -1;
1304*5b9c547cSRui Paulo 		}
1305*5b9c547cSRui Paulo 		if (os_memcmp(participant->lki.mi, body->lsrv_mi,
1306*5b9c547cSRui Paulo 			      sizeof(participant->lki.mi)) == 0 &&
1307*5b9c547cSRui Paulo 		    ntohl(body->lkn) == participant->lki.kn &&
1308*5b9c547cSRui Paulo 		    body->lan == participant->lan) {
1309*5b9c547cSRui Paulo 			peer->sak_used = TRUE;
1310*5b9c547cSRui Paulo 		}
1311*5b9c547cSRui Paulo 		if (body->ltx && peer->is_key_server) {
1312*5b9c547cSRui Paulo 			ieee802_1x_cp_set_servertransmitting(
1313*5b9c547cSRui Paulo 				participant->kay->cp, TRUE);
1314*5b9c547cSRui Paulo 			ieee802_1x_cp_sm_step(participant->kay->cp);
1315*5b9c547cSRui Paulo 		}
1316*5b9c547cSRui Paulo 	}
1317*5b9c547cSRui Paulo 
1318*5b9c547cSRui Paulo 	/* check old key is valid */
1319*5b9c547cSRui Paulo 	if (body->otx || body->orx) {
1320*5b9c547cSRui Paulo 		if (os_memcmp(participant->oki.mi, body->osrv_mi,
1321*5b9c547cSRui Paulo 			      sizeof(participant->oki.mi)) != 0 ||
1322*5b9c547cSRui Paulo 		    ntohl(body->okn) != participant->oki.kn ||
1323*5b9c547cSRui Paulo 		    body->oan != participant->oan) {
1324*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
1325*5b9c547cSRui Paulo 			return -1;
1326*5b9c547cSRui Paulo 		}
1327*5b9c547cSRui Paulo 	}
1328*5b9c547cSRui Paulo 
1329*5b9c547cSRui Paulo 	/* TODO: how to set the MACsec hardware when delay_protect is true */
1330*5b9c547cSRui Paulo 	if (body->delay_protect && (!ntohl(body->llpn) || !ntohl(body->olpn))) {
1331*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING,
1332*5b9c547cSRui Paulo 			   "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
1333*5b9c547cSRui Paulo 		return -1;
1334*5b9c547cSRui Paulo 	}
1335*5b9c547cSRui Paulo 
1336*5b9c547cSRui Paulo 	/* check all live peer have used the sak for receiving sa */
1337*5b9c547cSRui Paulo 	all_receiving = TRUE;
1338*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
1339*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
1340*5b9c547cSRui Paulo 		if (!peer->sak_used) {
1341*5b9c547cSRui Paulo 			all_receiving = FALSE;
1342*5b9c547cSRui Paulo 			break;
1343*5b9c547cSRui Paulo 		}
1344*5b9c547cSRui Paulo 	}
1345*5b9c547cSRui Paulo 	if (all_receiving) {
1346*5b9c547cSRui Paulo 		participant->to_dist_sak = FALSE;
1347*5b9c547cSRui Paulo 		ieee802_1x_cp_set_allreceiving(participant->kay->cp, TRUE);
1348*5b9c547cSRui Paulo 		ieee802_1x_cp_sm_step(participant->kay->cp);
1349*5b9c547cSRui Paulo 	}
1350*5b9c547cSRui Paulo 
1351*5b9c547cSRui Paulo 	/* if i'm key server, and detects peer member pn exhaustion, rekey.*/
1352*5b9c547cSRui Paulo 	lpn = ntohl(body->llpn);
1353*5b9c547cSRui Paulo 	if (lpn > participant->kay->pn_exhaustion) {
1354*5b9c547cSRui Paulo 		if (participant->is_key_server) {
1355*5b9c547cSRui Paulo 			participant->new_sak = TRUE;
1356*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
1357*5b9c547cSRui Paulo 		}
1358*5b9c547cSRui Paulo 	}
1359*5b9c547cSRui Paulo 
1360*5b9c547cSRui Paulo 	founded = FALSE;
1361*5b9c547cSRui Paulo 	dl_list_for_each(txsa, &participant->txsc->sa_list,
1362*5b9c547cSRui Paulo 			 struct transmit_sa, list) {
1363*5b9c547cSRui Paulo 		if (sa_key != NULL && txsa->pkey == sa_key) {
1364*5b9c547cSRui Paulo 			founded = TRUE;
1365*5b9c547cSRui Paulo 			break;
1366*5b9c547cSRui Paulo 		}
1367*5b9c547cSRui Paulo 	}
1368*5b9c547cSRui Paulo 	if (!founded) {
1369*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
1370*5b9c547cSRui Paulo 		return -1;
1371*5b9c547cSRui Paulo 	}
1372*5b9c547cSRui Paulo 
1373*5b9c547cSRui Paulo 	/* FIXME: Secy creates txsa with default npn. If MKA detected Latest Key
1374*5b9c547cSRui Paulo 	 * npn is larger than txsa's npn, set it to txsa.
1375*5b9c547cSRui Paulo 	 */
1376*5b9c547cSRui Paulo 	secy_get_transmit_next_pn(participant->kay, txsa);
1377*5b9c547cSRui Paulo 	if (lpn > txsa->next_pn) {
1378*5b9c547cSRui Paulo 		secy_set_transmit_next_pn(participant->kay, txsa);
1379*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
1380*5b9c547cSRui Paulo 	}
1381*5b9c547cSRui Paulo 
1382*5b9c547cSRui Paulo 	return 0;
1383*5b9c547cSRui Paulo }
1384*5b9c547cSRui Paulo 
1385*5b9c547cSRui Paulo 
1386*5b9c547cSRui Paulo /**
1387*5b9c547cSRui Paulo  * ieee802_1x_mka_dist_sak_body_present
1388*5b9c547cSRui Paulo  */
1389*5b9c547cSRui Paulo static Boolean
1390*5b9c547cSRui Paulo ieee802_1x_mka_dist_sak_body_present(
1391*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
1392*5b9c547cSRui Paulo {
1393*5b9c547cSRui Paulo 	if (!participant->to_dist_sak || !participant->new_key)
1394*5b9c547cSRui Paulo 		return FALSE;
1395*5b9c547cSRui Paulo 
1396*5b9c547cSRui Paulo 	return TRUE;
1397*5b9c547cSRui Paulo }
1398*5b9c547cSRui Paulo 
1399*5b9c547cSRui Paulo 
1400*5b9c547cSRui Paulo /**
1401*5b9c547cSRui Paulo  * ieee802_1x_kay_get_dist_sak_length
1402*5b9c547cSRui Paulo  */
1403*5b9c547cSRui Paulo static int
1404*5b9c547cSRui Paulo ieee802_1x_mka_get_dist_sak_length(
1405*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
1406*5b9c547cSRui Paulo {
1407*5b9c547cSRui Paulo 	int length;
1408*5b9c547cSRui Paulo 	int cs_index = participant->kay->macsec_csindex;
1409*5b9c547cSRui Paulo 
1410*5b9c547cSRui Paulo 	if (participant->advised_desired) {
1411*5b9c547cSRui Paulo 		length = sizeof(struct ieee802_1x_mka_dist_sak_body);
1412*5b9c547cSRui Paulo 		if (cs_index != DEFAULT_CS_INDEX)
1413*5b9c547cSRui Paulo 			length += CS_ID_LEN;
1414*5b9c547cSRui Paulo 
1415*5b9c547cSRui Paulo 		length += cipher_suite_tbl[cs_index].sak_len + 8;
1416*5b9c547cSRui Paulo 	} else {
1417*5b9c547cSRui Paulo 		length = MKA_HDR_LEN;
1418*5b9c547cSRui Paulo 	}
1419*5b9c547cSRui Paulo 	length = (length + 0x3) & ~0x3;
1420*5b9c547cSRui Paulo 
1421*5b9c547cSRui Paulo 	return length;
1422*5b9c547cSRui Paulo }
1423*5b9c547cSRui Paulo 
1424*5b9c547cSRui Paulo 
1425*5b9c547cSRui Paulo /**
1426*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_dist_sak_body -
1427*5b9c547cSRui Paulo  */
1428*5b9c547cSRui Paulo static int
1429*5b9c547cSRui Paulo ieee802_1x_mka_encode_dist_sak_body(
1430*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1431*5b9c547cSRui Paulo 	struct wpabuf *buf)
1432*5b9c547cSRui Paulo {
1433*5b9c547cSRui Paulo 	struct ieee802_1x_mka_dist_sak_body *body;
1434*5b9c547cSRui Paulo 	struct data_key *sak;
1435*5b9c547cSRui Paulo 	unsigned int length;
1436*5b9c547cSRui Paulo 	int cs_index;
1437*5b9c547cSRui Paulo 	int sak_pos;
1438*5b9c547cSRui Paulo 
1439*5b9c547cSRui Paulo 	length = ieee802_1x_mka_get_dist_sak_length(participant);
1440*5b9c547cSRui Paulo 	body = wpabuf_put(buf, length);
1441*5b9c547cSRui Paulo 	body->type = MKA_DISTRIBUTED_SAK;
1442*5b9c547cSRui Paulo 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
1443*5b9c547cSRui Paulo 	if (length == MKA_HDR_LEN) {
1444*5b9c547cSRui Paulo 		body->confid_offset = 0;
1445*5b9c547cSRui Paulo 		body->dan = 0;
1446*5b9c547cSRui Paulo 		return 0;
1447*5b9c547cSRui Paulo 	}
1448*5b9c547cSRui Paulo 
1449*5b9c547cSRui Paulo 	sak = participant->new_key;
1450*5b9c547cSRui Paulo 	body->confid_offset = sak->confidentiality_offset;
1451*5b9c547cSRui Paulo 	body->dan = sak->an;
1452*5b9c547cSRui Paulo 	body->kn = host_to_be32(sak->key_identifier.kn);
1453*5b9c547cSRui Paulo 	cs_index = participant->kay->macsec_csindex;
1454*5b9c547cSRui Paulo 	sak_pos = 0;
1455*5b9c547cSRui Paulo 	if (cs_index != DEFAULT_CS_INDEX) {
1456*5b9c547cSRui Paulo 		os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
1457*5b9c547cSRui Paulo 		sak_pos = CS_ID_LEN;
1458*5b9c547cSRui Paulo 	}
1459*5b9c547cSRui Paulo 	if (aes_wrap(participant->kek.key, 16,
1460*5b9c547cSRui Paulo 		     cipher_suite_tbl[cs_index].sak_len / 8,
1461*5b9c547cSRui Paulo 		     sak->key, body->sak + sak_pos)) {
1462*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
1463*5b9c547cSRui Paulo 		return -1;
1464*5b9c547cSRui Paulo 	}
1465*5b9c547cSRui Paulo 
1466*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_dist_sak_body(body);
1467*5b9c547cSRui Paulo 
1468*5b9c547cSRui Paulo 	return 0;
1469*5b9c547cSRui Paulo }
1470*5b9c547cSRui Paulo 
1471*5b9c547cSRui Paulo 
1472*5b9c547cSRui Paulo /**
1473*5b9c547cSRui Paulo  * ieee802_1x_kay_init_data_key -
1474*5b9c547cSRui Paulo  */
1475*5b9c547cSRui Paulo static struct data_key *
1476*5b9c547cSRui Paulo ieee802_1x_kay_init_data_key(const struct key_conf *conf)
1477*5b9c547cSRui Paulo {
1478*5b9c547cSRui Paulo 	struct data_key *pkey;
1479*5b9c547cSRui Paulo 
1480*5b9c547cSRui Paulo 	if (!conf)
1481*5b9c547cSRui Paulo 		return NULL;
1482*5b9c547cSRui Paulo 
1483*5b9c547cSRui Paulo 	pkey = os_zalloc(sizeof(*pkey));
1484*5b9c547cSRui Paulo 	if (pkey == NULL) {
1485*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
1486*5b9c547cSRui Paulo 		return NULL;
1487*5b9c547cSRui Paulo 	}
1488*5b9c547cSRui Paulo 
1489*5b9c547cSRui Paulo 	pkey->key = os_zalloc(conf->key_len);
1490*5b9c547cSRui Paulo 	if (pkey->key == NULL) {
1491*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
1492*5b9c547cSRui Paulo 		os_free(pkey);
1493*5b9c547cSRui Paulo 		return NULL;
1494*5b9c547cSRui Paulo 	}
1495*5b9c547cSRui Paulo 
1496*5b9c547cSRui Paulo 	os_memcpy(pkey->key, conf->key, conf->key_len);
1497*5b9c547cSRui Paulo 	os_memcpy(&pkey->key_identifier, &conf->ki,
1498*5b9c547cSRui Paulo 		  sizeof(pkey->key_identifier));
1499*5b9c547cSRui Paulo 	pkey->confidentiality_offset = conf->offset;
1500*5b9c547cSRui Paulo 	pkey->an = conf->an;
1501*5b9c547cSRui Paulo 	pkey->transmits = conf->tx;
1502*5b9c547cSRui Paulo 	pkey->receives = conf->rx;
1503*5b9c547cSRui Paulo 	os_get_time(&pkey->created_time);
1504*5b9c547cSRui Paulo 
1505*5b9c547cSRui Paulo 	pkey->user = 1;
1506*5b9c547cSRui Paulo 
1507*5b9c547cSRui Paulo 	return pkey;
1508*5b9c547cSRui Paulo }
1509*5b9c547cSRui Paulo 
1510*5b9c547cSRui Paulo 
1511*5b9c547cSRui Paulo /**
1512*5b9c547cSRui Paulo  * ieee802_1x_kay_decode_dist_sak_body -
1513*5b9c547cSRui Paulo  */
1514*5b9c547cSRui Paulo static int
1515*5b9c547cSRui Paulo ieee802_1x_mka_decode_dist_sak_body(
1516*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1517*5b9c547cSRui Paulo 	const u8 *mka_msg, size_t msg_len)
1518*5b9c547cSRui Paulo {
1519*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1520*5b9c547cSRui Paulo 	struct ieee802_1x_mka_dist_sak_body *body;
1521*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
1522*5b9c547cSRui Paulo 	struct macsec_ciphersuite *cs;
1523*5b9c547cSRui Paulo 	size_t body_len;
1524*5b9c547cSRui Paulo 	struct key_conf *conf;
1525*5b9c547cSRui Paulo 	struct data_key *sa_key = NULL;
1526*5b9c547cSRui Paulo 	struct ieee802_1x_mka_ki sak_ki;
1527*5b9c547cSRui Paulo 	int sak_len;
1528*5b9c547cSRui Paulo 	u8 *wrap_sak;
1529*5b9c547cSRui Paulo 	u8 *unwrap_sak;
1530*5b9c547cSRui Paulo 
1531*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
1532*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
1533*5b9c547cSRui Paulo 	if ((body_len != 0) && (body_len != 28) && (body_len < 36)) {
1534*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1535*5b9c547cSRui Paulo 			   "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 28, 36, or more octets",
1536*5b9c547cSRui Paulo 			   (int) body_len);
1537*5b9c547cSRui Paulo 		return -1;
1538*5b9c547cSRui Paulo 	}
1539*5b9c547cSRui Paulo 
1540*5b9c547cSRui Paulo 	if (!participant->principal) {
1541*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1542*5b9c547cSRui Paulo 			   "KaY: I can't accept the distributed SAK as I am not principal");
1543*5b9c547cSRui Paulo 		return -1;
1544*5b9c547cSRui Paulo 	}
1545*5b9c547cSRui Paulo 	if (participant->is_key_server) {
1546*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1547*5b9c547cSRui Paulo 			   "KaY: I can't accept the distributed SAK as myself is key server ");
1548*5b9c547cSRui Paulo 		return -1;
1549*5b9c547cSRui Paulo 	}
1550*5b9c547cSRui Paulo 	if (!participant->kay->macsec_desired ||
1551*5b9c547cSRui Paulo 	    participant->kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
1552*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1553*5b9c547cSRui Paulo 			   "KaY: I am not MACsec-desired or without MACsec capable");
1554*5b9c547cSRui Paulo 		return -1;
1555*5b9c547cSRui Paulo 	}
1556*5b9c547cSRui Paulo 
1557*5b9c547cSRui Paulo 	peer = ieee802_1x_kay_get_live_peer(participant,
1558*5b9c547cSRui Paulo 					    participant->current_peer_id.mi);
1559*5b9c547cSRui Paulo 	if (!peer) {
1560*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1561*5b9c547cSRui Paulo 			   "KaY: The key server is not in my live peers list");
1562*5b9c547cSRui Paulo 		return -1;
1563*5b9c547cSRui Paulo 	}
1564*5b9c547cSRui Paulo 	if (os_memcmp(&participant->kay->key_server_sci,
1565*5b9c547cSRui Paulo 		      &peer->sci, sizeof(struct ieee802_1x_mka_sci)) != 0) {
1566*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: The key server is not elected");
1567*5b9c547cSRui Paulo 		return -1;
1568*5b9c547cSRui Paulo 	}
1569*5b9c547cSRui Paulo 	if (body_len == 0) {
1570*5b9c547cSRui Paulo 		participant->kay->authenticated = TRUE;
1571*5b9c547cSRui Paulo 		participant->kay->secured = FALSE;
1572*5b9c547cSRui Paulo 		participant->kay->failed = FALSE;
1573*5b9c547cSRui Paulo 		participant->advised_desired = FALSE;
1574*5b9c547cSRui Paulo 		ieee802_1x_cp_connect_authenticated(participant->kay->cp);
1575*5b9c547cSRui Paulo 		ieee802_1x_cp_sm_step(participant->kay->cp);
1576*5b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
1577*5b9c547cSRui Paulo 		participant->to_use_sak = TRUE;
1578*5b9c547cSRui Paulo 		return 0;
1579*5b9c547cSRui Paulo 	}
1580*5b9c547cSRui Paulo 	participant->advised_desired = TRUE;
1581*5b9c547cSRui Paulo 	participant->kay->authenticated = FALSE;
1582*5b9c547cSRui Paulo 	participant->kay->secured = TRUE;
1583*5b9c547cSRui Paulo 	participant->kay->failed = FALSE;
1584*5b9c547cSRui Paulo 	ieee802_1x_cp_connect_secure(participant->kay->cp);
1585*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(participant->kay->cp);
1586*5b9c547cSRui Paulo 
1587*5b9c547cSRui Paulo 	body = (struct ieee802_1x_mka_dist_sak_body *)mka_msg;
1588*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_dist_sak_body(body);
1589*5b9c547cSRui Paulo 	dl_list_for_each(sa_key, &participant->sak_list, struct data_key, list)
1590*5b9c547cSRui Paulo 	{
1591*5b9c547cSRui Paulo 		if (os_memcmp(sa_key->key_identifier.mi,
1592*5b9c547cSRui Paulo 			      participant->current_peer_id.mi, MI_LEN) == 0 &&
1593*5b9c547cSRui Paulo 		    sa_key->key_identifier.kn == be_to_host32(body->kn)) {
1594*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING, "KaY:The Key has installed");
1595*5b9c547cSRui Paulo 			return 0;
1596*5b9c547cSRui Paulo 		}
1597*5b9c547cSRui Paulo 	}
1598*5b9c547cSRui Paulo 	if (body_len == 28) {
1599*5b9c547cSRui Paulo 		sak_len = DEFAULT_SA_KEY_LEN;
1600*5b9c547cSRui Paulo 		wrap_sak =  body->sak;
1601*5b9c547cSRui Paulo 		participant->kay->macsec_csindex = DEFAULT_CS_INDEX;
1602*5b9c547cSRui Paulo 	} else {
1603*5b9c547cSRui Paulo 		cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
1604*5b9c547cSRui Paulo 		if (!cs) {
1605*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
1606*5b9c547cSRui Paulo 				   "KaY: I can't support the Cipher Suite advised by key server");
1607*5b9c547cSRui Paulo 			return -1;
1608*5b9c547cSRui Paulo 		}
1609*5b9c547cSRui Paulo 		sak_len = cs->sak_len;
1610*5b9c547cSRui Paulo 		wrap_sak = body->sak + CS_ID_LEN;
1611*5b9c547cSRui Paulo 		participant->kay->macsec_csindex = cs->index;
1612*5b9c547cSRui Paulo 	}
1613*5b9c547cSRui Paulo 
1614*5b9c547cSRui Paulo 	unwrap_sak = os_zalloc(sak_len);
1615*5b9c547cSRui Paulo 	if (!unwrap_sak) {
1616*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
1617*5b9c547cSRui Paulo 		return -1;
1618*5b9c547cSRui Paulo 	}
1619*5b9c547cSRui Paulo 	if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak,
1620*5b9c547cSRui Paulo 		       unwrap_sak)) {
1621*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
1622*5b9c547cSRui Paulo 		os_free(unwrap_sak);
1623*5b9c547cSRui Paulo 		return -1;
1624*5b9c547cSRui Paulo 	}
1625*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
1626*5b9c547cSRui Paulo 
1627*5b9c547cSRui Paulo 	conf = os_zalloc(sizeof(*conf));
1628*5b9c547cSRui Paulo 	if (!conf) {
1629*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
1630*5b9c547cSRui Paulo 		os_free(unwrap_sak);
1631*5b9c547cSRui Paulo 		return -1;
1632*5b9c547cSRui Paulo 	}
1633*5b9c547cSRui Paulo 	conf->key_len = sak_len;
1634*5b9c547cSRui Paulo 
1635*5b9c547cSRui Paulo 	conf->key = os_zalloc(conf->key_len);
1636*5b9c547cSRui Paulo 	if (!conf->key) {
1637*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
1638*5b9c547cSRui Paulo 		os_free(unwrap_sak);
1639*5b9c547cSRui Paulo 		os_free(conf);
1640*5b9c547cSRui Paulo 		return -1;
1641*5b9c547cSRui Paulo 	}
1642*5b9c547cSRui Paulo 
1643*5b9c547cSRui Paulo 	os_memcpy(conf->key, unwrap_sak, conf->key_len);
1644*5b9c547cSRui Paulo 
1645*5b9c547cSRui Paulo 	os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
1646*5b9c547cSRui Paulo 		  sizeof(sak_ki.mi));
1647*5b9c547cSRui Paulo 	sak_ki.kn = be_to_host32(body->kn);
1648*5b9c547cSRui Paulo 
1649*5b9c547cSRui Paulo 	os_memcpy(conf->ki.mi, sak_ki.mi, MI_LEN);
1650*5b9c547cSRui Paulo 	conf->ki.kn = sak_ki.kn;
1651*5b9c547cSRui Paulo 	conf->an = body->dan;
1652*5b9c547cSRui Paulo 	conf->offset = body->confid_offset;
1653*5b9c547cSRui Paulo 	conf->rx = TRUE;
1654*5b9c547cSRui Paulo 	conf->tx = TRUE;
1655*5b9c547cSRui Paulo 
1656*5b9c547cSRui Paulo 	sa_key = ieee802_1x_kay_init_data_key(conf);
1657*5b9c547cSRui Paulo 	if (!sa_key) {
1658*5b9c547cSRui Paulo 		os_free(unwrap_sak);
1659*5b9c547cSRui Paulo 		os_free(conf->key);
1660*5b9c547cSRui Paulo 		os_free(conf);
1661*5b9c547cSRui Paulo 		return -1;
1662*5b9c547cSRui Paulo 	}
1663*5b9c547cSRui Paulo 
1664*5b9c547cSRui Paulo 	dl_list_add(&participant->sak_list, &sa_key->list);
1665*5b9c547cSRui Paulo 
1666*5b9c547cSRui Paulo 	ieee802_1x_cp_set_ciphersuite(
1667*5b9c547cSRui Paulo 		participant->kay->cp,
1668*5b9c547cSRui Paulo 		cipher_suite_tbl[participant->kay->macsec_csindex].id);
1669*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(participant->kay->cp);
1670*5b9c547cSRui Paulo 	ieee802_1x_cp_set_offset(participant->kay->cp, body->confid_offset);
1671*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(participant->kay->cp);
1672*5b9c547cSRui Paulo 	ieee802_1x_cp_set_distributedki(participant->kay->cp, &sak_ki);
1673*5b9c547cSRui Paulo 	ieee802_1x_cp_set_distributedan(participant->kay->cp, body->dan);
1674*5b9c547cSRui Paulo 	ieee802_1x_cp_signal_newsak(participant->kay->cp);
1675*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(participant->kay->cp);
1676*5b9c547cSRui Paulo 
1677*5b9c547cSRui Paulo 	participant->to_use_sak = TRUE;
1678*5b9c547cSRui Paulo 
1679*5b9c547cSRui Paulo 	os_free(unwrap_sak);
1680*5b9c547cSRui Paulo 	os_free(conf->key);
1681*5b9c547cSRui Paulo 	os_free(conf);
1682*5b9c547cSRui Paulo 
1683*5b9c547cSRui Paulo 	return 0;
1684*5b9c547cSRui Paulo }
1685*5b9c547cSRui Paulo 
1686*5b9c547cSRui Paulo 
1687*5b9c547cSRui Paulo /**
1688*5b9c547cSRui Paulo  * ieee802_1x_mka_icv_body_present
1689*5b9c547cSRui Paulo  */
1690*5b9c547cSRui Paulo static Boolean
1691*5b9c547cSRui Paulo ieee802_1x_mka_icv_body_present(struct ieee802_1x_mka_participant *participant)
1692*5b9c547cSRui Paulo {
1693*5b9c547cSRui Paulo 	return TRUE;
1694*5b9c547cSRui Paulo }
1695*5b9c547cSRui Paulo 
1696*5b9c547cSRui Paulo 
1697*5b9c547cSRui Paulo /**
1698*5b9c547cSRui Paulo  * ieee802_1x_kay_get_icv_length
1699*5b9c547cSRui Paulo  */
1700*5b9c547cSRui Paulo static int
1701*5b9c547cSRui Paulo ieee802_1x_mka_get_icv_length(struct ieee802_1x_mka_participant *participant)
1702*5b9c547cSRui Paulo {
1703*5b9c547cSRui Paulo 	int length;
1704*5b9c547cSRui Paulo 
1705*5b9c547cSRui Paulo 	length = sizeof(struct ieee802_1x_mka_icv_body);
1706*5b9c547cSRui Paulo 	length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
1707*5b9c547cSRui Paulo 
1708*5b9c547cSRui Paulo 	return (length + 0x3) & ~0x3;
1709*5b9c547cSRui Paulo }
1710*5b9c547cSRui Paulo 
1711*5b9c547cSRui Paulo 
1712*5b9c547cSRui Paulo /**
1713*5b9c547cSRui Paulo  * ieee802_1x_mka_encode_icv_body -
1714*5b9c547cSRui Paulo  */
1715*5b9c547cSRui Paulo static int
1716*5b9c547cSRui Paulo ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant,
1717*5b9c547cSRui Paulo 			       struct wpabuf *buf)
1718*5b9c547cSRui Paulo {
1719*5b9c547cSRui Paulo 	struct ieee802_1x_mka_icv_body *body;
1720*5b9c547cSRui Paulo 	unsigned int length;
1721*5b9c547cSRui Paulo 	u8 cmac[MAX_ICV_LEN];
1722*5b9c547cSRui Paulo 
1723*5b9c547cSRui Paulo 	length = ieee802_1x_mka_get_icv_length(participant);
1724*5b9c547cSRui Paulo 	if (length != DEFAULT_ICV_LEN)  {
1725*5b9c547cSRui Paulo 		body = wpabuf_put(buf, MKA_HDR_LEN);
1726*5b9c547cSRui Paulo 		body->type = MKA_ICV_INDICATOR;
1727*5b9c547cSRui Paulo 		set_mka_param_body_len(body, length - MKA_HDR_LEN);
1728*5b9c547cSRui Paulo 	}
1729*5b9c547cSRui Paulo 
1730*5b9c547cSRui Paulo 	if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash(
1731*5b9c547cSRui Paulo 		    participant->ick.key, wpabuf_head(buf), buf->used, cmac)) {
1732*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY, omac1_aes_128 failed");
1733*5b9c547cSRui Paulo 		return -1;
1734*5b9c547cSRui Paulo 	}
1735*5b9c547cSRui Paulo 
1736*5b9c547cSRui Paulo 	if (length != DEFAULT_ICV_LEN)  {
1737*5b9c547cSRui Paulo 		os_memcpy(wpabuf_put(buf, length - MKA_HDR_LEN), cmac,
1738*5b9c547cSRui Paulo 			  length - MKA_HDR_LEN);
1739*5b9c547cSRui Paulo 	} else {
1740*5b9c547cSRui Paulo 		os_memcpy(wpabuf_put(buf, length), cmac, length);
1741*5b9c547cSRui Paulo 	}
1742*5b9c547cSRui Paulo 
1743*5b9c547cSRui Paulo 	return 0;
1744*5b9c547cSRui Paulo }
1745*5b9c547cSRui Paulo 
1746*5b9c547cSRui Paulo /**
1747*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_icv_body -
1748*5b9c547cSRui Paulo  */
1749*5b9c547cSRui Paulo static u8 *
1750*5b9c547cSRui Paulo ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
1751*5b9c547cSRui Paulo 			       const u8 *mka_msg, size_t msg_len)
1752*5b9c547cSRui Paulo {
1753*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1754*5b9c547cSRui Paulo 	struct ieee802_1x_mka_icv_body *body;
1755*5b9c547cSRui Paulo 	size_t body_len;
1756*5b9c547cSRui Paulo 	size_t left_len;
1757*5b9c547cSRui Paulo 	int body_type;
1758*5b9c547cSRui Paulo 	const u8 *pos;
1759*5b9c547cSRui Paulo 
1760*5b9c547cSRui Paulo 	pos = mka_msg;
1761*5b9c547cSRui Paulo 	left_len = msg_len;
1762*5b9c547cSRui Paulo 	while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
1763*5b9c547cSRui Paulo 		hdr = (struct ieee802_1x_mka_hdr *) pos;
1764*5b9c547cSRui Paulo 		body_len = get_mka_param_body_len(hdr);
1765*5b9c547cSRui Paulo 		body_type = get_mka_param_body_type(hdr);
1766*5b9c547cSRui Paulo 
1767*5b9c547cSRui Paulo 		if (left_len < (body_len + MKA_HDR_LEN))
1768*5b9c547cSRui Paulo 			break;
1769*5b9c547cSRui Paulo 
1770*5b9c547cSRui Paulo 		if (body_type != MKA_ICV_INDICATOR) {
1771*5b9c547cSRui Paulo 			left_len -= MKA_HDR_LEN + body_len;
1772*5b9c547cSRui Paulo 			pos += MKA_HDR_LEN + body_len;
1773*5b9c547cSRui Paulo 			continue;
1774*5b9c547cSRui Paulo 		}
1775*5b9c547cSRui Paulo 
1776*5b9c547cSRui Paulo 		body = (struct ieee802_1x_mka_icv_body *)pos;
1777*5b9c547cSRui Paulo 		if (body_len
1778*5b9c547cSRui Paulo 			< mka_alg_tbl[participant->kay->mka_algindex].icv_len) {
1779*5b9c547cSRui Paulo 			return NULL;
1780*5b9c547cSRui Paulo 		}
1781*5b9c547cSRui Paulo 
1782*5b9c547cSRui Paulo 		return body->icv;
1783*5b9c547cSRui Paulo 	}
1784*5b9c547cSRui Paulo 
1785*5b9c547cSRui Paulo 	return (u8 *) (mka_msg + msg_len - DEFAULT_ICV_LEN);
1786*5b9c547cSRui Paulo }
1787*5b9c547cSRui Paulo 
1788*5b9c547cSRui Paulo 
1789*5b9c547cSRui Paulo /**
1790*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_dist_cak_body-
1791*5b9c547cSRui Paulo  */
1792*5b9c547cSRui Paulo static int
1793*5b9c547cSRui Paulo ieee802_1x_mka_decode_dist_cak_body(
1794*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1795*5b9c547cSRui Paulo 	const u8 *mka_msg, size_t msg_len)
1796*5b9c547cSRui Paulo {
1797*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1798*5b9c547cSRui Paulo 	size_t body_len;
1799*5b9c547cSRui Paulo 
1800*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
1801*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
1802*5b9c547cSRui Paulo 	if (body_len < 28) {
1803*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1804*5b9c547cSRui Paulo 			   "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 28 or more octets",
1805*5b9c547cSRui Paulo 			   (int) body_len);
1806*5b9c547cSRui Paulo 		return -1;
1807*5b9c547cSRui Paulo 	}
1808*5b9c547cSRui Paulo 
1809*5b9c547cSRui Paulo 	return 0;
1810*5b9c547cSRui Paulo }
1811*5b9c547cSRui Paulo 
1812*5b9c547cSRui Paulo 
1813*5b9c547cSRui Paulo /**
1814*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_kmd_body -
1815*5b9c547cSRui Paulo  */
1816*5b9c547cSRui Paulo static int
1817*5b9c547cSRui Paulo ieee802_1x_mka_decode_kmd_body(
1818*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1819*5b9c547cSRui Paulo 	const u8 *mka_msg, size_t msg_len)
1820*5b9c547cSRui Paulo {
1821*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
1822*5b9c547cSRui Paulo 	size_t body_len;
1823*5b9c547cSRui Paulo 
1824*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
1825*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
1826*5b9c547cSRui Paulo 	if (body_len < 5) {
1827*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1828*5b9c547cSRui Paulo 			   "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 5 or more octets",
1829*5b9c547cSRui Paulo 			   (int) body_len);
1830*5b9c547cSRui Paulo 		return -1;
1831*5b9c547cSRui Paulo 	}
1832*5b9c547cSRui Paulo 
1833*5b9c547cSRui Paulo 	return 0;
1834*5b9c547cSRui Paulo }
1835*5b9c547cSRui Paulo 
1836*5b9c547cSRui Paulo 
1837*5b9c547cSRui Paulo /**
1838*5b9c547cSRui Paulo  * ieee802_1x_mka_decode_announce_body -
1839*5b9c547cSRui Paulo  */
1840*5b9c547cSRui Paulo static int ieee802_1x_mka_decode_announce_body(
1841*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant,
1842*5b9c547cSRui Paulo 	const u8 *mka_msg, size_t msg_len)
1843*5b9c547cSRui Paulo {
1844*5b9c547cSRui Paulo 	return 0;
1845*5b9c547cSRui Paulo }
1846*5b9c547cSRui Paulo 
1847*5b9c547cSRui Paulo 
1848*5b9c547cSRui Paulo static struct mka_param_body_handler mak_body_handler[] = {
1849*5b9c547cSRui Paulo 	/* basic parameter set */
1850*5b9c547cSRui Paulo 	{
1851*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_basic_body,
1852*5b9c547cSRui Paulo 		NULL,
1853*5b9c547cSRui Paulo 		ieee802_1x_mka_basic_body_length,
1854*5b9c547cSRui Paulo 		ieee802_1x_mka_basic_body_present
1855*5b9c547cSRui Paulo 	},
1856*5b9c547cSRui Paulo 
1857*5b9c547cSRui Paulo 	/* live peer list parameter set */
1858*5b9c547cSRui Paulo 	{
1859*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_live_peer_body,
1860*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_live_peer_body,
1861*5b9c547cSRui Paulo 		ieee802_1x_mka_get_live_peer_length,
1862*5b9c547cSRui Paulo 		ieee802_1x_mka_live_peer_body_present
1863*5b9c547cSRui Paulo 	},
1864*5b9c547cSRui Paulo 
1865*5b9c547cSRui Paulo 	/* potential peer list parameter set */
1866*5b9c547cSRui Paulo 	{
1867*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_potential_peer_body,
1868*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_potential_peer_body,
1869*5b9c547cSRui Paulo 		ieee802_1x_mka_get_potential_peer_length,
1870*5b9c547cSRui Paulo 		ieee802_1x_mka_potential_peer_body_present
1871*5b9c547cSRui Paulo 	},
1872*5b9c547cSRui Paulo 
1873*5b9c547cSRui Paulo 	/* sak use parameter set */
1874*5b9c547cSRui Paulo 	{
1875*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_sak_use_body,
1876*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_sak_use_body,
1877*5b9c547cSRui Paulo 		ieee802_1x_mka_get_sak_use_length,
1878*5b9c547cSRui Paulo 		ieee802_1x_mka_sak_use_body_present
1879*5b9c547cSRui Paulo 	},
1880*5b9c547cSRui Paulo 
1881*5b9c547cSRui Paulo 	/* distribute sak parameter set */
1882*5b9c547cSRui Paulo 	{
1883*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_dist_sak_body,
1884*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_dist_sak_body,
1885*5b9c547cSRui Paulo 		ieee802_1x_mka_get_dist_sak_length,
1886*5b9c547cSRui Paulo 		ieee802_1x_mka_dist_sak_body_present
1887*5b9c547cSRui Paulo 	},
1888*5b9c547cSRui Paulo 
1889*5b9c547cSRui Paulo 	/* distribute cak parameter set */
1890*5b9c547cSRui Paulo 	{
1891*5b9c547cSRui Paulo 		NULL,
1892*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_dist_cak_body,
1893*5b9c547cSRui Paulo 		NULL,
1894*5b9c547cSRui Paulo 		NULL
1895*5b9c547cSRui Paulo 	},
1896*5b9c547cSRui Paulo 
1897*5b9c547cSRui Paulo 	/* kmd parameter set */
1898*5b9c547cSRui Paulo 	{
1899*5b9c547cSRui Paulo 		NULL,
1900*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_kmd_body,
1901*5b9c547cSRui Paulo 		NULL,
1902*5b9c547cSRui Paulo 		NULL
1903*5b9c547cSRui Paulo 	},
1904*5b9c547cSRui Paulo 
1905*5b9c547cSRui Paulo 	/* announce parameter set */
1906*5b9c547cSRui Paulo 	{
1907*5b9c547cSRui Paulo 		NULL,
1908*5b9c547cSRui Paulo 		ieee802_1x_mka_decode_announce_body,
1909*5b9c547cSRui Paulo 		NULL,
1910*5b9c547cSRui Paulo 		NULL
1911*5b9c547cSRui Paulo 	},
1912*5b9c547cSRui Paulo 
1913*5b9c547cSRui Paulo 	/* icv parameter set */
1914*5b9c547cSRui Paulo 	{
1915*5b9c547cSRui Paulo 		ieee802_1x_mka_encode_icv_body,
1916*5b9c547cSRui Paulo 		NULL,
1917*5b9c547cSRui Paulo 		ieee802_1x_mka_get_icv_length,
1918*5b9c547cSRui Paulo 		ieee802_1x_mka_icv_body_present
1919*5b9c547cSRui Paulo 	},
1920*5b9c547cSRui Paulo };
1921*5b9c547cSRui Paulo 
1922*5b9c547cSRui Paulo 
1923*5b9c547cSRui Paulo /**
1924*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit_data_key -
1925*5b9c547cSRui Paulo  */
1926*5b9c547cSRui Paulo void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
1927*5b9c547cSRui Paulo {
1928*5b9c547cSRui Paulo 	if (!pkey)
1929*5b9c547cSRui Paulo 		return;
1930*5b9c547cSRui Paulo 
1931*5b9c547cSRui Paulo 	pkey->user--;
1932*5b9c547cSRui Paulo 	if (pkey->user > 1)
1933*5b9c547cSRui Paulo 		return;
1934*5b9c547cSRui Paulo 
1935*5b9c547cSRui Paulo 	dl_list_del(&pkey->list);
1936*5b9c547cSRui Paulo 	os_free(pkey->key);
1937*5b9c547cSRui Paulo 	os_free(pkey);
1938*5b9c547cSRui Paulo }
1939*5b9c547cSRui Paulo 
1940*5b9c547cSRui Paulo 
1941*5b9c547cSRui Paulo /**
1942*5b9c547cSRui Paulo  * ieee802_1x_kay_generate_new_sak -
1943*5b9c547cSRui Paulo  */
1944*5b9c547cSRui Paulo static int
1945*5b9c547cSRui Paulo ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
1946*5b9c547cSRui Paulo {
1947*5b9c547cSRui Paulo 	struct data_key *sa_key = NULL;
1948*5b9c547cSRui Paulo 	struct key_conf *conf;
1949*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
1950*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = participant->kay;
1951*5b9c547cSRui Paulo 	int ctx_len, ctx_offset;
1952*5b9c547cSRui Paulo 	u8 *context;
1953*5b9c547cSRui Paulo 
1954*5b9c547cSRui Paulo 	/* check condition for generating a fresh SAK:
1955*5b9c547cSRui Paulo 	 * must have one live peer
1956*5b9c547cSRui Paulo 	 * and MKA life time elapse since last distribution
1957*5b9c547cSRui Paulo 	 * or potential peer is empty
1958*5b9c547cSRui Paulo 	 */
1959*5b9c547cSRui Paulo 	if (dl_list_empty(&participant->live_peers)) {
1960*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1961*5b9c547cSRui Paulo 			   "KaY: Live peers list must not empty when generating fresh SAK");
1962*5b9c547cSRui Paulo 		return -1;
1963*5b9c547cSRui Paulo 	}
1964*5b9c547cSRui Paulo 
1965*5b9c547cSRui Paulo 	/* FIXME: A fresh SAK not generated until
1966*5b9c547cSRui Paulo 	 * the live peer list contains at least one peer and
1967*5b9c547cSRui Paulo 	 * MKA life time has elapsed since the prior SAK was first distributed,
1968*5b9c547cSRui Paulo 	 * or the Key server's potential peer is empty
1969*5b9c547cSRui Paulo 	 * but I can't understand the second item, so
1970*5b9c547cSRui Paulo 	 * here only check first item and ingore
1971*5b9c547cSRui Paulo 	 *   && (!dl_list_empty(&participant->potential_peers))) {
1972*5b9c547cSRui Paulo 	 */
1973*5b9c547cSRui Paulo 	if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
1974*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
1975*5b9c547cSRui Paulo 			   "KaY: Life time have not elapsed since prior SAK distributed");
1976*5b9c547cSRui Paulo 		return -1;
1977*5b9c547cSRui Paulo 	}
1978*5b9c547cSRui Paulo 
1979*5b9c547cSRui Paulo 	conf = os_zalloc(sizeof(*conf));
1980*5b9c547cSRui Paulo 	if (!conf) {
1981*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
1982*5b9c547cSRui Paulo 		return -1;
1983*5b9c547cSRui Paulo 	}
1984*5b9c547cSRui Paulo 	conf->key_len = cipher_suite_tbl[kay->macsec_csindex].sak_len;
1985*5b9c547cSRui Paulo 
1986*5b9c547cSRui Paulo 	conf->key = os_zalloc(conf->key_len);
1987*5b9c547cSRui Paulo 	if (!conf->key) {
1988*5b9c547cSRui Paulo 		os_free(conf);
1989*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
1990*5b9c547cSRui Paulo 		return -1;
1991*5b9c547cSRui Paulo 	}
1992*5b9c547cSRui Paulo 
1993*5b9c547cSRui Paulo 	ctx_len = conf->key_len + sizeof(kay->dist_kn);
1994*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
1995*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list)
1996*5b9c547cSRui Paulo 		ctx_len += sizeof(peer->mi);
1997*5b9c547cSRui Paulo 	ctx_len += sizeof(participant->mi);
1998*5b9c547cSRui Paulo 
1999*5b9c547cSRui Paulo 	context = os_zalloc(ctx_len);
2000*5b9c547cSRui Paulo 	if (!context) {
2001*5b9c547cSRui Paulo 		os_free(conf->key);
2002*5b9c547cSRui Paulo 		os_free(conf);
2003*5b9c547cSRui Paulo 		return -1;
2004*5b9c547cSRui Paulo 	}
2005*5b9c547cSRui Paulo 	ctx_offset = 0;
2006*5b9c547cSRui Paulo 	if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
2007*5b9c547cSRui Paulo 		os_free(context);
2008*5b9c547cSRui Paulo 		os_free(conf->key);
2009*5b9c547cSRui Paulo 		os_free(conf);
2010*5b9c547cSRui Paulo 		return -1;
2011*5b9c547cSRui Paulo 	}
2012*5b9c547cSRui Paulo 	ctx_offset += conf->key_len;
2013*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
2014*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
2015*5b9c547cSRui Paulo 		os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
2016*5b9c547cSRui Paulo 		ctx_offset += sizeof(peer->mi);
2017*5b9c547cSRui Paulo 	}
2018*5b9c547cSRui Paulo 	os_memcpy(context + ctx_offset, participant->mi,
2019*5b9c547cSRui Paulo 		  sizeof(participant->mi));
2020*5b9c547cSRui Paulo 	ctx_offset += sizeof(participant->mi);
2021*5b9c547cSRui Paulo 	os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
2022*5b9c547cSRui Paulo 
2023*5b9c547cSRui Paulo 	if (conf->key_len == 16) {
2024*5b9c547cSRui Paulo 		ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
2025*5b9c547cSRui Paulo 						context, ctx_len, conf->key);
2026*5b9c547cSRui Paulo 	} else if (conf->key_len == 32) {
2027*5b9c547cSRui Paulo 		ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
2028*5b9c547cSRui Paulo 						context, ctx_len, conf->key);
2029*5b9c547cSRui Paulo 	} else {
2030*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
2031*5b9c547cSRui Paulo 		os_free(conf->key);
2032*5b9c547cSRui Paulo 		os_free(conf);
2033*5b9c547cSRui Paulo 		os_free(context);
2034*5b9c547cSRui Paulo 		return -1;
2035*5b9c547cSRui Paulo 	}
2036*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK",
2037*5b9c547cSRui Paulo 		    conf->key, conf->key_len);
2038*5b9c547cSRui Paulo 
2039*5b9c547cSRui Paulo 	os_memcpy(conf->ki.mi, participant->mi, MI_LEN);
2040*5b9c547cSRui Paulo 	conf->ki.kn = participant->kay->dist_kn;
2041*5b9c547cSRui Paulo 	conf->an = participant->kay->dist_an;
2042*5b9c547cSRui Paulo 	conf->offset = kay->macsec_confidentiality;
2043*5b9c547cSRui Paulo 	conf->rx = TRUE;
2044*5b9c547cSRui Paulo 	conf->tx = TRUE;
2045*5b9c547cSRui Paulo 
2046*5b9c547cSRui Paulo 	sa_key = ieee802_1x_kay_init_data_key(conf);
2047*5b9c547cSRui Paulo 	if (!sa_key) {
2048*5b9c547cSRui Paulo 		os_free(conf->key);
2049*5b9c547cSRui Paulo 		os_free(conf);
2050*5b9c547cSRui Paulo 		os_free(context);
2051*5b9c547cSRui Paulo 		return -1;
2052*5b9c547cSRui Paulo 	}
2053*5b9c547cSRui Paulo 	participant->new_key = sa_key;
2054*5b9c547cSRui Paulo 
2055*5b9c547cSRui Paulo 	dl_list_add(&participant->sak_list, &sa_key->list);
2056*5b9c547cSRui Paulo 	ieee802_1x_cp_set_ciphersuite(participant->kay->cp,
2057*5b9c547cSRui Paulo 				      cipher_suite_tbl[kay->macsec_csindex].id);
2058*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(kay->cp);
2059*5b9c547cSRui Paulo 	ieee802_1x_cp_set_offset(kay->cp, conf->offset);
2060*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(kay->cp);
2061*5b9c547cSRui Paulo 	ieee802_1x_cp_set_distributedki(kay->cp, &conf->ki);
2062*5b9c547cSRui Paulo 	ieee802_1x_cp_set_distributedan(kay->cp, conf->an);
2063*5b9c547cSRui Paulo 	ieee802_1x_cp_signal_newsak(kay->cp);
2064*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_step(kay->cp);
2065*5b9c547cSRui Paulo 
2066*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
2067*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list)
2068*5b9c547cSRui Paulo 		peer->sak_used = FALSE;
2069*5b9c547cSRui Paulo 
2070*5b9c547cSRui Paulo 	participant->kay->dist_kn++;
2071*5b9c547cSRui Paulo 	participant->kay->dist_an++;
2072*5b9c547cSRui Paulo 	if (participant->kay->dist_an > 3)
2073*5b9c547cSRui Paulo 		participant->kay->dist_an = 0;
2074*5b9c547cSRui Paulo 
2075*5b9c547cSRui Paulo 	participant->kay->dist_time = time(NULL);
2076*5b9c547cSRui Paulo 
2077*5b9c547cSRui Paulo 	os_free(conf->key);
2078*5b9c547cSRui Paulo 	os_free(conf);
2079*5b9c547cSRui Paulo 	os_free(context);
2080*5b9c547cSRui Paulo 	return 0;
2081*5b9c547cSRui Paulo }
2082*5b9c547cSRui Paulo 
2083*5b9c547cSRui Paulo 
2084*5b9c547cSRui Paulo /**
2085*5b9c547cSRui Paulo  * ieee802_1x_kay_elect_key_server - elect the key server
2086*5b9c547cSRui Paulo  * when to elect: whenever the live peers list changes
2087*5b9c547cSRui Paulo  */
2088*5b9c547cSRui Paulo static int
2089*5b9c547cSRui Paulo ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
2090*5b9c547cSRui Paulo {
2091*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
2092*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *key_server = NULL;
2093*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = participant->kay;
2094*5b9c547cSRui Paulo 	Boolean i_is_key_server;
2095*5b9c547cSRui Paulo 	int i;
2096*5b9c547cSRui Paulo 
2097*5b9c547cSRui Paulo 	if (participant->is_obliged_key_server) {
2098*5b9c547cSRui Paulo 		participant->new_sak = TRUE;
2099*5b9c547cSRui Paulo 		participant->to_dist_sak = FALSE;
2100*5b9c547cSRui Paulo 		ieee802_1x_cp_set_electedself(kay->cp, TRUE);
2101*5b9c547cSRui Paulo 		return 0;
2102*5b9c547cSRui Paulo 	}
2103*5b9c547cSRui Paulo 
2104*5b9c547cSRui Paulo 	/* elect the key server among the peers */
2105*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
2106*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
2107*5b9c547cSRui Paulo 		if (!peer->is_key_server)
2108*5b9c547cSRui Paulo 			continue;
2109*5b9c547cSRui Paulo 
2110*5b9c547cSRui Paulo 		if (!key_server) {
2111*5b9c547cSRui Paulo 			key_server = peer;
2112*5b9c547cSRui Paulo 			continue;
2113*5b9c547cSRui Paulo 		}
2114*5b9c547cSRui Paulo 
2115*5b9c547cSRui Paulo 		if (peer->key_server_priority <
2116*5b9c547cSRui Paulo 		    key_server->key_server_priority) {
2117*5b9c547cSRui Paulo 			key_server = peer;
2118*5b9c547cSRui Paulo 		} else if (peer->key_server_priority ==
2119*5b9c547cSRui Paulo 			   key_server->key_server_priority) {
2120*5b9c547cSRui Paulo 			for (i = 0; i < 6; i++) {
2121*5b9c547cSRui Paulo 				if (peer->sci.addr[i] <
2122*5b9c547cSRui Paulo 				    key_server->sci.addr[i])
2123*5b9c547cSRui Paulo 					key_server = peer;
2124*5b9c547cSRui Paulo 			}
2125*5b9c547cSRui Paulo 		}
2126*5b9c547cSRui Paulo 	}
2127*5b9c547cSRui Paulo 
2128*5b9c547cSRui Paulo 	/* elect the key server between me and the above elected peer */
2129*5b9c547cSRui Paulo 	i_is_key_server = FALSE;
2130*5b9c547cSRui Paulo 	if (key_server && participant->can_be_key_server) {
2131*5b9c547cSRui Paulo 		if (kay->actor_priority
2132*5b9c547cSRui Paulo 			   < key_server->key_server_priority) {
2133*5b9c547cSRui Paulo 			i_is_key_server = TRUE;
2134*5b9c547cSRui Paulo 		} else if (kay->actor_priority
2135*5b9c547cSRui Paulo 					== key_server->key_server_priority) {
2136*5b9c547cSRui Paulo 			for (i = 0; i < 6; i++) {
2137*5b9c547cSRui Paulo 				if (kay->actor_sci.addr[i]
2138*5b9c547cSRui Paulo 					< key_server->sci.addr[i]) {
2139*5b9c547cSRui Paulo 					i_is_key_server = TRUE;
2140*5b9c547cSRui Paulo 				}
2141*5b9c547cSRui Paulo 			}
2142*5b9c547cSRui Paulo 		}
2143*5b9c547cSRui Paulo 	}
2144*5b9c547cSRui Paulo 
2145*5b9c547cSRui Paulo 	if (!key_server && !i_is_key_server) {
2146*5b9c547cSRui Paulo 		participant->principal = FALSE;
2147*5b9c547cSRui Paulo 		participant->is_key_server = FALSE;
2148*5b9c547cSRui Paulo 		participant->is_elected = FALSE;
2149*5b9c547cSRui Paulo 		return 0;
2150*5b9c547cSRui Paulo 	}
2151*5b9c547cSRui Paulo 
2152*5b9c547cSRui Paulo 	if (i_is_key_server) {
2153*5b9c547cSRui Paulo 		ieee802_1x_cp_set_electedself(kay->cp, TRUE);
2154*5b9c547cSRui Paulo 		if (os_memcmp(&kay->key_server_sci, &kay->actor_sci,
2155*5b9c547cSRui Paulo 			      sizeof(kay->key_server_sci))) {
2156*5b9c547cSRui Paulo 			ieee802_1x_cp_signal_chgdserver(kay->cp);
2157*5b9c547cSRui Paulo 			ieee802_1x_cp_sm_step(kay->cp);
2158*5b9c547cSRui Paulo 		}
2159*5b9c547cSRui Paulo 
2160*5b9c547cSRui Paulo 		participant->is_key_server = TRUE;
2161*5b9c547cSRui Paulo 		participant->principal = TRUE;
2162*5b9c547cSRui Paulo 		participant->new_sak = TRUE;
2163*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "KaY: I is elected as key server");
2164*5b9c547cSRui Paulo 		participant->to_dist_sak = FALSE;
2165*5b9c547cSRui Paulo 		participant->is_elected = TRUE;
2166*5b9c547cSRui Paulo 
2167*5b9c547cSRui Paulo 		os_memcpy(&kay->key_server_sci, &kay->actor_sci,
2168*5b9c547cSRui Paulo 			  sizeof(kay->key_server_sci));
2169*5b9c547cSRui Paulo 		kay->key_server_priority = kay->actor_priority;
2170*5b9c547cSRui Paulo 	}
2171*5b9c547cSRui Paulo 
2172*5b9c547cSRui Paulo 	if (key_server) {
2173*5b9c547cSRui Paulo 		ieee802_1x_cp_set_electedself(kay->cp, FALSE);
2174*5b9c547cSRui Paulo 		if (os_memcmp(&kay->key_server_sci, &key_server->sci,
2175*5b9c547cSRui Paulo 			      sizeof(kay->key_server_sci))) {
2176*5b9c547cSRui Paulo 			ieee802_1x_cp_signal_chgdserver(kay->cp);
2177*5b9c547cSRui Paulo 			ieee802_1x_cp_sm_step(kay->cp);
2178*5b9c547cSRui Paulo 		}
2179*5b9c547cSRui Paulo 
2180*5b9c547cSRui Paulo 		participant->is_key_server = FALSE;
2181*5b9c547cSRui Paulo 		participant->principal = TRUE;
2182*5b9c547cSRui Paulo 		participant->is_elected = TRUE;
2183*5b9c547cSRui Paulo 
2184*5b9c547cSRui Paulo 		os_memcpy(&kay->key_server_sci, &key_server->sci,
2185*5b9c547cSRui Paulo 			  sizeof(kay->key_server_sci));
2186*5b9c547cSRui Paulo 		kay->key_server_priority = key_server->key_server_priority;
2187*5b9c547cSRui Paulo 	}
2188*5b9c547cSRui Paulo 
2189*5b9c547cSRui Paulo 	return 0;
2190*5b9c547cSRui Paulo }
2191*5b9c547cSRui Paulo 
2192*5b9c547cSRui Paulo 
2193*5b9c547cSRui Paulo /**
2194*5b9c547cSRui Paulo  * ieee802_1x_kay_decide_macsec_use - the key server determinate
2195*5b9c547cSRui Paulo  *		 how to use MACsec: whether use MACsec and its capability
2196*5b9c547cSRui Paulo  * protectFrames will be advised if the key server and one of its live peers are
2197*5b9c547cSRui Paulo  * MACsec capable and one of those request MACsec protection
2198*5b9c547cSRui Paulo  */
2199*5b9c547cSRui Paulo static int
2200*5b9c547cSRui Paulo ieee802_1x_kay_decide_macsec_use(
2201*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
2202*5b9c547cSRui Paulo {
2203*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = participant->kay;
2204*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
2205*5b9c547cSRui Paulo 	enum macsec_cap less_capability;
2206*5b9c547cSRui Paulo 	Boolean has_peer;
2207*5b9c547cSRui Paulo 
2208*5b9c547cSRui Paulo 	if (!participant->is_key_server)
2209*5b9c547cSRui Paulo 		return -1;
2210*5b9c547cSRui Paulo 
2211*5b9c547cSRui Paulo 	/* key server self is MACsec-desired and requesting MACsec */
2212*5b9c547cSRui Paulo 	if (!kay->macsec_desired) {
2213*5b9c547cSRui Paulo 		participant->advised_desired = FALSE;
2214*5b9c547cSRui Paulo 		return -1;
2215*5b9c547cSRui Paulo 	}
2216*5b9c547cSRui Paulo 	if (kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
2217*5b9c547cSRui Paulo 		participant->advised_desired = FALSE;
2218*5b9c547cSRui Paulo 		return -1;
2219*5b9c547cSRui Paulo 	}
2220*5b9c547cSRui Paulo 	less_capability = kay->macsec_capable;
2221*5b9c547cSRui Paulo 
2222*5b9c547cSRui Paulo 	/* at least one of peers is MACsec-desired and requesting MACsec */
2223*5b9c547cSRui Paulo 	has_peer = FALSE;
2224*5b9c547cSRui Paulo 	dl_list_for_each(peer, &participant->live_peers,
2225*5b9c547cSRui Paulo 			 struct ieee802_1x_kay_peer, list) {
2226*5b9c547cSRui Paulo 		if (!peer->macsec_desired)
2227*5b9c547cSRui Paulo 			continue;
2228*5b9c547cSRui Paulo 
2229*5b9c547cSRui Paulo 		if (peer->macsec_capbility == MACSEC_CAP_NOT_IMPLEMENTED)
2230*5b9c547cSRui Paulo 			continue;
2231*5b9c547cSRui Paulo 
2232*5b9c547cSRui Paulo 		less_capability = (less_capability < peer->macsec_capbility) ?
2233*5b9c547cSRui Paulo 			less_capability : peer->macsec_capbility;
2234*5b9c547cSRui Paulo 		has_peer = TRUE;
2235*5b9c547cSRui Paulo 	}
2236*5b9c547cSRui Paulo 
2237*5b9c547cSRui Paulo 	if (has_peer) {
2238*5b9c547cSRui Paulo 		participant->advised_desired = TRUE;
2239*5b9c547cSRui Paulo 		participant->advised_capability = less_capability;
2240*5b9c547cSRui Paulo 		kay->authenticated = FALSE;
2241*5b9c547cSRui Paulo 		kay->secured = TRUE;
2242*5b9c547cSRui Paulo 		kay->failed = FALSE;
2243*5b9c547cSRui Paulo 		ieee802_1x_cp_connect_secure(kay->cp);
2244*5b9c547cSRui Paulo 		ieee802_1x_cp_sm_step(kay->cp);
2245*5b9c547cSRui Paulo 	} else {
2246*5b9c547cSRui Paulo 		participant->advised_desired = FALSE;
2247*5b9c547cSRui Paulo 		participant->advised_capability = MACSEC_CAP_NOT_IMPLEMENTED;
2248*5b9c547cSRui Paulo 		participant->to_use_sak = FALSE;
2249*5b9c547cSRui Paulo 		kay->authenticated = TRUE;
2250*5b9c547cSRui Paulo 		kay->secured = FALSE;
2251*5b9c547cSRui Paulo 		kay->failed = FALSE;
2252*5b9c547cSRui Paulo 		kay->ltx_kn = 0;
2253*5b9c547cSRui Paulo 		kay->ltx_an = 0;
2254*5b9c547cSRui Paulo 		kay->lrx_kn = 0;
2255*5b9c547cSRui Paulo 		kay->lrx_an = 0;
2256*5b9c547cSRui Paulo 		kay->otx_kn = 0;
2257*5b9c547cSRui Paulo 		kay->otx_an = 0;
2258*5b9c547cSRui Paulo 		kay->orx_kn = 0;
2259*5b9c547cSRui Paulo 		kay->orx_an = 0;
2260*5b9c547cSRui Paulo 		ieee802_1x_cp_connect_authenticated(kay->cp);
2261*5b9c547cSRui Paulo 		ieee802_1x_cp_sm_step(kay->cp);
2262*5b9c547cSRui Paulo 	}
2263*5b9c547cSRui Paulo 
2264*5b9c547cSRui Paulo 	return 0;
2265*5b9c547cSRui Paulo }
2266*5b9c547cSRui Paulo 
2267*5b9c547cSRui Paulo static const u8 pae_group_addr[ETH_ALEN] = {
2268*5b9c547cSRui Paulo 	0x01, 0x80, 0xc2, 0x00, 0x00, 0x03
2269*5b9c547cSRui Paulo };
2270*5b9c547cSRui Paulo 
2271*5b9c547cSRui Paulo 
2272*5b9c547cSRui Paulo /**
2273*5b9c547cSRui Paulo  * ieee802_1x_kay_encode_mkpdu -
2274*5b9c547cSRui Paulo  */
2275*5b9c547cSRui Paulo static int
2276*5b9c547cSRui Paulo ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
2277*5b9c547cSRui Paulo 			    struct wpabuf *pbuf)
2278*5b9c547cSRui Paulo {
2279*5b9c547cSRui Paulo 	unsigned int i;
2280*5b9c547cSRui Paulo 	struct ieee8023_hdr *ether_hdr;
2281*5b9c547cSRui Paulo 	struct ieee802_1x_hdr *eapol_hdr;
2282*5b9c547cSRui Paulo 
2283*5b9c547cSRui Paulo 	ether_hdr = wpabuf_put(pbuf, sizeof(*ether_hdr));
2284*5b9c547cSRui Paulo 	os_memcpy(ether_hdr->dest, pae_group_addr, sizeof(ether_hdr->dest));
2285*5b9c547cSRui Paulo 	os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
2286*5b9c547cSRui Paulo 		  sizeof(ether_hdr->dest));
2287*5b9c547cSRui Paulo 	ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
2288*5b9c547cSRui Paulo 
2289*5b9c547cSRui Paulo 	eapol_hdr = wpabuf_put(pbuf, sizeof(*eapol_hdr));
2290*5b9c547cSRui Paulo 	eapol_hdr->version = EAPOL_VERSION;
2291*5b9c547cSRui Paulo 	eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
2292*5b9c547cSRui Paulo 	eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
2293*5b9c547cSRui Paulo 
2294*5b9c547cSRui Paulo 	for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
2295*5b9c547cSRui Paulo 		if (mak_body_handler[i].body_present &&
2296*5b9c547cSRui Paulo 		    mak_body_handler[i].body_present(participant)) {
2297*5b9c547cSRui Paulo 			if (mak_body_handler[i].body_tx(participant, pbuf))
2298*5b9c547cSRui Paulo 				return -1;
2299*5b9c547cSRui Paulo 		}
2300*5b9c547cSRui Paulo 	}
2301*5b9c547cSRui Paulo 
2302*5b9c547cSRui Paulo 	return 0;
2303*5b9c547cSRui Paulo }
2304*5b9c547cSRui Paulo 
2305*5b9c547cSRui Paulo /**
2306*5b9c547cSRui Paulo  * ieee802_1x_participant_send_mkpdu -
2307*5b9c547cSRui Paulo  */
2308*5b9c547cSRui Paulo static int
2309*5b9c547cSRui Paulo ieee802_1x_participant_send_mkpdu(
2310*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant)
2311*5b9c547cSRui Paulo {
2312*5b9c547cSRui Paulo 	struct wpabuf *buf;
2313*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = participant->kay;
2314*5b9c547cSRui Paulo 	size_t length = 0;
2315*5b9c547cSRui Paulo 	unsigned int i;
2316*5b9c547cSRui Paulo 
2317*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
2318*5b9c547cSRui Paulo 	length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
2319*5b9c547cSRui Paulo 	for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
2320*5b9c547cSRui Paulo 		if (mak_body_handler[i].body_present &&
2321*5b9c547cSRui Paulo 		    mak_body_handler[i].body_present(participant))
2322*5b9c547cSRui Paulo 			length += mak_body_handler[i].body_length(participant);
2323*5b9c547cSRui Paulo 	}
2324*5b9c547cSRui Paulo 
2325*5b9c547cSRui Paulo 	buf = wpabuf_alloc(length);
2326*5b9c547cSRui Paulo 	if (!buf) {
2327*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: out of memory");
2328*5b9c547cSRui Paulo 		return -1;
2329*5b9c547cSRui Paulo 	}
2330*5b9c547cSRui Paulo 
2331*5b9c547cSRui Paulo 	if (ieee802_1x_kay_encode_mkpdu(participant, buf)) {
2332*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail!");
2333*5b9c547cSRui Paulo 		return -1;
2334*5b9c547cSRui Paulo 	}
2335*5b9c547cSRui Paulo 
2336*5b9c547cSRui Paulo 	l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
2337*5b9c547cSRui Paulo 	wpabuf_free(buf);
2338*5b9c547cSRui Paulo 
2339*5b9c547cSRui Paulo 	kay->active = TRUE;
2340*5b9c547cSRui Paulo 	participant->active = TRUE;
2341*5b9c547cSRui Paulo 
2342*5b9c547cSRui Paulo 	return 0;
2343*5b9c547cSRui Paulo }
2344*5b9c547cSRui Paulo 
2345*5b9c547cSRui Paulo 
2346*5b9c547cSRui Paulo static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa);
2347*5b9c547cSRui Paulo /**
2348*5b9c547cSRui Paulo  * ieee802_1x_participant_timer -
2349*5b9c547cSRui Paulo  */
2350*5b9c547cSRui Paulo static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
2351*5b9c547cSRui Paulo {
2352*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
2353*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay;
2354*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer, *pre_peer;
2355*5b9c547cSRui Paulo 	time_t now = time(NULL);
2356*5b9c547cSRui Paulo 	Boolean lp_changed;
2357*5b9c547cSRui Paulo 	struct receive_sc *rxsc, *pre_rxsc;
2358*5b9c547cSRui Paulo 	struct transmit_sa *txsa, *pre_txsa;
2359*5b9c547cSRui Paulo 
2360*5b9c547cSRui Paulo 	participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
2361*5b9c547cSRui Paulo 	kay = participant->kay;
2362*5b9c547cSRui Paulo 	if (participant->cak_life) {
2363*5b9c547cSRui Paulo 		if (now > participant->cak_life) {
2364*5b9c547cSRui Paulo 			kay->authenticated = FALSE;
2365*5b9c547cSRui Paulo 			kay->secured = FALSE;
2366*5b9c547cSRui Paulo 			kay->failed = TRUE;
2367*5b9c547cSRui Paulo 			ieee802_1x_kay_delete_mka(kay, &participant->ckn);
2368*5b9c547cSRui Paulo 			return;
2369*5b9c547cSRui Paulo 		}
2370*5b9c547cSRui Paulo 	}
2371*5b9c547cSRui Paulo 
2372*5b9c547cSRui Paulo 	/* should delete MKA instance if there are not live peers
2373*5b9c547cSRui Paulo 	 * when the MKA life elapsed since its creating */
2374*5b9c547cSRui Paulo 	if (participant->mka_life) {
2375*5b9c547cSRui Paulo 		if (dl_list_empty(&participant->live_peers)) {
2376*5b9c547cSRui Paulo 			if (now > participant->mka_life) {
2377*5b9c547cSRui Paulo 				kay->authenticated = FALSE;
2378*5b9c547cSRui Paulo 				kay->secured = FALSE;
2379*5b9c547cSRui Paulo 				kay->failed = TRUE;
2380*5b9c547cSRui Paulo 				ieee802_1x_kay_delete_mka(kay,
2381*5b9c547cSRui Paulo 							  &participant->ckn);
2382*5b9c547cSRui Paulo 				return;
2383*5b9c547cSRui Paulo 			}
2384*5b9c547cSRui Paulo 		} else {
2385*5b9c547cSRui Paulo 			participant->mka_life = 0;
2386*5b9c547cSRui Paulo 		}
2387*5b9c547cSRui Paulo 	}
2388*5b9c547cSRui Paulo 
2389*5b9c547cSRui Paulo 	lp_changed = FALSE;
2390*5b9c547cSRui Paulo 	dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
2391*5b9c547cSRui Paulo 			      struct ieee802_1x_kay_peer, list) {
2392*5b9c547cSRui Paulo 		if (now > peer->expire) {
2393*5b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "KaY: Live peer removed");
2394*5b9c547cSRui Paulo 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
2395*5b9c547cSRui Paulo 				    sizeof(peer->mi));
2396*5b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
2397*5b9c547cSRui Paulo 			dl_list_for_each_safe(rxsc, pre_rxsc,
2398*5b9c547cSRui Paulo 					      &participant->rxsc_list,
2399*5b9c547cSRui Paulo 					      struct receive_sc, list) {
2400*5b9c547cSRui Paulo 				if (os_memcmp(&rxsc->sci, &peer->sci,
2401*5b9c547cSRui Paulo 					      sizeof(rxsc->sci)) == 0) {
2402*5b9c547cSRui Paulo 					secy_delete_receive_sc(kay, rxsc);
2403*5b9c547cSRui Paulo 					ieee802_1x_kay_deinit_receive_sc(
2404*5b9c547cSRui Paulo 						participant, rxsc);
2405*5b9c547cSRui Paulo 				}
2406*5b9c547cSRui Paulo 			}
2407*5b9c547cSRui Paulo 			dl_list_del(&peer->list);
2408*5b9c547cSRui Paulo 			os_free(peer);
2409*5b9c547cSRui Paulo 			lp_changed = TRUE;
2410*5b9c547cSRui Paulo 		}
2411*5b9c547cSRui Paulo 	}
2412*5b9c547cSRui Paulo 
2413*5b9c547cSRui Paulo 	if (lp_changed) {
2414*5b9c547cSRui Paulo 		if (dl_list_empty(&participant->live_peers)) {
2415*5b9c547cSRui Paulo 			participant->advised_desired = FALSE;
2416*5b9c547cSRui Paulo 			participant->advised_capability =
2417*5b9c547cSRui Paulo 				MACSEC_CAP_NOT_IMPLEMENTED;
2418*5b9c547cSRui Paulo 			participant->to_use_sak = FALSE;
2419*5b9c547cSRui Paulo 			kay->authenticated = TRUE;
2420*5b9c547cSRui Paulo 			kay->secured = FALSE;
2421*5b9c547cSRui Paulo 			kay->failed = FALSE;
2422*5b9c547cSRui Paulo 			kay->ltx_kn = 0;
2423*5b9c547cSRui Paulo 			kay->ltx_an = 0;
2424*5b9c547cSRui Paulo 			kay->lrx_kn = 0;
2425*5b9c547cSRui Paulo 			kay->lrx_an = 0;
2426*5b9c547cSRui Paulo 			kay->otx_kn = 0;
2427*5b9c547cSRui Paulo 			kay->otx_an = 0;
2428*5b9c547cSRui Paulo 			kay->orx_kn = 0;
2429*5b9c547cSRui Paulo 			kay->orx_an = 0;
2430*5b9c547cSRui Paulo 			dl_list_for_each_safe(txsa, pre_txsa,
2431*5b9c547cSRui Paulo 					      &participant->txsc->sa_list,
2432*5b9c547cSRui Paulo 					      struct transmit_sa, list) {
2433*5b9c547cSRui Paulo 				secy_disable_transmit_sa(kay, txsa);
2434*5b9c547cSRui Paulo 				ieee802_1x_kay_deinit_transmit_sa(txsa);
2435*5b9c547cSRui Paulo 			}
2436*5b9c547cSRui Paulo 
2437*5b9c547cSRui Paulo 			ieee802_1x_cp_connect_authenticated(kay->cp);
2438*5b9c547cSRui Paulo 			ieee802_1x_cp_sm_step(kay->cp);
2439*5b9c547cSRui Paulo 		} else {
2440*5b9c547cSRui Paulo 			ieee802_1x_kay_elect_key_server(participant);
2441*5b9c547cSRui Paulo 			ieee802_1x_kay_decide_macsec_use(participant);
2442*5b9c547cSRui Paulo 		}
2443*5b9c547cSRui Paulo 	}
2444*5b9c547cSRui Paulo 
2445*5b9c547cSRui Paulo 	dl_list_for_each_safe(peer, pre_peer, &participant->potential_peers,
2446*5b9c547cSRui Paulo 			      struct ieee802_1x_kay_peer, list) {
2447*5b9c547cSRui Paulo 		if (now > peer->expire) {
2448*5b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "KaY: Potential peer removed");
2449*5b9c547cSRui Paulo 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
2450*5b9c547cSRui Paulo 				    sizeof(peer->mi));
2451*5b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
2452*5b9c547cSRui Paulo 			dl_list_del(&peer->list);
2453*5b9c547cSRui Paulo 			os_free(peer);
2454*5b9c547cSRui Paulo 		}
2455*5b9c547cSRui Paulo 	}
2456*5b9c547cSRui Paulo 
2457*5b9c547cSRui Paulo 	if (participant->new_sak) {
2458*5b9c547cSRui Paulo 		if (!ieee802_1x_kay_generate_new_sak(participant))
2459*5b9c547cSRui Paulo 			participant->to_dist_sak = TRUE;
2460*5b9c547cSRui Paulo 
2461*5b9c547cSRui Paulo 		participant->new_sak = FALSE;
2462*5b9c547cSRui Paulo 	}
2463*5b9c547cSRui Paulo 
2464*5b9c547cSRui Paulo 	if (participant->retry_count < MAX_RETRY_CNT) {
2465*5b9c547cSRui Paulo 		ieee802_1x_participant_send_mkpdu(participant);
2466*5b9c547cSRui Paulo 		participant->retry_count++;
2467*5b9c547cSRui Paulo 	}
2468*5b9c547cSRui Paulo 
2469*5b9c547cSRui Paulo 	eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
2470*5b9c547cSRui Paulo 			       ieee802_1x_participant_timer,
2471*5b9c547cSRui Paulo 			       participant, NULL);
2472*5b9c547cSRui Paulo }
2473*5b9c547cSRui Paulo 
2474*5b9c547cSRui Paulo 
2475*5b9c547cSRui Paulo /**
2476*5b9c547cSRui Paulo  * ieee802_1x_kay_init_transmit_sa -
2477*5b9c547cSRui Paulo  */
2478*5b9c547cSRui Paulo static struct transmit_sa *
2479*5b9c547cSRui Paulo ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
2480*5b9c547cSRui Paulo 				struct data_key *key)
2481*5b9c547cSRui Paulo {
2482*5b9c547cSRui Paulo 	struct transmit_sa *psa;
2483*5b9c547cSRui Paulo 
2484*5b9c547cSRui Paulo 	key->tx_latest = TRUE;
2485*5b9c547cSRui Paulo 	key->rx_latest = TRUE;
2486*5b9c547cSRui Paulo 
2487*5b9c547cSRui Paulo 	psa = os_zalloc(sizeof(*psa));
2488*5b9c547cSRui Paulo 	if (!psa) {
2489*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
2490*5b9c547cSRui Paulo 		return NULL;
2491*5b9c547cSRui Paulo 	}
2492*5b9c547cSRui Paulo 
2493*5b9c547cSRui Paulo 	if (key->confidentiality_offset >= CONFIDENTIALITY_OFFSET_0 &&
2494*5b9c547cSRui Paulo 	    key->confidentiality_offset <= CONFIDENTIALITY_OFFSET_50)
2495*5b9c547cSRui Paulo 		psa->confidentiality = TRUE;
2496*5b9c547cSRui Paulo 	else
2497*5b9c547cSRui Paulo 		psa->confidentiality = FALSE;
2498*5b9c547cSRui Paulo 
2499*5b9c547cSRui Paulo 	psa->an = an;
2500*5b9c547cSRui Paulo 	psa->pkey = key;
2501*5b9c547cSRui Paulo 	psa->next_pn = next_PN;
2502*5b9c547cSRui Paulo 	psa->sc = psc;
2503*5b9c547cSRui Paulo 
2504*5b9c547cSRui Paulo 	os_get_time(&psa->created_time);
2505*5b9c547cSRui Paulo 	psa->in_use = FALSE;
2506*5b9c547cSRui Paulo 
2507*5b9c547cSRui Paulo 	dl_list_add(&psc->sa_list, &psa->list);
2508*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
2509*5b9c547cSRui Paulo 		   "KaY: Create transmit SA(an: %d, next_PN: %u) of SC(channel: %d)",
2510*5b9c547cSRui Paulo 		   (int) an, next_PN, psc->channel);
2511*5b9c547cSRui Paulo 
2512*5b9c547cSRui Paulo 	return psa;
2513*5b9c547cSRui Paulo }
2514*5b9c547cSRui Paulo 
2515*5b9c547cSRui Paulo 
2516*5b9c547cSRui Paulo /**
2517*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit_transmit_sa -
2518*5b9c547cSRui Paulo  */
2519*5b9c547cSRui Paulo static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
2520*5b9c547cSRui Paulo {
2521*5b9c547cSRui Paulo 	psa->pkey = NULL;
2522*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
2523*5b9c547cSRui Paulo 		   "KaY: Delete transmit SA(an: %d) of SC(channel: %d)",
2524*5b9c547cSRui Paulo 		   psa->an, psa->sc->channel);
2525*5b9c547cSRui Paulo 	dl_list_del(&psa->list);
2526*5b9c547cSRui Paulo 	os_free(psa);
2527*5b9c547cSRui Paulo }
2528*5b9c547cSRui Paulo 
2529*5b9c547cSRui Paulo 
2530*5b9c547cSRui Paulo /**
2531*5b9c547cSRui Paulo  * init_transmit_sc -
2532*5b9c547cSRui Paulo  */
2533*5b9c547cSRui Paulo static struct transmit_sc *
2534*5b9c547cSRui Paulo ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
2535*5b9c547cSRui Paulo 				int channel)
2536*5b9c547cSRui Paulo {
2537*5b9c547cSRui Paulo 	struct transmit_sc *psc;
2538*5b9c547cSRui Paulo 
2539*5b9c547cSRui Paulo 	psc = os_zalloc(sizeof(*psc));
2540*5b9c547cSRui Paulo 	if (!psc) {
2541*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
2542*5b9c547cSRui Paulo 		return NULL;
2543*5b9c547cSRui Paulo 	}
2544*5b9c547cSRui Paulo 	os_memcpy(&psc->sci, sci, sizeof(psc->sci));
2545*5b9c547cSRui Paulo 	psc->channel = channel;
2546*5b9c547cSRui Paulo 
2547*5b9c547cSRui Paulo 	os_get_time(&psc->created_time);
2548*5b9c547cSRui Paulo 	psc->transmitting = FALSE;
2549*5b9c547cSRui Paulo 	psc->encoding_sa = FALSE;
2550*5b9c547cSRui Paulo 	psc->enciphering_sa = FALSE;
2551*5b9c547cSRui Paulo 
2552*5b9c547cSRui Paulo 	dl_list_init(&psc->sa_list);
2553*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Create transmit SC(channel: %d)", channel);
2554*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)sci , sizeof(*sci));
2555*5b9c547cSRui Paulo 
2556*5b9c547cSRui Paulo 	return psc;
2557*5b9c547cSRui Paulo }
2558*5b9c547cSRui Paulo 
2559*5b9c547cSRui Paulo 
2560*5b9c547cSRui Paulo /**
2561*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit_transmit_sc -
2562*5b9c547cSRui Paulo  */
2563*5b9c547cSRui Paulo static void
2564*5b9c547cSRui Paulo ieee802_1x_kay_deinit_transmit_sc(
2565*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant, struct transmit_sc *psc)
2566*5b9c547cSRui Paulo {
2567*5b9c547cSRui Paulo 	struct transmit_sa *psa, *tmp;
2568*5b9c547cSRui Paulo 
2569*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Delete transmit SC(channel: %d)",
2570*5b9c547cSRui Paulo 		   psc->channel);
2571*5b9c547cSRui Paulo 	dl_list_for_each_safe(psa, tmp, &psc->sa_list, struct transmit_sa,
2572*5b9c547cSRui Paulo 			      list) {
2573*5b9c547cSRui Paulo 		secy_disable_transmit_sa(participant->kay, psa);
2574*5b9c547cSRui Paulo 		ieee802_1x_kay_deinit_transmit_sa(psa);
2575*5b9c547cSRui Paulo 	}
2576*5b9c547cSRui Paulo 
2577*5b9c547cSRui Paulo 	os_free(psc);
2578*5b9c547cSRui Paulo }
2579*5b9c547cSRui Paulo 
2580*5b9c547cSRui Paulo 
2581*5b9c547cSRui Paulo /****************** Interface between CP and KAY *********************/
2582*5b9c547cSRui Paulo /**
2583*5b9c547cSRui Paulo  * ieee802_1x_kay_set_latest_sa_attr -
2584*5b9c547cSRui Paulo  */
2585*5b9c547cSRui Paulo int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
2586*5b9c547cSRui Paulo 				      struct ieee802_1x_mka_ki *lki, u8 lan,
2587*5b9c547cSRui Paulo 				      Boolean ltx, Boolean lrx)
2588*5b9c547cSRui Paulo {
2589*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2590*5b9c547cSRui Paulo 
2591*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2592*5b9c547cSRui Paulo 	if (!principal)
2593*5b9c547cSRui Paulo 		return -1;
2594*5b9c547cSRui Paulo 
2595*5b9c547cSRui Paulo 	if (!lki)
2596*5b9c547cSRui Paulo 		os_memset(&principal->lki, 0, sizeof(principal->lki));
2597*5b9c547cSRui Paulo 	else
2598*5b9c547cSRui Paulo 		os_memcpy(&principal->lki, lki, sizeof(principal->lki));
2599*5b9c547cSRui Paulo 
2600*5b9c547cSRui Paulo 	principal->lan = lan;
2601*5b9c547cSRui Paulo 	principal->ltx = ltx;
2602*5b9c547cSRui Paulo 	principal->lrx = lrx;
2603*5b9c547cSRui Paulo 	if (!lki) {
2604*5b9c547cSRui Paulo 		kay->ltx_kn = 0;
2605*5b9c547cSRui Paulo 		kay->lrx_kn = 0;
2606*5b9c547cSRui Paulo 	} else {
2607*5b9c547cSRui Paulo 		kay->ltx_kn = lki->kn;
2608*5b9c547cSRui Paulo 		kay->lrx_kn = lki->kn;
2609*5b9c547cSRui Paulo 	}
2610*5b9c547cSRui Paulo 	kay->ltx_an = lan;
2611*5b9c547cSRui Paulo 	kay->lrx_an = lan;
2612*5b9c547cSRui Paulo 
2613*5b9c547cSRui Paulo 	return 0;
2614*5b9c547cSRui Paulo }
2615*5b9c547cSRui Paulo 
2616*5b9c547cSRui Paulo 
2617*5b9c547cSRui Paulo /**
2618*5b9c547cSRui Paulo  * ieee802_1x_kay_set_old_sa_attr -
2619*5b9c547cSRui Paulo  */
2620*5b9c547cSRui Paulo int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
2621*5b9c547cSRui Paulo 				   struct ieee802_1x_mka_ki *oki,
2622*5b9c547cSRui Paulo 				   u8 oan, Boolean otx, Boolean orx)
2623*5b9c547cSRui Paulo {
2624*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2625*5b9c547cSRui Paulo 
2626*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2627*5b9c547cSRui Paulo 	if (!principal)
2628*5b9c547cSRui Paulo 		return -1;
2629*5b9c547cSRui Paulo 
2630*5b9c547cSRui Paulo 	if (!oki)
2631*5b9c547cSRui Paulo 		os_memset(&principal->oki, 0, sizeof(principal->oki));
2632*5b9c547cSRui Paulo 	else
2633*5b9c547cSRui Paulo 		os_memcpy(&principal->oki, oki, sizeof(principal->oki));
2634*5b9c547cSRui Paulo 
2635*5b9c547cSRui Paulo 	principal->oan = oan;
2636*5b9c547cSRui Paulo 	principal->otx = otx;
2637*5b9c547cSRui Paulo 	principal->orx = orx;
2638*5b9c547cSRui Paulo 
2639*5b9c547cSRui Paulo 	if (!oki) {
2640*5b9c547cSRui Paulo 		kay->otx_kn = 0;
2641*5b9c547cSRui Paulo 		kay->orx_kn = 0;
2642*5b9c547cSRui Paulo 	} else {
2643*5b9c547cSRui Paulo 		kay->otx_kn = oki->kn;
2644*5b9c547cSRui Paulo 		kay->orx_kn = oki->kn;
2645*5b9c547cSRui Paulo 	}
2646*5b9c547cSRui Paulo 	kay->otx_an = oan;
2647*5b9c547cSRui Paulo 	kay->orx_an = oan;
2648*5b9c547cSRui Paulo 
2649*5b9c547cSRui Paulo 	return 0;
2650*5b9c547cSRui Paulo }
2651*5b9c547cSRui Paulo 
2652*5b9c547cSRui Paulo 
2653*5b9c547cSRui Paulo /**
2654*5b9c547cSRui Paulo  * ieee802_1x_kay_create_sas -
2655*5b9c547cSRui Paulo  */
2656*5b9c547cSRui Paulo int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
2657*5b9c547cSRui Paulo 			      struct ieee802_1x_mka_ki *lki)
2658*5b9c547cSRui Paulo {
2659*5b9c547cSRui Paulo 	struct data_key *sa_key, *latest_sak;
2660*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2661*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
2662*5b9c547cSRui Paulo 	struct receive_sa *rxsa;
2663*5b9c547cSRui Paulo 	struct transmit_sa *txsa;
2664*5b9c547cSRui Paulo 
2665*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2666*5b9c547cSRui Paulo 	if (!principal)
2667*5b9c547cSRui Paulo 		return -1;
2668*5b9c547cSRui Paulo 
2669*5b9c547cSRui Paulo 	latest_sak = NULL;
2670*5b9c547cSRui Paulo 	dl_list_for_each(sa_key, &principal->sak_list, struct data_key, list) {
2671*5b9c547cSRui Paulo 		if (is_ki_equal(&sa_key->key_identifier, lki)) {
2672*5b9c547cSRui Paulo 			sa_key->rx_latest = TRUE;
2673*5b9c547cSRui Paulo 			sa_key->tx_latest = TRUE;
2674*5b9c547cSRui Paulo 			latest_sak = sa_key;
2675*5b9c547cSRui Paulo 			principal->to_use_sak = TRUE;
2676*5b9c547cSRui Paulo 		} else {
2677*5b9c547cSRui Paulo 			sa_key->rx_latest = FALSE;
2678*5b9c547cSRui Paulo 			sa_key->tx_latest = FALSE;
2679*5b9c547cSRui Paulo 		}
2680*5b9c547cSRui Paulo 	}
2681*5b9c547cSRui Paulo 	if (!latest_sak) {
2682*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "lki related sak not found");
2683*5b9c547cSRui Paulo 		return -1;
2684*5b9c547cSRui Paulo 	}
2685*5b9c547cSRui Paulo 
2686*5b9c547cSRui Paulo 	dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
2687*5b9c547cSRui Paulo 		rxsa = ieee802_1x_kay_init_receive_sa(rxsc, latest_sak->an, 1,
2688*5b9c547cSRui Paulo 						      latest_sak);
2689*5b9c547cSRui Paulo 		if (!rxsa)
2690*5b9c547cSRui Paulo 			return -1;
2691*5b9c547cSRui Paulo 
2692*5b9c547cSRui Paulo 		secy_create_receive_sa(kay, rxsa);
2693*5b9c547cSRui Paulo 	}
2694*5b9c547cSRui Paulo 
2695*5b9c547cSRui Paulo 	txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
2696*5b9c547cSRui Paulo 					       1, latest_sak);
2697*5b9c547cSRui Paulo 	if (!txsa)
2698*5b9c547cSRui Paulo 		return -1;
2699*5b9c547cSRui Paulo 
2700*5b9c547cSRui Paulo 	secy_create_transmit_sa(kay, txsa);
2701*5b9c547cSRui Paulo 
2702*5b9c547cSRui Paulo 
2703*5b9c547cSRui Paulo 
2704*5b9c547cSRui Paulo 	return 0;
2705*5b9c547cSRui Paulo }
2706*5b9c547cSRui Paulo 
2707*5b9c547cSRui Paulo 
2708*5b9c547cSRui Paulo /**
2709*5b9c547cSRui Paulo  * ieee802_1x_kay_delete_sas -
2710*5b9c547cSRui Paulo  */
2711*5b9c547cSRui Paulo int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
2712*5b9c547cSRui Paulo 			      struct ieee802_1x_mka_ki *ki)
2713*5b9c547cSRui Paulo {
2714*5b9c547cSRui Paulo 	struct data_key *sa_key, *pre_key;
2715*5b9c547cSRui Paulo 	struct transmit_sa *txsa, *pre_txsa;
2716*5b9c547cSRui Paulo 	struct receive_sa *rxsa, *pre_rxsa;
2717*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
2718*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2719*5b9c547cSRui Paulo 
2720*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: Entry into %s", __func__);
2721*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2722*5b9c547cSRui Paulo 	if (!principal)
2723*5b9c547cSRui Paulo 		return -1;
2724*5b9c547cSRui Paulo 
2725*5b9c547cSRui Paulo 	/* remove the transmit sa */
2726*5b9c547cSRui Paulo 	dl_list_for_each_safe(txsa, pre_txsa, &principal->txsc->sa_list,
2727*5b9c547cSRui Paulo 			      struct transmit_sa, list) {
2728*5b9c547cSRui Paulo 		if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
2729*5b9c547cSRui Paulo 			secy_disable_transmit_sa(kay, txsa);
2730*5b9c547cSRui Paulo 			ieee802_1x_kay_deinit_transmit_sa(txsa);
2731*5b9c547cSRui Paulo 		}
2732*5b9c547cSRui Paulo 	}
2733*5b9c547cSRui Paulo 
2734*5b9c547cSRui Paulo 	/* remove the receive sa */
2735*5b9c547cSRui Paulo 	dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
2736*5b9c547cSRui Paulo 		dl_list_for_each_safe(rxsa, pre_rxsa, &rxsc->sa_list,
2737*5b9c547cSRui Paulo 				      struct receive_sa, list) {
2738*5b9c547cSRui Paulo 			if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
2739*5b9c547cSRui Paulo 				secy_disable_receive_sa(kay, rxsa);
2740*5b9c547cSRui Paulo 				ieee802_1x_kay_deinit_receive_sa(rxsa);
2741*5b9c547cSRui Paulo 			}
2742*5b9c547cSRui Paulo 		}
2743*5b9c547cSRui Paulo 	}
2744*5b9c547cSRui Paulo 
2745*5b9c547cSRui Paulo 	/* remove the sak */
2746*5b9c547cSRui Paulo 	dl_list_for_each_safe(sa_key, pre_key, &principal->sak_list,
2747*5b9c547cSRui Paulo 			      struct data_key, list) {
2748*5b9c547cSRui Paulo 		if (is_ki_equal(&sa_key->key_identifier, ki)) {
2749*5b9c547cSRui Paulo 			ieee802_1x_kay_deinit_data_key(sa_key);
2750*5b9c547cSRui Paulo 			break;
2751*5b9c547cSRui Paulo 		}
2752*5b9c547cSRui Paulo 		if (principal->new_key == sa_key)
2753*5b9c547cSRui Paulo 			principal->new_key = NULL;
2754*5b9c547cSRui Paulo 	}
2755*5b9c547cSRui Paulo 
2756*5b9c547cSRui Paulo 	return 0;
2757*5b9c547cSRui Paulo }
2758*5b9c547cSRui Paulo 
2759*5b9c547cSRui Paulo 
2760*5b9c547cSRui Paulo /**
2761*5b9c547cSRui Paulo  * ieee802_1x_kay_enable_tx_sas -
2762*5b9c547cSRui Paulo  */
2763*5b9c547cSRui Paulo int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
2764*5b9c547cSRui Paulo 				 struct ieee802_1x_mka_ki *lki)
2765*5b9c547cSRui Paulo {
2766*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2767*5b9c547cSRui Paulo 	struct transmit_sa *txsa;
2768*5b9c547cSRui Paulo 
2769*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2770*5b9c547cSRui Paulo 	if (!principal)
2771*5b9c547cSRui Paulo 		return -1;
2772*5b9c547cSRui Paulo 
2773*5b9c547cSRui Paulo 	dl_list_for_each(txsa, &principal->txsc->sa_list, struct transmit_sa,
2774*5b9c547cSRui Paulo 			 list) {
2775*5b9c547cSRui Paulo 		if (is_ki_equal(&txsa->pkey->key_identifier, lki)) {
2776*5b9c547cSRui Paulo 			txsa->in_use = TRUE;
2777*5b9c547cSRui Paulo 			secy_enable_transmit_sa(kay, txsa);
2778*5b9c547cSRui Paulo 			ieee802_1x_cp_set_usingtransmitas(
2779*5b9c547cSRui Paulo 				principal->kay->cp, TRUE);
2780*5b9c547cSRui Paulo 			ieee802_1x_cp_sm_step(principal->kay->cp);
2781*5b9c547cSRui Paulo 		}
2782*5b9c547cSRui Paulo 	}
2783*5b9c547cSRui Paulo 
2784*5b9c547cSRui Paulo 	return 0;
2785*5b9c547cSRui Paulo }
2786*5b9c547cSRui Paulo 
2787*5b9c547cSRui Paulo 
2788*5b9c547cSRui Paulo /**
2789*5b9c547cSRui Paulo  * ieee802_1x_kay_enable_rx_sas -
2790*5b9c547cSRui Paulo  */
2791*5b9c547cSRui Paulo int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
2792*5b9c547cSRui Paulo 				 struct ieee802_1x_mka_ki *lki)
2793*5b9c547cSRui Paulo {
2794*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2795*5b9c547cSRui Paulo 	struct receive_sa *rxsa;
2796*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
2797*5b9c547cSRui Paulo 
2798*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2799*5b9c547cSRui Paulo 	if (!principal)
2800*5b9c547cSRui Paulo 		return -1;
2801*5b9c547cSRui Paulo 
2802*5b9c547cSRui Paulo 	dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
2803*5b9c547cSRui Paulo 		dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
2804*5b9c547cSRui Paulo 		{
2805*5b9c547cSRui Paulo 			if (is_ki_equal(&rxsa->pkey->key_identifier, lki)) {
2806*5b9c547cSRui Paulo 				rxsa->in_use = TRUE;
2807*5b9c547cSRui Paulo 				secy_enable_receive_sa(kay, rxsa);
2808*5b9c547cSRui Paulo 				ieee802_1x_cp_set_usingreceivesas(
2809*5b9c547cSRui Paulo 					principal->kay->cp, TRUE);
2810*5b9c547cSRui Paulo 				ieee802_1x_cp_sm_step(principal->kay->cp);
2811*5b9c547cSRui Paulo 			}
2812*5b9c547cSRui Paulo 		}
2813*5b9c547cSRui Paulo 	}
2814*5b9c547cSRui Paulo 
2815*5b9c547cSRui Paulo 	return 0;
2816*5b9c547cSRui Paulo }
2817*5b9c547cSRui Paulo 
2818*5b9c547cSRui Paulo 
2819*5b9c547cSRui Paulo /**
2820*5b9c547cSRui Paulo  * ieee802_1x_kay_enable_new_info -
2821*5b9c547cSRui Paulo  */
2822*5b9c547cSRui Paulo int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
2823*5b9c547cSRui Paulo {
2824*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *principal;
2825*5b9c547cSRui Paulo 
2826*5b9c547cSRui Paulo 	principal = ieee802_1x_kay_get_principal_participant(kay);
2827*5b9c547cSRui Paulo 	if (!principal)
2828*5b9c547cSRui Paulo 		return -1;
2829*5b9c547cSRui Paulo 
2830*5b9c547cSRui Paulo 	if (principal->retry_count < MAX_RETRY_CNT) {
2831*5b9c547cSRui Paulo 		ieee802_1x_participant_send_mkpdu(principal);
2832*5b9c547cSRui Paulo 		principal->retry_count++;
2833*5b9c547cSRui Paulo 	}
2834*5b9c547cSRui Paulo 
2835*5b9c547cSRui Paulo 	return 0;
2836*5b9c547cSRui Paulo }
2837*5b9c547cSRui Paulo 
2838*5b9c547cSRui Paulo 
2839*5b9c547cSRui Paulo /**
2840*5b9c547cSRui Paulo  * ieee802_1x_kay_cp_conf -
2841*5b9c547cSRui Paulo  */
2842*5b9c547cSRui Paulo int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
2843*5b9c547cSRui Paulo 			   struct ieee802_1x_cp_conf *pconf)
2844*5b9c547cSRui Paulo {
2845*5b9c547cSRui Paulo 	pconf->protect = kay->macsec_protect;
2846*5b9c547cSRui Paulo 	pconf->replay_protect = kay->macsec_replay_protect;
2847*5b9c547cSRui Paulo 	pconf->validate = kay->macsec_validate;
2848*5b9c547cSRui Paulo 
2849*5b9c547cSRui Paulo 	return 0;
2850*5b9c547cSRui Paulo }
2851*5b9c547cSRui Paulo 
2852*5b9c547cSRui Paulo 
2853*5b9c547cSRui Paulo /**
2854*5b9c547cSRui Paulo  * ieee802_1x_kay_alloc_cp_sm -
2855*5b9c547cSRui Paulo  */
2856*5b9c547cSRui Paulo static struct ieee802_1x_cp_sm *
2857*5b9c547cSRui Paulo ieee802_1x_kay_alloc_cp_sm(struct ieee802_1x_kay *kay)
2858*5b9c547cSRui Paulo {
2859*5b9c547cSRui Paulo 	struct ieee802_1x_cp_conf conf;
2860*5b9c547cSRui Paulo 
2861*5b9c547cSRui Paulo 	os_memset(&conf, 0, sizeof(conf));
2862*5b9c547cSRui Paulo 	conf.protect = kay->macsec_protect;
2863*5b9c547cSRui Paulo 	conf.replay_protect = kay->macsec_replay_protect;
2864*5b9c547cSRui Paulo 	conf.validate = kay->macsec_validate;
2865*5b9c547cSRui Paulo 	conf.replay_window = kay->macsec_replay_window;
2866*5b9c547cSRui Paulo 
2867*5b9c547cSRui Paulo 	return ieee802_1x_cp_sm_init(kay, &conf);
2868*5b9c547cSRui Paulo }
2869*5b9c547cSRui Paulo 
2870*5b9c547cSRui Paulo 
2871*5b9c547cSRui Paulo /**
2872*5b9c547cSRui Paulo  * ieee802_1x_kay_mkpdu_sanity_check -
2873*5b9c547cSRui Paulo  *     sanity check specified in clause 11.11.2 of IEEE802.1X-2010
2874*5b9c547cSRui Paulo  */
2875*5b9c547cSRui Paulo static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
2876*5b9c547cSRui Paulo 					     const u8 *buf, size_t len)
2877*5b9c547cSRui Paulo {
2878*5b9c547cSRui Paulo 	struct ieee8023_hdr *eth_hdr;
2879*5b9c547cSRui Paulo 	struct ieee802_1x_hdr *eapol_hdr;
2880*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *mka_hdr;
2881*5b9c547cSRui Paulo 	struct ieee802_1x_mka_basic_body *body;
2882*5b9c547cSRui Paulo 	size_t mka_msg_len;
2883*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
2884*5b9c547cSRui Paulo 	size_t body_len;
2885*5b9c547cSRui Paulo 	u8 icv[MAX_ICV_LEN];
2886*5b9c547cSRui Paulo 	u8 *msg_icv;
2887*5b9c547cSRui Paulo 
2888*5b9c547cSRui Paulo 	eth_hdr = (struct ieee8023_hdr *) buf;
2889*5b9c547cSRui Paulo 	eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
2890*5b9c547cSRui Paulo 	mka_hdr = (struct ieee802_1x_mka_hdr *) (eapol_hdr + 1);
2891*5b9c547cSRui Paulo 
2892*5b9c547cSRui Paulo 	/* destination address should be not individual address */
2893*5b9c547cSRui Paulo 	if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) {
2894*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP,
2895*5b9c547cSRui Paulo 			   "KaY: ethernet destination address is not PAE group address");
2896*5b9c547cSRui Paulo 		return -1;
2897*5b9c547cSRui Paulo 	}
2898*5b9c547cSRui Paulo 
2899*5b9c547cSRui Paulo 	/* MKPDU should not less than 32 octets */
2900*5b9c547cSRui Paulo 	mka_msg_len = be_to_host16(eapol_hdr->length);
2901*5b9c547cSRui Paulo 	if (mka_msg_len < 32) {
2902*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP, "KaY: MKPDU is less than 32 octets");
2903*5b9c547cSRui Paulo 		return -1;
2904*5b9c547cSRui Paulo 	}
2905*5b9c547cSRui Paulo 	/* MKPDU should multiple 4 octets */
2906*5b9c547cSRui Paulo 	if ((mka_msg_len % 4) != 0) {
2907*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP,
2908*5b9c547cSRui Paulo 			   "KaY: MKPDU is not multiple of 4 octets");
2909*5b9c547cSRui Paulo 		return -1;
2910*5b9c547cSRui Paulo 	}
2911*5b9c547cSRui Paulo 
2912*5b9c547cSRui Paulo 	body = (struct ieee802_1x_mka_basic_body *) mka_hdr;
2913*5b9c547cSRui Paulo 	ieee802_1x_mka_dump_basic_body(body);
2914*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(body);
2915*5b9c547cSRui Paulo 	/* EAPOL-MKA body should comprise basic parameter set and ICV */
2916*5b9c547cSRui Paulo 	if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
2917*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
2918*5b9c547cSRui Paulo 			   "KaY: Received EAPOL-MKA Packet Body Length (%d bytes) is less than the Basic Parameter Set Header Length (%d bytes) + the Basic Parameter Set Body Length (%d bytes) + %d bytes of ICV",
2919*5b9c547cSRui Paulo 			   (int) mka_msg_len, (int) MKA_HDR_LEN,
2920*5b9c547cSRui Paulo 			   (int) body_len, DEFAULT_ICV_LEN);
2921*5b9c547cSRui Paulo 		return -1;
2922*5b9c547cSRui Paulo 	}
2923*5b9c547cSRui Paulo 
2924*5b9c547cSRui Paulo 	/* CKN should be owned by I */
2925*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_participant(kay, body->ckn);
2926*5b9c547cSRui Paulo 	if (!participant) {
2927*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "CKN is not included in my CA");
2928*5b9c547cSRui Paulo 		return -1;
2929*5b9c547cSRui Paulo 	}
2930*5b9c547cSRui Paulo 
2931*5b9c547cSRui Paulo 	/* algorithm agility check */
2932*5b9c547cSRui Paulo 	if (os_memcmp(body->algo_agility, mka_algo_agility,
2933*5b9c547cSRui Paulo 		      sizeof(body->algo_agility)) != 0) {
2934*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
2935*5b9c547cSRui Paulo 			   "KaY: peer's algorithm agility not supported for me");
2936*5b9c547cSRui Paulo 		return -1;
2937*5b9c547cSRui Paulo 	}
2938*5b9c547cSRui Paulo 
2939*5b9c547cSRui Paulo 	/* ICV check */
2940*5b9c547cSRui Paulo 	/*
2941*5b9c547cSRui Paulo 	 * The ICV will comprise the final octets of the packet body, whatever
2942*5b9c547cSRui Paulo 	 * its size, not the fixed length 16 octets, indicated by the EAPOL
2943*5b9c547cSRui Paulo 	 * packet body length.
2944*5b9c547cSRui Paulo 	 */
2945*5b9c547cSRui Paulo 	if (mka_alg_tbl[kay->mka_algindex].icv_hash(
2946*5b9c547cSRui Paulo 		    participant->ick.key,
2947*5b9c547cSRui Paulo 		    buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
2948*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
2949*5b9c547cSRui Paulo 		return -1;
2950*5b9c547cSRui Paulo 	}
2951*5b9c547cSRui Paulo 	msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
2952*5b9c547cSRui Paulo 						 mka_msg_len);
2953*5b9c547cSRui Paulo 
2954*5b9c547cSRui Paulo 	if (msg_icv) {
2955*5b9c547cSRui Paulo 		if (os_memcmp_const(msg_icv, icv,
2956*5b9c547cSRui Paulo 				    mka_alg_tbl[kay->mka_algindex].icv_len) !=
2957*5b9c547cSRui Paulo 		    0) {
2958*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
2959*5b9c547cSRui Paulo 				   "KaY: Computed ICV is not equal to Received ICV");
2960*5b9c547cSRui Paulo 		return -1;
2961*5b9c547cSRui Paulo 		}
2962*5b9c547cSRui Paulo 	} else {
2963*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: No ICV");
2964*5b9c547cSRui Paulo 		return -1;
2965*5b9c547cSRui Paulo 	}
2966*5b9c547cSRui Paulo 
2967*5b9c547cSRui Paulo 	return 0;
2968*5b9c547cSRui Paulo }
2969*5b9c547cSRui Paulo 
2970*5b9c547cSRui Paulo 
2971*5b9c547cSRui Paulo /**
2972*5b9c547cSRui Paulo  * ieee802_1x_kay_decode_mkpdu -
2973*5b9c547cSRui Paulo  */
2974*5b9c547cSRui Paulo static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
2975*5b9c547cSRui Paulo 				       const u8 *buf, size_t len)
2976*5b9c547cSRui Paulo {
2977*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
2978*5b9c547cSRui Paulo 	struct ieee802_1x_mka_hdr *hdr;
2979*5b9c547cSRui Paulo 	size_t body_len;
2980*5b9c547cSRui Paulo 	size_t left_len;
2981*5b9c547cSRui Paulo 	int body_type;
2982*5b9c547cSRui Paulo 	int i;
2983*5b9c547cSRui Paulo 	const u8 *pos;
2984*5b9c547cSRui Paulo 	Boolean my_included;
2985*5b9c547cSRui Paulo 	Boolean handled[256];
2986*5b9c547cSRui Paulo 
2987*5b9c547cSRui Paulo 	if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
2988*5b9c547cSRui Paulo 		return -1;
2989*5b9c547cSRui Paulo 
2990*5b9c547cSRui Paulo 	/* handle basic parameter set */
2991*5b9c547cSRui Paulo 	pos = buf + sizeof(struct ieee8023_hdr) + sizeof(struct ieee802_1x_hdr);
2992*5b9c547cSRui Paulo 	left_len = len - sizeof(struct ieee8023_hdr) -
2993*5b9c547cSRui Paulo 		sizeof(struct ieee802_1x_hdr);
2994*5b9c547cSRui Paulo 	participant = ieee802_1x_mka_decode_basic_body(kay, pos, left_len);
2995*5b9c547cSRui Paulo 	if (!participant)
2996*5b9c547cSRui Paulo 		return -1;
2997*5b9c547cSRui Paulo 
2998*5b9c547cSRui Paulo 	/* to skip basic parameter set */
2999*5b9c547cSRui Paulo 	hdr = (struct ieee802_1x_mka_hdr *) pos;
3000*5b9c547cSRui Paulo 	body_len = get_mka_param_body_len(hdr);
3001*5b9c547cSRui Paulo 	pos += body_len + MKA_HDR_LEN;
3002*5b9c547cSRui Paulo 	left_len -= body_len + MKA_HDR_LEN;
3003*5b9c547cSRui Paulo 
3004*5b9c547cSRui Paulo 	/* check i am in the peer's peer list */
3005*5b9c547cSRui Paulo 	my_included = ieee802_1x_mka_i_in_peerlist(participant, pos, left_len);
3006*5b9c547cSRui Paulo 	if (my_included) {
3007*5b9c547cSRui Paulo 		/* accept the peer as live peer */
3008*5b9c547cSRui Paulo 		if (!ieee802_1x_kay_is_in_peer(
3009*5b9c547cSRui Paulo 			    participant,
3010*5b9c547cSRui Paulo 			    participant->current_peer_id.mi)) {
3011*5b9c547cSRui Paulo 			if (!ieee802_1x_kay_create_live_peer(
3012*5b9c547cSRui Paulo 				    participant,
3013*5b9c547cSRui Paulo 				    participant->current_peer_id.mi,
3014*5b9c547cSRui Paulo 				    participant->current_peer_id.mn))
3015*5b9c547cSRui Paulo 				return -1;
3016*5b9c547cSRui Paulo 			ieee802_1x_kay_elect_key_server(participant);
3017*5b9c547cSRui Paulo 			ieee802_1x_kay_decide_macsec_use(participant);
3018*5b9c547cSRui Paulo 		}
3019*5b9c547cSRui Paulo 		if (ieee802_1x_kay_is_in_potential_peer(
3020*5b9c547cSRui Paulo 			    participant, participant->current_peer_id.mi)) {
3021*5b9c547cSRui Paulo 			ieee802_1x_kay_move_live_peer(
3022*5b9c547cSRui Paulo 				participant, participant->current_peer_id.mi,
3023*5b9c547cSRui Paulo 				participant->current_peer_id.mn);
3024*5b9c547cSRui Paulo 			ieee802_1x_kay_elect_key_server(participant);
3025*5b9c547cSRui Paulo 			ieee802_1x_kay_decide_macsec_use(participant);
3026*5b9c547cSRui Paulo 		}
3027*5b9c547cSRui Paulo 	}
3028*5b9c547cSRui Paulo 
3029*5b9c547cSRui Paulo 	/*
3030*5b9c547cSRui Paulo 	 * Handle other parameter set than basic parameter set.
3031*5b9c547cSRui Paulo 	 * Each parameter set should be present only once.
3032*5b9c547cSRui Paulo 	 */
3033*5b9c547cSRui Paulo 	for (i = 0; i < 256; i++)
3034*5b9c547cSRui Paulo 		handled[i] = FALSE;
3035*5b9c547cSRui Paulo 
3036*5b9c547cSRui Paulo 	handled[0] = TRUE;
3037*5b9c547cSRui Paulo 	while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
3038*5b9c547cSRui Paulo 		hdr = (struct ieee802_1x_mka_hdr *) pos;
3039*5b9c547cSRui Paulo 		body_len = get_mka_param_body_len(hdr);
3040*5b9c547cSRui Paulo 		body_type = get_mka_param_body_type(hdr);
3041*5b9c547cSRui Paulo 
3042*5b9c547cSRui Paulo 		if (body_type == MKA_ICV_INDICATOR)
3043*5b9c547cSRui Paulo 			return 0;
3044*5b9c547cSRui Paulo 
3045*5b9c547cSRui Paulo 		if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
3046*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
3047*5b9c547cSRui Paulo 				   "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
3048*5b9c547cSRui Paulo 				   (int) left_len, (int) MKA_HDR_LEN,
3049*5b9c547cSRui Paulo 				   (int) body_len, DEFAULT_ICV_LEN);
3050*5b9c547cSRui Paulo 			goto next_para_set;
3051*5b9c547cSRui Paulo 		}
3052*5b9c547cSRui Paulo 
3053*5b9c547cSRui Paulo 		if (handled[body_type])
3054*5b9c547cSRui Paulo 			goto next_para_set;
3055*5b9c547cSRui Paulo 
3056*5b9c547cSRui Paulo 		handled[body_type] = TRUE;
3057*5b9c547cSRui Paulo 		if (mak_body_handler[body_type].body_rx) {
3058*5b9c547cSRui Paulo 			mak_body_handler[body_type].body_rx
3059*5b9c547cSRui Paulo 				(participant, pos, left_len);
3060*5b9c547cSRui Paulo 		} else {
3061*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
3062*5b9c547cSRui Paulo 				   "The type %d not supported in this MKA version %d",
3063*5b9c547cSRui Paulo 				   body_type, MKA_VERSION_ID);
3064*5b9c547cSRui Paulo 		}
3065*5b9c547cSRui Paulo 
3066*5b9c547cSRui Paulo next_para_set:
3067*5b9c547cSRui Paulo 		pos += body_len + MKA_HDR_LEN;
3068*5b9c547cSRui Paulo 		left_len -= body_len + MKA_HDR_LEN;
3069*5b9c547cSRui Paulo 	}
3070*5b9c547cSRui Paulo 
3071*5b9c547cSRui Paulo 	kay->active = TRUE;
3072*5b9c547cSRui Paulo 	participant->retry_count = 0;
3073*5b9c547cSRui Paulo 	participant->active = TRUE;
3074*5b9c547cSRui Paulo 
3075*5b9c547cSRui Paulo 	return 0;
3076*5b9c547cSRui Paulo }
3077*5b9c547cSRui Paulo 
3078*5b9c547cSRui Paulo 
3079*5b9c547cSRui Paulo 
3080*5b9c547cSRui Paulo static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
3081*5b9c547cSRui Paulo 			   size_t len)
3082*5b9c547cSRui Paulo {
3083*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay = ctx;
3084*5b9c547cSRui Paulo 	struct ieee8023_hdr *eth_hdr;
3085*5b9c547cSRui Paulo 	struct ieee802_1x_hdr *eapol_hdr;
3086*5b9c547cSRui Paulo 
3087*5b9c547cSRui Paulo 	/* must contain at least ieee8023_hdr + ieee802_1x_hdr */
3088*5b9c547cSRui Paulo 	if (len < sizeof(*eth_hdr) + sizeof(*eapol_hdr)) {
3089*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP, "KaY: EAPOL frame too short (%lu)",
3090*5b9c547cSRui Paulo 			   (unsigned long) len);
3091*5b9c547cSRui Paulo 		return;
3092*5b9c547cSRui Paulo 	}
3093*5b9c547cSRui Paulo 
3094*5b9c547cSRui Paulo 	eth_hdr = (struct ieee8023_hdr *) buf;
3095*5b9c547cSRui Paulo 	eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
3096*5b9c547cSRui Paulo 	if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
3097*5b9c547cSRui Paulo 	    ntohs(eapol_hdr->length)) {
3098*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
3099*5b9c547cSRui Paulo 			   (unsigned long) len,
3100*5b9c547cSRui Paulo 			   (unsigned long) ntohs(eapol_hdr->length));
3101*5b9c547cSRui Paulo 		return;
3102*5b9c547cSRui Paulo 	}
3103*5b9c547cSRui Paulo 
3104*5b9c547cSRui Paulo 	if (eapol_hdr->version < EAPOL_VERSION) {
3105*5b9c547cSRui Paulo 		wpa_printf(MSG_MSGDUMP, "KaY: version %d does not support MKA",
3106*5b9c547cSRui Paulo 			   eapol_hdr->version);
3107*5b9c547cSRui Paulo 		return;
3108*5b9c547cSRui Paulo 	}
3109*5b9c547cSRui Paulo 	if (ntohs(eth_hdr->ethertype) != ETH_P_PAE ||
3110*5b9c547cSRui Paulo 	    eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
3111*5b9c547cSRui Paulo 		return;
3112*5b9c547cSRui Paulo 
3113*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "RX EAPOL-MKA: ", buf, len);
3114*5b9c547cSRui Paulo 	if (dl_list_empty(&kay->participant_list)) {
3115*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: no MKA participant instance");
3116*5b9c547cSRui Paulo 		return;
3117*5b9c547cSRui Paulo 	}
3118*5b9c547cSRui Paulo 
3119*5b9c547cSRui Paulo 	ieee802_1x_kay_decode_mkpdu(kay, buf, len);
3120*5b9c547cSRui Paulo }
3121*5b9c547cSRui Paulo 
3122*5b9c547cSRui Paulo 
3123*5b9c547cSRui Paulo /**
3124*5b9c547cSRui Paulo  * ieee802_1x_kay_init -
3125*5b9c547cSRui Paulo  */
3126*5b9c547cSRui Paulo struct ieee802_1x_kay *
3127*5b9c547cSRui Paulo ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
3128*5b9c547cSRui Paulo 		    const char *ifname, const u8 *addr)
3129*5b9c547cSRui Paulo {
3130*5b9c547cSRui Paulo 	struct ieee802_1x_kay *kay;
3131*5b9c547cSRui Paulo 
3132*5b9c547cSRui Paulo 	kay = os_zalloc(sizeof(*kay));
3133*5b9c547cSRui Paulo 	if (!kay) {
3134*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
3135*5b9c547cSRui Paulo 		return NULL;
3136*5b9c547cSRui Paulo 	}
3137*5b9c547cSRui Paulo 
3138*5b9c547cSRui Paulo 	kay->ctx = ctx;
3139*5b9c547cSRui Paulo 
3140*5b9c547cSRui Paulo 	kay->enable = TRUE;
3141*5b9c547cSRui Paulo 	kay->active = FALSE;
3142*5b9c547cSRui Paulo 
3143*5b9c547cSRui Paulo 	kay->authenticated = FALSE;
3144*5b9c547cSRui Paulo 	kay->secured = FALSE;
3145*5b9c547cSRui Paulo 	kay->failed = FALSE;
3146*5b9c547cSRui Paulo 	kay->policy = policy;
3147*5b9c547cSRui Paulo 
3148*5b9c547cSRui Paulo 	os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
3149*5b9c547cSRui Paulo 	os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
3150*5b9c547cSRui Paulo 	kay->actor_sci.port = 0x0001;
3151*5b9c547cSRui Paulo 	kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
3152*5b9c547cSRui Paulo 
3153*5b9c547cSRui Paulo 	/* While actor acts as a key server, shall distribute sakey */
3154*5b9c547cSRui Paulo 	kay->dist_kn = 1;
3155*5b9c547cSRui Paulo 	kay->dist_an = 0;
3156*5b9c547cSRui Paulo 	kay->dist_time = 0;
3157*5b9c547cSRui Paulo 
3158*5b9c547cSRui Paulo 	kay->pn_exhaustion = PENDING_PN_EXHAUSTION;
3159*5b9c547cSRui Paulo 	kay->macsec_csindex = DEFAULT_CS_INDEX;
3160*5b9c547cSRui Paulo 	kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
3161*5b9c547cSRui Paulo 	kay->mka_version = MKA_VERSION_ID;
3162*5b9c547cSRui Paulo 
3163*5b9c547cSRui Paulo 	os_memcpy(kay->algo_agility, mka_algo_agility,
3164*5b9c547cSRui Paulo 		  sizeof(kay->algo_agility));
3165*5b9c547cSRui Paulo 
3166*5b9c547cSRui Paulo 	dl_list_init(&kay->participant_list);
3167*5b9c547cSRui Paulo 
3168*5b9c547cSRui Paulo 	if (policy == DO_NOT_SECURE) {
3169*5b9c547cSRui Paulo 		kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
3170*5b9c547cSRui Paulo 		kay->macsec_desired = FALSE;
3171*5b9c547cSRui Paulo 		kay->macsec_protect = FALSE;
3172*5b9c547cSRui Paulo 		kay->macsec_validate = Disabled;
3173*5b9c547cSRui Paulo 		kay->macsec_replay_protect = FALSE;
3174*5b9c547cSRui Paulo 		kay->macsec_replay_window = 0;
3175*5b9c547cSRui Paulo 		kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
3176*5b9c547cSRui Paulo 	} else {
3177*5b9c547cSRui Paulo 		kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
3178*5b9c547cSRui Paulo 		kay->macsec_desired = TRUE;
3179*5b9c547cSRui Paulo 		kay->macsec_protect = TRUE;
3180*5b9c547cSRui Paulo 		kay->macsec_validate = Strict;
3181*5b9c547cSRui Paulo 		kay->macsec_replay_protect = FALSE;
3182*5b9c547cSRui Paulo 		kay->macsec_replay_window = 0;
3183*5b9c547cSRui Paulo 		kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
3184*5b9c547cSRui Paulo 	}
3185*5b9c547cSRui Paulo 
3186*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: state machine created");
3187*5b9c547cSRui Paulo 
3188*5b9c547cSRui Paulo 	/* Initialize the SecY must be prio to CP, as CP will control SecY */
3189*5b9c547cSRui Paulo 	secy_init_macsec(kay);
3190*5b9c547cSRui Paulo 	secy_get_available_transmit_sc(kay, &kay->sc_ch);
3191*5b9c547cSRui Paulo 
3192*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: secy init macsec done");
3193*5b9c547cSRui Paulo 
3194*5b9c547cSRui Paulo 	/* init CP */
3195*5b9c547cSRui Paulo 	kay->cp = ieee802_1x_kay_alloc_cp_sm(kay);
3196*5b9c547cSRui Paulo 	if (kay->cp == NULL) {
3197*5b9c547cSRui Paulo 		ieee802_1x_kay_deinit(kay);
3198*5b9c547cSRui Paulo 		return NULL;
3199*5b9c547cSRui Paulo 	}
3200*5b9c547cSRui Paulo 
3201*5b9c547cSRui Paulo 	if (policy == DO_NOT_SECURE) {
3202*5b9c547cSRui Paulo 		ieee802_1x_cp_connect_authenticated(kay->cp);
3203*5b9c547cSRui Paulo 		ieee802_1x_cp_sm_step(kay->cp);
3204*5b9c547cSRui Paulo 	} else {
3205*5b9c547cSRui Paulo 		kay->l2_mka = l2_packet_init(kay->if_name, NULL, ETH_P_PAE,
3206*5b9c547cSRui Paulo 					     kay_l2_receive, kay, 1);
3207*5b9c547cSRui Paulo 		if (kay->l2_mka == NULL) {
3208*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING,
3209*5b9c547cSRui Paulo 				   "KaY: Failed to initialize L2 packet processing for MKA packet");
3210*5b9c547cSRui Paulo 			ieee802_1x_kay_deinit(kay);
3211*5b9c547cSRui Paulo 			return NULL;
3212*5b9c547cSRui Paulo 		}
3213*5b9c547cSRui Paulo 	}
3214*5b9c547cSRui Paulo 
3215*5b9c547cSRui Paulo 	return kay;
3216*5b9c547cSRui Paulo }
3217*5b9c547cSRui Paulo 
3218*5b9c547cSRui Paulo 
3219*5b9c547cSRui Paulo /**
3220*5b9c547cSRui Paulo  * ieee802_1x_kay_deinit -
3221*5b9c547cSRui Paulo  */
3222*5b9c547cSRui Paulo void
3223*5b9c547cSRui Paulo ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay)
3224*5b9c547cSRui Paulo {
3225*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3226*5b9c547cSRui Paulo 
3227*5b9c547cSRui Paulo 	if (!kay)
3228*5b9c547cSRui Paulo 		return;
3229*5b9c547cSRui Paulo 
3230*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: state machine removed");
3231*5b9c547cSRui Paulo 
3232*5b9c547cSRui Paulo 	while (!dl_list_empty(&kay->participant_list)) {
3233*5b9c547cSRui Paulo 		participant = dl_list_entry(kay->participant_list.next,
3234*5b9c547cSRui Paulo 					    struct ieee802_1x_mka_participant,
3235*5b9c547cSRui Paulo 					    list);
3236*5b9c547cSRui Paulo 		ieee802_1x_kay_delete_mka(kay, &participant->ckn);
3237*5b9c547cSRui Paulo 	}
3238*5b9c547cSRui Paulo 
3239*5b9c547cSRui Paulo 	ieee802_1x_cp_sm_deinit(kay->cp);
3240*5b9c547cSRui Paulo 	secy_deinit_macsec(kay);
3241*5b9c547cSRui Paulo 
3242*5b9c547cSRui Paulo 	if (kay->l2_mka) {
3243*5b9c547cSRui Paulo 		l2_packet_deinit(kay->l2_mka);
3244*5b9c547cSRui Paulo 		kay->l2_mka = NULL;
3245*5b9c547cSRui Paulo 	}
3246*5b9c547cSRui Paulo 
3247*5b9c547cSRui Paulo 	os_free(kay->ctx);
3248*5b9c547cSRui Paulo 	os_free(kay);
3249*5b9c547cSRui Paulo }
3250*5b9c547cSRui Paulo 
3251*5b9c547cSRui Paulo 
3252*5b9c547cSRui Paulo /**
3253*5b9c547cSRui Paulo  * ieee802_1x_kay_create_mka -
3254*5b9c547cSRui Paulo  */
3255*5b9c547cSRui Paulo struct ieee802_1x_mka_participant *
3256*5b9c547cSRui Paulo ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
3257*5b9c547cSRui Paulo 			  struct mka_key *cak, u32 life,
3258*5b9c547cSRui Paulo 			  enum mka_created_mode mode, Boolean is_authenticator)
3259*5b9c547cSRui Paulo {
3260*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3261*5b9c547cSRui Paulo 	unsigned int usecs;
3262*5b9c547cSRui Paulo 
3263*5b9c547cSRui Paulo 	if (!kay || !ckn || !cak) {
3264*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: ckn or cak is null");
3265*5b9c547cSRui Paulo 		return NULL;
3266*5b9c547cSRui Paulo 	}
3267*5b9c547cSRui Paulo 
3268*5b9c547cSRui Paulo 	if (cak->len != mka_alg_tbl[kay->mka_algindex].cak_len) {
3269*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: CAK length not follow key schema");
3270*5b9c547cSRui Paulo 		return NULL;
3271*5b9c547cSRui Paulo 	}
3272*5b9c547cSRui Paulo 	if (ckn->len > MAX_CKN_LEN) {
3273*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: CKN is out of range(<=32 bytes)");
3274*5b9c547cSRui Paulo 		return NULL;
3275*5b9c547cSRui Paulo 	}
3276*5b9c547cSRui Paulo 	if (!kay->enable) {
3277*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: Now is at disable state");
3278*5b9c547cSRui Paulo 		return NULL;
3279*5b9c547cSRui Paulo 	}
3280*5b9c547cSRui Paulo 
3281*5b9c547cSRui Paulo 	participant = os_zalloc(sizeof(*participant));
3282*5b9c547cSRui Paulo 	if (!participant) {
3283*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
3284*5b9c547cSRui Paulo 		return NULL;
3285*5b9c547cSRui Paulo 	}
3286*5b9c547cSRui Paulo 
3287*5b9c547cSRui Paulo 	participant->ckn.len = ckn->len;
3288*5b9c547cSRui Paulo 	os_memcpy(participant->ckn.name, ckn->name, ckn->len);
3289*5b9c547cSRui Paulo 	participant->cak.len = cak->len;
3290*5b9c547cSRui Paulo 	os_memcpy(participant->cak.key, cak->key, cak->len);
3291*5b9c547cSRui Paulo 	if (life)
3292*5b9c547cSRui Paulo 		participant->cak_life = life + time(NULL);
3293*5b9c547cSRui Paulo 
3294*5b9c547cSRui Paulo 	switch (mode) {
3295*5b9c547cSRui Paulo 	case EAP_EXCHANGE:
3296*5b9c547cSRui Paulo 		if (is_authenticator) {
3297*5b9c547cSRui Paulo 			participant->is_obliged_key_server = TRUE;
3298*5b9c547cSRui Paulo 			participant->can_be_key_server = TRUE;
3299*5b9c547cSRui Paulo 			participant->is_key_server = TRUE;
3300*5b9c547cSRui Paulo 			participant->principal = TRUE;
3301*5b9c547cSRui Paulo 
3302*5b9c547cSRui Paulo 			os_memcpy(&kay->key_server_sci, &kay->actor_sci,
3303*5b9c547cSRui Paulo 				  sizeof(kay->key_server_sci));
3304*5b9c547cSRui Paulo 			kay->key_server_priority = kay->actor_priority;
3305*5b9c547cSRui Paulo 			participant->is_elected = TRUE;
3306*5b9c547cSRui Paulo 		} else {
3307*5b9c547cSRui Paulo 			participant->is_obliged_key_server = FALSE;
3308*5b9c547cSRui Paulo 			participant->can_be_key_server = FALSE;
3309*5b9c547cSRui Paulo 			participant->is_key_server = FALSE;
3310*5b9c547cSRui Paulo 			participant->is_elected = TRUE;
3311*5b9c547cSRui Paulo 		}
3312*5b9c547cSRui Paulo 		break;
3313*5b9c547cSRui Paulo 
3314*5b9c547cSRui Paulo 	default:
3315*5b9c547cSRui Paulo 		participant->is_obliged_key_server = FALSE;
3316*5b9c547cSRui Paulo 		participant->can_be_key_server = TRUE;
3317*5b9c547cSRui Paulo 		participant->is_key_server = FALSE;
3318*5b9c547cSRui Paulo 		participant->is_elected = FALSE;
3319*5b9c547cSRui Paulo 		break;
3320*5b9c547cSRui Paulo 	}
3321*5b9c547cSRui Paulo 
3322*5b9c547cSRui Paulo 	participant->cached = FALSE;
3323*5b9c547cSRui Paulo 
3324*5b9c547cSRui Paulo 	participant->active = FALSE;
3325*5b9c547cSRui Paulo 	participant->participant = FALSE;
3326*5b9c547cSRui Paulo 	participant->retain = FALSE;
3327*5b9c547cSRui Paulo 	participant->activate = DEFAULT;
3328*5b9c547cSRui Paulo 
3329*5b9c547cSRui Paulo 	if (participant->is_key_server)
3330*5b9c547cSRui Paulo 		participant->principal = TRUE;
3331*5b9c547cSRui Paulo 
3332*5b9c547cSRui Paulo 	dl_list_init(&participant->live_peers);
3333*5b9c547cSRui Paulo 	dl_list_init(&participant->potential_peers);
3334*5b9c547cSRui Paulo 
3335*5b9c547cSRui Paulo 	participant->retry_count = 0;
3336*5b9c547cSRui Paulo 	participant->kay = kay;
3337*5b9c547cSRui Paulo 
3338*5b9c547cSRui Paulo 	if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
3339*5b9c547cSRui Paulo 		goto fail;
3340*5b9c547cSRui Paulo 	participant->mn = 0;
3341*5b9c547cSRui Paulo 
3342*5b9c547cSRui Paulo 	participant->lrx = FALSE;
3343*5b9c547cSRui Paulo 	participant->ltx = FALSE;
3344*5b9c547cSRui Paulo 	participant->orx = FALSE;
3345*5b9c547cSRui Paulo 	participant->otx = FALSE;
3346*5b9c547cSRui Paulo 	participant->to_dist_sak = FALSE;
3347*5b9c547cSRui Paulo 	participant->to_use_sak = FALSE;
3348*5b9c547cSRui Paulo 	participant->new_sak = FALSE;
3349*5b9c547cSRui Paulo 	dl_list_init(&participant->sak_list);
3350*5b9c547cSRui Paulo 	participant->new_key = NULL;
3351*5b9c547cSRui Paulo 	dl_list_init(&participant->rxsc_list);
3352*5b9c547cSRui Paulo 	participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci,
3353*5b9c547cSRui Paulo 							    kay->sc_ch);
3354*5b9c547cSRui Paulo 	secy_cp_control_protect_frames(kay, kay->macsec_protect);
3355*5b9c547cSRui Paulo 	secy_cp_control_replay(kay, kay->macsec_replay_protect,
3356*5b9c547cSRui Paulo 			       kay->macsec_replay_window);
3357*5b9c547cSRui Paulo 	secy_create_transmit_sc(kay, participant->txsc);
3358*5b9c547cSRui Paulo 
3359*5b9c547cSRui Paulo 	/* to derive KEK from CAK and CKN */
3360*5b9c547cSRui Paulo 	participant->kek.len = mka_alg_tbl[kay->mka_algindex].kek_len;
3361*5b9c547cSRui Paulo 	if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
3362*5b9c547cSRui Paulo 						    participant->ckn.name,
3363*5b9c547cSRui Paulo 						    participant->ckn.len,
3364*5b9c547cSRui Paulo 						    participant->kek.key)) {
3365*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: Derived KEK failed");
3366*5b9c547cSRui Paulo 		goto fail;
3367*5b9c547cSRui Paulo 	}
3368*5b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "KaY: Derived KEK",
3369*5b9c547cSRui Paulo 			participant->kek.key, participant->kek.len);
3370*5b9c547cSRui Paulo 
3371*5b9c547cSRui Paulo 	/* to derive ICK from CAK and CKN */
3372*5b9c547cSRui Paulo 	participant->ick.len = mka_alg_tbl[kay->mka_algindex].ick_len;
3373*5b9c547cSRui Paulo 	if (mka_alg_tbl[kay->mka_algindex].ick_trfm(participant->cak.key,
3374*5b9c547cSRui Paulo 						    participant->ckn.name,
3375*5b9c547cSRui Paulo 						    participant->ckn.len,
3376*5b9c547cSRui Paulo 						    participant->ick.key)) {
3377*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "KaY: Derived ICK failed");
3378*5b9c547cSRui Paulo 		goto fail;
3379*5b9c547cSRui Paulo 	}
3380*5b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK",
3381*5b9c547cSRui Paulo 			participant->ick.key, participant->ick.len);
3382*5b9c547cSRui Paulo 
3383*5b9c547cSRui Paulo 	dl_list_add(&kay->participant_list, &participant->list);
3384*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "KaY: Participant created:",
3385*5b9c547cSRui Paulo 		    ckn->name, ckn->len);
3386*5b9c547cSRui Paulo 
3387*5b9c547cSRui Paulo 	usecs = os_random() % (MKA_HELLO_TIME * 1000);
3388*5b9c547cSRui Paulo 	eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
3389*5b9c547cSRui Paulo 			       participant, NULL);
3390*5b9c547cSRui Paulo 	participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
3391*5b9c547cSRui Paulo 		usecs / 1000000;
3392*5b9c547cSRui Paulo 
3393*5b9c547cSRui Paulo 	return participant;
3394*5b9c547cSRui Paulo 
3395*5b9c547cSRui Paulo fail:
3396*5b9c547cSRui Paulo 	os_free(participant);
3397*5b9c547cSRui Paulo 	return NULL;
3398*5b9c547cSRui Paulo }
3399*5b9c547cSRui Paulo 
3400*5b9c547cSRui Paulo 
3401*5b9c547cSRui Paulo /**
3402*5b9c547cSRui Paulo  * ieee802_1x_kay_delete_mka -
3403*5b9c547cSRui Paulo  */
3404*5b9c547cSRui Paulo void
3405*5b9c547cSRui Paulo ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
3406*5b9c547cSRui Paulo {
3407*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3408*5b9c547cSRui Paulo 	struct ieee802_1x_kay_peer *peer;
3409*5b9c547cSRui Paulo 	struct data_key *sak;
3410*5b9c547cSRui Paulo 	struct receive_sc *rxsc;
3411*5b9c547cSRui Paulo 
3412*5b9c547cSRui Paulo 	if (!kay || !ckn)
3413*5b9c547cSRui Paulo 		return;
3414*5b9c547cSRui Paulo 
3415*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: participant removed");
3416*5b9c547cSRui Paulo 
3417*5b9c547cSRui Paulo 	/* get the participant */
3418*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_participant(kay, ckn->name);
3419*5b9c547cSRui Paulo 	if (!participant) {
3420*5b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG, "KaY: participant is not found",
3421*5b9c547cSRui Paulo 			    ckn->name, ckn->len);
3422*5b9c547cSRui Paulo 		return;
3423*5b9c547cSRui Paulo 	}
3424*5b9c547cSRui Paulo 
3425*5b9c547cSRui Paulo 	dl_list_del(&participant->list);
3426*5b9c547cSRui Paulo 
3427*5b9c547cSRui Paulo 	/* remove live peer */
3428*5b9c547cSRui Paulo 	while (!dl_list_empty(&participant->live_peers)) {
3429*5b9c547cSRui Paulo 		peer = dl_list_entry(participant->live_peers.next,
3430*5b9c547cSRui Paulo 				     struct ieee802_1x_kay_peer, list);
3431*5b9c547cSRui Paulo 		dl_list_del(&peer->list);
3432*5b9c547cSRui Paulo 		os_free(peer);
3433*5b9c547cSRui Paulo 	}
3434*5b9c547cSRui Paulo 
3435*5b9c547cSRui Paulo 	/* remove potential peer */
3436*5b9c547cSRui Paulo 	while (!dl_list_empty(&participant->potential_peers)) {
3437*5b9c547cSRui Paulo 		peer = dl_list_entry(participant->potential_peers.next,
3438*5b9c547cSRui Paulo 				     struct ieee802_1x_kay_peer, list);
3439*5b9c547cSRui Paulo 		dl_list_del(&peer->list);
3440*5b9c547cSRui Paulo 		os_free(peer);
3441*5b9c547cSRui Paulo 	}
3442*5b9c547cSRui Paulo 
3443*5b9c547cSRui Paulo 	/* remove sak */
3444*5b9c547cSRui Paulo 	while (!dl_list_empty(&participant->sak_list)) {
3445*5b9c547cSRui Paulo 		sak = dl_list_entry(participant->sak_list.next,
3446*5b9c547cSRui Paulo 				    struct data_key, list);
3447*5b9c547cSRui Paulo 		dl_list_del(&sak->list);
3448*5b9c547cSRui Paulo 		os_free(sak->key);
3449*5b9c547cSRui Paulo 		os_free(sak);
3450*5b9c547cSRui Paulo 	}
3451*5b9c547cSRui Paulo 	while (!dl_list_empty(&participant->rxsc_list)) {
3452*5b9c547cSRui Paulo 		rxsc = dl_list_entry(participant->rxsc_list.next,
3453*5b9c547cSRui Paulo 				     struct receive_sc, list);
3454*5b9c547cSRui Paulo 		secy_delete_receive_sc(kay, rxsc);
3455*5b9c547cSRui Paulo 		ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
3456*5b9c547cSRui Paulo 	}
3457*5b9c547cSRui Paulo 	secy_delete_transmit_sc(kay, participant->txsc);
3458*5b9c547cSRui Paulo 	ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
3459*5b9c547cSRui Paulo 
3460*5b9c547cSRui Paulo 	os_memset(&participant->cak, 0, sizeof(participant->cak));
3461*5b9c547cSRui Paulo 	os_memset(&participant->kek, 0, sizeof(participant->kek));
3462*5b9c547cSRui Paulo 	os_memset(&participant->ick, 0, sizeof(participant->ick));
3463*5b9c547cSRui Paulo 	os_free(participant);
3464*5b9c547cSRui Paulo }
3465*5b9c547cSRui Paulo 
3466*5b9c547cSRui Paulo 
3467*5b9c547cSRui Paulo /**
3468*5b9c547cSRui Paulo  * ieee802_1x_kay_mka_participate -
3469*5b9c547cSRui Paulo  */
3470*5b9c547cSRui Paulo void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
3471*5b9c547cSRui Paulo 				    struct mka_key_name *ckn,
3472*5b9c547cSRui Paulo 				    Boolean status)
3473*5b9c547cSRui Paulo {
3474*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3475*5b9c547cSRui Paulo 
3476*5b9c547cSRui Paulo 	if (!kay || !ckn)
3477*5b9c547cSRui Paulo 		return;
3478*5b9c547cSRui Paulo 
3479*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_participant(kay, ckn->name);
3480*5b9c547cSRui Paulo 	if (!participant)
3481*5b9c547cSRui Paulo 		return;
3482*5b9c547cSRui Paulo 
3483*5b9c547cSRui Paulo 	participant->active = status;
3484*5b9c547cSRui Paulo }
3485*5b9c547cSRui Paulo 
3486*5b9c547cSRui Paulo 
3487*5b9c547cSRui Paulo /**
3488*5b9c547cSRui Paulo  * ieee802_1x_kay_new_sak -
3489*5b9c547cSRui Paulo  */
3490*5b9c547cSRui Paulo int
3491*5b9c547cSRui Paulo ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
3492*5b9c547cSRui Paulo {
3493*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3494*5b9c547cSRui Paulo 
3495*5b9c547cSRui Paulo 	if (!kay)
3496*5b9c547cSRui Paulo 		return -1;
3497*5b9c547cSRui Paulo 
3498*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_principal_participant(kay);
3499*5b9c547cSRui Paulo 	if (!participant)
3500*5b9c547cSRui Paulo 		return -1;
3501*5b9c547cSRui Paulo 
3502*5b9c547cSRui Paulo 	participant->new_sak = TRUE;
3503*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "KaY: new SAK signal");
3504*5b9c547cSRui Paulo 
3505*5b9c547cSRui Paulo 	return 0;
3506*5b9c547cSRui Paulo }
3507*5b9c547cSRui Paulo 
3508*5b9c547cSRui Paulo 
3509*5b9c547cSRui Paulo /**
3510*5b9c547cSRui Paulo  * ieee802_1x_kay_change_cipher_suite -
3511*5b9c547cSRui Paulo  */
3512*5b9c547cSRui Paulo int
3513*5b9c547cSRui Paulo ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
3514*5b9c547cSRui Paulo {
3515*5b9c547cSRui Paulo 	struct ieee802_1x_mka_participant *participant;
3516*5b9c547cSRui Paulo 
3517*5b9c547cSRui Paulo 	if (!kay)
3518*5b9c547cSRui Paulo 		return -1;
3519*5b9c547cSRui Paulo 
3520*5b9c547cSRui Paulo 	if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
3521*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
3522*5b9c547cSRui Paulo 			   "KaY: Configured cipher suite index is out of range");
3523*5b9c547cSRui Paulo 		return -1;
3524*5b9c547cSRui Paulo 	}
3525*5b9c547cSRui Paulo 	if (kay->macsec_csindex == cs_index)
3526*5b9c547cSRui Paulo 		return -2;
3527*5b9c547cSRui Paulo 
3528*5b9c547cSRui Paulo 	if (cs_index == 0)
3529*5b9c547cSRui Paulo 		kay->macsec_desired = FALSE;
3530*5b9c547cSRui Paulo 
3531*5b9c547cSRui Paulo 	kay->macsec_csindex = cs_index;
3532*5b9c547cSRui Paulo 	kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
3533*5b9c547cSRui Paulo 
3534*5b9c547cSRui Paulo 	participant = ieee802_1x_kay_get_principal_participant(kay);
3535*5b9c547cSRui Paulo 	if (participant) {
3536*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
3537*5b9c547cSRui Paulo 		participant->new_sak = TRUE;
3538*5b9c547cSRui Paulo 	}
3539*5b9c547cSRui Paulo 
3540*5b9c547cSRui Paulo 	return 0;
3541*5b9c547cSRui Paulo }
3542