Beispiel #1
0
static int ieee80211w_set_keys(struct wpa_sm *sm,
			       struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
		return 0;

	if (ie->igtk) {
		const struct wpa_igtk_kde *igtk;
		u16 keyidx;
		if (ie->igtk_len != sizeof(*igtk))
			return -1;
		igtk = (const struct wpa_igtk_kde *) ie->igtk;
		keyidx = WPA_GET_LE16(igtk->keyid);
		lwip_log("WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x\n",
			   keyidx, MAC2STR(igtk->pn));
		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
				igtk->igtk, WPA_IGTK_LEN);
		if (keyidx > 4095) {
			lwip_log("WPA: Invalid IGTK KeyID %d\n",
				   keyidx);
			return -1;
		}
		if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
				   (u8 *) "\xff\xff\xff\xff\xff\xff",
				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
				   igtk->igtk, WPA_IGTK_LEN) < 0) {
			lwip_log("WPA: Failed to configure IGTK to the driver\n");
			return -1;
		}
	}

	if (ie->dhv) {
		const struct wpa_dhv_kde *dhv;
		if (ie->dhv_len != sizeof(*dhv))
			return -1;
		dhv = (const struct wpa_dhv_kde *) ie->dhv;
		wpa_hexdump_key(MSG_DEBUG, "WPA: DHV", dhv->dhv, WPA_DHV_LEN);
		if (wpa_sm_set_key(sm, WPA_ALG_DHV,
				   (u8 *) "\xff\xff\xff\xff\xff\xff", 0, 0,
				   NULL, 0, dhv->dhv, WPA_DHV_LEN) < 0) {
			lwip_log("WPA: Failed to configure DHV to the driver\n");
			return -1;
		}
	}

	return 0;
#else /* CONFIG_IEEE80211W */
	return 0;
