Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / rsn_supp / peerkey.c
index 9d60d4a..79764d9 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -20,6 +14,7 @@
 #include "eloop.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "wpa.h"
 #include "wpa_i.h"
@@ -70,6 +65,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
 {
        size_t rlen;
        struct wpa_eapol_key *err;
+       struct wpa_eapol_key_192 *err192;
        struct rsn_error_kde error;
        u8 *rbuf, *pos;
        size_t kde_len;
@@ -84,6 +80,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
                                  (void *) &err);
        if (rbuf == NULL)
                return -1;
+       err192 = (struct wpa_eapol_key_192 *) err;
 
        err->type = EAPOL_KEY_TYPE_RSN;
        key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -117,8 +114,8 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
                           "(mui %d error_type %d)", mui, error_type);
        }
 
-       wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
-                          rbuf, rlen, err->key_mic);
+       wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+                          ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
 
        return 0;
 }
@@ -131,6 +128,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
 {
        size_t rlen;
        struct wpa_eapol_key *reply;
+       struct wpa_eapol_key_192 *reply192;
        u8 *rbuf, *pos;
        size_t kde_len;
        u16 key_info;
@@ -145,6 +143,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
                                  (void *) &reply);
        if (rbuf == NULL)
                return -1;
+       reply192 = (struct wpa_eapol_key_192 *) reply;
 
        reply->type = EAPOL_KEY_TYPE_RSN;
        key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -169,8 +168,8 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
        wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
 
        wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
-       wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
-                          rbuf, rlen, reply->key_mic);
+       wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
+                          ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
 
        return 0;
 }
@@ -222,20 +221,17 @@ static int wpa_supplicant_process_smk_m2(
                return -1;
        }
 
-       cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
-       if (cipher & WPA_CIPHER_CCMP) {
-               wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
-               cipher = WPA_CIPHER_CCMP;
-       } else if (cipher & WPA_CIPHER_TKIP) {
-               wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
-               cipher = WPA_CIPHER_TKIP;
-       } else {
+       cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+                                         sm->allowed_pairwise_cipher, 0);
+       if (cipher < 0) {
                wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
                wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
                                              STK_MUI_SMK, STK_ERR_CPHR_NS,
                                              ver);
                return -1;
        }
+       wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+                  wpa_cipher_txt(cipher));
 
        /* TODO: find existing entry and if found, use that instead of adding
         * a new one; how to handle the case where both ends initiate at the
@@ -248,13 +244,9 @@ static int wpa_supplicant_process_smk_m2(
        os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
        peerkey->rsnie_i_len = kde.rsn_ie_len;
        peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
-       if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                          WPA_KEY_MGMT_PSK_SHA256))
-               peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+       peerkey->akmp = ie.key_mgmt;
 
-       if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "WPA: Failed to get random data for PNonce");
                wpa_supplicant_peerkey_free(sm, peerkey);
@@ -272,10 +264,7 @@ static int wpa_supplicant_process_smk_m2(
        /* Include only the selected cipher in pairwise cipher suite */
        WPA_PUT_LE16(pos, 1);
        pos += 2;
-       if (cipher == WPA_CIPHER_CCMP)
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-       else if (cipher == WPA_CIPHER_TKIP)
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+       RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
        pos += RSN_SELECTOR_LEN;
 
        hdr->len = (pos - peerkey->rsnie_p) - 2;
@@ -299,14 +288,14 @@ static int wpa_supplicant_process_smk_m2(
  * @mac_p: Peer MAC address
  * @inonce: Initiator Nonce
  * @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
  *
  * 8.5.1.4 Station to station (STK) key hierarchy
  * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
  */
 static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
                      const u8 *inonce, const u8 *mac_i, u8 *smkid,
-                     int use_sha256)
+                     int akmp)
 {
        char *title = "SMK Name";
        const u8 *addr[5];
@@ -321,7 +310,7 @@ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
        addr[4] = mac_i;
 
 #ifdef CONFIG_IEEE80211W
-       if (use_sha256)
+       if (wpa_key_mgmt_sha256(akmp))
                hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
        else
 #endif /* CONFIG_IEEE80211W */
@@ -349,7 +338,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
 
        msg->type = EAPOL_KEY_TYPE_RSN;
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -357,7 +346,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
        key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
        WPA_PUT_BE16(msg->key_info, key_info);
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                WPA_PUT_BE16(msg->key_length, 16);
        else
                WPA_PUT_BE16(msg->key_length, 32);
@@ -370,7 +359,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
        wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
                    peerkey->smkid, PMKID_LEN);
 
