static int ar6000_new_sta(struct ar6000_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct ieee80211req_wpaie *ie; int ielen, res; u8 *iebuf = NULL; u8 buf[528]; //sizeof(struct ieee80211req_wpaie) + 4 + extra 6 bytes /* * Fetch negotiated WPA/RSN parameters from the system. */ memset(buf, 0, sizeof(buf)); ((int *)buf)[0] = IEEE80211_IOCTL_GETWPAIE; ie = (struct ieee80211req_wpaie *)&buf[4]; memcpy(ie->wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, AR6000_IOCTL_EXTENDED, buf, sizeof(*ie)+4)) { wpa_printf(MSG_ERROR, "%s: Failed to get WPA/RSN IE", __func__); goto no_ie; } ie = (struct ieee80211req_wpaie *)&buf[4]; wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", ie->wpa_ie, IEEE80211_MAX_OPT_IE); wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", ie->rsn_ie, IEEE80211_MAX_OPT_IE); #ifdef ATH_WPS_IE wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", ie->wps_ie, IEEE80211_MAX_OPT_IE); #endif /* ATH_WPS_IE */ iebuf = ie->wpa_ie; ielen = iebuf[1]; /* atheros seems to return some random data if WPA/RSN IE is not set. * Assume the IE was not included if the IE type is unknown. */ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) iebuf[1] = 0; if (iebuf[1] == 0 && ie->rsn_ie[1] > 0) { /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not * set. This is needed for WPA2. */ iebuf = ie->rsn_ie; if (iebuf[0] != WLAN_EID_RSN) iebuf[1] = 0; } ielen = iebuf[1]; #ifdef ATH_WPS_IE /* if WPS IE is present, preference is given to WPS */ if (ie->wps_ie && (ie->wps_ie[1] > 0 && (ie->wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) { iebuf = ie->wps_ie; ielen = ie->wps_ie[1]; } #endif /* ATH_WPS_IE */ if (ielen == 0) iebuf = NULL; else ielen += 2; no_ie: drv_event_assoc(hapd, addr, iebuf, ielen, 0); if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { /* Cached accounting data is not valid anymore. */ memset(drv->acct_mac, 0, ETH_ALEN); memset(&drv->acct_data, 0, sizeof(drv->acct_data)); } return 0; }
/** * wpa_parse_wpa_ie_rsn - Parse RSN IE * @rsn_ie: Buffer containing RSN IE * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) * @data: Pointer to structure that will be filled in with parsed data * Returns: 0 on success, <0 on failure */ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { const struct rsn_ie_hdr *hdr; const u8 *pos; int left; int i, count; os_memset(data, 0, sizeof(*data)); data->proto = WPA_PROTO_RSN; data->pairwise_cipher = WPA_CIPHER_CCMP; data->group_cipher = WPA_CIPHER_CCMP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; data->pmkid = NULL; data->num_pmkid = 0; #ifdef CONFIG_IEEE80211W data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; #else /* CONFIG_IEEE80211W */ data->mgmt_group_cipher = 0; #endif /* CONFIG_IEEE80211W */ if (rsn_ie_len == 0) { /* No RSN IE - fail silently */ return -1; } if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) rsn_ie_len); return -1; } hdr = (const struct rsn_ie_hdr *) rsn_ie; if (hdr->elem_id != WLAN_EID_RSN || hdr->len != rsn_ie_len - 2 || WPA_GET_LE16(hdr->version) != RSN_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", __func__); return -2; } pos = (const u8 *) (hdr + 1); left = rsn_ie_len - sizeof(*hdr); if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); if (!wpa_cipher_valid_group(data->group_cipher)) { wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x", __func__, data->group_cipher); return -1; } pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", __func__, left); return -3; } if (left >= 2) { data->pairwise_cipher = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -4; } for (i = 0; i < count; i++) { data->pairwise_cipher |= rsn_selector_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } #ifdef CONFIG_IEEE80211W if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " "pairwise cipher", __func__); return -1; } #endif /* CONFIG_IEEE80211W */ } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", __func__); return -5; } if (left >= 2) { data->key_mgmt = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -6; } for (i = 0; i < count; i++) { data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", __func__); return -7; } if (left >= 2) { data->capabilities = WPA_GET_LE16(pos); pos += 2; left -= 2; } if (left >= 2) { data->num_pmkid = WPA_GET_LE16(pos); pos += 2; left -= 2; if (left < (int) data->num_pmkid * PMKID_LEN) { wpa_printf(MSG_DEBUG, "%s: PMKID underflow " "(num_pmkid=%lu left=%d)", __func__, (unsigned long) data->num_pmkid, left); data->num_pmkid = 0; return -9; } else { data->pmkid = pos; pos += data->num_pmkid * PMKID_LEN; left -= data->num_pmkid * PMKID_LEN; } } #ifdef CONFIG_IEEE80211W if (left >= 4) { data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { wpa_printf(MSG_DEBUG, "%s: Unsupported management " "group cipher 0x%x", __func__, data->mgmt_group_cipher); return -10; } pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ if (left > 0) { wpa_hexdump(MSG_DEBUG, "wpa_parse_wpa_ie_rsn: ignore trailing bytes", pos, left); } return 0; }
/** * eap_gpsk_derive_keys - Derive EAP-GPSK keys * @psk: Pre-shared key * @psk_len: Length of psk in bytes * @vendor: CSuite/Vendor * @specifier: CSuite/Specifier * @rand_peer: 32-byte RAND_Peer * @rand_server: 32-byte RAND_Server * @id_peer: ID_Peer * @id_peer_len: Length of ID_Peer * @id_server: ID_Server * @id_server_len: Length of ID_Server * @msk: Buffer for 64-byte MSK * @emsk: Buffer for 64-byte EMSK * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes) * @sk_len: Buffer for returning length of SK * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes) * @pk_len: Buffer for returning length of PK * Returns: 0 on success, -1 on failure */ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, int specifier, const u8 *rand_peer, const u8 *rand_server, const u8 *id_peer, size_t id_peer_len, const u8 *id_server, size_t id_server_len, u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, u8 *pk, size_t *pk_len) { u8 *seed, *pos; size_t seed_len; int ret; wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", vendor, specifier); if (vendor != EAP_GPSK_VENDOR_IETF) return -1; wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; seed = os_malloc(seed_len); if (seed == NULL) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " "for key derivation"); return -1; } pos = seed; os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); pos += EAP_GPSK_RAND_LEN; os_memcpy(pos, id_peer, id_peer_len); pos += id_peer_len; os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); pos += EAP_GPSK_RAND_LEN; os_memcpy(pos, id_server, id_server_len); pos += id_server_len; wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); switch (specifier) { case EAP_GPSK_CIPHER_AES: ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len, msk, emsk, sk, sk_len, pk, pk_len); break; #ifdef EAP_GPSK_SHA256 case EAP_GPSK_CIPHER_SHA256: ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len, msk, emsk, sk, sk_len); break; #endif /* EAP_GPSK_SHA256 */ default: wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " "key derivation", vendor, specifier); ret = -1; break; } os_free(seed); return ret; }
static void rx_data_bss_prot_group(struct wlantest *wt, const struct ieee80211_hdr *hdr, const u8 *qos, const u8 *dst, const u8 *src, const u8 *data, size_t len) { struct wlantest_bss *bss; int keyid; u8 *decrypted; size_t dlen; u8 pn[6]; bss = bss_get(wt, hdr->addr2); if (bss == NULL) return; if (len < 4) { wpa_printf(MSG_INFO, "Too short group addressed data frame"); return; } if (bss->group_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) && !(data[3] & 0x20)) { wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from " MACSTR " did not have ExtIV bit set to 1", MAC2STR(bss->bssid)); return; } if (bss->group_cipher == WPA_CIPHER_TKIP) { if (data[3] & 0x1f) { wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used " "non-zero reserved bit", MAC2STR(bss->bssid)); } if (data[1] != ((data[0] | 0x20) & 0x7f)) { wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used " "incorrect WEPSeed[1] (was 0x%x, expected " "0x%x)", MAC2STR(bss->bssid), data[1], (data[0] | 0x20) & 0x7f); } } else if (bss->group_cipher == WPA_CIPHER_CCMP) { if (data[2] != 0 || (data[3] & 0x1f) != 0) { wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used " "non-zero reserved bit", MAC2STR(bss->bssid)); } } keyid = data[3] >> 6; if (bss->gtk_len[keyid] == 0 && bss->group_cipher != WPA_CIPHER_WEP40) { wpa_printf(MSG_MSGDUMP, "No GTK known to decrypt the frame " "(A2=" MACSTR " KeyID=%d)", MAC2STR(hdr->addr2), keyid); return; } if (bss->group_cipher == WPA_CIPHER_TKIP) tkip_get_pn(pn, data); else if (bss->group_cipher == WPA_CIPHER_WEP40) goto skip_replay_det; else ccmp_get_pn(pn, data); if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) { u16 seq_ctrl = le_to_host16(hdr->seq_ctrl); wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3), WLAN_GET_SEQ_SEQ(seq_ctrl), WLAN_GET_SEQ_FRAG(seq_ctrl)); wpa_hexdump(MSG_INFO, "RX PN", pn, 6); wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6); } skip_replay_det: if (bss->group_cipher == WPA_CIPHER_TKIP) decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len, &dlen); else if (bss->group_cipher == WPA_CIPHER_WEP40) decrypted = wep_decrypt(wt, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len, &dlen); if (decrypted) { rx_data_process(wt, bss->bssid, NULL, dst, src, decrypted, dlen, 1, NULL); os_memcpy(bss->rsc[keyid], pn, 6); write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0), decrypted, dlen); } os_free(decrypted); }
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *mdie, size_t mdie_len) { struct wpa_ie_data data; int ciphers, key_mgmt, res, version; u32 selector; size_t i; const u8 *pmkid = NULL; if (wpa_auth == NULL || sm == NULL) return WPA_NOT_ENABLED; if (wpa_ie == NULL || wpa_ie_len < 1) return WPA_INVALID_IE; if (wpa_ie[0] == WLAN_EID_RSN) version = WPA_PROTO_RSN; else version = WPA_PROTO_WPA; if (!(wpa_auth->conf.wpa & version)) { wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, version, MAC2STR(sm->addr)); return WPA_INVALID_PROTO; } if (version == WPA_PROTO_RSN) { res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; if (0) { } #ifdef CONFIG_IEEE80211R else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_FT_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) selector = RSN_AUTH_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_PSK) selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; selector = RSN_CIPHER_SUITE_CCMP; if (data.pairwise_cipher & WPA_CIPHER_CCMP) selector = RSN_CIPHER_SUITE_CCMP; else if (data.pairwise_cipher & WPA_CIPHER_TKIP) selector = RSN_CIPHER_SUITE_TKIP; else if (data.pairwise_cipher & WPA_CIPHER_WEP104) selector = RSN_CIPHER_SUITE_WEP104; else if (data.pairwise_cipher & WPA_CIPHER_WEP40) selector = RSN_CIPHER_SUITE_WEP40; else if (data.pairwise_cipher & WPA_CIPHER_NONE) selector = RSN_CIPHER_SUITE_NONE; wpa_auth->dot11RSNAPairwiseCipherSelected = selector; selector = RSN_CIPHER_SUITE_CCMP; if (data.group_cipher & WPA_CIPHER_CCMP) selector = RSN_CIPHER_SUITE_CCMP; else if (data.group_cipher & WPA_CIPHER_TKIP) selector = RSN_CIPHER_SUITE_TKIP; else if (data.group_cipher & WPA_CIPHER_WEP104) selector = RSN_CIPHER_SUITE_WEP104; else if (data.group_cipher & WPA_CIPHER_WEP40) selector = RSN_CIPHER_SUITE_WEP40; else if (data.group_cipher & WPA_CIPHER_NONE) selector = RSN_CIPHER_SUITE_NONE; wpa_auth->dot11RSNAGroupCipherSelected = selector; } else { res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_PSK) selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; selector = WPA_CIPHER_SUITE_TKIP; if (data.pairwise_cipher & WPA_CIPHER_CCMP) selector = WPA_CIPHER_SUITE_CCMP; else if (data.pairwise_cipher & WPA_CIPHER_TKIP) selector = WPA_CIPHER_SUITE_TKIP; else if (data.pairwise_cipher & WPA_CIPHER_WEP104) selector = WPA_CIPHER_SUITE_WEP104; else if (data.pairwise_cipher & WPA_CIPHER_WEP40) selector = WPA_CIPHER_SUITE_WEP40; else if (data.pairwise_cipher & WPA_CIPHER_NONE) selector = WPA_CIPHER_SUITE_NONE; wpa_auth->dot11RSNAPairwiseCipherSelected = selector; selector = WPA_CIPHER_SUITE_TKIP; if (data.group_cipher & WPA_CIPHER_CCMP) selector = WPA_CIPHER_SUITE_CCMP; else if (data.group_cipher & WPA_CIPHER_TKIP) selector = WPA_CIPHER_SUITE_TKIP; else if (data.group_cipher & WPA_CIPHER_WEP104) selector = WPA_CIPHER_SUITE_WEP104; else if (data.group_cipher & WPA_CIPHER_WEP40) selector = WPA_CIPHER_SUITE_WEP40; else if (data.group_cipher & WPA_CIPHER_NONE) selector = WPA_CIPHER_SUITE_NONE; wpa_auth->dot11RSNAGroupCipherSelected = selector; } if (res) { wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " MACSTR " (res=%d)", MAC2STR(sm->addr), res); wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); return WPA_INVALID_IE; } if (data.group_cipher != wpa_auth->conf.wpa_group) { wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " MACSTR, data.group_cipher, MAC2STR(sm->addr)); return WPA_INVALID_GROUP; } key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; if (!key_mgmt) { wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " MACSTR, data.key_mgmt, MAC2STR(sm->addr)); return WPA_INVALID_AKMP; } if (0) { } #ifdef CONFIG_IEEE80211R else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; else sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; if (version == WPA_PROTO_RSN) ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; else ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; if (!ciphers) { wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " "from " MACSTR, version == WPA_PROTO_RSN ? "RSN" : "WPA", data.pairwise_cipher, MAC2STR(sm->addr)); return WPA_INVALID_PAIRWISE; } #ifdef CONFIG_IEEE80211W if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_DEBUG, "Management frame protection " "required, but client did not enable it"); return WPA_MGMT_FRAME_PROTECTION_VIOLATION; } if (ciphers & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "Management frame protection " "cannot use TKIP"); return WPA_MGMT_FRAME_PROTECTION_VIOLATION; } if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "Unsupported management group " "cipher %d", data.mgmt_group_cipher); return WPA_INVALID_MGMT_GROUP_CIPHER; } } if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || !(data.capabilities & WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; else sm->mgmt_frame_prot = 1; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " "MDIE not included"); return WPA_INVALID_MDIE; } if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); return WPA_INVALID_MDIE; } } #endif /* CONFIG_IEEE80211R */ if (ciphers & WPA_CIPHER_CCMP) sm->pairwise = WPA_CIPHER_CCMP; else sm->pairwise = WPA_CIPHER_TKIP; /* TODO: clear WPA/WPA2 state if STA changes from one to another */ if (wpa_ie[0] == WLAN_EID_RSN) sm->wpa = WPA_VERSION_WPA2; else sm->wpa = WPA_VERSION_WPA; sm->pmksa = NULL; for (i = 0; i < data.num_pmkid; i++) { wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", &data.pmkid[i * PMKID_LEN], PMKID_LEN); sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, &data.pmkid[i * PMKID_LEN]); if (sm->pmksa) { pmkid = sm->pmksa->pmkid; break; } } for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && i < data.num_pmkid; i++) { struct wpa_auth_okc_iter_data idata; idata.pmksa = NULL; idata.aa = wpa_auth->addr; idata.spa = sm->addr; idata.pmkid = &data.pmkid[i * PMKID_LEN]; wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); if (idata.pmksa) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "OKC match for PMKID"); sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, idata.pmksa, wpa_auth->addr, idata.pmkid); pmkid = idata.pmkid; break; } } if (sm->pmksa) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "PMKID found from PMKSA cache " "eap_type=%d vlan_id=%d", sm->pmksa->eap_type_authsrv, sm->pmksa->vlan_id); os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); } if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { os_free(sm->wpa_ie); sm->wpa_ie = os_malloc(wpa_ie_len); if (sm->wpa_ie == NULL) return WPA_ALLOC_FAIL; } os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); sm->wpa_ie_len = wpa_ie_len; return WPA_IE_OK; }
static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data) { struct eap_peer_config *conf; struct wpa_supplicant *wpa_s = sm->msg_ctx; int slotId=-1; wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm"); conf = eap_get_config(sm); if (conf == NULL) return -1; if(!wpa_s->conf->software_sim) { #ifdef MTK_EAP_SIM_AKA if (conf->pcsc) { if(os_strcmp(conf->sim_slot,"0")==0) { slotId=0; } if(os_strcmp(conf->sim_slot,"1")==0) { slotId=1; } if (scard_gsm_auth(slotId, data->rand[0], data->sres[0], data->kc[0]) || scard_gsm_auth(slotId, data->rand[1], data->sres[1], data->kc[1]) || (data->num_chal > 2 && scard_gsm_auth(slotId, data->rand[2], data->sres[2], data->kc[2]))) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM " "authentication could not be completed"); return -1; } return 0; } #else if (conf->pcsc) { if (scard_gsm_auth(sm->scard_ctx, data->rand[0], data->sres[0], data->kc[0]) || scard_gsm_auth(sm->scard_ctx, data->rand[1], data->sres[1], data->kc[1]) || (data->num_chal > 2 && scard_gsm_auth(sm->scard_ctx, data->rand[2], data->sres[2], data->kc[2]))) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM " "authentication could not be completed"); return -1; } return 0; } #endif } else { #ifdef CONFIG_SIM_SIMULATOR //if (conf->password) { conf->password = os_malloc(100); if(conf->password == NULL) return -1; strcpy(conf->password,"90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581"); conf->password_len=strlen(conf->password); u8 opc[16], k[16]; const char *pos; size_t i; wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage " "implementation for authentication"); if (conf->password_len < 65) { wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage " "password"); return -1; } pos = (const char *) conf->password; if (hexstr2bin(pos, k, 16)) return -1; pos += 32; if (*pos != ':') return -1; pos++; if (hexstr2bin(pos, opc, 16)) return -1; for (i = 0; i < data->num_chal; i++) { if (gsm_milenage(opc, k, data->rand[i], data->sres[i], data->kc[i])) { wpa_printf(MSG_DEBUG, "EAP-SIM: " "GSM-Milenage authentication " "could not be completed"); return -1; } wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND", data->rand[i], GSM_RAND_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES", data->sres[i], EAP_SIM_SRES_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc", data->kc[i], EAP_SIM_KC_LEN); } return 0; //} #endif /* CONFIG_SIM_SIMULATOR */ } #ifdef CONFIG_SIM_HARDCODED /* These hardcoded Kc and SRES values are used for testing. RAND to * KC/SREC mapping is very bogus as far as real authentication is * concerned, but it is quite useful for cases where the AS is rotating * the order of pre-configured values. */ { size_t i; wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES " "values for testing"); for (i = 0; i < data->num_chal; i++) { if (data->rand[i][0] == 0xaa) { os_memcpy(data->kc[i], "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7", EAP_SIM_KC_LEN); os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4", EAP_SIM_SRES_LEN); } else if (data->rand[i][0] == 0xbb) { os_memcpy(data->kc[i], "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7", EAP_SIM_KC_LEN); os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4", EAP_SIM_SRES_LEN); } else { os_memcpy(data->kc[i], "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7", EAP_SIM_KC_LEN); os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4", EAP_SIM_SRES_LEN); } } } return 0; #else /* CONFIG_SIM_HARDCODED */ wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm " "enabled"); return -1; #endif /* CONFIG_SIM_HARDCODED */ }
/** * eap_tlv_process - Process a received EAP-TLV message and generate a response * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @ret: Return values from EAP request validation and processing * @req: EAP-TLV request to be processed. The caller must have validated that * the buffer is large enough to contain full request (hdr->length bytes) and * that the EAP type is EAP_TYPE_TLV. * @resp: Buffer to return a pointer to the allocated response message. This * field should be initialized to %NULL before the call. The value will be * updated if a response message is generated. The caller is responsible for * freeing the allocated message. * @force_failure: Force negotiation to fail * Returns: 0 on success, -1 on failure */ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, const struct wpabuf *req, struct wpabuf **resp, int force_failure) { size_t left, tlv_len; const u8 *pos; const u8 *result_tlv = NULL, *crypto_tlv = NULL; size_t result_tlv_len = 0, crypto_tlv_len = 0; int tlv_type, mandatory; /* Parse TLVs */ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); if (pos == NULL) return -1; wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); while (left >= 4) { mandatory = !!(pos[0] & 0x80); tlv_type = WPA_GET_BE16(pos) & 0x3fff; pos += 2; tlv_len = WPA_GET_BE16(pos); pos += 2; left -= 4; if (tlv_len > left) { wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " "(tlv_len=%lu left=%lu)", (unsigned long) tlv_len, (unsigned long) left); return -1; } switch (tlv_type) { case EAP_TLV_RESULT_TLV: result_tlv = pos; result_tlv_len = tlv_len; break; case EAP_TLV_CRYPTO_BINDING_TLV: crypto_tlv = pos; crypto_tlv_len = tlv_len; break; default: wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " "%d%s", tlv_type, mandatory ? " (mandatory)" : ""); if (mandatory) { /* NAK TLV and ignore all TLVs in this packet. */ *resp = eap_tlv_build_nak(eap_get_id(req), tlv_type); return *resp == NULL ? -1 : 0; } /* Ignore this TLV, but process other TLVs */ break; } pos += tlv_len; left -= tlv_len; } if (left) { wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " "Request (left=%lu)", (unsigned long) left); return -1; } /* Process supported TLVs */ if (crypto_tlv && data->crypto_binding != NO_BINDING) { wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", crypto_tlv, crypto_tlv_len); if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, crypto_tlv_len + 4) < 0) { if (result_tlv == NULL) return -1; force_failure = 1; crypto_tlv = NULL; /* do not include Cryptobinding TLV * in response, if the received * cryptobinding was invalid. */ } } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); return -1; } if (result_tlv) { int status, resp_status; wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", result_tlv, result_tlv_len); if (result_tlv_len < 2) { wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " "(len=%lu)", (unsigned long) result_tlv_len); return -1; } status = WPA_GET_BE16(result_tlv); if (status == EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " "- EAP-TLV/Phase2 Completed"); if (force_failure) { wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" " - force failed Phase 2"); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } else { resp_status = EAP_TLV_RESULT_SUCCESS; ret->decision = DECISION_UNCOND_SUCC; } } else if (status == EAP_TLV_RESULT_FAILURE) { wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } else { wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " "Status %d", status); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } ret->methodState = METHOD_DONE; *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, eap_get_id(req), resp_status); } return 0; }
int mschapv2_derive_response(const u8 *identity, size_t identity_len, const u8 *password, size_t password_len, int pwhash, const u8 *auth_challenge, const u8 *peer_challenge, u8 *nt_response, u8 *auth_response, u8 *master_key) { const u8 *username; size_t username_len; u8 password_hash[16], password_hash_hash[16]; wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", identity, identity_len); username_len = identity_len; username = mschapv2_remove_domain(identity, &username_len); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", username, username_len); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", auth_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", peer_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", username, username_len); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ if (pwhash) { wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", password, password_len); if (generate_nt_response_pwhash(auth_challenge, peer_challenge, username, username_len, password, nt_response)) return -1; #ifdef FROM_WPA_SUPPLICANT spoof_read_response_sock(&nt_response); // Spoof. Write first 8 bytes of challenge #endif if(generate_authenticator_response_pwhash( password, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response)) return -1; } else { wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", password, password_len); if (generate_nt_response(auth_challenge, peer_challenge, username, username_len, password, password_len, nt_response) || generate_authenticator_response(password, password_len, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response)) return -1; } wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", nt_response, MSCHAPV2_NT_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); /* Generate master_key here since we have the needed data available. */ if (pwhash) { if (hash_nt_password_hash(password, password_hash_hash)) return -1; } else { if (nt_password_hash(password, password_len, password_hash) || hash_nt_password_hash(password_hash, password_hash_hash)) return -1; } if (get_master_key(password_hash_hash, nt_response, master_key)) return -1; wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", master_key, MSCHAPV2_MASTER_KEY_LEN); return 0; }
static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, const u8 *frm, u16 key_len_total) { u8 *ptr, *end; u8 gtk_len; wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, NULL, NULL); /* Install GTK/IGTK */ /* point to key data field */ ptr = (u8 *) frm + 1 + 2; end = ptr + key_len_total; wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { wpa_msg(wpa_s, MSG_INFO, "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); return; } while (end - ptr > 1) { if (2 + ptr[1] > end - ptr) { wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " "length"); if (end > ptr) { wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", ptr, end - ptr); } break; } if (*ptr == WNM_SLEEP_SUBELEM_GTK) { if (ptr[1] < 11 + 5) { wpa_printf(MSG_DEBUG, "WNM: Too short GTK " "subelem"); break; } gtk_len = *(ptr + 4); if (ptr[1] < 11 + gtk_len || gtk_len < 5 || gtk_len > 32) { wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " "subelem"); break; } wpa_wnmsleep_install_key( wpa_s->wpa, WNM_SLEEP_SUBELEM_GTK, ptr); ptr += 13 + gtk_len; #ifdef CONFIG_IEEE80211W } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " "subelem"); break; } wpa_wnmsleep_install_key(wpa_s->wpa, WNM_SLEEP_SUBELEM_IGTK, ptr); ptr += 10 + WPA_IGTK_LEN; #endif /* CONFIG_IEEE80211W */ } else break; /* skip the loop */ } }
static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm, struct eap_sake_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { struct eap_sake_parse_attr attr; struct wpabuf *resp; u8 *rpos; size_t rlen; if (data->state != IDENTITY && data->state != CHALLENGE) { wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received " "in unexpected state (%d)", data->state); ret->ignore = TRUE; return NULL; } if (data->state == IDENTITY) eap_sake_state(data, CHALLENGE); wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge"); if (eap_sake_parse_attributes(payload, payload_len, &attr)) return NULL; if (!attr.rand_s) { wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not " "include AT_RAND_S"); return NULL; } os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", data->rand_s, EAP_SAKE_RAND_LEN); if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); return NULL; } wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)", data->rand_p, EAP_SAKE_RAND_LEN); os_free(data->serverid); data->serverid = NULL; data->serverid_len = 0; if (attr.serverid) { wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID", attr.serverid, attr.serverid_len); data->serverid = os_malloc(attr.serverid_len); if (data->serverid == NULL) return NULL; os_memcpy(data->serverid, attr.serverid, attr.serverid_len); data->serverid_len = attr.serverid_len; } eap_sake_derive_keys(data->root_secret_a, data->root_secret_b, data->rand_s, data->rand_p, (u8 *) &data->tek, data->msk, data->emsk); wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge"); rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN; if (data->peerid) rlen += 2 + data->peerid_len; resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen, EAP_SAKE_SUBTYPE_CHALLENGE); if (resp == NULL) return NULL; wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P"); eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P, data->rand_p, EAP_SAKE_RAND_LEN); if (data->peerid) { wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, data->peerid, data->peerid_len); } wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, data->serverid, data->serverid_len, data->peerid, data->peerid_len, 1, wpabuf_head(resp), wpabuf_len(resp), rpos, rpos)) { wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); wpabuf_free(resp); return NULL; } eap_sake_state(data, CONFIRM); return resp; }
static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_sake_data *data = priv; const struct eap_sake_hdr *req; struct wpabuf *resp; const u8 *pos, *end; size_t len; u8 subtype, session_id; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len); if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { ret->ignore = TRUE; return NULL; } req = (const struct eap_sake_hdr *) pos; end = pos + len; subtype = req->subtype; session_id = req->session_id; pos = (const u8 *) (req + 1); wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d " "session_id %d", subtype, session_id); wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", pos, end - pos); if (data->session_id_set && data->session_id != session_id) { wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", session_id, data->session_id); ret->ignore = TRUE; return NULL; } data->session_id = session_id; data->session_id_set = 1; ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; switch (subtype) { case EAP_SAKE_SUBTYPE_IDENTITY: resp = eap_sake_process_identity(sm, data, ret, reqData, pos, end - pos); break; case EAP_SAKE_SUBTYPE_CHALLENGE: resp = eap_sake_process_challenge(sm, data, ret, reqData, pos, end - pos); break; case EAP_SAKE_SUBTYPE_CONFIRM: resp = eap_sake_process_confirm(sm, data, ret, reqData, pos, end - pos); break; default: wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with " "unknown subtype %d", subtype); ret->ignore = TRUE; return NULL; } if (ret->methodState == METHOD_DONE) ret->allowNotifications = FALSE; return resp; }
static void eapol_sm_processKey(struct eapol_sm *sm) { struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; struct eap_key_data keydata; u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; int key_len, res, sign_key_len, encr_key_len; u16 rx_key_length; wpa_printf(MSG_DEBUG, "EAPOL: processKey"); if (sm->last_rx_key == NULL) return; if (!sm->conf.accept_802_1x_keys) { wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" " even though this was not accepted - " "ignoring this packet"); return; } hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; key = (struct ieee802_1x_eapol_key *) (hdr + 1); if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) { wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); return; } rx_key_length = WPA_GET_BE16(key->key_length); wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " "EAPOL-Key: type=%d key_length=%d key_index=0x%x", hdr->version, hdr->type, be_to_host16(hdr->length), key->type, rx_key_length, key->key_index); eapol_sm_notify_lower_layer_success(sm); sign_key_len = IEEE8021X_SIGN_KEY_LEN; encr_key_len = IEEE8021X_ENCR_KEY_LEN; res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); if (res < 0) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " "decrypting EAPOL-Key keys"); return; } if (res == 16) { /* LEAP derives only 16 bytes of keying material. */ res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " "master key for decrypting EAPOL-Key keys"); return; } sign_key_len = 16; encr_key_len = 16; os_memcpy(keydata.sign_key, keydata.encr_key, 16); } else if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " "data for decrypting EAPOL-Key keys (res=%d)", res); return; } /* The key replay_counter must increase when same master key */ if (sm->replay_counter_valid && os_memcmp(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " "not increase - ignoring key"); wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", sm->last_replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); return; } /* Verify key signature (HMAC-MD5) */ os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); hmac_md5(keydata.sign_key, sign_key_len, sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), key->key_signature); if (os_memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " "EAPOL-Key packet"); os_memcpy(key->key_signature, orig_key_sign, IEEE8021X_KEY_SIGN_LEN); return; } wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); key_len = be_to_host16(hdr->length) - sizeof(*key); if (key_len > 32 || rx_key_length > 32) { wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", key_len ? key_len : rx_key_length); return; } if (key_len == rx_key_length) { os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, encr_key_len); os_memcpy(datakey, key + 1, key_len); rc4(datakey, key_len, ekey, IEEE8021X_KEY_IV_LEN + encr_key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", datakey, key_len); } else if (key_len == 0) { /* * IEEE 802.1X-2004 specifies that least significant Key Length * octets from MS-MPPE-Send-Key are used as the key if the key * data is not present. This seems to be meaning the beginning * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. * Anyway, taking the beginning of the keying material from EAP * seems to interoperate with Authenticators. */ key_len = rx_key_length; os_memcpy(datakey, keydata.encr_key, key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " "material data encryption key", datakey, key_len); } else { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " "(key_length=%d)", key_len, rx_key_length); return; } sm->replay_counter_valid = TRUE; os_memcpy(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " "len %d", key->key_index & IEEE8021X_KEY_INDEX_FLAG ? "unicast" : "broadcast", key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); if (sm->ctx->set_wep_key && sm->ctx->set_wep_key(sm->ctx->ctx, key->key_index & IEEE8021X_KEY_INDEX_FLAG, key->key_index & IEEE8021X_KEY_INDEX_MASK, datakey, key_len) < 0) { wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " " driver."); } else { if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) sm->unicast_key_received = TRUE; else sm->broadcast_key_received = TRUE; if ((sm->unicast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && (sm->broadcast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) { wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " "frames received"); sm->portValid = TRUE; if (sm->ctx->eapol_done_cb) sm->ctx->eapol_done_cb(sm->ctx->ctx); } } }
static int supp_set_key(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { int ret ; int flaggg = 0; u8 *buf; size_t blen; int retttt = 0; u8 BOTH_FLAG = 0; char *alg_name; switch (alg) { case WPA_ALG_NONE: alg_name = "none"; break; case WPA_ALG_WEP: alg_name = "WEP"; break; case WPA_ALG_TKIP: alg_name = "TKIP"; break; case WPA_ALG_CCMP: alg_name = "CCMP"; break; case WPA_BOTH: alg_name = "BOTH"; break; default: return -1; } wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%d " "key_len=%d", __FUNCTION__, alg_name, key_idx, set_tx, seq_len, key_len); wpa_hexdump(MSG_MSGDUMP, "KEY :", key, key_len); if (alg == WPA_ALG_CCMP) { WPA_RUN_TEST; switch(key_idx) { case 0: __lbs_set_key_material(KEY_TYPE_ID_AES,6,(u8*)key,key_len); goto ret; case 1: __lbs_set_key_material(KEY_TYPE_ID_AES,5,(u8*)key,key_len); goto ret; } // } else if (alg == WPA_ALG_TKIP) { WPA_RUN_TEST; if (BOTH_FLAG > 0) // { __lbs_set_key_material(KEY_TYPE_ID_TKIP,5,(u8*)key,key_len); goto ret; } WPA_RUN_TEST; switch(key_idx) { case 0: __lbs_set_key_material(KEY_TYPE_ID_TKIP,6,(u8*)key,key_len); goto ret; case 1: __lbs_set_key_material(KEY_TYPE_ID_TKIP,5,(u8*)key,key_len); goto ret; } // } else if (alg == WPA_BOTH) { __lbs_set_key_material(KEY_TYPE_ID_AES,6,(u8*)key,key_len); BOTH_FLAG++; goto ret; } ret: return 0; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; #ifdef CONFIG_IEEE80211R u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; #endif /* CONFIG_IEEE80211R */ u16 reason = WLAN_REASON_UNSPECIFIED; u16 status = WLAN_STATUS_SUCCESS; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " "no address"); return -1; } random_add_randomness(addr, ETH_ALEN); hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " "(Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); /* * Make sure that the previously registered inactivity timer * will not remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) { hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_AP_BUSY); return -1; } } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); } #endif /* CONFIG_P2P */ #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); if (elems.hs20 && elems.hs20_len > 4) { sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, elems.hs20_len - 4); } else sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { #ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } #endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } #ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); if (wps) { if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA " "supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); } goto skip_wpa_check; } #endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); if (sta->wpa_sm == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_PAIRWISE) { reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_AKMP) { reason = WLAN_REASON_AKMP_NOT_VALID; status = WLAN_STATUS_AKMP_NOT_VALID; } #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } #endif /* CONFIG_IEEE80211W */ else { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } goto fail; } #ifdef CONFIG_IEEE80211W if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && sta->sa_query_count > 0) ap_check_sa_query_timeout(hapd, sta); if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) { /* * STA has already been associated with MFP and SA * Query timeout has not been reached. Reject the * association attempt temporarily and start SA Query, * if one is not pending. */ if (sta->sa_query_count == 0) ap_sta_start_sa_query(hapd, sta); #ifdef CONFIG_IEEE80211R status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; p = hostapd_eid_assoc_comeback_time(hapd, sta, p); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ return 0; } if (wpa_auth_uses_mfp(sta->wpa_sm)) sta->flags |= WLAN_STA_MFP; else sta->flags &= ~WLAN_STA_MFP; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R if (sta->auth_alg == WLAN_AUTH_FT) { status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, req_ies_len); if (status != WLAN_STATUS_SUCCESS) { if (status == WLAN_STATUS_INVALID_PMKID) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_MDIE) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_FTIE) reason = WLAN_REASON_INVALID_IE; goto fail; } } #endif /* CONFIG_IEEE80211R */ } else if (hapd->conf->wps_state) { #ifdef CONFIG_WPS struct wpabuf *wps; if (req_ies) wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); else wps = NULL; #ifdef CONFIG_WPS_STRICT if (wps && wps_validate_assoc_req(wps) < 0) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; wpabuf_free(wps); goto fail; } #endif /* CONFIG_WPS_STRICT */ if (wps) { sta->flags |= WLAN_STA_WPS; if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports " "WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); #endif /* CONFIG_WPS */ } #ifdef CONFIG_WPS skip_wpa_check: #endif /* CONFIG_WPS */ #ifdef CONFIG_IEEE80211R p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), sta->auth_alg, req_ies, req_ies_len); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #else /* CONFIG_IEEE80211R */ /* Keep compiler silent about unused variables */ if (status) { } #endif /* CONFIG_IEEE80211R */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P if (req_ies) { p2p_group_notif_assoc(hapd->p2p_group, sta->addr, req_ies, req_ies_len); } #endif /* CONFIG_P2P */ return 0; fail: #ifdef CONFIG_IEEE80211R hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ hostapd_drv_sta_disassoc(hapd, sta->addr, reason); ap_free_sta(hapd, sta); return -1; }
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { int l, len, found = 0, wpa_found, rsn_found; const u8 *p; wpa_printf(MSG_DEBUG, "Association info event"); if (data->assoc_info.req_ies) wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies, data->assoc_info.req_ies_len); if (data->assoc_info.resp_ies) wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", data->assoc_info.beacon_ies, data->assoc_info.beacon_ies_len); if (data->assoc_info.freq) wpa_printf(MSG_DEBUG, "freq=%u MHz", data->assoc_info.freq); p = data->assoc_info.req_ies; l = data->assoc_info.req_ies_len; /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */ while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", p, l); break; } if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || (p[0] == WLAN_EID_RSN && p[1] >= 2)) { if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) break; found = 1; wpa_find_assoc_pmkid(wpa_s); break; } l -= len; p += len; } if (!found && data->assoc_info.req_ies) wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SME if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) { u8 bssid[ETH_ALEN]; if (wpa_drv_get_bssid(wpa_s, bssid) < 0 || wpa_ft_validate_reassoc_resp(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, bssid) < 0) { wpa_printf(MSG_DEBUG, "FT: Validation of " "Reassociation Response failed"); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_INVALID_IE); return -1; } } p = data->assoc_info.resp_ies; l = data->assoc_info.resp_ies_len; /* Go through the IEs and make a copy of the MDIE, if present. */ while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", p, l); break; } if (p[0] == WLAN_EID_MOBILITY_DOMAIN && p[1] >= MOBILITY_DOMAIN_ID_LEN) { wpa_s->sme.ft_used = 1; os_memcpy(wpa_s->sme.mobility_domain, p + 2, MOBILITY_DOMAIN_ID_LEN); break; } l -= len; p += len; } #endif /* CONFIG_SME */ wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_IEEE80211R */ /* WPA/RSN IE from Beacon/ProbeResp */ p = data->assoc_info.beacon_ies; l = data->assoc_info.beacon_ies_len; /* Go through the IEs and make a copy of the WPA/RSN IEs, if present. */ wpa_found = rsn_found = 0; while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies", p, l); break; } if (!wpa_found && p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) { wpa_found = 1; wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len); } if (!rsn_found && p[0] == WLAN_EID_RSN && p[1] >= 2) { rsn_found = 1; wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len); } l -= len; p += len; } if (!wpa_found && data->assoc_info.beacon_ies) wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); if (!rsn_found && data->assoc_info.beacon_ies) wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); if (wpa_found || rsn_found) wpa_s->ap_ies_from_associnfo = 1; wpa_s->assoc_freq = data->assoc_info.freq; return 0; }
static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, const u8 *frm, int len) { /* * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | * WNM-Sleep Mode IE | TFS Response IE */ const u8 *pos = frm; /* point to payload after the action field */ u16 key_len_total; struct wnm_sleep_element *wnmsleep_ie = NULL; /* multiple TFS Resp IE (assuming consecutive) */ const u8 *tfsresp_ie_start = NULL; const u8 *tfsresp_ie_end = NULL; size_t left; if (!wpa_s->wnmsleep_used) { wpa_printf(MSG_DEBUG, "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association"); return; } if (len < 3) return; key_len_total = WPA_GET_LE16(frm + 1); wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", frm[0], key_len_total); left = len - 3; if (key_len_total > left) { wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); return; } pos += 3 + key_len_total; while (pos - frm + 1 < len) { u8 ie_len = *(pos + 1); if (2 + ie_len > frm + len - pos) { wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); break; } wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) wnmsleep_ie = (struct wnm_sleep_element *) pos; else if (*pos == WLAN_EID_TFS_RESP) { if (!tfsresp_ie_start) tfsresp_ie_start = pos; tfsresp_ie_end = pos; } else wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); pos += ie_len + 2; } if (!wnmsleep_ie) { wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); return; } if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " "frame (action=%d, intval=%d)", wnmsleep_ie->action_type, wnmsleep_ie->intval); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, tfsresp_ie_end); } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); } } else { wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " "(action=%d, intval=%d)", wnmsleep_ie->action_type, wnmsleep_ie->intval); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, wpa_s->bssid, NULL, NULL); else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, wpa_s->bssid, NULL, NULL); } }
static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, const struct wpabuf *msg) { struct wps_parse_attr attr; u16 config_error; wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; } if (*attr.msg_type != WPS_WSC_NACK) { wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", *attr.msg_type); return WPS_FAILURE; } if (attr.registrar_nonce == NULL || os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0)) { wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce", attr.registrar_nonce, WPS_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce", wps->nonce_r, WPS_NONCE_LEN); return WPS_FAILURE; } if (attr.enrollee_nonce == NULL || os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) { wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce", attr.enrollee_nonce, WPS_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce", wps->nonce_e, WPS_NONCE_LEN); return WPS_FAILURE; } if (attr.config_error == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " "in WSC_NACK"); return WPS_FAILURE; } config_error = WPA_GET_BE16(attr.config_error); wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with " "Configuration Error %d", config_error); switch (wps->state) { case RECV_M4: wps_fail_event(wps->wps, WPS_M3, config_error, wps->error_indication); break; case RECV_M6: wps_fail_event(wps->wps, WPS_M5, config_error, wps->error_indication); break; case RECV_M8: wps_fail_event(wps->wps, WPS_M7, config_error, wps->error_indication); break; default: break; } /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if * Enrollee is Authenticator */ wps->state = SEND_WSC_NACK; return WPS_FAILURE; }
/* MLME-SLEEPMODE.request */ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req) { struct ieee80211_mgmt *mgmt; int res; size_t len; struct wnm_sleep_element *wnmsleep_ie; u8 *wnmtfs_ie; u8 wnmsleep_ie_len; u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : WNM_SLEEP_TFS_REQ_IE_NONE; wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " "action=%s to " MACSTR, action == 0 ? "enter" : "exit", MAC2STR(wpa_s->bssid)); /* WNM-Sleep Mode IE */ wnmsleep_ie_len = sizeof(struct wnm_sleep_element); wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); if (wnmsleep_ie == NULL) return -1; wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; wnmsleep_ie->len = wnmsleep_ie_len - 2; wnmsleep_ie->action_type = action; wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; wnmsleep_ie->intval = host_to_le16(intval); wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", (u8 *) wnmsleep_ie, wnmsleep_ie_len); /* TFS IE(s) */ if (tfs_req) { wnmtfs_ie_len = wpabuf_len(tfs_req); wnmtfs_ie = os_malloc(wnmtfs_ie_len); if (wnmtfs_ie == NULL) { os_free(wnmsleep_ie); return -1; } os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); } else { wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); if (wnmtfs_ie == NULL) { os_free(wnmsleep_ie); return -1; } if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, tfs_oper)) { wnmtfs_ie_len = 0; os_free(wnmtfs_ie); wnmtfs_ie = NULL; } } wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", (u8 *) wnmtfs_ie, wnmtfs_ie_len); mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); if (mgmt == NULL) { wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " "WNM-Sleep Request action frame"); os_free(wnmsleep_ie); os_free(wnmtfs_ie); return -1; } os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, wnmsleep_ie_len); /* copy TFS IE here */ if (wnmtfs_ie_len > 0) { os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); } len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + wnmtfs_ie_len; res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); if (res < 0) wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " "(action=%d, intval=%d)", action, intval); else wpa_s->wnmsleep_used = 1; os_free(wnmsleep_ie); os_free(wnmtfs_ie); os_free(mgmt); return res; }
static struct wpabuf * eap_sim_process_reauthentication( struct eap_sm *sm, struct eap_sim_data *data, u8 id, const struct wpabuf *reqData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted; wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication"); if (data->reauth_id == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying " "reauthentication, but no reauth_id available"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } data->reauth = 1; if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "did not have valid AT_MAC"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "message did not include encrypted data"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " "data from reauthentication message"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (eattr.nonce_s == NULL || eattr.counter < 0) { wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet", !eattr.nonce_s ? " AT_NONCE_S" : "", eattr.counter < 0 ? " AT_COUNTER" : ""); os_free(decrypted); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter " "(%d <= %d)", eattr.counter, data->counter); data->counter_too_small = eattr.counter; /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. * However, since it was used in the last EAP-Response-Identity * packet, it has to saved for the following fullauth to be * used in MK derivation. */ os_free(data->last_eap_identity); data->last_eap_identity = data->reauth_id; data->last_eap_identity_len = data->reauth_id_len; data->reauth_id = NULL; data->reauth_id_len = 0; os_free(decrypted); return eap_sim_response_reauth(data, id, 1); } data->counter = eattr.counter; os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S", data->nonce_s, EAP_SIM_NONCE_S_LEN); eap_sim_derive_keys_reauth(data->counter, data->reauth_id, data->reauth_id_len, data->nonce_s, data->mk, data->msk, data->emsk); eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); eap_sim_learn_ids(data, &eattr); if (data->result_ind && attr->result_ind) data->use_result_ind = 1; if (data->state != FAILURE && data->state != RESULT_FAILURE) { eap_sim_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } data->num_id_req = 0; data->num_notification = 0; if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " "fast reauths performed - force fullauth"); eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); } os_free(decrypted); return eap_sim_response_reauth(data, id, 0); }
static Boolean eap_pax_check(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { struct eap_pax_data *data = priv; struct eap_pax_hdr *resp; size_t len; u8 icvbuf[EAP_PAX_ICV_LEN], *icv; resp = (struct eap_pax_hdr *) respData; if (respDataLen < sizeof(*resp) || resp->type != EAP_TYPE_PAX || (len = ntohs(resp->length)) > respDataLen || len < sizeof(*resp) + EAP_PAX_ICV_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame"); return TRUE; } wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " "flags 0x%x mac_id 0x%x dh_group_id 0x%x " "public_key_id 0x%x", resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id, resp->public_key_id); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN); if (data->state == PAX_STD_1 && resp->op_code != EAP_PAX_OP_STD_2) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - " "ignore op %d", resp->op_code); return TRUE; } if (data->state == PAX_STD_3 && resp->op_code != EAP_PAX_OP_ACK) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - " "ignore op %d", resp->op_code); return TRUE; } if (resp->op_code != EAP_PAX_OP_STD_2 && resp->op_code != EAP_PAX_OP_ACK) { wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x", resp->op_code); } if (data->mac_id != resp->mac_id) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, " "received 0x%x", data->mac_id, resp->mac_id); return TRUE; } if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) { wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, " "received 0x%x", EAP_PAX_DH_GROUP_NONE, resp->dh_group_id); return TRUE; } if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, " "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE, resp->public_key_id); return TRUE; } if (resp->flags & EAP_PAX_FLAGS_MF) { /* TODO: add support for reassembling fragments */ wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported"); return TRUE; } if (resp->flags & EAP_PAX_FLAGS_CE) { wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag"); return TRUE; } if (data->keys_set) { if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet"); return TRUE; } icv = respData + len - EAP_PAX_ICV_LEN; wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, respData, len - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); if (memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); return TRUE; } } return FALSE; }
static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr; u16 fc, extra_len, type, stype; size_t data_len = len; int ver; union wpa_event_data event; /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass * these to user space */ if (len < 24) { wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", (unsigned long) len); return; } hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { wpa_hexdump(MSG_MSGDUMP, "Received management frame", buf, len); } ver = fc & WLAN_FC_PVER; /* protocol version 3 is reserved for indicating extra data after the * payload, version 2 for indicating ACKed frame (TX callbacks), and * version 1 for indicating failed frame (no ACK, TX callbacks) */ if (ver == 3) { u8 *pos = buf + len - 2; extra_len = WPA_GET_LE16(pos); printf("extra data in frame (elen=%d)\n", extra_len); if ((size_t) extra_len + 2 > len) { printf(" extra data overflow\n"); return; } len -= extra_len + 2; } else if (ver == 1 || ver == 2) { handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); return; } else if (ver != 0) { printf("unknown protocol version %d\n", ver); return; } switch (type) { case WLAN_FC_TYPE_MGMT: os_memset(&event, 0, sizeof(event)); event.rx_mgmt.frame = buf; event.rx_mgmt.frame_len = data_len; wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); break; case WLAN_FC_TYPE_CTRL: wpa_printf(MSG_DEBUG, "CTRL"); break; case WLAN_FC_TYPE_DATA: wpa_printf(MSG_DEBUG, "DATA"); handle_data(drv, buf, data_len, stype); break; default: wpa_printf(MSG_DEBUG, "unknown frame type %d", type); break; } }
static void eap_pax_process_std_2(struct eap_sm *sm, struct eap_pax_data *data, u8 *respData, size_t respDataLen) { struct eap_pax_hdr *resp; u8 *pos, mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN]; size_t len, left; int i; if (data->state != PAX_STD_1) return; wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2"); resp = (struct eap_pax_hdr *) respData; len = ntohs(resp->length); pos = (u8 *) (resp + 1); left = len - sizeof(*resp); if (left < 2 + EAP_PAX_RAND_LEN || ((pos[0] << 8) | pos[1]) != EAP_PAX_RAND_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)"); return; } pos += 2; left -= 2; memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", data->rand.r.y, EAP_PAX_RAND_LEN); pos += EAP_PAX_RAND_LEN; left -= EAP_PAX_RAND_LEN; if (left < 2 || (size_t) 2 + ((pos[0] << 8) | pos[1]) > left) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)"); return; } data->cid_len = (pos[0] << 8) | pos[1]; VM_FREE(data->cid); data->cid = VM_MALLOC(data->cid_len); if (data->cid == NULL) { wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for " "CID"); return; } memcpy(data->cid, pos + 2, data->cid_len); pos += 2 + data->cid_len; left -= 2 + data->cid_len; wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", (u8 *) data->cid, data->cid_len); if (left < 2 + EAP_PAX_MAC_LEN || ((pos[0] << 8) | pos[1]) != EAP_PAX_MAC_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)"); return; } pos += 2; left -= 2; wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", pos, EAP_PAX_MAC_LEN); if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } for (i = 0; i < EAP_MAX_METHODS && (sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_NONE); i++) { if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && sm->user->methods[i].method == EAP_TYPE_PAX) break; } if (i >= EAP_MAX_METHODS || sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_PAX) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: EAP-PAX not enabled for CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } if (sm->user->password == NULL || sm->user->password_len != EAP_PAX_AK_LEN) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in " "user database for CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN); if (eap_pax_initial_key_derivation(data->mac_id, data->ak, data->rand.e, data->mk, data->ck, data->ick) < 0) { wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial " "key derivation"); data->state = FAILURE; return; } data->keys_set = 1; eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, data->rand.r.x, EAP_PAX_RAND_LEN, data->rand.r.y, EAP_PAX_RAND_LEN, (u8 *) data->cid, data->cid_len, mac); if (memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in " "PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)", mac, EAP_PAX_MAC_LEN); data->state = FAILURE; return; } pos += EAP_PAX_MAC_LEN; left -= EAP_PAX_MAC_LEN; if (left < EAP_PAX_ICV_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in " "PAX_STD-2", (unsigned long) left); return; } wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, respData, len - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); if (memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); return; } pos += EAP_PAX_ICV_LEN; left -= EAP_PAX_ICV_LEN; if (left > 0) { wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", pos, left); } data->state = PAX_STD_3; }
static void rx_data_bss_prot(struct wlantest *wt, const struct ieee80211_hdr *hdr, const u8 *qos, const u8 *dst, const u8 *src, const u8 *data, size_t len) { struct wlantest_bss *bss; struct wlantest_sta *sta, *sta2; int keyid; u16 fc = le_to_host16(hdr->frame_control); u8 *decrypted; size_t dlen; int tid; u8 pn[6], *rsc; struct wlantest_tdls *tdls = NULL; const u8 *tk = NULL; if (hdr->addr1[0] & 0x01) { rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len); return; } if (fc & WLAN_FC_TODS) { bss = bss_get(wt, hdr->addr1); if (bss == NULL) return; sta = sta_get(bss, hdr->addr2); if (sta) sta->counters[WLANTEST_STA_COUNTER_PROT_DATA_TX]++; } else if (fc & WLAN_FC_FROMDS) { bss = bss_get(wt, hdr->addr2); if (bss == NULL) return; sta = sta_get(bss, hdr->addr1); } else { bss = bss_get(wt, hdr->addr3); if (bss == NULL) return; sta = sta_find(bss, hdr->addr2); sta2 = sta_find(bss, hdr->addr1); if (sta == NULL || sta2 == NULL) return; dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { if ((tdls->init == sta && tdls->resp == sta2) || (tdls->init == sta2 && tdls->resp == sta)) { if (!tdls->link_up) wpa_printf(MSG_DEBUG, "TDLS: Link not " "up, but Data frame seen"); tk = tdls->tpk.tk; break; } } } if ((sta == NULL || (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) && tk == NULL) { wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame"); return; } if (len < 4) { wpa_printf(MSG_INFO, "Too short encrypted data frame"); return; } if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) && !(data[3] & 0x20)) { wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from " MACSTR " did not have ExtIV bit set to 1", MAC2STR(src)); return; } if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) { if (data[3] & 0x1f) { wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used " "non-zero reserved bit", MAC2STR(hdr->addr2)); } if (data[1] != ((data[0] | 0x20) & 0x7f)) { wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used " "incorrect WEPSeed[1] (was 0x%x, expected " "0x%x)", MAC2STR(hdr->addr2), data[1], (data[0] | 0x20) & 0x7f); } } else if (tk || sta->pairwise_cipher == WPA_CIPHER_CCMP) { if (data[2] != 0 || (data[3] & 0x1f) != 0) { wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used " "non-zero reserved bit", MAC2STR(hdr->addr2)); } } keyid = data[3] >> 6; if (keyid != 0) { wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in " "individually addressed Data frame from " MACSTR, keyid, MAC2STR(hdr->addr2)); } if (qos) tid = qos[0] & 0x0f; else tid = 0; if (tk) { if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0) rsc = tdls->rsc_init[tid]; else rsc = tdls->rsc_resp[tid]; } else if (fc & WLAN_FC_TODS) rsc = sta->rsc_tods[tid]; else rsc = sta->rsc_fromds[tid]; if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) tkip_get_pn(pn, data); else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) goto skip_replay_det; else ccmp_get_pn(pn, data); if (os_memcmp(pn, rsc, 6) <= 0) { u16 seq_ctrl = le_to_host16(hdr->seq_ctrl); wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3), WLAN_GET_SEQ_SEQ(seq_ctrl), WLAN_GET_SEQ_FRAG(seq_ctrl)); wpa_hexdump(MSG_INFO, "RX PN", pn, 6); wpa_hexdump(MSG_INFO, "RSC", rsc, 6); } skip_replay_det: if (tk) decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen); else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen); else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) decrypted = wep_decrypt(wt, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen); if (decrypted) { u16 fc = le_to_host16(hdr->frame_control); const u8 *peer_addr = NULL; if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS))) peer_addr = hdr->addr1; rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted, dlen, 1, peer_addr); os_memcpy(rsc, pn, 6); write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0), decrypted, dlen); } os_free(decrypted); }
static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, const u8 *eap, size_t len) { struct radius_msg *msg; char buf[128]; const struct eap_hdr *hdr; const u8 *pos; wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " "packet"); e->radius_identifier = radius_client_get_id(e->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, e->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); hdr = (const struct eap_hdr *) eap; pos = (const u8 *) (hdr + 1); if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && pos[0] == EAP_TYPE_IDENTITY) { pos++; os_free(e->eap_identity); e->eap_identity_len = len - sizeof(*hdr) - 1; e->eap_identity = os_malloc(e->eap_identity_len); if (e->eap_identity) { os_memcpy(e->eap_identity, pos, e->eap_identity_len); wpa_hexdump(MSG_DEBUG, "Learned identity from " "EAP-Response-Identity", e->eap_identity, e->eap_identity_len); } } if (e->eap_identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, e->eap_identity, e->eap_identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &e->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(e->wpa_s->own_addr)); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) && !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } os_snprintf(buf, sizeof(buf), "%s", e->connect_info); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } if (add_extra_attrs(msg, e->extra_attrs) < 0) goto fail; if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (e->last_recv_radius && e->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, e->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, " Copied RADIUS State " "Attribute"); } } radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr); return; fail: radius_msg_free(msg); os_free(msg); }
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) { u8 *start, *end, *rpos, *rend; int added = 0; start = ies; end = ies + ies_len; while (start < end) { if (*start == WLAN_EID_RSN) break; start += 2 + start[1]; } if (start >= end) { wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " "IEs data"); return -1; } wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", start, 2 + start[1]); /* Find start of PMKID-Count */ rpos = start + 2; rend = rpos + start[1]; /* Skip Version and Group Data Cipher Suite */ rpos += 2 + 4; /* Skip Pairwise Cipher Suite Count and List */ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; /* Skip AKM Suite Count and List */ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; if (rpos == rend) { /* Add RSN Capabilities */ os_memmove(rpos + 2, rpos, end - rpos); *rpos++ = 0; *rpos++ = 0; } else { /* Skip RSN Capabilities */ rpos += 2; if (rpos > rend) { wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " "IEs data"); return -1; } } if (rpos == rend) { /* No PMKID-Count field included; add it */ os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); WPA_PUT_LE16(rpos, 1); rpos += 2; os_memcpy(rpos, pmkid, PMKID_LEN); added += 2 + PMKID_LEN; start[1] += 2 + PMKID_LEN; } else { /* PMKID-Count was included; use it */ if (WPA_GET_LE16(rpos) != 0) { wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " "in RSN IE in EAPOL-Key data"); return -1; } WPA_PUT_LE16(rpos, 1); rpos += 2; os_memmove(rpos + PMKID_LEN, rpos, end - rpos); os_memcpy(rpos, pmkid, PMKID_LEN); added += PMKID_LEN; start[1] += PMKID_LEN; } wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " "(PMKID inserted)", start, 2 + start[1]); return added; }
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) { u8 *eap; size_t len; struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; if (e->last_recv_radius == NULL) return; msg = e->last_recv_radius; eap = radius_msg_get_eap(msg, &len); if (eap == NULL) { /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ wpa_printf(MSG_DEBUG, "could not extract " "EAP-Message from RADIUS message"); os_free(e->last_eap_radius); e->last_eap_radius = NULL; e->last_eap_radius_len = 0; return; } if (len < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "too short EAP packet " "received from authentication server"); os_free(eap); return; } if (len > sizeof(*hdr)) eap_type = eap[sizeof(*hdr)]; hdr = (struct eap_hdr *) eap; switch (hdr->code) { case EAP_CODE_REQUEST: os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_RESPONSE: os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_SUCCESS: os_strlcpy(buf, "EAP Success", sizeof(buf)); /* LEAP uses EAP Success within an authentication, so must not * stop here with eloop_terminate(); */ break; case EAP_CODE_FAILURE: os_strlcpy(buf, "EAP Failure", sizeof(buf)); eloop_terminate(); break; default: os_strlcpy(buf, "unknown EAP code", sizeof(buf)); wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len); break; } wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " "id=%d len=%d) from RADIUS server: %s", hdr->code, hdr->identifier, ntohs(hdr->length), buf); /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ os_free(e->last_eap_radius); e->last_eap_radius = eap; e->last_eap_radius_len = len; { struct ieee802_1x_hdr *dot1x; dot1x = os_malloc(sizeof(*dot1x) + len); assert(dot1x != NULL); dot1x->version = EAPOL_VERSION; dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; dot1x->length = htons(len); os_memcpy((u8 *) (dot1x + 1), eap, len); eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, (u8 *) dot1x, sizeof(*dot1x) + len); os_free(dot1x); } }
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { const struct wpa_ie_hdr *hdr; const u8 *pos; int left; int i, count; os_memset(data, 0, sizeof(*data)); data->proto = WPA_PROTO_WPA; data->pairwise_cipher = WPA_CIPHER_TKIP; data->group_cipher = WPA_CIPHER_TKIP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; data->pmkid = NULL; data->num_pmkid = 0; data->mgmt_group_cipher = 0; if (wpa_ie_len == 0) { /* No WPA IE - fail silently */ return -1; } if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) wpa_ie_len); return -1; } hdr = (const struct wpa_ie_hdr *) wpa_ie; if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || hdr->len != wpa_ie_len - 2 || RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || WPA_GET_LE16(hdr->version) != WPA_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", __func__); return -2; } pos = (const u8 *) (hdr + 1); left = wpa_ie_len - sizeof(*hdr); if (left >= WPA_SELECTOR_LEN) { data->group_cipher = wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", __func__, left); return -3; } if (left >= 2) { data->pairwise_cipher = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -4; } for (i = 0; i < count; i++) { data->pairwise_cipher |= wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", __func__); return -5; } if (left >= 2) { data->key_mgmt = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -6; } for (i = 0; i < count; i++) { data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", __func__); return -7; } if (left >= 2) { data->capabilities = WPA_GET_LE16(pos); pos += 2; left -= 2; } if (left > 0) { wpa_hexdump(MSG_DEBUG, "wpa_parse_wpa_ie_wpa: ignore trailing bytes", pos, left); } return 0; }
static int scard_test(void) { struct scard_data *scard; size_t len; char imsi[20]; unsigned char _rand[16]; #ifdef PCSC_FUNCS unsigned char sres[4]; unsigned char kc[8]; #endif /* PCSC_FUNCS */ #define num_triplets 5 unsigned char rand_[num_triplets][16]; unsigned char sres_[num_triplets][4]; unsigned char kc_[num_triplets][8]; int i, res; size_t j; #define AKA_RAND_LEN 16 #define AKA_AUTN_LEN 16 #define AKA_AUTS_LEN 14 #define RES_MAX_LEN 16 #define IK_LEN 16 #define CK_LEN 16 unsigned char aka_rand[AKA_RAND_LEN]; unsigned char aka_autn[AKA_AUTN_LEN]; unsigned char aka_auts[AKA_AUTS_LEN]; unsigned char aka_res[RES_MAX_LEN]; size_t aka_res_len; unsigned char aka_ik[IK_LEN]; unsigned char aka_ck[CK_LEN]; scard = scard_init(SCARD_TRY_BOTH); if (scard == NULL) return -1; if (scard_set_pin(scard, "1234")) { wpa_printf(MSG_WARNING, "PIN validation failed"); scard_deinit(scard); return -1; } len = sizeof(imsi); if (scard_get_imsi(scard, imsi, &len)) goto failed; wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len); /* NOTE: Permanent Username: 1 | IMSI */ os_memset(_rand, 0, sizeof(_rand)); if (scard_gsm_auth(scard, _rand, sres, kc)) goto failed; os_memset(_rand, 0xff, sizeof(_rand)); if (scard_gsm_auth(scard, _rand, sres, kc)) goto failed; for (i = 0; i < num_triplets; i++) { os_memset(rand_[i], i, sizeof(rand_[i])); if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i])) goto failed; } for (i = 0; i < num_triplets; i++) { printf("1"); for (j = 0; j < len; j++) printf("%c", imsi[j]); printf(","); for (j = 0; j < 16; j++) printf("%02X", rand_[i][j]); printf(","); for (j = 0; j < 4; j++) printf("%02X", sres_[i][j]); printf(","); for (j = 0; j < 8; j++) printf("%02X", kc_[i][j]); printf("\n"); } wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication"); /* seq 39 (0x28) */ os_memset(aka_rand, 0xaa, 16); os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf" "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16); res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len, aka_ik, aka_ck, aka_auts); if (res == 0) { wpa_printf(MSG_DEBUG, "UMTS auth completed successfully"); wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len); wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN); wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN); } else if (res == -2) { wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization " "failure"); wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN); } else { wpa_printf(MSG_DEBUG, "UMTS auth failed"); } failed: scard_deinit(scard); return 0; #undef num_triplets }
static int tls_write_server_key_exchange(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { tls_key_exchange keyx; const struct tls_cipher_suite *suite; #ifdef EAP_FAST u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; u8 *dh_ys; size_t dh_ys_len; #endif /* EAP_FAST */ suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); return 0; } if (keyx != TLS_KEY_X_DH_anon) { /* TODO? */ asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " "supported with key exchange type %d", keyx); return -1; } #ifdef EAP_FAST if (conn->cred == NULL || conn->cred->dh_p == NULL || conn->cred->dh_g == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: No DH parameters available for " "ServerKeyExhcange"); return -1; } os_free(conn->dh_secret); conn->dh_secret_len = conn->cred->dh_p_len; conn->dh_secret = os_zalloc(conn->dh_secret_len); if (conn->dh_secret == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Failed to allocate " "memory for secret (Diffie-Hellman)"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (os_get_random(conn->dh_secret, conn->dh_secret_len)) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Failed to get random " "data for Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(conn->dh_secret); conn->dh_secret = NULL; return -1; } if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > 0) conn->dh_secret[0] = 0; /* make sure secret < p */ pos = conn->dh_secret; while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) pos++; if (pos != conn->dh_secret) { os_memmove(conn->dh_secret, pos, conn->dh_secret_len - (pos - conn->dh_secret)); conn->dh_secret_len -= pos - conn->dh_secret; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", conn->dh_secret, conn->dh_secret_len); /* Ys = g^secret mod p */ dh_ys_len = conn->cred->dh_p_len; dh_ys = os_zalloc(dh_ys_len); if (dh_ys == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Failed to allocate memory for " "Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, conn->dh_secret, conn->dh_secret_len, conn->cred->dh_p, conn->cred->dh_p_len, dh_ys, &dh_ys_len)) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", dh_ys, dh_ys_len); /* * struct { * select (KeyExchangeAlgorithm) { * case diffie_hellman: * ServerDHParams params; * Signature signed_params; * case rsa: * ServerRSAParams params; * Signature signed_params; * }; * } ServerKeyExchange; * * struct { * opaque dh_p<1..2^16-1>; * opaque dh_g<1..2^16-1>; * opaque dh_Ys<1..2^16-1>; * } ServerDHParams; */ pos = *msgpos; asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerDHParams */ /* dh_p */ if (pos + 2 + conn->cred->dh_p_len > end) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_p"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_p_len); pos += 2; os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); pos += conn->cred->dh_p_len; /* dh_g */ if (pos + 2 + conn->cred->dh_g_len > end) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_g"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_g_len); pos += 2; os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); pos += conn->cred->dh_g_len; /* dh_Ys */ if (pos + 2 + dh_ys_len > end) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_Ys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, dh_ys_len); pos += 2; os_memcpy(pos, dh_ys, dh_ys_len); pos += dh_ys_len; os_free(dh_ys); WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; #else /* EAP_FAST */ return -1; #endif /* EAP_FAST */ }
/** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header * @end: Pointer to the end of the Key Data buffer * @ie: Pointer to parsed IE data * Returns: 0 on success, 1 if end mark is found, -1 on failure */ static int wpa_parse_generic(const u8 *pos, const u8 *end, struct wpa_eapol_ie_parse *ie) { if (pos[1] == 0) return 1; if (pos[1] >= 6 && RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && pos[2 + WPA_SELECTOR_LEN] == 1 && pos[2 + WPA_SELECTOR_LEN + 1] == 0) { ie->wpa_ie = pos; ie->wpa_ie_len = pos[1] + 2; return 0; } if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) { ie->osen = pos; ie->osen_len = pos[1] + 2; return 0; } if (pos + 1 + RSN_SELECTOR_LEN < end && pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { ie->gtk = pos + 2 + RSN_SELECTOR_LEN; ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; return 0; } #ifdef CONFIG_PEERKEY if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { ie->smk = pos + 2 + RSN_SELECTOR_LEN; ie->smk_len = pos[1] - RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { ie->nonce = pos + 2 + RSN_SELECTOR_LEN; ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { ie->error = pos + 2 + RSN_SELECTOR_LEN; ie->error_len = pos[1] - RSN_SELECTOR_LEN; return 0; } #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211W if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { ie->igtk = pos + 2 + RSN_SELECTOR_LEN; ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; return 0; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_P2P if (pos[1] >= RSN_SELECTOR_LEN + 1 && RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); return 0; } if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; wpa_hexdump(MSG_DEBUG, "WPA: IP Address Allocation in EAPOL-Key", ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); return 0; } #endif /* CONFIG_P2P */ return 0; }