#endif /* CONFIG_IEEE80211W */
}
Beispiel #2
0
static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
{
	int keylen;
	enum wpa_alg alg;
	u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };

	wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");

	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
		wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
			   sm->pairwise_cipher);
		return -1;
	}

	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
	keylen = wpa_cipher_key_len(sm->pairwise_cipher);

	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
		return -1;
	}

	return 0;
}
Beispiel #3
0
static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
{
    int keylen;
    wpa_alg alg;
    u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };

    wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");

    switch (sm->pairwise_cipher) {
    case WPA_CIPHER_CCMP:
        alg = WPA_ALG_CCMP;
        keylen = 16;
        break;
    case WPA_CIPHER_TKIP:
        alg = WPA_ALG_TKIP;
        keylen = 32;
        break;
    default:
        wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
                   sm->pairwise_cipher);
        return -1;
    }

    if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
                       sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
        wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
        return -1;
    }

    return 0;
}
Beispiel #4
0
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
				      const struct wpa_eapol_key *key)
{
	int keylen, rsclen;
	enum wpa_alg alg;
	const u8 *key_rsc;
	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

	wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");

	switch (sm->pairwise_cipher) {
	case WPA_CIPHER_CCMP:
		alg = WPA_ALG_CCMP;
		keylen = 16;
		rsclen = 6;
		break;
	case WPA_CIPHER_TKIP:
		alg = WPA_ALG_TKIP;
		keylen = 32;
		rsclen = 6;
		break;
	case WPA_CIPHER_NONE:
		wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
			   "NONE - do not use pairwise keys");
		return 0;
	default:
		wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
			   sm->pairwise_cipher);
		return -1;
	}

	if (sm->proto == WPA_PROTO_RSN) {
		key_rsc = null_rsc;
	} else {
		key_rsc = key->key_rsc;
		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
	}

	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
			   (u8 *) sm->ptk.tk1, keylen) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
			   "driver (alg=%d keylen=%d bssid=" MACSTR ")",
			   alg, keylen, MAC2STR(sm->bssid));
		return -1;
	}

	if (sm->wpa_ptk_rekey) {
		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
				       sm, NULL);
	}

	return 0;
}
Beispiel #5
0
static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
				      const struct wpa_gtk_data *gd,
				      const u8 *key_rsc)
{
	const u8 *_gtk = gd->gtk;
	u8 gtk_buf[32];

	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
	wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
		   "(keyidx=%d tx=%d len=%d).", gd->keyidx, gd->tx,
		   gd->gtk_len);
	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
	if (sm->group_cipher == WPA_CIPHER_TKIP) {
		/* Swap Tx/Rx keys for Michael MIC */
		os_memcpy(gtk_buf, gd->gtk, 16);
		os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
		os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
		_gtk = gtk_buf;
	}
	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
		if (wpa_sm_set_key(sm, gd->alg,
				   (u8 *) "\xff\xff\xff\xff\xff\xff",
				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
				   _gtk, gd->gtk_len) < 0) {
			wpa_printf(MSG_WARNING, "WPA: Failed to set "
				   "GTK to the driver (Group only).");
			return -1;
		}
	} else if (wpa_sm_set_key(sm, gd->alg,
				  (u8 *) "\xff\xff\xff\xff\xff\xff",
				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
				  _gtk, gd->gtk_len) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
			   "the driver (alg=%d keylen=%d keyidx=%d)",
			   gd->alg, gd->gtk_len, gd->keyidx);
		return -1;
	}

	return 0;
}
Beispiel #6
0
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
				       size_t igtk_elem_len)
{
	u8 igtk[WPA_IGTK_LEN];
	u16 keyidx;

	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
		return 0;

	if (igtk_elem == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
		return 0;
	}

	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
			igtk_elem, igtk_elem_len);

	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
			   "length %lu", (unsigned long) igtk_elem_len);
		return -1;
	}
	if (igtk_elem[8] != WPA_IGTK_LEN) {
		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
			   "%d", igtk_elem[8]);
		return -1;
	}

	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
		       igtk_elem + 9, igtk)) {
		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
			   "decrypt IGTK");
		return -1;
	}

	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */

	keyidx = WPA_GET_LE16(igtk_elem);

	wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
			WPA_IGTK_LEN);
	if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
			   igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
			   "driver.");
		return -1;
	}

	return 0;
}
Beispiel #7
0
static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
					      struct wpa_peerkey *peerkey,
					      const struct wpa_eapol_key *key,
					      u16 ver)
{
	u8 rsc[6];

	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);

	os_memset(rsc, 0, 6);
	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
			   rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
			   "driver.");
		return;
	}
}
Beispiel #8
0
static int ieee80211w_set_keys(struct wpa_sm *sm,
			       struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
		return 0;

	if (ie->igtk) {
		const struct wpa_igtk_kde *igtk;
		u16 keyidx;
		if (ie->igtk_len != sizeof(*igtk))
			return -1;
		igtk = (const struct wpa_igtk_kde *) ie->igtk;
		keyidx = WPA_GET_LE16(igtk->keyid);
		wpa_printf(MSG_DEBUG, "WPA: IGTK keyid %d "
			   "pn %02x%02x%02x%02x%02x%02x",
			   keyidx, MAC2STR(igtk->pn));
		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
				igtk->igtk, WPA_IGTK_LEN);
		if (keyidx > 4095) {
			wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KeyID %d",
				   keyidx);
			return -1;
		}
		if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
				   (u8 *) "\xff\xff\xff\xff\xff\xff",
				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
				   igtk->igtk, WPA_IGTK_LEN) < 0) {
			wpa_printf(MSG_WARNING, "WPA: Failed to configure IGTK"
				   " to the driver");
			return -1;
		}
	}

	return 0;
#else /* CONFIG_IEEE80211W */
	return 0;