-       if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "RSN: Failed to get random data for INonce (STK)");
                os_free(mbuf);
@@ -382,7 +371,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
 
        wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
                   MAC2STR(peerkey->addr));
-       wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+       wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
                           mbuf, mlen, NULL);
 }
 
@@ -408,7 +397,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
 
        msg->type = EAPOL_KEY_TYPE_RSN;
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -417,7 +406,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
                WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
        WPA_PUT_BE16(msg->key_info, key_info);
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                WPA_PUT_BE16(msg->key_length, 16);
        else
                WPA_PUT_BE16(msg->key_length, 32);
@@ -437,8 +426,9 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
 
        wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
                   MAC2STR(peerkey->addr));
-       wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
-                          ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+       wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+                          peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+                          msg->key_mic);
 }
 
 
@@ -501,14 +491,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
        peerkey->rsnie_p_len = kde->rsn_ie_len;
        os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
 
-       cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
-       if (cipher & WPA_CIPHER_CCMP) {
-               wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
-               peerkey->cipher = WPA_CIPHER_CCMP;
-       } else if (cipher & WPA_CIPHER_TKIP) {
-               wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
-               peerkey->cipher = WPA_CIPHER_TKIP;
-       } else {
+       cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+                                         sm->allowed_pairwise_cipher, 0);
+       if (cipher < 0) {
                wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
                           "unacceptable cipher", MAC2STR(kde->mac_addr));
                wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
@@ -517,6 +502,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
                /* TODO: abort negotiation */
                return -1;
        }
+       wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+                  wpa_cipher_txt(cipher));
+       peerkey->cipher = cipher;
 
        return 0;
 }
@@ -529,7 +517,6 @@ static int wpa_supplicant_process_smk_m45(
        struct wpa_peerkey *peerkey;
        struct wpa_eapol_ie_parse kde;
        u32 lifetime;
-       struct os_time now;
 
        if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
                wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
@@ -581,22 +568,20 @@ static int wpa_supplicant_process_smk_m45(
        lifetime = WPA_GET_BE32(kde.lifetime);
        wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
        if (lifetime > 1000000000)
-               lifetime = 1000000000; /* avoid overflowing expiration time */
+               lifetime = 1000000000; /* avoid overflowing eloop time */
        peerkey->lifetime = lifetime;
-       os_get_time(&now);
-       peerkey->expiration = now.sec + lifetime;
        eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
                               sm, peerkey);
 
        if (peerkey->initiator) {
                rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
                          peerkey->inonce, sm->own_addr, peerkey->smkid,
-                         peerkey->use_sha256);
+                         peerkey->akmp);
                wpa_supplicant_send_stk_1_of_4(sm, peerkey);
        } else {
                rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
                          peerkey->inonce, peerkey->addr, peerkey->smkid,
-                         peerkey->use_sha256);
+                         peerkey->akmp);
        }
        wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
 
@@ -669,11 +654,11 @@ static int wpa_supplicant_process_smk_error(
 static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
                                              struct wpa_peerkey *peerkey,
                                              const struct wpa_eapol_key *key,
-                                             u16 ver)
+                                             u16 ver, const u8 *key_data,
+                                             size_t key_data_len)
 {
        struct wpa_eapol_ie_parse ie;
-       const u8 *kde;
-       size_t len, kde_buf_len;
+       size_t kde_buf_len;
        struct wpa_ptk *stk;
        u8 buf[8], *kde_buf, *pos;
        be32 lifetime;
@@ -684,20 +669,19 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
        os_memset(&ie, 0, sizeof(ie));
 
        /* RSN: msg 1/4 should contain SMKID for the selected SMK */
-       kde = (const u8 *) (key + 1);
-       len = WPA_GET_BE16(key->key_data_length);
-       wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
-       if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+       wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
+       if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
+           ie.pmkid == NULL) {
                wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
                return;
        }
-       if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+       if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
                wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
                            ie.pmkid, PMKID_LEN);
                return;
        }
 
-       if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "RSN: Failed to get random data for PNonce");
                return;
