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