#endif /* CONFIG_IEEE80211W */
}
Beispiel #9
0
static int cckm_install_ptk(struct wpa_sm *sm)
{
	int keylen, rsclen;
	enum wpa_alg alg;
	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

	wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");

	switch (sm->pairwise_cipher) {
	case WPA_CIPHER_CCMP:
		alg = WPA_ALG_CCMP;
		keylen = 16;
		rsclen = 6;
		break;
	case WPA_CIPHER_TKIP:
		alg = WPA_ALG_TKIP;
		keylen = 32;
		rsclen = 6;
		break;
	case WPA_CIPHER_NONE:
		wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
				"NONE - do not use pairwise keys");
		return 0;
	default:
		wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
				sm->pairwise_cipher);
		return -1;
	}

	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
				(u8 *) sm->ptk.tk1, keylen) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
				"driver.");
		return -1;
	}

	return 0;
}
Beispiel #10
0
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)
{
	struct wpa_eapol_ie_parse kde;
	const u8 *keydata;
	size_t len, key_len;
	const u8 *_key;
	u8 key_buf[32], rsc[6];

	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);

	os_memset(&kde, 0, sizeof(kde));

	/* 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_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
			   "STK 3/4");
		return;
	}

	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
			   "handshakes did not match");
		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
			    "handshake",
			    peerkey->rsnie_i, peerkey->rsnie_i_len);
		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
			    "handshake",
			    kde.rsn_ie, kde.rsn_ie_len);
		return;
	}

	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
			   "4-Way Handshake differs from 3 of STK 4-Way "
			   "Handshake - drop packet (src=" MACSTR ")",
			   MAC2STR(peerkey->addr));
		return;
	}

	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);

	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
				       WPA_GET_BE16(key->key_info),
				       NULL, 0, &peerkey->stk))
		return;

	_key = (u8 *) peerkey->stk.tk1;
	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);
		_key = key_buf;
		key_len = 32;
	} else
		key_len = 16;

	os_memset(rsc, 0, 6);
	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
			   rsc, sizeof(rsc), _key, key_len) < 0) {
		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
			   "driver.");
		return;
	}
}
Beispiel #11
0
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
				      size_t gtk_elem_len)
{
	u8 gtk[32];
	int keyidx;
	enum wpa_alg alg;
	size_t gtk_len, keylen, rsc_len;

	if (gtk_elem == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
		return 0;
	}

	wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
			gtk_elem, gtk_elem_len);

	if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
	    gtk_elem_len - 19 > sizeof(gtk)) {
		wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
			   "length %lu", (unsigned long) gtk_elem_len);
		return -1;
	}
	gtk_len = gtk_elem_len - 19;
	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
		       gtk)) {
		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
			   "decrypt GTK");
		return -1;
	}

	keylen = wpa_cipher_key_len(sm->group_cipher);
	rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
	alg = wpa_cipher_to_alg(sm->group_cipher);
	if (alg == WPA_ALG_NONE) {
		wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
			   sm->group_cipher);
		return -1;
	}

	if (gtk_len < keylen) {
		wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
		return -1;
	}

	/* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */

	keyidx = WPA_GET_LE16(gtk_elem) & 0x03;

	if (gtk_elem[2] != keylen) {
		wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
			   "negotiated %lu",
			   gtk_elem[2], (unsigned long) keylen);
		return -1;
	}

	wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
	if (sm->group_cipher == WPA_CIPHER_TKIP) {
		/* Swap Tx/Rx keys for Michael MIC */
		u8 tmp[8];
		os_memcpy(tmp, gtk + 16, 8);
		os_memcpy(gtk + 16, gtk + 24, 8);
		os_memcpy(gtk + 24, tmp, 8);
	}
	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
			   "driver.");
		return -1;
	}

	return 0;
}
Beispiel #12
0
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
                                      size_t gtk_elem_len)
{
    u8 gtk[32];
    int keyidx;
    wpa_alg alg;
    size_t gtk_len, keylen, rsc_len;

    if (gtk_elem == NULL) {
        wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
        return 0;
    }

    wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
                    gtk_elem, gtk_elem_len);

    if (gtk_elem_len < 10 + 24 || (gtk_elem_len - 10) % 8 ||
            gtk_elem_len - 18 > sizeof(gtk)) {
        wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
                   "length %lu", (unsigned long) gtk_elem_len);
        return -1;
    }
    gtk_len = gtk_elem_len - 18;
    if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 10, gtk)) {
        wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
                   "decrypt GTK");
        return -1;
    }

    switch (sm->group_cipher) {
    case WPA_CIPHER_CCMP:
        keylen = 16;
        rsc_len = 6;
        alg = WPA_ALG_CCMP;
        break;
    case WPA_CIPHER_TKIP:
        keylen = 32;
        rsc_len = 6;
        alg = WPA_ALG_TKIP;
        break;
    case WPA_CIPHER_WEP104:
        keylen = 13;
        rsc_len = 0;
        alg = WPA_ALG_WEP;
        break;
    case WPA_CIPHER_WEP40:
        keylen = 5;
        rsc_len = 0;
        alg = WPA_ALG_WEP;
        break;
    default:
        wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
                   sm->group_cipher);
        return -1;
    }

    if (gtk_len < keylen) {
        wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
        return -1;
    }

    /* Key Info[1] | Key Length[1] | RSC[8] | Key[5..32]. */

    keyidx = gtk_elem[0] & 0x03;

    if (gtk_elem[1] != keylen) {
        wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
                   "negotiated %lu",
                   gtk_elem[1], (unsigned long) keylen);
        return -1;
    }

    wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
    if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
                       keyidx, 0, gtk_elem + 2, rsc_len, gtk, keylen) <
            0) {
        wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
                   "driver.");
        return -1;
    }

    return 0;
}
Beispiel #13
0
/**
 * cckm_egtk_to_gtk - Calculate GTK from Encrypted GTK
 * @cckm_rn: Association Request Numner
 * @gtk: Length of BTK
 * @gtk_len: Length of GTK
 *
 * GTK = RC4(RN | PTK-802.1X-Encrypt-Key, EGTK)
 * GTK = AES-Keywrap(PTK-802.1X-Encrypt-Key, EGTK)
 * - where PTK-802.1X-Encrypt-Key is the key as defined in Section 0
 * - Note that while the IV is not transmitted in the clear, its encrypted
 *   value is included in the EGTK. Thus, the EGTK length shall be the GTK
 *   key length plus 8 octets (e.g. the IV length). More explicitly, if the
 *   broadcast cipher is TKIP, while the GTK is 32 octets, the EGTK shall
 *   be 40 octets; similarly for AESCCMP, the GTK is 16 octets while the
 *   EGTK shall be 24 octets.
 */
