]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/pae/ieee802_1x_kay.c
mka: Add driver op to get macsec capabilities
[thirdparty/hostap.git] / src / pae / ieee802_1x_kay.c
index d29187dc88f8206288de015c1a1a5a5de19631da..52eeeff415e77de31d3c38a37bc9795879b3e08d 100644 (file)
@@ -339,18 +339,6 @@ ieee802_1x_kay_is_in_live_peer(
 }
 
 
-/**
- * ieee802_1x_kay_is_in_peer
- */
-static Boolean
-ieee802_1x_kay_is_in_peer(struct ieee802_1x_mka_participant *participant,
-                         const u8 *mi)
-{
-       return ieee802_1x_kay_is_in_live_peer(participant, mi) ||
-               ieee802_1x_kay_is_in_potential_peer(participant, mi);
-}
-
-
 /**
  * ieee802_1x_kay_get_peer
  */
@@ -373,12 +361,17 @@ ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
  */
 static struct macsec_ciphersuite *
 ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
-                               u8 *cs_id)
+                               const u8 *cs_id)
 {
        unsigned int i;
+       u64 cs;
+       be64 _cs;
+
+       os_memcpy(&_cs, cs_id, CS_ID_LEN);
+       cs = be_to_host64(_cs);
 
        for (i = 0; i < CS_TABLE_SIZE; i++) {
-               if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
+               if (cipher_suite_tbl[i].id == cs)
                        return &cipher_suite_tbl[i];
        }
 
@@ -1395,10 +1388,7 @@ static Boolean
 ieee802_1x_mka_dist_sak_body_present(
        struct ieee802_1x_mka_participant *participant)
 {
-       if (!participant->to_dist_sak || !participant->new_key)
-               return FALSE;
-
-       return TRUE;
+       return participant->to_dist_sak && participant->new_key;
 }
 
 
@@ -1410,9 +1400,9 @@ ieee802_1x_mka_get_dist_sak_length(
        struct ieee802_1x_mka_participant *participant)
 {
        int length = MKA_HDR_LEN;
-       int cs_index = participant->kay->macsec_csindex;
+       unsigned int cs_index = participant->kay->macsec_csindex;
 
-       if (participant->advised_desired) {
+       if (participant->advised_desired && cs_index < CS_TABLE_SIZE) {
                length = sizeof(struct ieee802_1x_mka_dist_sak_body);
                if (cs_index != DEFAULT_CS_INDEX)
                        length += CS_ID_LEN;
@@ -1435,7 +1425,7 @@ ieee802_1x_mka_encode_dist_sak_body(
        struct ieee802_1x_mka_dist_sak_body *body;
        struct data_key *sak;
        unsigned int length;
-       int cs_index;
+       unsigned int cs_index;
        int sak_pos;
 
        length = ieee802_1x_mka_get_dist_sak_length(participant);
@@ -1454,8 +1444,13 @@ ieee802_1x_mka_encode_dist_sak_body(
        body->kn = host_to_be32(sak->key_identifier.kn);
        cs_index = participant->kay->macsec_csindex;
        sak_pos = 0;
+       if (cs_index >= CS_TABLE_SIZE)
+               return -1;
        if (cs_index != DEFAULT_CS_INDEX) {
-               os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
+               be64 cs;
+
+               cs = host_to_be64(cipher_suite_tbl[cs_index].id);
+               os_memcpy(body->sak, &cs, CS_ID_LEN);
                sak_pos = CS_ID_LEN;
        }
        if (aes_wrap(participant->kek.key, 16,
@@ -1474,39 +1469,13 @@ ieee802_1x_mka_encode_dist_sak_body(
 /**
  * ieee802_1x_kay_init_data_key -
  */
-static struct data_key *
-ieee802_1x_kay_init_data_key(const struct key_conf *conf)
+static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
 {
-       struct data_key *pkey;
-
-       if (!conf)
-               return NULL;
-
-       pkey = os_zalloc(sizeof(*pkey));
-       if (pkey == NULL) {
-               wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
-               return NULL;
-       }
-
-       pkey->key = os_zalloc(conf->key_len);
-       if (pkey->key == NULL) {
-               wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
-               os_free(pkey);
-               return NULL;
-       }
-
-       os_memcpy(pkey->key, conf->key, conf->key_len);
-       os_memcpy(&pkey->key_identifier, &conf->ki,
-                 sizeof(pkey->key_identifier));
-       pkey->confidentiality_offset = conf->offset;
-       pkey->an = conf->an;
-       pkey->transmits = conf->tx;
-       pkey->receives = conf->rx;
+       pkey->transmits = TRUE;
+       pkey->receives = TRUE;
        os_get_time(&pkey->created_time);
 
        pkey->user = 1;
-
-       return pkey;
 }
 
 
@@ -1523,9 +1492,7 @@ ieee802_1x_mka_decode_dist_sak_body(
        struct ieee802_1x_kay_peer *peer;
        struct macsec_ciphersuite *cs;
        size_t body_len;
-       struct key_conf *conf;
        struct data_key *sa_key = NULL;
-       struct ieee802_1x_mka_ki sak_ki;
        int sak_len;
        u8 *wrap_sak;
        u8 *unwrap_sak;
@@ -1604,6 +1571,7 @@ ieee802_1x_mka_decode_dist_sak_body(
                sak_len = DEFAULT_SA_KEY_LEN;
                wrap_sak =  body->sak;
                kay->macsec_csindex = DEFAULT_CS_INDEX;
+               cs = &cipher_suite_tbl[kay->macsec_csindex];
        } else {
                cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
                if (!cs) {
@@ -1629,61 +1597,36 @@ ieee802_1x_mka_decode_dist_sak_body(
        }
        wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
 
-       conf = os_zalloc(sizeof(*conf));
-       if (!conf) {
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
-               os_free(unwrap_sak);
-               return -1;
-       }
-       conf->key_len = sak_len;
-
-       conf->key = os_zalloc(conf->key_len);
-       if (!conf->key) {
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+       sa_key = os_zalloc(sizeof(*sa_key));
+       if (!sa_key) {
                os_free(unwrap_sak);
-               os_free(conf);
                return -1;
        }
 
-       os_memcpy(conf->key, unwrap_sak, conf->key_len);
-
-       os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
-                 sizeof(sak_ki.mi));
-       sak_ki.kn = be_to_host32(body->kn);
+       os_memcpy(&sa_key->key_identifier.mi, &participant->current_peer_id.mi,
+                 MI_LEN);
+       sa_key->key_identifier.kn = be_to_host32(body->kn);
 
-       os_memcpy(conf->ki.mi, sak_ki.mi, MI_LEN);
-       conf->ki.kn = sak_ki.kn;
-       conf->an = body->dan;
-       conf->offset = body->confid_offset;
-       conf->rx = TRUE;
-       conf->tx = TRUE;
+       sa_key->key = unwrap_sak;
+       sa_key->key_len = sak_len;
 
-       sa_key = ieee802_1x_kay_init_data_key(conf);
-       if (!sa_key) {
-               os_free(unwrap_sak);
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
+       sa_key->confidentiality_offset = body->confid_offset;
+       sa_key->an = body->dan;
+       ieee802_1x_kay_init_data_key(sa_key);
 
        dl_list_add(&participant->sak_list, &sa_key->list);
 
-       ieee802_1x_cp_set_ciphersuite(kay->cp,
-                                     cipher_suite_tbl[kay->macsec_csindex].id);
+       ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
        ieee802_1x_cp_sm_step(kay->cp);
        ieee802_1x_cp_set_offset(kay->cp, body->confid_offset);
        ieee802_1x_cp_sm_step(kay->cp);
-       ieee802_1x_cp_set_distributedki(kay->cp, &sak_ki);
+       ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
        ieee802_1x_cp_set_distributedan(kay->cp, body->dan);
        ieee802_1x_cp_signal_newsak(kay->cp);
        ieee802_1x_cp_sm_step(kay->cp);
 
        participant->to_use_sak = TRUE;
 
-       os_free(unwrap_sak);
-       os_free(conf->key);
-       os_free(conf);
-
        return 0;
 }
 
@@ -1956,11 +1899,13 @@ static int
 ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
 {
        struct data_key *sa_key = NULL;
-       struct key_conf *conf;
        struct ieee802_1x_kay_peer *peer;
        struct ieee802_1x_kay *kay = participant->kay;
        int ctx_len, ctx_offset;
        u8 *context;
+       unsigned int key_len;
+       u8 *key;
+       struct macsec_ciphersuite *cs;
 
        /* check condition for generating a fresh SAK:
         * must have one live peer
@@ -1987,40 +1932,29 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
                return -1;
        }
 
-       conf = os_zalloc(sizeof(*conf));
-       if (!conf) {
+       cs = &cipher_suite_tbl[kay->macsec_csindex];
+       key_len = cs->sak_len;
+       key = os_zalloc(key_len);
+       if (!key) {
                wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
                return -1;
        }
-       conf->key_len = cipher_suite_tbl[kay->macsec_csindex].sak_len;
 
-       conf->key = os_zalloc(conf->key_len);
-       if (!conf->key) {
-               os_free(conf);
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
-               return -1;
-       }
-
-       ctx_len = conf->key_len + sizeof(kay->dist_kn);
+       ctx_len = key_len + sizeof(kay->dist_kn);
        dl_list_for_each(peer, &participant->live_peers,
                         struct ieee802_1x_kay_peer, list)
                ctx_len += sizeof(peer->mi);
        ctx_len += sizeof(participant->mi);
 
        context = os_zalloc(ctx_len);
-       if (!context) {
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
+       if (!context)
+               goto fail;
+
        ctx_offset = 0;
-       if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
-               os_free(context);
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
-       ctx_offset += conf->key_len;
+       if (os_get_random(context + ctx_offset, key_len) < 0)
+               goto fail;
+
+       ctx_offset += key_len;
        dl_list_for_each(peer, &participant->live_peers,
                         struct ieee802_1x_kay_peer, list) {
                os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
@@ -2031,46 +1965,44 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
        ctx_offset += sizeof(participant->mi);
        os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
 
-       if (conf->key_len == 16) {
+       if (key_len == 16) {
                ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
-                                               context, ctx_len, conf->key);
-       } else if (conf->key_len == 32) {
+                                               context, ctx_len, key);
+       } else if (key_len == 32) {
                ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
-                                               context, ctx_len, conf->key);
+                                               context, ctx_len, key);
        } else {
                wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
-               os_free(conf->key);
-               os_free(conf);
-               os_free(context);
-               return -1;
+               goto fail;
        }
-       wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK",
-                   conf->key, conf->key_len);
-
-       os_memcpy(conf->ki.mi, participant->mi, MI_LEN);
-       conf->ki.kn = kay->dist_kn;
-       conf->an = kay->dist_an;
-       conf->offset = kay->macsec_confidentiality;
-       conf->rx = TRUE;
-       conf->tx = TRUE;
+       wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+       os_free(context);
+       context = NULL;
 
-       sa_key = ieee802_1x_kay_init_data_key(conf);
+       sa_key = os_zalloc(sizeof(*sa_key));
        if (!sa_key) {
-               os_free(conf->key);
-               os_free(conf);
-               os_free(context);
-               return -1;
+               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+               goto fail;
        }
+
+       sa_key->key = key;
+       sa_key->key_len = key_len;
+       os_memcpy(sa_key->key_identifier.mi, participant->mi, MI_LEN);
+       sa_key->key_identifier.kn = kay->dist_kn;
+
+       sa_key->confidentiality_offset = kay->macsec_confidentiality;
+       sa_key->an = kay->dist_an;
+       ieee802_1x_kay_init_data_key(sa_key);
+
        participant->new_key = sa_key;
 
        dl_list_add(&participant->sak_list, &sa_key->list);
-       ieee802_1x_cp_set_ciphersuite(kay->cp,
-                                     cipher_suite_tbl[kay->macsec_csindex].id);
+       ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
        ieee802_1x_cp_sm_step(kay->cp);
-       ieee802_1x_cp_set_offset(kay->cp, conf->offset);
+       ieee802_1x_cp_set_offset(kay->cp, kay->macsec_confidentiality);
        ieee802_1x_cp_sm_step(kay->cp);
-       ieee802_1x_cp_set_distributedki(kay->cp, &conf->ki);
-       ieee802_1x_cp_set_distributedan(kay->cp, conf->an);
+       ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+       ieee802_1x_cp_set_distributedan(kay->cp, sa_key->an);
        ieee802_1x_cp_signal_newsak(kay->cp);
        ieee802_1x_cp_sm_step(kay->cp);
 
@@ -2085,10 +2017,24 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
 
        kay->dist_time = time(NULL);
 
-       os_free(conf->key);
-       os_free(conf);
-       os_free(context);
        return 0;
+
+fail:
+       os_free(key);
+       os_free(context);
+       return -1;
+}
+
+
+static int compare_priorities(const struct ieee802_1x_kay_peer *peer,
+                             const struct ieee802_1x_kay_peer *other)
+{
+       if (peer->key_server_priority < other->key_server_priority)
+               return -1;
+       if (other->key_server_priority < peer->key_server_priority)
+               return 1;
+
+       return os_memcmp(peer->sci.addr, other->sci.addr, ETH_ALEN);
 }
 
 
@@ -2122,29 +2068,19 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
                        continue;
                }
 
-               if (peer->key_server_priority <
-                   key_server->key_server_priority) {
+               if (compare_priorities(peer, key_server) < 0)
                        key_server = peer;
-               } else if (peer->key_server_priority ==
-                          key_server->key_server_priority) {
-                       if (os_memcmp(peer->sci.addr, key_server->sci.addr,
-                                     ETH_ALEN) < 0)
-                               key_server = peer;
-               }
        }
 
        /* elect the key server between me and the above elected peer */
        i_is_key_server = FALSE;
        if (key_server && participant->can_be_key_server) {
-               if (kay->actor_priority
-                          < key_server->key_server_priority) {
+               struct ieee802_1x_kay_peer tmp;
+
+               tmp.key_server_priority = kay->actor_priority;
+               os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
+               if (compare_priorities(&tmp, key_server) < 0)
                        i_is_key_server = TRUE;
-               } else if (kay->actor_priority
-                                       == key_server->key_server_priority) {
-                       if (os_memcmp(kay->actor_sci.addr, key_server->sci.addr,
-                                     ETH_ALEN) < 0)
-                               i_is_key_server = TRUE;
-               }
        } else if (participant->can_be_key_server) {
                i_is_key_server = TRUE;
        }
@@ -2360,27 +2296,16 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
        participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
        kay = participant->kay;
        if (participant->cak_life) {
-               if (now > participant->cak_life) {
-                       kay->authenticated = FALSE;
-                       kay->secured = FALSE;
-                       kay->failed = TRUE;
-                       ieee802_1x_kay_delete_mka(kay, &participant->ckn);
-                       return;
-               }
+               if (now > participant->cak_life)
+                       goto delete_mka;
        }
 
        /* should delete MKA instance if there are not live peers
         * when the MKA life elapsed since its creating */
        if (participant->mka_life) {
                if (dl_list_empty(&participant->live_peers)) {
-                       if (now > participant->mka_life) {
-                               kay->authenticated = FALSE;
-                               kay->secured = FALSE;
-                               kay->failed = TRUE;
-                               ieee802_1x_kay_delete_mka(kay,
-                                                         &participant->ckn);
-                               return;
-                       }
+                       if (now > participant->mka_life)
+                               goto delete_mka;
                } else {
                        participant->mka_life = 0;
                }
@@ -2468,6 +2393,14 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
        eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
                               ieee802_1x_participant_timer,
                               participant, NULL);
+
+       return;
+
+delete_mka:
+       kay->authenticated = FALSE;
+       kay->secured = FALSE;
+       kay->failed = TRUE;
+       ieee802_1x_kay_delete_mka(kay, &participant->ckn);
 }
 
 
@@ -2835,38 +2768,6 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
 }
 
 
-/**
- * ieee802_1x_kay_cp_conf -
- */
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
-                          struct ieee802_1x_cp_conf *pconf)
-{
-       pconf->protect = kay->macsec_protect;
-       pconf->replay_protect = kay->macsec_replay_protect;
-       pconf->validate = kay->macsec_validate;
-
-       return 0;
-}
-
-
-/**
- * ieee802_1x_kay_alloc_cp_sm -
- */
-static struct ieee802_1x_cp_sm *
-ieee802_1x_kay_alloc_cp_sm(struct ieee802_1x_kay *kay)
-{
-       struct ieee802_1x_cp_conf conf;
-
-       os_memset(&conf, 0, sizeof(conf));
-       conf.protect = kay->macsec_protect;
-       conf.replay_protect = kay->macsec_replay_protect;
-       conf.validate = kay->macsec_validate;
-       conf.replay_window = kay->macsec_replay_window;
-
-       return ieee802_1x_cp_sm_init(kay, &conf);
-}
-
-
 /**
  * ieee802_1x_kay_mkpdu_sanity_check -
  *     sanity check specified in clause 11.11.2 of IEEE802.1X-2010
@@ -2947,21 +2848,19 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
                wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
                return -1;
        }
+
        msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
                                                 mka_msg_len);
-
-       if (msg_icv) {
-               if (os_memcmp_const(msg_icv, icv,
-                                   mka_alg_tbl[kay->mka_algindex].icv_len) !=
-                   0) {
-                       wpa_printf(MSG_ERROR,
-                                  "KaY: Computed ICV is not equal to Received ICV");
-               return -1;
-               }
-       } else {
+       if (!msg_icv) {
                wpa_printf(MSG_ERROR, "KaY: No ICV");
                return -1;
        }
+       if (os_memcmp_const(msg_icv, icv,
+                           mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
+               wpa_printf(MSG_ERROR,
+                          "KaY: Computed ICV is not equal to Received ICV");
+               return -1;
+       }
 
        return 0;
 }
@@ -2980,7 +2879,6 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
        u8 body_type;
        int i;
        const u8 *pos;
-       Boolean my_included;
        Boolean handled[256];
 
        if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
@@ -3001,21 +2899,10 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
        left_len -= body_len + MKA_HDR_LEN;
 
        /* check i am in the peer's peer list */
-       my_included = ieee802_1x_mka_i_in_peerlist(participant, pos, left_len);
-       if (my_included) {
+       if (ieee802_1x_mka_i_in_peerlist(participant, pos, left_len) &&
+           !ieee802_1x_kay_is_in_live_peer(participant,
+                                           participant->current_peer_id.mi)) {
                /* accept the peer as live peer */
-               if (!ieee802_1x_kay_is_in_peer(
-                           participant,
-                           participant->current_peer_id.mi)) {
-                       if (!ieee802_1x_kay_create_live_peer(
-                                   participant,
-                                   participant->current_peer_id.mi,
-                                   be_to_host32(
-                                           participant->current_peer_id.mn)))
-                               return -1;
-                       ieee802_1x_kay_elect_key_server(participant);
-                       ieee802_1x_kay_decide_macsec_use(participant);
-               }
                if (ieee802_1x_kay_is_in_potential_peer(
                            participant, participant->current_peer_id.mi)) {
                        if (!ieee802_1x_kay_move_live_peer(
@@ -3024,9 +2911,15 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
                                    be_to_host32(participant->
                                                 current_peer_id.mn)))
                                return -1;
-                       ieee802_1x_kay_elect_key_server(participant);
-                       ieee802_1x_kay_decide_macsec_use(participant);
+               } else if (!ieee802_1x_kay_create_live_peer(
+                                  participant, participant->current_peer_id.mi,
+                                  be_to_host32(participant->
+                                               current_peer_id.mn))) {
+                               return -1;
                }
+
+               ieee802_1x_kay_elect_key_server(participant);
+               ieee802_1x_kay_decide_macsec_use(participant);
        }
 
        /*
@@ -3176,13 +3069,20 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
                kay->macsec_replay_window = 0;
                kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
        } else {
-               kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
+               if (secy_get_capability(kay, &kay->macsec_capable) < 0) {
+                       os_free(kay);
+                       return NULL;
+               }
+
                kay->macsec_desired = TRUE;
                kay->macsec_protect = TRUE;
                kay->macsec_validate = Strict;
                kay->macsec_replay_protect = FALSE;
                kay->macsec_replay_window = 0;
-               kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+               if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF)
+                       kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+               else
+                       kay->macsec_confidentiality = MACSEC_CAP_INTEGRITY;
        }
 
        wpa_printf(MSG_DEBUG, "KaY: state machine created");
@@ -3194,7 +3094,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
        wpa_printf(MSG_DEBUG, "KaY: secy init macsec done");
 
        /* init CP */
-       kay->cp = ieee802_1x_kay_alloc_cp_sm(kay);
+       kay->cp = ieee802_1x_cp_sm_init(kay);
        if (kay->cp == NULL) {
                ieee802_1x_kay_deinit(kay);
                return NULL;
@@ -3512,14 +3412,16 @@ ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
  * ieee802_1x_kay_change_cipher_suite -
  */
 int
-ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
+ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
+                                  unsigned int cs_index)
 {
        struct ieee802_1x_mka_participant *participant;
+       enum macsec_cap secy_cap;
 
        if (!kay)
                return -1;
 
-       if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
+       if (cs_index >= CS_TABLE_SIZE) {
                wpa_printf(MSG_ERROR,
                           "KaY: Configured cipher suite index is out of range");
                return -1;
@@ -3533,6 +3435,12 @@ ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
        kay->macsec_csindex = cs_index;
        kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
 
+       if (secy_get_capability(kay, &secy_cap) < 0)
+               return -3;
+
+       if (kay->macsec_capable > secy_cap)
+               kay->macsec_capable = secy_cap;
+
        participant = ieee802_1x_kay_get_principal_participant(kay);
        if (participant) {
                wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");