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 */ }
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; }
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; }
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; }
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; }
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; }
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; } }
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 */ }
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; }
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; } }
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; }
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; }
/** * 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; }