15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * IEEE 802.1X-2010 KaY Interface
35b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
45b9c547cSRui Paulo *
55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo * See README for more details.
75b9c547cSRui Paulo */
885732ac8SCy Schubert
95b9c547cSRui Paulo #include "utils/includes.h"
105b9c547cSRui Paulo
115b9c547cSRui Paulo #include "utils/common.h"
125b9c547cSRui Paulo #include "eap_peer/eap.h"
135b9c547cSRui Paulo #include "eap_peer/eap_i.h"
145b9c547cSRui Paulo #include "eapol_supp/eapol_supp_sm.h"
155b9c547cSRui Paulo #include "pae/ieee802_1x_key.h"
165b9c547cSRui Paulo #include "pae/ieee802_1x_kay.h"
175b9c547cSRui Paulo #include "wpa_supplicant_i.h"
185b9c547cSRui Paulo #include "config.h"
195b9c547cSRui Paulo #include "config_ssid.h"
205b9c547cSRui Paulo #include "driver_i.h"
215b9c547cSRui Paulo #include "wpas_kay.h"
225b9c547cSRui Paulo
235b9c547cSRui Paulo
245b9c547cSRui Paulo #define DEFAULT_KEY_LEN 16
255b9c547cSRui Paulo /* secure Connectivity Association Key Name (CKN) */
265b9c547cSRui Paulo #define DEFAULT_CKN_LEN 16
275b9c547cSRui Paulo
285b9c547cSRui Paulo
wpas_macsec_init(void * priv,struct macsec_init_params * params)295b9c547cSRui Paulo static int wpas_macsec_init(void *priv, struct macsec_init_params *params)
305b9c547cSRui Paulo {
315b9c547cSRui Paulo return wpa_drv_macsec_init(priv, params);
325b9c547cSRui Paulo }
335b9c547cSRui Paulo
345b9c547cSRui Paulo
wpas_macsec_deinit(void * priv)355b9c547cSRui Paulo static int wpas_macsec_deinit(void *priv)
365b9c547cSRui Paulo {
375b9c547cSRui Paulo return wpa_drv_macsec_deinit(priv);
385b9c547cSRui Paulo }
395b9c547cSRui Paulo
405b9c547cSRui Paulo
wpas_macsec_get_capability(void * priv,enum macsec_cap * cap)4185732ac8SCy Schubert static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap)
4285732ac8SCy Schubert {
4385732ac8SCy Schubert return wpa_drv_macsec_get_capability(priv, cap);
4485732ac8SCy Schubert }
4585732ac8SCy Schubert
4685732ac8SCy Schubert
wpas_enable_protect_frames(void * wpa_s,bool enabled)47c1d255d3SCy Schubert static int wpas_enable_protect_frames(void *wpa_s, bool enabled)
485b9c547cSRui Paulo {
495b9c547cSRui Paulo return wpa_drv_enable_protect_frames(wpa_s, enabled);
505b9c547cSRui Paulo }
515b9c547cSRui Paulo
525b9c547cSRui Paulo
wpas_enable_encrypt(void * wpa_s,bool enabled)53c1d255d3SCy Schubert static int wpas_enable_encrypt(void *wpa_s, bool enabled)
5485732ac8SCy Schubert {
5585732ac8SCy Schubert return wpa_drv_enable_encrypt(wpa_s, enabled);
5685732ac8SCy Schubert }
5785732ac8SCy Schubert
5885732ac8SCy Schubert
wpas_set_replay_protect(void * wpa_s,bool enabled,u32 window)59c1d255d3SCy Schubert static int wpas_set_replay_protect(void *wpa_s, bool enabled, u32 window)
605b9c547cSRui Paulo {
615b9c547cSRui Paulo return wpa_drv_set_replay_protect(wpa_s, enabled, window);
625b9c547cSRui Paulo }
635b9c547cSRui Paulo
645b9c547cSRui Paulo
wpas_set_current_cipher_suite(void * wpa_s,u64 cs)65780fb4a2SCy Schubert static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
665b9c547cSRui Paulo {
67780fb4a2SCy Schubert return wpa_drv_set_current_cipher_suite(wpa_s, cs);
685b9c547cSRui Paulo }
695b9c547cSRui Paulo
705b9c547cSRui Paulo
wpas_enable_controlled_port(void * wpa_s,bool enabled)71c1d255d3SCy Schubert static int wpas_enable_controlled_port(void *wpa_s, bool enabled)
725b9c547cSRui Paulo {
735b9c547cSRui Paulo return wpa_drv_enable_controlled_port(wpa_s, enabled);
745b9c547cSRui Paulo }
755b9c547cSRui Paulo
765b9c547cSRui Paulo
wpas_get_receive_lowest_pn(void * wpa_s,struct receive_sa * sa)7785732ac8SCy Schubert static int wpas_get_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
785b9c547cSRui Paulo {
7985732ac8SCy Schubert return wpa_drv_get_receive_lowest_pn(wpa_s, sa);
805b9c547cSRui Paulo }
815b9c547cSRui Paulo
825b9c547cSRui Paulo
wpas_get_transmit_next_pn(void * wpa_s,struct transmit_sa * sa)8385732ac8SCy Schubert static int wpas_get_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
845b9c547cSRui Paulo {
8585732ac8SCy Schubert return wpa_drv_get_transmit_next_pn(wpa_s, sa);
865b9c547cSRui Paulo }
875b9c547cSRui Paulo
885b9c547cSRui Paulo
wpas_set_transmit_next_pn(void * wpa_s,struct transmit_sa * sa)8985732ac8SCy Schubert static int wpas_set_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
905b9c547cSRui Paulo {
9185732ac8SCy Schubert return wpa_drv_set_transmit_next_pn(wpa_s, sa);
925b9c547cSRui Paulo }
935b9c547cSRui Paulo
945b9c547cSRui Paulo
wpas_set_receive_lowest_pn(void * wpa_s,struct receive_sa * sa)954bc52338SCy Schubert static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
964bc52338SCy Schubert {
974bc52338SCy Schubert return wpa_drv_set_receive_lowest_pn(wpa_s, sa);
984bc52338SCy Schubert }
994bc52338SCy Schubert
1004bc52338SCy Schubert
wpas_set_offload(void * wpa_s,u8 offload)101*a90b9d01SCy Schubert static int wpas_set_offload(void *wpa_s, u8 offload)
102*a90b9d01SCy Schubert {
103*a90b9d01SCy Schubert return wpa_drv_set_offload(wpa_s, offload);
104*a90b9d01SCy Schubert }
105*a90b9d01SCy Schubert
106*a90b9d01SCy Schubert
conf_offset_val(enum confidentiality_offset co)1075b9c547cSRui Paulo static unsigned int conf_offset_val(enum confidentiality_offset co)
1085b9c547cSRui Paulo {
1095b9c547cSRui Paulo switch (co) {
1105b9c547cSRui Paulo case CONFIDENTIALITY_OFFSET_30:
1115b9c547cSRui Paulo return 30;
1125b9c547cSRui Paulo case CONFIDENTIALITY_OFFSET_50:
1135b9c547cSRui Paulo return 50;
1145b9c547cSRui Paulo default:
1155b9c547cSRui Paulo return 0;
1165b9c547cSRui Paulo }
1175b9c547cSRui Paulo }
1185b9c547cSRui Paulo
1195b9c547cSRui Paulo
wpas_create_receive_sc(void * wpa_s,struct receive_sc * sc,enum validate_frames vf,enum confidentiality_offset co)12085732ac8SCy Schubert static int wpas_create_receive_sc(void *wpa_s, struct receive_sc *sc,
1215b9c547cSRui Paulo enum validate_frames vf,
1225b9c547cSRui Paulo enum confidentiality_offset co)
1235b9c547cSRui Paulo {
12485732ac8SCy Schubert return wpa_drv_create_receive_sc(wpa_s, sc, conf_offset_val(co), vf);
1255b9c547cSRui Paulo }
1265b9c547cSRui Paulo
1275b9c547cSRui Paulo
wpas_delete_receive_sc(void * wpa_s,struct receive_sc * sc)12885732ac8SCy Schubert static int wpas_delete_receive_sc(void *wpa_s, struct receive_sc *sc)
1295b9c547cSRui Paulo {
13085732ac8SCy Schubert return wpa_drv_delete_receive_sc(wpa_s, sc);
1315b9c547cSRui Paulo }
1325b9c547cSRui Paulo
1335b9c547cSRui Paulo
wpas_create_receive_sa(void * wpa_s,struct receive_sa * sa)13485732ac8SCy Schubert static int wpas_create_receive_sa(void *wpa_s, struct receive_sa *sa)
1355b9c547cSRui Paulo {
13685732ac8SCy Schubert return wpa_drv_create_receive_sa(wpa_s, sa);
1375b9c547cSRui Paulo }
1385b9c547cSRui Paulo
1395b9c547cSRui Paulo
wpas_delete_receive_sa(void * wpa_s,struct receive_sa * sa)14085732ac8SCy Schubert static int wpas_delete_receive_sa(void *wpa_s, struct receive_sa *sa)
1415b9c547cSRui Paulo {
14285732ac8SCy Schubert return wpa_drv_delete_receive_sa(wpa_s, sa);
1435b9c547cSRui Paulo }
1445b9c547cSRui Paulo
1455b9c547cSRui Paulo
wpas_enable_receive_sa(void * wpa_s,struct receive_sa * sa)14685732ac8SCy Schubert static int wpas_enable_receive_sa(void *wpa_s, struct receive_sa *sa)
1475b9c547cSRui Paulo {
14885732ac8SCy Schubert return wpa_drv_enable_receive_sa(wpa_s, sa);
1495b9c547cSRui Paulo }
1505b9c547cSRui Paulo
1515b9c547cSRui Paulo
wpas_disable_receive_sa(void * wpa_s,struct receive_sa * sa)15285732ac8SCy Schubert static int wpas_disable_receive_sa(void *wpa_s, struct receive_sa *sa)
1535b9c547cSRui Paulo {
15485732ac8SCy Schubert return wpa_drv_disable_receive_sa(wpa_s, sa);
1555b9c547cSRui Paulo }
1565b9c547cSRui Paulo
1575b9c547cSRui Paulo
1585b9c547cSRui Paulo static int
wpas_create_transmit_sc(void * wpa_s,struct transmit_sc * sc,enum confidentiality_offset co)15985732ac8SCy Schubert wpas_create_transmit_sc(void *wpa_s, struct transmit_sc *sc,
1605b9c547cSRui Paulo enum confidentiality_offset co)
1615b9c547cSRui Paulo {
16285732ac8SCy Schubert return wpa_drv_create_transmit_sc(wpa_s, sc, conf_offset_val(co));
1635b9c547cSRui Paulo }
1645b9c547cSRui Paulo
1655b9c547cSRui Paulo
wpas_delete_transmit_sc(void * wpa_s,struct transmit_sc * sc)16685732ac8SCy Schubert static int wpas_delete_transmit_sc(void *wpa_s, struct transmit_sc *sc)
1675b9c547cSRui Paulo {
16885732ac8SCy Schubert return wpa_drv_delete_transmit_sc(wpa_s, sc);
1695b9c547cSRui Paulo }
1705b9c547cSRui Paulo
1715b9c547cSRui Paulo
wpas_create_transmit_sa(void * wpa_s,struct transmit_sa * sa)17285732ac8SCy Schubert static int wpas_create_transmit_sa(void *wpa_s, struct transmit_sa *sa)
1735b9c547cSRui Paulo {
17485732ac8SCy Schubert return wpa_drv_create_transmit_sa(wpa_s, sa);
1755b9c547cSRui Paulo }
1765b9c547cSRui Paulo
1775b9c547cSRui Paulo
wpas_delete_transmit_sa(void * wpa_s,struct transmit_sa * sa)17885732ac8SCy Schubert static int wpas_delete_transmit_sa(void *wpa_s, struct transmit_sa *sa)
1795b9c547cSRui Paulo {
18085732ac8SCy Schubert return wpa_drv_delete_transmit_sa(wpa_s, sa);
1815b9c547cSRui Paulo }
1825b9c547cSRui Paulo
1835b9c547cSRui Paulo
wpas_enable_transmit_sa(void * wpa_s,struct transmit_sa * sa)18485732ac8SCy Schubert static int wpas_enable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
1855b9c547cSRui Paulo {
18685732ac8SCy Schubert return wpa_drv_enable_transmit_sa(wpa_s, sa);
18785732ac8SCy Schubert }
18885732ac8SCy Schubert
18985732ac8SCy Schubert
wpas_disable_transmit_sa(void * wpa_s,struct transmit_sa * sa)19085732ac8SCy Schubert static int wpas_disable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
19185732ac8SCy Schubert {
19285732ac8SCy Schubert return wpa_drv_disable_transmit_sa(wpa_s, sa);
1935b9c547cSRui Paulo }
1945b9c547cSRui Paulo
1955b9c547cSRui Paulo
ieee802_1x_alloc_kay_sm(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1965b9c547cSRui Paulo int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
1975b9c547cSRui Paulo {
1985b9c547cSRui Paulo struct ieee802_1x_kay_ctx *kay_ctx;
1995b9c547cSRui Paulo struct ieee802_1x_kay *res = NULL;
2005b9c547cSRui Paulo enum macsec_policy policy;
2015b9c547cSRui Paulo
2025b9c547cSRui Paulo ieee802_1x_dealloc_kay_sm(wpa_s);
2035b9c547cSRui Paulo
2045b9c547cSRui Paulo if (!ssid || ssid->macsec_policy == 0)
2055b9c547cSRui Paulo return 0;
2065b9c547cSRui Paulo
20785732ac8SCy Schubert if (ssid->macsec_policy == 1) {
20885732ac8SCy Schubert if (ssid->macsec_integ_only == 1)
20985732ac8SCy Schubert policy = SHOULD_SECURE;
21085732ac8SCy Schubert else
21185732ac8SCy Schubert policy = SHOULD_ENCRYPT;
21285732ac8SCy Schubert } else {
21385732ac8SCy Schubert policy = DO_NOT_SECURE;
21485732ac8SCy Schubert }
2155b9c547cSRui Paulo
2165b9c547cSRui Paulo kay_ctx = os_zalloc(sizeof(*kay_ctx));
2175b9c547cSRui Paulo if (!kay_ctx)
2185b9c547cSRui Paulo return -1;
2195b9c547cSRui Paulo
2205b9c547cSRui Paulo kay_ctx->ctx = wpa_s;
2215b9c547cSRui Paulo
2225b9c547cSRui Paulo kay_ctx->macsec_init = wpas_macsec_init;
2235b9c547cSRui Paulo kay_ctx->macsec_deinit = wpas_macsec_deinit;
22485732ac8SCy Schubert kay_ctx->macsec_get_capability = wpas_macsec_get_capability;
2255b9c547cSRui Paulo kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
22685732ac8SCy Schubert kay_ctx->enable_encrypt = wpas_enable_encrypt;
2275b9c547cSRui Paulo kay_ctx->set_replay_protect = wpas_set_replay_protect;
228*a90b9d01SCy Schubert kay_ctx->set_offload = wpas_set_offload;
2295b9c547cSRui Paulo kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
2305b9c547cSRui Paulo kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
2315b9c547cSRui Paulo kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn;
2325b9c547cSRui Paulo kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn;
2335b9c547cSRui Paulo kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn;
2344bc52338SCy Schubert kay_ctx->set_receive_lowest_pn = wpas_set_receive_lowest_pn;
2355b9c547cSRui Paulo kay_ctx->create_receive_sc = wpas_create_receive_sc;
2365b9c547cSRui Paulo kay_ctx->delete_receive_sc = wpas_delete_receive_sc;
2375b9c547cSRui Paulo kay_ctx->create_receive_sa = wpas_create_receive_sa;
23885732ac8SCy Schubert kay_ctx->delete_receive_sa = wpas_delete_receive_sa;
2395b9c547cSRui Paulo kay_ctx->enable_receive_sa = wpas_enable_receive_sa;
2405b9c547cSRui Paulo kay_ctx->disable_receive_sa = wpas_disable_receive_sa;
2415b9c547cSRui Paulo kay_ctx->create_transmit_sc = wpas_create_transmit_sc;
2425b9c547cSRui Paulo kay_ctx->delete_transmit_sc = wpas_delete_transmit_sc;
2435b9c547cSRui Paulo kay_ctx->create_transmit_sa = wpas_create_transmit_sa;
24485732ac8SCy Schubert kay_ctx->delete_transmit_sa = wpas_delete_transmit_sa;
2455b9c547cSRui Paulo kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
2465b9c547cSRui Paulo kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
2475b9c547cSRui Paulo
2484bc52338SCy Schubert res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect,
249*a90b9d01SCy Schubert ssid->macsec_replay_window,
250*a90b9d01SCy Schubert ssid->macsec_offload, ssid->macsec_port,
251*a90b9d01SCy Schubert ssid->mka_priority, ssid->macsec_csindex,
252*a90b9d01SCy Schubert wpa_s->ifname, wpa_s->own_addr);
25385732ac8SCy Schubert /* ieee802_1x_kay_init() frees kay_ctx on failure */
25485732ac8SCy Schubert if (res == NULL)
2555b9c547cSRui Paulo return -1;
2565b9c547cSRui Paulo
2575b9c547cSRui Paulo wpa_s->kay = res;
2585b9c547cSRui Paulo
2595b9c547cSRui Paulo return 0;
2605b9c547cSRui Paulo }
2615b9c547cSRui Paulo
2625b9c547cSRui Paulo
ieee802_1x_dealloc_kay_sm(struct wpa_supplicant * wpa_s)2635b9c547cSRui Paulo void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
2645b9c547cSRui Paulo {
2655b9c547cSRui Paulo if (!wpa_s->kay)
2665b9c547cSRui Paulo return;
2675b9c547cSRui Paulo
2685b9c547cSRui Paulo ieee802_1x_kay_deinit(wpa_s->kay);
2695b9c547cSRui Paulo wpa_s->kay = NULL;
2705b9c547cSRui Paulo }
2715b9c547cSRui Paulo
2725b9c547cSRui Paulo
ieee802_1x_auth_get_msk(struct wpa_supplicant * wpa_s,const u8 * addr,u8 * msk,size_t * len)2735b9c547cSRui Paulo static int ieee802_1x_auth_get_msk(struct wpa_supplicant *wpa_s, const u8 *addr,
2745b9c547cSRui Paulo u8 *msk, size_t *len)
2755b9c547cSRui Paulo {
2765b9c547cSRui Paulo u8 key[EAP_MSK_LEN];
2775b9c547cSRui Paulo size_t keylen;
2785b9c547cSRui Paulo struct eapol_sm *sm;
2795b9c547cSRui Paulo int res;
2805b9c547cSRui Paulo
2815b9c547cSRui Paulo sm = wpa_s->eapol;
2825b9c547cSRui Paulo if (sm == NULL)
2835b9c547cSRui Paulo return -1;
2845b9c547cSRui Paulo
2855b9c547cSRui Paulo keylen = EAP_MSK_LEN;
2865b9c547cSRui Paulo res = eapol_sm_get_key(sm, key, keylen);
2875b9c547cSRui Paulo if (res) {
2885b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
2895b9c547cSRui Paulo "Failed to get MSK from EAPOL state machines");
2905b9c547cSRui Paulo return -1;
2915b9c547cSRui Paulo }
2925b9c547cSRui Paulo
2935b9c547cSRui Paulo if (keylen > *len)
2945b9c547cSRui Paulo keylen = *len;
2955b9c547cSRui Paulo os_memcpy(msk, key, keylen);
2965b9c547cSRui Paulo *len = keylen;
2975b9c547cSRui Paulo
2985b9c547cSRui Paulo return 0;
2995b9c547cSRui Paulo }
3005b9c547cSRui Paulo
3015b9c547cSRui Paulo
ieee802_1x_notify_create_actor(struct wpa_supplicant * wpa_s,const u8 * peer_addr)3025b9c547cSRui Paulo void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
3035b9c547cSRui Paulo const u8 *peer_addr)
3045b9c547cSRui Paulo {
305*a90b9d01SCy Schubert const u8 *sid;
306*a90b9d01SCy Schubert size_t sid_len;
3075b9c547cSRui Paulo struct mka_key_name *ckn;
3085b9c547cSRui Paulo struct mka_key *cak;
3095b9c547cSRui Paulo struct mka_key *msk;
3105b9c547cSRui Paulo void *res = NULL;
3115b9c547cSRui Paulo
3125b9c547cSRui Paulo if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
3135b9c547cSRui Paulo return NULL;
3145b9c547cSRui Paulo
3155b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
3165b9c547cSRui Paulo "IEEE 802.1X: External notification - Create MKA for "
3175b9c547cSRui Paulo MACSTR, MAC2STR(peer_addr));
3185b9c547cSRui Paulo
3195b9c547cSRui Paulo msk = os_zalloc(sizeof(*msk));
3205b9c547cSRui Paulo ckn = os_zalloc(sizeof(*ckn));
3215b9c547cSRui Paulo cak = os_zalloc(sizeof(*cak));
322*a90b9d01SCy Schubert if (!msk || !ckn || !cak)
3235b9c547cSRui Paulo goto fail;
3245b9c547cSRui Paulo
3255b9c547cSRui Paulo msk->len = DEFAULT_KEY_LEN;
3265b9c547cSRui Paulo if (ieee802_1x_auth_get_msk(wpa_s, wpa_s->bssid, msk->key, &msk->len)) {
3275b9c547cSRui Paulo wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
3285b9c547cSRui Paulo goto fail;
3295b9c547cSRui Paulo }
3305b9c547cSRui Paulo
331*a90b9d01SCy Schubert sid = eapol_sm_get_session_id(wpa_s->eapol, &sid_len);
332*a90b9d01SCy Schubert if (!sid) {
3335b9c547cSRui Paulo wpa_printf(MSG_ERROR,
3345b9c547cSRui Paulo "IEEE 802.1X: Could not get EAP Session Id");
3355b9c547cSRui Paulo goto fail;
3365b9c547cSRui Paulo }
3375b9c547cSRui Paulo
3385b9c547cSRui Paulo /* Derive CAK from MSK */
3395b9c547cSRui Paulo cak->len = DEFAULT_KEY_LEN;
3404bc52338SCy Schubert if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
3414bc52338SCy Schubert peer_addr, cak->key, cak->len)) {
3425b9c547cSRui Paulo wpa_printf(MSG_ERROR,
3435b9c547cSRui Paulo "IEEE 802.1X: Deriving CAK failed");
3445b9c547cSRui Paulo goto fail;
3455b9c547cSRui Paulo }
3465b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
3475b9c547cSRui Paulo
3485b9c547cSRui Paulo /* Derive CKN from MSK */
3495b9c547cSRui Paulo ckn->len = DEFAULT_CKN_LEN;
3504bc52338SCy Schubert if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
3514bc52338SCy Schubert peer_addr, sid, sid_len, ckn->name)) {
3525b9c547cSRui Paulo wpa_printf(MSG_ERROR,
3535b9c547cSRui Paulo "IEEE 802.1X: Deriving CKN failed");
3545b9c547cSRui Paulo goto fail;
3555b9c547cSRui Paulo }
3565b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
3575b9c547cSRui Paulo
3585b9c547cSRui Paulo res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
359c1d255d3SCy Schubert EAP_EXCHANGE, false);
3605b9c547cSRui Paulo
3615b9c547cSRui Paulo fail:
3625b9c547cSRui Paulo if (msk) {
3635b9c547cSRui Paulo os_memset(msk, 0, sizeof(*msk));
3645b9c547cSRui Paulo os_free(msk);
3655b9c547cSRui Paulo }
3665b9c547cSRui Paulo os_free(ckn);
3675b9c547cSRui Paulo if (cak) {
3685b9c547cSRui Paulo os_memset(cak, 0, sizeof(*cak));
3695b9c547cSRui Paulo os_free(cak);
3705b9c547cSRui Paulo }
3715b9c547cSRui Paulo
3725b9c547cSRui Paulo return res;
3735b9c547cSRui Paulo }
37485732ac8SCy Schubert
37585732ac8SCy Schubert
ieee802_1x_create_preshared_mka(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)37685732ac8SCy Schubert void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
37785732ac8SCy Schubert struct wpa_ssid *ssid)
37885732ac8SCy Schubert {
37985732ac8SCy Schubert struct mka_key *cak;
38085732ac8SCy Schubert struct mka_key_name *ckn;
38185732ac8SCy Schubert void *res = NULL;
38285732ac8SCy Schubert
38385732ac8SCy Schubert if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
38485732ac8SCy Schubert goto end;
38585732ac8SCy Schubert
38685732ac8SCy Schubert ckn = os_zalloc(sizeof(*ckn));
38785732ac8SCy Schubert if (!ckn)
38885732ac8SCy Schubert goto end;
38985732ac8SCy Schubert
39085732ac8SCy Schubert cak = os_zalloc(sizeof(*cak));
39185732ac8SCy Schubert if (!cak)
39285732ac8SCy Schubert goto free_ckn;
39385732ac8SCy Schubert
39485732ac8SCy Schubert if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0 || !wpa_s->kay)
39585732ac8SCy Schubert goto free_cak;
39685732ac8SCy Schubert
39785732ac8SCy Schubert if (wpa_s->kay->policy == DO_NOT_SECURE)
39885732ac8SCy Schubert goto dealloc;
39985732ac8SCy Schubert
4004bc52338SCy Schubert cak->len = ssid->mka_cak_len;
40185732ac8SCy Schubert os_memcpy(cak->key, ssid->mka_cak, cak->len);
40285732ac8SCy Schubert
4034bc52338SCy Schubert ckn->len = ssid->mka_ckn_len;
40485732ac8SCy Schubert os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
40585732ac8SCy Schubert
406c1d255d3SCy Schubert res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, false);
40785732ac8SCy Schubert if (res)
40885732ac8SCy Schubert goto free_cak;
40985732ac8SCy Schubert
41085732ac8SCy Schubert dealloc:
41185732ac8SCy Schubert /* Failed to create MKA */
41285732ac8SCy Schubert ieee802_1x_dealloc_kay_sm(wpa_s);
41385732ac8SCy Schubert free_cak:
41485732ac8SCy Schubert os_free(cak);
41585732ac8SCy Schubert free_ckn:
41685732ac8SCy Schubert os_free(ckn);
41785732ac8SCy Schubert end:
41885732ac8SCy Schubert return res;
41985732ac8SCy Schubert }
420