static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, u8 op_class, u8 chan, u8 phy_type, u8 pref) { u8 *pos = buf; if (len < 18) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for Neighbor Report element"); return -1; } *pos++ = WLAN_EID_NEIGHBOR_REPORT; /* length: 13 for basic neighbor report + 3 for preference subelement */ *pos++ = 16; os_memcpy(pos, bssid, ETH_ALEN); pos += ETH_ALEN; WPA_PUT_LE32(pos, bss_info); pos += 4; *pos++ = op_class; *pos++ = chan; *pos++ = phy_type; *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; *pos++ = 1; *pos++ = pref; return pos - buf; }
static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, struct wpa_ft_pmk_r0_sa *pmk_r0, struct ft_remote_r1kh *r1kh, const u8 *s1kh_id, int pairwise) { struct ft_r0kh_r1kh_push_frame frame, f; struct os_time now; os_memset(&frame, 0, sizeof(frame)); frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH; frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN); os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN); /* aes_wrap() does not support inplace encryption, so use a temporary * buffer for the data. */ os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN); os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN); os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN); wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id, s1kh_id, f.pmk_r1, f.pmk_r1_name); wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id)); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name, WPA_PMK_NAME_LEN); os_get_time(&now); WPA_PUT_LE32(f.timestamp, now.sec); f.pairwise = host_to_le16(pairwise); if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, f.timestamp, frame.timestamp) < 0) return; wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame)); }
static void test_vector_ccmp(void) { u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85, 0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f }; u8 pn[] = { 0xB5, 0x03, 0x97, 0x76, 0xE7, 0x0C }; u8 frame[] = { 0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28, 0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33, 0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae, 0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb, 0x7e, 0x78, 0xa0, 0x50 }; u8 *enc, *plain; size_t enc_len, plain_len; u8 fcs[4]; wpa_printf(MSG_INFO, "\nIEEE Std 802.11-2012, M.6.4 CCMP test " "vector\n"); wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk)); wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn)); wpa_hexdump(MSG_INFO, "802.11 Header", frame, 24); wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 24, sizeof(frame) - 24); enc = ccmp_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0, &enc_len); if (enc == NULL) { wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame"); return; } wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len); WPA_PUT_LE32(fcs, crc32(enc, enc_len)); wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs)); wpa_debug_level = MSG_INFO; plain = ccmp_decrypt(tk, (const struct ieee80211_hdr *) enc, enc + 24, enc_len - 24, &plain_len); wpa_debug_level = MSG_EXCESSIVE; os_free(enc); if (plain == NULL) { wpa_printf(MSG_ERROR, "Failed to decrypt CCMP frame"); return; } if (plain_len != sizeof(frame) - 24 || os_memcmp(plain, frame + 24, plain_len) != 0) { wpa_hexdump(MSG_ERROR, "Decryption result did not match", plain, plain_len); } os_free(plain); }
/** * wpa_btk_to_ptk - Calculate PTK from BTK, address, and Replay Counter * @btk: Base Transient Key * @btk_len: Length of BTK * @bssid: BSSID / AP ID * @ptk: Buffer for Pairwise Transient Key * @ptk_len: Length of PTK * * PTK = PRF-512(BTK, "", RN || AP_ID) */ void wpa_btk_to_ptk(const u8 *btk, size_t btk_len, const u8 *bssid, u32 cckm_rn, u8 *ptk, size_t ptk_len) { u8 data[ETH_ALEN + 4]; WPA_PUT_LE32(data, cckm_rn); os_memcpy(data + 4, bssid, ETH_ALEN); sha1_prf(btk, btk_len, NULL, data, sizeof(data), ptk, ptk_len); wpa_hexdump_key(MSG_DEBUG, "WPA: BTK-PTK", ptk, ptk_len); }
int cckm_build_request (struct wpa_sm *sm, u8 *bssid, u64 timestamp) { struct cckm_ie_req *cie; u8 data[128]; u32 data_len = ETH_ALEN; if (sm->cckm_req_ie) { os_free(sm->cckm_req_ie); } sm->cckm_req_ie = os_malloc(32); if (sm->cckm_req_ie == NULL) return -1; cie = (struct cckm_ie_req *)sm->cckm_req_ie; os_memcpy(data, sm->own_addr, ETH_ALEN); os_memcpy(data+data_len, bssid, ETH_ALEN); data_len += ETH_ALEN; if (sm->connect_wpa_ie && sm->connect_wpa_ie_len) { os_memcpy(data + data_len, sm->connect_wpa_ie, sm->connect_wpa_ie_len); data_len += sm->connect_wpa_ie_len; } sm->cckm_rn++; cie->elem_id = WLAN_EID_CCKM; cie->len = 24; os_memcpy(cie->oui, aironet_oui, sizeof(aironet_oui)); WPA_PUT_LE64(cie->timestamp, timestamp); WPA_PUT_LE32(cie->rn, sm->cckm_rn); os_memcpy(data+data_len, cie->timestamp, 8); data_len += 8; os_memcpy(data+data_len, cie->rn, 4); data_len += 4; if (sm->proto == WPA_PROTO_RSN) { hmac_sha1(sm->cgk.krk, CCKM_KRK_LEN, data, data_len, cie->mn_mic); } else { hmac_md5(sm->cgk.krk, CCKM_KRK_LEN, data, data_len, cie->mn_mic); } sm->cckm_req_ie_len = sizeof(struct cckm_ie_req); wpa_hexdump(MSG_DEBUG, "req data ", data, data_len); wpa_hexdump(MSG_DEBUG, "cckm_req ", sm->cckm_req_ie, sm->cckm_req_ie_len); wpa_sm_update_cckm_ies(sm, sm->cckm_req_ie, sm->cckm_req_ie_len); return 0; }
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, struct sta_info *sta, u8 *eid) { u8 *pos = eid; u32 timeout, tu; struct os_reltime now, passed; *pos++ = WLAN_EID_TIMEOUT_INTERVAL; *pos++ = 5; *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; os_get_reltime(&now); os_reltime_sub(&now, &sta->sa_query_start, &passed); tu = (passed.sec * 1000000 + passed.usec) / 1024; if (hapd->conf->assoc_sa_query_max_timeout > tu) timeout = hapd->conf->assoc_sa_query_max_timeout - tu; else timeout = 0; if (timeout < hapd->conf->assoc_sa_query_max_timeout) timeout++; /* add some extra time for local timers */ WPA_PUT_LE32(pos, timeout); pos += 4; return pos; }
static int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p, u32 adv_id, u16 config_methods, const char *svc_name, u8 **ie_len, u8 **pos, size_t *total_len, u8 *attr_len) { size_t svc_len; size_t remaining; size_t info_len; p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id); svc_len = os_strlen(svc_name); info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) + svc_len; if (info_len + *total_len > MAX_SVC_ADV_LEN) { p2p_dbg(p2p, "Unsufficient buffer, failed to add advertised service info"); return -1; } if (svc_len > 255) { p2p_dbg(p2p, "Invalid service name length (%u bytes), failed to add advertised service info", (unsigned int) svc_len); return -1; } if (*ie_len) { int ie_data_len = (*pos - *ie_len) - 1; if (ie_data_len < 0 || ie_data_len > 255) { p2p_dbg(p2p, "Invalid IE length, failed to add advertised service info"); return -1; } remaining = 255 - ie_data_len; } else { /* * Adding new P2P IE header takes 6 extra bytes: * - 2 byte IE header (1 byte IE id and 1 byte length) * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below */ *ie_len = p2p_buf_add_ie_hdr(buf); remaining = 255 - 4; } if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) { /* * Split adv_id, config_methods, and svc_name_len between two * IEs. */ size_t front = remaining; size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front; u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)]; WPA_PUT_LE32(holder, adv_id); WPA_PUT_BE16(&holder[sizeof(u32)], config_methods); holder[sizeof(u32) + sizeof(u16)] = svc_len; if (front) wpabuf_put_data(buf, holder, front); p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); wpabuf_put_data(buf, &holder[front], back); remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) - back; } else { wpabuf_put_le32(buf, adv_id); wpabuf_put_be16(buf, config_methods); wpabuf_put_u8(buf, svc_len); remaining -= sizeof(adv_id) + sizeof(config_methods) + sizeof(u8); } if (remaining < svc_len) { /* split svc_name between two or three IEs */ size_t front = remaining; size_t back = svc_len - front; if (front) wpabuf_put_data(buf, svc_name, front); p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); /* In rare cases, we must split across 3 attributes */ if (back > 255 - 4) { wpabuf_put_data(buf, &svc_name[front], 255 - 4); back -= 255 - 4; front += 255 - 4; p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); } wpabuf_put_data(buf, &svc_name[front], back); remaining = 255 - 4 - back; } else { wpabuf_put_data(buf, svc_name, svc_len); remaining -= svc_len; } p2p_buf_update_ie_hdr(buf, *ie_len); /* set *ie_len to NULL if a new IE has to be added on the next call */ if (!remaining) *ie_len = NULL; /* set *pos to point to the next byte to update */ *pos = wpabuf_put(buf, 0); *total_len += info_len; WPA_PUT_LE16(attr_len, (u16) *total_len); return 0; }
/** * cckm_egtk_to_gtk - Calculate GTK from Encrypted GTK * @cckm_rn: Association Request Numner * @gtk: Length of BTK * @gtk_len: Length of GTK * * GTK = RC4(RN | PTK-802.1X-Encrypt-Key, EGTK) * GTK = AES-Keywrap(PTK-802.1X-Encrypt-Key, EGTK) * - where PTK-802.1X-Encrypt-Key is the key as defined in Section 0 * - Note that while the IV is not transmitted in the clear, its encrypted * value is included in the EGTK. Thus, the EGTK length shall be the GTK * key length plus 8 octets (e.g. the IV length). More explicitly, if the * broadcast cipher is TKIP, while the GTK is 32 octets, the EGTK shall * be 40 octets; similarly for AESCCMP, the GTK is 16 octets while the * EGTK shall be 24 octets. */ static int cckm_install_gtk(struct wpa_sm *sm, u32 cckm_rn, u8 *gtk, int gtk_len, int keyidx, const u8 *key_rsc, int key_rsc_len) { u8 gtk_buf[32]; enum wpa_alg alg; switch (sm->group_cipher) { case WPA_CIPHER_CCMP: alg = WPA_ALG_CCMP; break; case WPA_CIPHER_TKIP: alg = WPA_ALG_TKIP; break; case WPA_CIPHER_NONE: wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: " "NONE - do not use pairwise keys"); return 0; default: wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d", sm->pairwise_cipher); return -1; } if (sm->group_cipher == WPA_CIPHER_CCMP) { gtk_len -= 8; if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk, gtk_buf)) { wpa_printf(MSG_WARNING, "WPA: AES unwrap " "failed - could not decrypt GTK"); return -1; } gtk = gtk_buf; } else if (sm->group_cipher == WPA_CIPHER_TKIP) { u8 data[20]; WPA_PUT_LE32(data, cckm_rn); os_memcpy(data + 4, &sm->ptk.kek, sizeof(sm->ptk.kek)); wpa_hexdump_key(MSG_DEBUG, "EGTK-Data", data, sizeof(data)); rc4_skip(data, sizeof(data), 256, gtk, gtk_len); /* Swap Tx/Rx keys for Michael MIC */ os_memcpy(gtk_buf, gtk, 16); os_memcpy(gtk_buf + 16, gtk + 24, 8); os_memcpy(gtk_buf + 24, gtk + 16, 8); gtk = gtk_buf; } wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len); wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver " "(keyidx=%d tx=%d len=%d).", keyidx, 0, gtk_len); wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, key_rsc_len); if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", keyidx, 0, key_rsc, key_rsc_len, gtk, gtk_len) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to " "the driver."); return -1; } return 0; }