1351377Scy/* 2351377Scy * IEEE 802.1X-2010 KaY Interface 3351377Scy * Copyright (c) 2019, The Linux Foundation 4351377Scy * 5351377Scy * This software may be distributed under the terms of the BSD license. 6351377Scy * See README for more details. 7351377Scy */ 8351377Scy 9351377Scy#include "utils/includes.h" 10351377Scy 11351377Scy#include "utils/common.h" 12351377Scy#include "pae/ieee802_1x_key.h" 13351377Scy#include "pae/ieee802_1x_kay.h" 14351377Scy#include "hostapd.h" 15351377Scy#include "sta_info.h" 16351377Scy#include "wpa_auth_kay.h" 17351377Scy#include "ieee802_1x.h" 18351377Scy 19351377Scy 20351377Scy#define DEFAULT_KEY_LEN 16 21351377Scy/* secure Connectivity Association Key Name (CKN) */ 22351377Scy#define DEFAULT_CKN_LEN 16 23351377Scy 24351377Scy 25351377Scystatic int hapd_macsec_init(void *priv, struct macsec_init_params *params) 26351377Scy{ 27351377Scy struct hostapd_data *hapd = priv; 28351377Scy 29351377Scy if (!hapd->driver->macsec_init) 30351377Scy return -1; 31351377Scy return hapd->driver->macsec_init(hapd->drv_priv, params); 32351377Scy} 33351377Scy 34351377Scy 35351377Scystatic int hapd_macsec_deinit(void *priv) 36351377Scy{ 37351377Scy struct hostapd_data *hapd = priv; 38351377Scy 39351377Scy if (!hapd->driver->macsec_deinit) 40351377Scy return -1; 41351377Scy return hapd->driver->macsec_deinit(hapd->drv_priv); 42351377Scy} 43351377Scy 44351377Scy 45351377Scystatic int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap) 46351377Scy{ 47351377Scy struct hostapd_data *hapd = priv; 48351377Scy 49351377Scy if (!hapd->driver->macsec_get_capability) 50351377Scy return -1; 51351377Scy return hapd->driver->macsec_get_capability(hapd->drv_priv, cap); 52351377Scy} 53351377Scy 54351377Scy 55351377Scystatic int hapd_enable_protect_frames(void *priv, Boolean enabled) 56351377Scy{ 57351377Scy struct hostapd_data *hapd = priv; 58351377Scy 59351377Scy if (!hapd->driver->enable_protect_frames) 60351377Scy return -1; 61351377Scy return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled); 62351377Scy} 63351377Scy 64351377Scy 65351377Scystatic int hapd_enable_encrypt(void *priv, Boolean enabled) 66351377Scy{ 67351377Scy struct hostapd_data *hapd = priv; 68351377Scy 69351377Scy if (!hapd->driver->enable_encrypt) 70351377Scy return -1; 71351377Scy return hapd->driver->enable_encrypt(hapd->drv_priv, enabled); 72351377Scy} 73351377Scy 74351377Scy 75351377Scystatic int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window) 76351377Scy{ 77351377Scy struct hostapd_data *hapd = priv; 78351377Scy 79351377Scy if (!hapd->driver->set_replay_protect) 80351377Scy return -1; 81351377Scy return hapd->driver->set_replay_protect(hapd->drv_priv, enabled, 82351377Scy window); 83351377Scy} 84351377Scy 85351377Scy 86351377Scystatic int hapd_set_current_cipher_suite(void *priv, u64 cs) 87351377Scy{ 88351377Scy struct hostapd_data *hapd = priv; 89351377Scy 90351377Scy if (!hapd->driver->set_current_cipher_suite) 91351377Scy return -1; 92351377Scy return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs); 93351377Scy} 94351377Scy 95351377Scy 96351377Scystatic int hapd_enable_controlled_port(void *priv, Boolean enabled) 97351377Scy{ 98351377Scy struct hostapd_data *hapd = priv; 99351377Scy 100351377Scy if (!hapd->driver->enable_controlled_port) 101351377Scy return -1; 102351377Scy return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled); 103351377Scy} 104351377Scy 105351377Scy 106351377Scystatic int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa) 107351377Scy{ 108351377Scy struct hostapd_data *hapd = priv; 109351377Scy 110351377Scy if (!hapd->driver->get_receive_lowest_pn) 111351377Scy return -1; 112351377Scy return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa); 113351377Scy} 114351377Scy 115351377Scy 116351377Scystatic int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa) 117351377Scy{ 118351377Scy struct hostapd_data *hapd = priv; 119351377Scy 120351377Scy if (!hapd->driver->get_transmit_next_pn) 121351377Scy return -1; 122351377Scy return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa); 123351377Scy} 124351377Scy 125351377Scy 126351377Scystatic int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa) 127351377Scy{ 128351377Scy struct hostapd_data *hapd = priv; 129351377Scy 130351377Scy if (!hapd->driver->set_transmit_next_pn) 131351377Scy return -1; 132351377Scy return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa); 133351377Scy} 134351377Scy 135351377Scy 136351377Scystatic unsigned int conf_offset_val(enum confidentiality_offset co) 137351377Scy{ 138351377Scy switch (co) { 139351377Scy case CONFIDENTIALITY_OFFSET_30: 140351377Scy return 30; 141351377Scy break; 142351377Scy case CONFIDENTIALITY_OFFSET_50: 143351377Scy return 50; 144351377Scy default: 145351377Scy return 0; 146351377Scy } 147351377Scy} 148351377Scy 149351377Scy 150351377Scystatic int hapd_create_receive_sc(void *priv, struct receive_sc *sc, 151351377Scy enum validate_frames vf, 152351377Scy enum confidentiality_offset co) 153351377Scy{ 154351377Scy struct hostapd_data *hapd = priv; 155351377Scy 156351377Scy if (!hapd->driver->create_receive_sc) 157351377Scy return -1; 158351377Scy return hapd->driver->create_receive_sc(hapd->drv_priv, sc, 159351377Scy conf_offset_val(co), vf); 160351377Scy} 161351377Scy 162351377Scy 163351377Scystatic int hapd_delete_receive_sc(void *priv, struct receive_sc *sc) 164351377Scy{ 165351377Scy struct hostapd_data *hapd = priv; 166351377Scy 167351377Scy if (!hapd->driver->delete_receive_sc) 168351377Scy return -1; 169351377Scy return hapd->driver->delete_receive_sc(hapd->drv_priv, sc); 170351377Scy} 171351377Scy 172351377Scy 173351377Scystatic int hapd_create_receive_sa(void *priv, struct receive_sa *sa) 174351377Scy{ 175351377Scy struct hostapd_data *hapd = priv; 176351377Scy 177351377Scy if (!hapd->driver->create_receive_sa) 178351377Scy return -1; 179351377Scy return hapd->driver->create_receive_sa(hapd->drv_priv, sa); 180351377Scy} 181351377Scy 182351377Scy 183351377Scystatic int hapd_delete_receive_sa(void *priv, struct receive_sa *sa) 184351377Scy{ 185351377Scy struct hostapd_data *hapd = priv; 186351377Scy 187351377Scy if (!hapd->driver->delete_receive_sa) 188351377Scy return -1; 189351377Scy return hapd->driver->delete_receive_sa(hapd->drv_priv, sa); 190351377Scy} 191351377Scy 192351377Scy 193351377Scystatic int hapd_enable_receive_sa(void *priv, struct receive_sa *sa) 194351377Scy{ 195351377Scy struct hostapd_data *hapd = priv; 196351377Scy 197351377Scy if (!hapd->driver->enable_receive_sa) 198351377Scy return -1; 199351377Scy return hapd->driver->enable_receive_sa(hapd->drv_priv, sa); 200351377Scy} 201351377Scy 202351377Scy 203351377Scystatic int hapd_disable_receive_sa(void *priv, struct receive_sa *sa) 204351377Scy{ 205351377Scy struct hostapd_data *hapd = priv; 206351377Scy 207351377Scy if (!hapd->driver->disable_receive_sa) 208351377Scy return -1; 209351377Scy return hapd->driver->disable_receive_sa(hapd->drv_priv, sa); 210351377Scy} 211351377Scy 212351377Scy 213351377Scystatic int 214351377Scyhapd_create_transmit_sc(void *priv, struct transmit_sc *sc, 215351377Scy enum confidentiality_offset co) 216351377Scy{ 217351377Scy struct hostapd_data *hapd = priv; 218351377Scy 219351377Scy if (!hapd->driver->create_transmit_sc) 220351377Scy return -1; 221351377Scy return hapd->driver->create_transmit_sc(hapd->drv_priv, sc, 222351377Scy conf_offset_val(co)); 223351377Scy} 224351377Scy 225351377Scy 226351377Scystatic int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc) 227351377Scy{ 228351377Scy struct hostapd_data *hapd = priv; 229351377Scy 230351377Scy if (!hapd->driver->delete_transmit_sc) 231351377Scy return -1; 232351377Scy return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc); 233351377Scy} 234351377Scy 235351377Scy 236351377Scystatic int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa) 237351377Scy{ 238351377Scy struct hostapd_data *hapd = priv; 239351377Scy 240351377Scy if (!hapd->driver->create_transmit_sa) 241351377Scy return -1; 242351377Scy return hapd->driver->create_transmit_sa(hapd->drv_priv, sa); 243351377Scy} 244351377Scy 245351377Scy 246351377Scystatic int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa) 247351377Scy{ 248351377Scy struct hostapd_data *hapd = priv; 249351377Scy 250351377Scy if (!hapd->driver->delete_transmit_sa) 251351377Scy return -1; 252351377Scy return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa); 253351377Scy} 254351377Scy 255351377Scy 256351377Scystatic int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa) 257351377Scy{ 258351377Scy struct hostapd_data *hapd = priv; 259351377Scy 260351377Scy if (!hapd->driver->enable_transmit_sa) 261351377Scy return -1; 262351377Scy return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa); 263351377Scy} 264351377Scy 265351377Scy 266351377Scystatic int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa) 267351377Scy{ 268351377Scy struct hostapd_data *hapd = priv; 269351377Scy 270351377Scy if (!hapd->driver->disable_transmit_sa) 271351377Scy return -1; 272351377Scy return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa); 273351377Scy} 274351377Scy 275351377Scy 276351377Scyint ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd, 277351377Scy struct sta_info *sta) 278351377Scy{ 279351377Scy struct ieee802_1x_kay_ctx *kay_ctx; 280351377Scy struct ieee802_1x_kay *res = NULL; 281351377Scy enum macsec_policy policy; 282351377Scy 283351377Scy ieee802_1x_dealloc_kay_sm_hapd(hapd); 284351377Scy 285351377Scy if (!hapd->conf || hapd->conf->macsec_policy == 0) 286351377Scy return 0; 287351377Scy 288351377Scy if (hapd->conf->macsec_policy == 1) { 289351377Scy if (hapd->conf->macsec_integ_only == 1) 290351377Scy policy = SHOULD_SECURE; 291351377Scy else 292351377Scy policy = SHOULD_ENCRYPT; 293351377Scy } else { 294351377Scy policy = DO_NOT_SECURE; 295351377Scy } 296351377Scy 297351377Scy wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface); 298351377Scy kay_ctx = os_zalloc(sizeof(*kay_ctx)); 299351377Scy if (!kay_ctx) 300351377Scy return -1; 301351377Scy 302351377Scy kay_ctx->ctx = hapd; 303351377Scy 304351377Scy kay_ctx->macsec_init = hapd_macsec_init; 305351377Scy kay_ctx->macsec_deinit = hapd_macsec_deinit; 306351377Scy kay_ctx->macsec_get_capability = hapd_macsec_get_capability; 307351377Scy kay_ctx->enable_protect_frames = hapd_enable_protect_frames; 308351377Scy kay_ctx->enable_encrypt = hapd_enable_encrypt; 309351377Scy kay_ctx->set_replay_protect = hapd_set_replay_protect; 310351377Scy kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite; 311351377Scy kay_ctx->enable_controlled_port = hapd_enable_controlled_port; 312351377Scy kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn; 313351377Scy kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn; 314351377Scy kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn; 315351377Scy kay_ctx->create_receive_sc = hapd_create_receive_sc; 316351377Scy kay_ctx->delete_receive_sc = hapd_delete_receive_sc; 317351377Scy kay_ctx->create_receive_sa = hapd_create_receive_sa; 318351377Scy kay_ctx->delete_receive_sa = hapd_delete_receive_sa; 319351377Scy kay_ctx->enable_receive_sa = hapd_enable_receive_sa; 320351377Scy kay_ctx->disable_receive_sa = hapd_disable_receive_sa; 321351377Scy kay_ctx->create_transmit_sc = hapd_create_transmit_sc; 322351377Scy kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc; 323351377Scy kay_ctx->create_transmit_sa = hapd_create_transmit_sa; 324351377Scy kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa; 325351377Scy kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa; 326351377Scy kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa; 327351377Scy 328351377Scy res = ieee802_1x_kay_init(kay_ctx, policy, 329351377Scy hapd->conf->macsec_replay_protect, 330351377Scy hapd->conf->macsec_replay_window, 331351377Scy hapd->conf->macsec_port, 332351377Scy hapd->conf->mka_priority, hapd->conf->iface, 333351377Scy hapd->own_addr); 334351377Scy /* ieee802_1x_kay_init() frees kay_ctx on failure */ 335351377Scy if (!res) 336351377Scy return -1; 337351377Scy 338351377Scy hapd->kay = res; 339351377Scy 340351377Scy return 0; 341351377Scy} 342351377Scy 343351377Scy 344351377Scyvoid ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd) 345351377Scy{ 346351377Scy if (!hapd->kay) 347351377Scy return; 348351377Scy 349351377Scy ieee802_1x_kay_deinit(hapd->kay); 350351377Scy hapd->kay = NULL; 351351377Scy} 352351377Scy 353351377Scy 354351377Scystatic int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd, 355351377Scy struct sta_info *sta, u8 *sid, 356351377Scy size_t *len) 357351377Scy{ 358351377Scy const u8 *session_id; 359351377Scy size_t id_len, need_len; 360351377Scy 361351377Scy session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len); 362351377Scy if (!session_id) { 363351377Scy wpa_printf(MSG_DEBUG, 364351377Scy "MACsec: Failed to get SessionID from EAPOL state machines"); 365351377Scy return -1; 366351377Scy } 367351377Scy 368351377Scy need_len = 1 + 2 * 32 /* random size */; 369351377Scy if (need_len > id_len) { 370351377Scy wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough"); 371351377Scy return -1; 372351377Scy } 373351377Scy 374351377Scy os_memcpy(sid, session_id, need_len); 375351377Scy *len = need_len; 376351377Scy 377351377Scy return 0; 378351377Scy} 379351377Scy 380351377Scy 381351377Scystatic int ieee802_1x_auth_get_msk(struct hostapd_data *hapd, 382351377Scy struct sta_info *sta, u8 *msk, size_t *len) 383351377Scy{ 384351377Scy const u8 *key; 385351377Scy size_t keylen; 386351377Scy 387351377Scy if (!sta->eapol_sm) 388351377Scy return -1; 389351377Scy 390351377Scy key = ieee802_1x_get_key(sta->eapol_sm, &keylen); 391351377Scy if (key == NULL) { 392351377Scy wpa_printf(MSG_DEBUG, 393351377Scy "MACsec: Failed to get MSK from EAPOL state machines"); 394351377Scy return -1; 395351377Scy } 396351377Scy wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)", 397351377Scy (unsigned long) keylen); 398351377Scy wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen); 399351377Scy 400351377Scy if (keylen > *len) 401351377Scy keylen = *len; 402351377Scy os_memcpy(msk, key, keylen); 403351377Scy *len = keylen; 404351377Scy 405351377Scy return 0; 406351377Scy} 407351377Scy 408351377Scy 409351377Scyvoid * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd, 410351377Scy struct sta_info *sta) 411351377Scy{ 412351377Scy u8 *sid; 413351377Scy size_t sid_len = 128; 414351377Scy struct mka_key_name *ckn; 415351377Scy struct mka_key *cak; 416351377Scy struct mka_key *msk; 417351377Scy void *res = NULL; 418351377Scy 419351377Scy if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE) 420351377Scy return NULL; 421351377Scy 422351377Scy wpa_printf(MSG_DEBUG, 423351377Scy "IEEE 802.1X: External notification - Create MKA for " 424351377Scy MACSTR, MAC2STR(sta->addr)); 425351377Scy 426351377Scy msk = os_zalloc(sizeof(*msk)); 427351377Scy sid = os_zalloc(sid_len); 428351377Scy ckn = os_zalloc(sizeof(*ckn)); 429351377Scy cak = os_zalloc(sizeof(*cak)); 430351377Scy if (!msk || !sid || !ckn || !cak) 431351377Scy goto fail; 432351377Scy 433351377Scy msk->len = DEFAULT_KEY_LEN; 434351377Scy if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) { 435351377Scy wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK"); 436351377Scy goto fail; 437351377Scy } 438351377Scy 439351377Scy if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len)) 440351377Scy { 441351377Scy wpa_printf(MSG_ERROR, 442351377Scy "IEEE 802.1X: Could not get EAP Session Id"); 443351377Scy goto fail; 444351377Scy } 445351377Scy 446351377Scy wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN); 447351377Scy wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN); 448351377Scy 449351377Scy /* Derive CAK from MSK */ 450351377Scy cak->len = DEFAULT_KEY_LEN; 451351377Scy if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr, 452351377Scy sta->addr, cak->key, cak->len)) { 453351377Scy wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed"); 454351377Scy goto fail; 455351377Scy } 456351377Scy wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len); 457351377Scy 458351377Scy /* Derive CKN from MSK */ 459351377Scy ckn->len = DEFAULT_CKN_LEN; 460351377Scy if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr, 461351377Scy sta->addr, sid, sid_len, ckn->name)) { 462351377Scy wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed"); 463351377Scy goto fail; 464351377Scy } 465351377Scy wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len); 466351377Scy 467351377Scy res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE, 468351377Scy TRUE); 469351377Scy 470351377Scyfail: 471351377Scy bin_clear_free(msk, sizeof(*msk)); 472351377Scy os_free(sid); 473351377Scy os_free(ckn); 474351377Scy bin_clear_free(cak, sizeof(*cak)); 475351377Scy 476351377Scy return res; 477351377Scy} 478351377Scy 479351377Scy 480351377Scyvoid * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd, 481351377Scy struct sta_info *sta) 482351377Scy{ 483351377Scy struct mka_key *cak; 484351377Scy struct mka_key_name *ckn; 485351377Scy void *res = NULL; 486351377Scy 487351377Scy if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET) 488351377Scy goto end; 489351377Scy 490351377Scy ckn = os_zalloc(sizeof(*ckn)); 491351377Scy if (!ckn) 492351377Scy goto end; 493351377Scy 494351377Scy cak = os_zalloc(sizeof(*cak)); 495351377Scy if (!cak) 496351377Scy goto free_ckn; 497351377Scy 498351377Scy if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay) 499351377Scy goto free_cak; 500351377Scy 501351377Scy if (hapd->kay->policy == DO_NOT_SECURE) 502351377Scy goto dealloc; 503351377Scy 504351377Scy cak->len = hapd->conf->mka_cak_len; 505351377Scy os_memcpy(cak->key, hapd->conf->mka_cak, cak->len); 506351377Scy 507351377Scy ckn->len = hapd->conf->mka_ckn_len;; 508351377Scy os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len); 509351377Scy 510351377Scy res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE); 511351377Scy if (res) 512351377Scy goto free_cak; 513351377Scy 514351377Scydealloc: 515351377Scy /* Failed to create MKA */ 516351377Scy ieee802_1x_dealloc_kay_sm_hapd(hapd); 517351377Scyfree_cak: 518351377Scy os_free(cak); 519351377Scyfree_ckn: 520351377Scy os_free(ckn); 521351377Scyend: 522351377Scy return res; 523351377Scy} 524