@@ -711,12 +695,11 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
        wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
                       sm->own_addr, peerkey->addr,
                       peerkey->pnonce, key->key_nonce,
-                      (u8 *) stk, sizeof(*stk),
-                      peerkey->use_sha256);
+                      stk, peerkey->akmp, peerkey->cipher);
        /* Supplicant: swap tx/rx Mic keys */
-       os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
-       os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
-       os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+       os_memcpy(buf, &stk->tk[16], 8);
+       os_memcpy(&stk->tk[16], &stk->tk[24], 8);
+       os_memcpy(&stk->tk[24], buf, 8);
        peerkey->tstk_set = 1;
 
        kde_buf_len = peerkey->rsnie_p_len +
@@ -749,7 +732,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
                                               struct wpa_eapol_ie_parse *kde)
 {
        u32 lifetime;
-       struct os_time now;
 
        if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
                return;
@@ -768,8 +750,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
                   lifetime, peerkey->lifetime);
        peerkey->lifetime = lifetime;
 
-       os_get_time(&now);
-       peerkey->expiration = now.sec + lifetime;
        eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
        eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
                               sm, peerkey);
@@ -779,11 +759,10 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
 static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
                                              struct wpa_peerkey *peerkey,
                                              const struct wpa_eapol_key *key,
-                                             u16 ver)
+                                             u16 ver, const u8 *key_data,
+                                             size_t key_data_len)
 {
        struct wpa_eapol_ie_parse kde;
-       const u8 *keydata;
-       size_t len;
 
        wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
                   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
@@ -792,16 +771,14 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
 
        /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
         * from the peer. It may also include Lifetime KDE. */
-       keydata = (const u8 *) (key + 1);
-       len = WPA_GET_BE16(key->key_data_length);
-       wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
-       if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+       wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
+       if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
            kde.pmkid == NULL || kde.rsn_ie == NULL) {
                wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
                return;
        }
 
-       if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+       if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
                wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
                            kde.pmkid, PMKID_LEN);
                return;
@@ -828,11 +805,11 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
 static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
                                              struct wpa_peerkey *peerkey,
                                              const struct wpa_eapol_key *key,
-                                             u16 ver)
+                                             u16 ver, const u8 *key_data,
+                                             size_t key_data_len)
 {
        struct wpa_eapol_ie_parse kde;
-       const u8 *keydata;
-       size_t len, key_len;
+       size_t key_len;
        const u8 *_key;
        u8 key_buf[32], rsc[6];
 
@@ -843,10 +820,8 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
 
        /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
         * Lifetime KDE. */
-       keydata = (const u8 *) (key + 1);
-       len = WPA_GET_BE16(key->key_data_length);
-       wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
-       if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+       wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
+       if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
                wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
                           "STK 3/4");
                return;
@@ -877,15 +852,15 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
 
        if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
                                       WPA_GET_BE16(key->key_info),
-                                      NULL, 0, &peerkey->stk))
+                                      &peerkey->stk))
                return;
 
-       _key = (u8 *) peerkey->stk.tk1;
+       _key = peerkey->stk.tk;
        if (peerkey->cipher == WPA_CIPHER_TKIP) {
                /* Swap Tx/Rx keys for Michael MIC */
                os_memcpy(key_buf, _key, 16);
-               os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
-               os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+               os_memcpy(key_buf + 16, _key + 24, 8);
+               os_memcpy(key_buf + 24, _key + 16, 8);
                _key = key_buf;
                key_len = 32;
        } else
@@ -894,10 +869,12 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
        os_memset(rsc, 0, 6);
        if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
                           rsc, sizeof(rsc), _key, key_len) < 0) {
+               os_memset(key_buf, 0, sizeof(key_buf));
                wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
                           "driver.");
                return;
        }
+       os_memset(key_buf, 0, sizeof(key_buf));
 }
 
 
@@ -913,7 +890,7 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
 
        os_memset(rsc, 0, 6);
        if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
-                          rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+                          rsc, sizeof(rsc), peerkey->stk.tk,
                           peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
                wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
                           "driver.");
@@ -934,27 +911,27 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
  */
 int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
                                 struct wpa_peerkey *peerkey,