static int cckm_install_gtk(struct wpa_sm *sm, u32 cckm_rn, u8 *gtk,
		int gtk_len, int keyidx, const u8 *key_rsc, int key_rsc_len)
{
	u8 gtk_buf[32];
	enum wpa_alg alg;

	switch (sm->group_cipher) {
		case WPA_CIPHER_CCMP:
			alg = WPA_ALG_CCMP;
			break;
		case WPA_CIPHER_TKIP:
			alg = WPA_ALG_TKIP;
			break;
		case WPA_CIPHER_NONE:
			wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
					"NONE - do not use pairwise keys");
			return 0;
		default:
			wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
					sm->pairwise_cipher);
			return -1;
	}

	if (sm->group_cipher == WPA_CIPHER_CCMP) {
		gtk_len -= 8;
		if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk, gtk_buf)) {
			wpa_printf(MSG_WARNING, "WPA: AES unwrap "
					"failed - could not decrypt GTK");
			return -1;
		}
		gtk = gtk_buf;
	} else if (sm->group_cipher == WPA_CIPHER_TKIP) {
		u8 data[20];

		WPA_PUT_LE32(data, cckm_rn);
		os_memcpy(data + 4, &sm->ptk.kek, sizeof(sm->ptk.kek));
		wpa_hexdump_key(MSG_DEBUG, "EGTK-Data", data, sizeof(data));

		rc4_skip(data, sizeof(data), 256, gtk, gtk_len);

		/* Swap Tx/Rx keys for Michael MIC */
		os_memcpy(gtk_buf, gtk, 16);
		os_memcpy(gtk_buf + 16, gtk + 24, 8);
		os_memcpy(gtk_buf + 24, gtk + 16, 8);
		gtk = gtk_buf;
	}

	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len);
	wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
			"(keyidx=%d tx=%d len=%d).", keyidx, 0, gtk_len);
	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, key_rsc_len);

	if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
				keyidx, 0, key_rsc, key_rsc_len,
				gtk, gtk_len) < 0) {
		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
				"the driver.");
		return -1;
	}

	return 0;
}