-                                struct wpa_eapol_key *key, u16 ver,
+                                struct wpa_eapol_key_192 *key, u16 ver,
                                 const u8 *buf, size_t len)
 {
-       u8 mic[16];
+       u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+       size_t mic_len = 16;
        int ok = 0;
 
        if (peerkey->initiator && !peerkey->stk_set) {
                wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
                               sm->own_addr, peerkey->addr,
                               peerkey->inonce, key->key_nonce,
-                              (u8 *) &peerkey->stk, sizeof(peerkey->stk),
-                              peerkey->use_sha256);
+                              &peerkey->stk, peerkey->akmp, peerkey->cipher);
                peerkey->stk_set = 1;
        }
 
-       os_memcpy(mic, key->key_mic, 16);
+       os_memcpy(mic, key->key_mic, mic_len);
        if (peerkey->tstk_set) {
-               os_memset(key->key_mic, 0, 16);
-               wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
-                                 key->key_mic);
-               if (os_memcmp(mic, key->key_mic, 16) != 0) {
+               os_memset(key->key_mic, 0, mic_len);
+               wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
+                                 sm->key_mgmt, ver, buf, len, key->key_mic);
+               if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
                        wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
                                   "when using TSTK - ignoring TSTK");
                } else {
@@ -963,14 +940,15 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
                        peerkey->stk_set = 1;
                        os_memcpy(&peerkey->stk, &peerkey->tstk,
                                  sizeof(peerkey->stk));
+                       os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
                }
        }
 
        if (!ok && peerkey->stk_set) {
-               os_memset(key->key_mic, 0, 16);
-               wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
-                                 key->key_mic);
-               if (os_memcmp(mic, key->key_mic, 16) != 0) {
+               os_memset(key->key_mic, 0, mic_len);
+               wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
+                                 sm->key_mgmt, ver, buf, len, key->key_mic);
+               if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
                        wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
                                   "- dropping packet");
                        return -1;
@@ -1021,7 +999,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
                return -1;
        }
 
-       if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+       if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1039,10 +1017,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
                return -1;
        peerkey->initiator = 1;
        os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
-       if (wpa_key_mgmt_sha256(sm->key_mgmt))
-               peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+       peerkey->akmp = sm->key_mgmt;
 
        /* SMK M1:
         * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
@@ -1060,17 +1035,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
        count_pos = pos;
        pos += 2;
 
-       count = 0;
-       if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-               pos += RSN_SELECTOR_LEN;
-               count++;
-       }
-       if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-               pos += RSN_SELECTOR_LEN;
-               count++;
-       }
+       count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
+       pos += count * RSN_SELECTOR_LEN;
        WPA_PUT_LE16(count_pos, count);
 
        hdr->len = (pos - peerkey->rsnie_i) - 2;
@@ -1097,7 +1063,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
                  WPA_REPLAY_COUNTER_LEN);
        inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
 
-       if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
+       if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                        "WPA: Failed to get random data for INonce");
                os_free(rbuf);
@@ -1118,8 +1084,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
 
        wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
                   MACSTR ")", MAC2STR(peer));
-       wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
-                          rbuf, rlen, req->key_mic);
+       wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+                          ETH_P_EAPOL, rbuf, rlen, req->key_mic);
 
        peerkey->next = sm->peerkey;
        sm->peerkey = peerkey;
@@ -1138,27 +1104,32 @@ void peerkey_deinit(struct wpa_sm *sm)
        while (peerkey) {
                prev = peerkey;
                peerkey = peerkey->next;
-               os_free(prev);
+               wpa_supplicant_peerkey_free(sm, prev);
        }
+       sm->peerkey = NULL;
 }
 
 
 void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
-                          struct wpa_eapol_key *key, u16 key_info, u16 ver)
+                          struct wpa_eapol_key *key, u16 key_info, u16 ver,
+                          const u8 *key_data, size_t key_data_len)
 {
        if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
            (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
                /* 3/4 STK 4-Way Handshake */
-               wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
+               wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
+                                                 key_data, key_data_len);
        } else if (key_info & WPA_KEY_INFO_ACK) {
                /* 1/4 STK 4-Way Handshake */
-               wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
+               wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
+                                                 key_data, key_data_len);
        } else if (key_info & WPA_KEY_INFO_SECURE) {
                /* 4/4 STK 4-Way Handshake */
                wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
        } else {
                /* 2/4 STK 4-Way Handshake */
-               wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
+               wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
+                                                 key_data, key_data_len);
        }
 }