static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data, u8 *aad, size_t *aad_len, u8 *nonce) { u16 fc, stype, seq; int qos = 0, addr4 = 0; u8 *pos; nonce[0] = 0; fc = le_to_host16(hdr->frame_control); stype = WLAN_FC_GET_STYPE(fc); if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == (WLAN_FC_TODS | WLAN_FC_FROMDS)) addr4 = 1; if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { fc &= ~0x0070; /* Mask subtype bits */ if (stype & 0x08) { const u8 *qc; qos = 1; fc &= ~WLAN_FC_ORDER; qc = (const u8 *) (hdr + 1); if (addr4) qc += ETH_ALEN; nonce[0] = qc[0] & 0x0f; } } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) nonce[0] |= 0x10; /* Management */ fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA); fc |= WLAN_FC_ISWEP; WPA_PUT_LE16(aad, fc); pos = aad + 2; os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN); pos += 3 * ETH_ALEN; seq = le_to_host16(hdr->seq_ctrl); seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */ WPA_PUT_LE16(pos, seq); pos += 2; os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2); pos += addr4 * ETH_ALEN; if (qos) { pos[0] &= ~0x70; if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */) pos[0] &= ~0x80; pos++; *pos++ = 0x00; } *aad_len = pos - aad; os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN); nonce[7] = data[7]; /* PN5 */ nonce[8] = data[6]; /* PN4 */ nonce[9] = data[5]; /* PN3 */ nonce[10] = data[4]; /* PN2 */ nonce[11] = data[1]; /* PN1 */ nonce[12] = data[0]; /* PN0 */ }
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) { if (len < 2 + 5) return eid; #ifdef CONFIG_TESTING_OPTIONS if (hapd->conf->bss_load_test_set) { *eid++ = WLAN_EID_BSS_LOAD; *eid++ = 5; os_memcpy(eid, hapd->conf->bss_load_test, 5); eid += 5; return eid; } #endif /* CONFIG_TESTING_OPTIONS */ if (hapd->conf->bss_load_update_period) { *eid++ = WLAN_EID_BSS_LOAD; *eid++ = 5; WPA_PUT_LE16(eid, hapd->num_sta); eid += 2; *eid++ = hapd->iface->channel_utilization; WPA_PUT_LE16(eid, 0); /* no available admission capabity */ eid += 2; } return eid; }
static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt) { u8 *pos, *len; u32 suite; if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) return -1; pos = wpa_ie; *pos++ = WLAN_EID_VENDOR_SPECIFIC; len = pos++; /* to be filled */ WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); if (suite == 0) { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); if (suite == 0 || (!wpa_cipher_valid_pairwise(pairwise_cipher) && pairwise_cipher != WPA_CIPHER_NONE)) { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); pos += RSN_SELECTOR_LEN; *len = pos - len - 1; WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); return pos - wpa_ie; }
int hostapd_update_time_adv(struct hostapd_data *hapd) { const int elen = 2 + 1 + 10 + 5 + 1; struct os_time t; struct os_tm tm; u8 *pos; if (hapd->conf->time_advertisement != 2) return 0; if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0) return -1; if (!hapd->time_adv) { hapd->time_adv = wpabuf_alloc(elen); if (hapd->time_adv == NULL) return -1; pos = wpabuf_put(hapd->time_adv, elen); } else pos = wpabuf_mhead_u8(hapd->time_adv); *pos++ = WLAN_EID_TIME_ADVERTISEMENT; *pos++ = 1 + 10 + 5 + 1; *pos++ = 2; /* UTC time at which the TSF timer is 0 */ /* Time Value at TSF 0 */ /* FIX: need to calculate this based on the current TSF value */ WPA_PUT_LE16(pos, tm.year); /* Year */ pos += 2; *pos++ = tm.month; /* Month */ *pos++ = tm.day; /* Day of month */ *pos++ = tm.hour; /* Hours */ *pos++ = tm.min; /* Minutes */ *pos++ = tm.sec; /* Seconds */ WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */ pos += 2; *pos++ = 0; /* Reserved */ /* Time Error */ /* TODO: fill in an estimate on the error */ *pos++ = 0; *pos++ = 0; *pos++ = 0; *pos++ = 0; *pos++ = 0; *pos++ = hapd->time_update_counter++; return 0; }
u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid, size_t *prot_len) { u8 *prot, *pos, *buf; u8 mic[16]; u16 fc; struct ieee80211_hdr *hdr; size_t plen; plen = len + 18; prot = os_malloc(plen); if (prot == NULL) return NULL; os_memcpy(prot, frame, len); pos = prot + len; *pos++ = WLAN_EID_MMIE; *pos++ = 16; WPA_PUT_LE16(pos, keyid); pos += 2; os_memcpy(pos, ipn, 6); pos += 6; os_memset(pos, 0, 8); /* MIC */ buf = os_malloc(plen + 20 - 24); if (buf == NULL) { os_free(prot); return NULL; } /* BIP AAD: FC(masked) A1 A2 A3 */ hdr = (struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA); WPA_PUT_LE16(buf, fc); os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN); os_memcpy(buf + 20, prot + 24, plen - 24); wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24); /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */ if (omac1_aes_128(igtk, buf, plen + 20 - 24, mic) < 0) { os_free(prot); os_free(buf); return NULL; } os_free(buf); os_memcpy(pos, mic, 8); wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8); *prot_len = plen; return prot; }
/** * sha384_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function * @key: Key for KDF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bits of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key. If the requested buf_len is not divisible by eight, the least * significant 1-7 bits of the last octet in the output are not part of the * requested output. */ void sha384_prf_bits(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len_bits) { u16 counter = 1; size_t pos, plen; u8 hash[SHA384_MAC_LEN]; const u8 *addr[4]; size_t len[4]; u8 counter_le[2], length_le[2]; size_t buf_len = (buf_len_bits + 7) / 8; addr[0] = counter_le; len[0] = 2; addr[1] = (u8 *) label; len[1] = os_strlen(label); addr[2] = data; len[2] = data_len; addr[3] = length_le; len[3] = sizeof(length_le); WPA_PUT_LE16(length_le, buf_len_bits); pos = 0; while (pos < buf_len) { plen = buf_len - pos; WPA_PUT_LE16(counter_le, counter); if (plen >= SHA384_MAC_LEN) { hmac_sha384_vector(key, key_len, 4, addr, len, &buf[pos]); pos += SHA384_MAC_LEN; } else { hmac_sha384_vector(key, key_len, 4, addr, len, hash); os_memcpy(&buf[pos], hash, plen); pos += plen; break; } counter++; } /* * Mask out unused bits in the last octet if it does not use all the * bits. */ if (buf_len_bits % 8) { u8 mask = 0xff << (8 - buf_len_bits % 8); buf[pos - 1] &= mask; } os_memset(hash, 0, sizeof(hash)); }
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) { u8 *len; u16 capab; if (!hapd->conf->osen) return eid; *eid++ = WLAN_EID_VENDOR_SPECIFIC; len = eid++; /* to be filled */ WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); eid += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); eid += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); eid += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0; if (hapd->conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(eid, capab); eid += 2; *len = eid - len - 1; return eid; }
/** * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5A.3) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key. */ void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u16 counter = 0; size_t pos, plen; u8 hash[SHA256_MAC_LEN]; const u8 *addr[3]; size_t len[3]; u8 counter_le[2]; addr[0] = counter_le; len[0] = 2; addr[1] = (u8 *) label; len[1] = strlen(label) + 1; addr[2] = data; len[2] = data_len; pos = 0; while (pos < buf_len) { plen = buf_len - pos; WPA_PUT_LE16(counter_le, counter); if (plen >= SHA256_MAC_LEN) { hmac_sha256_vector(key, key_len, 3, addr, len, &buf[pos]); pos += SHA256_MAC_LEN; } else { hmac_sha256_vector(key, key_len, 3, addr, len, hash); memcpy(&buf[pos], hash, plen); break; } counter++; } }
/** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) * Returns: 0 on success, -1 on failure */ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t ucs2_len, offset; u8 *pos; os_memset(pw_block, 0, PWBLOCK_LEN); if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0) return -1; if (ucs2_len > 256) return -1; offset = (256 - ucs2_len) * 2; if (offset != 0) { os_memmove(pw_block + offset, pw_block, ucs2_len * 2); if (os_get_random(pw_block, offset) < 0) return -1; } /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. */ pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); return 0; }
static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, const u8 *current_ap, const u8 *sta_addr, const u8 *body, size_t len) { struct wpa_state_machine *sm; u16 status; u8 *resp_ies, *pos; size_t resp_ies_len, rlen; struct ft_rrb_frame *frame; sm = wpa_ft_add_sta(wpa_auth, sta_addr); if (sm == NULL) { wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on " "RRB Request"); return -1; } wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len); status = wpa_ft_process_auth_req(sm, body, len, &resp_ies, &resp_ies_len); wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR " CurrentAP=" MACSTR " status=%d", MAC2STR(sm->addr), MAC2STR(current_ap), status); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); /* RRB - Forward action frame response to the Current AP */ /* * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6] * Status_Code[2] FT Request action frame body[variable] */ rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len; frame = os_malloc(sizeof(*frame) + rlen); frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; frame->packet_type = FT_PACKET_RESPONSE; frame->action_length = host_to_le16(rlen); os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN); pos = (u8 *) (frame + 1); *pos++ = WLAN_ACTION_FT; *pos++ = 2; /* Action: Response */ os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, wpa_auth->addr, ETH_ALEN); pos += ETH_ALEN; WPA_PUT_LE16(pos, status); pos += 2; if (resp_ies) { os_memcpy(pos, resp_ies, resp_ies_len); os_free(resp_ies); } wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame, sizeof(*frame) + rlen); os_free(frame); return 0; }
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { u8 *group_info; struct wpabuf *ie; struct p2p_group_member *m; u8 *len; ie = wpabuf_alloc(257); if (ie == NULL) return NULL; len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_group_add_noa(ie, group->noa); /* P2P Device Info */ p2p_buf_add_device_info(ie, group->p2p, NULL); /* P2P Group Info */ group_info = wpabuf_put(ie, 0); wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO); wpabuf_put_le16(ie, 0); /* Length to be filled */ for (m = group->members; m; m = m->next) p2p_client_info(ie, m); WPA_PUT_LE16(group_info + 1, (u8 *) wpabuf_put(ie, 0) - group_info - 3); p2p_buf_update_ie_hdr(ie, len); return ie; }
/** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) * Returns: 0 on success, -1 on failure */ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t i, offset; u8 *pos; if (password_len > 256) return -1; os_memset(pw_block, 0, PWBLOCK_LEN); offset = (256 - password_len) * 2; if (os_get_random(pw_block, offset) < 0) return -1; for (i = 0; i < password_len; i++) pw_block[offset + i * 2] = password[i]; /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. */ pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); return 0; }
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; #ifdef CONFIG_WNM if (hapd->conf->ap_max_inactivity > 0) { unsigned int val; *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; *pos++ = 3; val = hapd->conf->ap_max_inactivity; if (val > 68000) val = 68000; val *= 1000; val /= 1024; if (val == 0) val = 1; if (val > 65535) val = 65535; WPA_PUT_LE16(pos, val); pos += 2; *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ } #endif /* CONFIG_WNM */ return pos; }
/** * gas_anqp_set_len - Set Query Request/Response Length * @buf: GAS message * * This function is used to update the Query Request/Response Length field once * the payload has been filled. */ void gas_anqp_set_len(struct wpabuf *buf) { u8 action; size_t offset; u8 *len; if (buf == NULL || wpabuf_len(buf) < 2) return; action = *(wpabuf_head_u8(buf) + 1); switch (action) { case WLAN_PA_GAS_INITIAL_REQ: offset = 3 + 4; break; case WLAN_PA_GAS_INITIAL_RESP: offset = 7 + 4; break; case WLAN_PA_GAS_COMEBACK_RESP: offset = 8 + 4; break; default: return; } if (wpabuf_len(buf) < offset + 2) return; len = wpabuf_mhead_u8(buf) + offset; WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); }
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) { u8 *subelem, *pos; struct wpa_group *gsm = sm->group; size_t subelem_len; /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] | * Key[16+8] */ subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8; subelem = os_zalloc(subelem_len); if (subelem == NULL) return NULL; pos = subelem; *pos++ = FTIE_SUBELEM_IGTK; *pos++ = subelem_len - 2; WPA_PUT_LE16(pos, gsm->GN_igtk); pos += 2; wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos); pos += 6; *pos++ = WPA_IGTK_LEN; if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, gsm->IGTK[gsm->GN_igtk - 4], pos)) { os_free(subelem); return NULL; } *len = subelem_len; return subelem; }
static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, u16 comeback_delay, u16 update_indic, const struct wpabuf *tlvs) { struct wpabuf *buf; u8 *len_pos, *len_pos2; buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0)); if (buf == NULL) return NULL; wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP); wpabuf_put_u8(buf, dialog_token); wpabuf_put_le16(buf, status_code); wpabuf_put_le16(buf, comeback_delay); /* Advertisement Protocol IE */ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); wpabuf_put_u8(buf, 2); /* Length */ wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ /* Query Response */ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ if (tlvs) { /* NQP Query Response Frame */ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); /* Service Update Indicator */ wpabuf_put_le16(buf, update_indic); wpabuf_put_buf(buf, tlvs); WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); } WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); return buf; }
/** * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding * @utf8_string: UTF-8 string (IN) * @utf8_string_len: Length of utf8_string (IN) * @ucs2_buffer: UCS-2 buffer (OUT) * @ucs2_buffer_size: Length of UCS-2 buffer (IN) * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string * Returns: 0 on success, -1 on failure */ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len, u8 *ucs2_buffer, size_t ucs2_buffer_size, size_t *ucs2_string_size) { size_t i, j; for (i = 0, j = 0; i < utf8_string_len; i++) { u8 c = utf8_string[i]; if (j >= ucs2_buffer_size) { /* input too long */ return -1; } if (c <= 0x7F) { WPA_PUT_LE16(ucs2_buffer + j, c); j += 2; } else if (i == utf8_string_len - 1 || j >= ucs2_buffer_size - 1) { /* incomplete surrogate */ return -1; } else { u8 c2 = utf8_string[++i]; if ((c & 0xE0) == 0xC0) { /* two-byte encoding */ WPA_PUT_LE16(ucs2_buffer + j, ((c & 0x1F) << 6) | (c2 & 0x3F)); j += 2; } else if (i == utf8_string_len || j >= ucs2_buffer_size - 1) { /* incomplete surrogate */ return -1; } else { /* three-byte encoding */ u8 c3 = utf8_string[++i]; WPA_PUT_LE16(ucs2_buffer + j, ((c & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); j += 2; } } } if (ucs2_string_size) *ucs2_string_size = j / 2; return 0; }
void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, struct p2p_device *peer) { u8 *len; u16 methods; size_t nlen, i; /* P2P Device Info */ wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); len = wpabuf_put(buf, 2); /* IE length to be filled */ /* P2P Device address */ wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); /* Config Methods */ methods = 0; if (peer && peer->wps_method != WPS_NOT_READY) { if (peer->wps_method == WPS_PBC) methods |= WPS_CONFIG_PUSHBUTTON; else if (peer->wps_method == WPS_PIN_DISPLAY || peer->wps_method == WPS_PIN_KEYPAD) { methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; methods |= WPS_CONFIG_P2PS; } } else if (p2p->cfg->config_methods) { methods |= p2p->cfg->config_methods & (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS); } else { methods |= WPS_CONFIG_PUSHBUTTON; methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; methods |= WPS_CONFIG_P2PS; } wpabuf_put_be16(buf, methods); /* Primary Device Type */ wpabuf_put_data(buf, p2p->cfg->pri_dev_type, sizeof(p2p->cfg->pri_dev_type)); /* Number of Secondary Device Types */ wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); /* Secondary Device Type List */ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], WPS_DEV_TYPE_LEN); /* Device Name */ nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; wpabuf_put_be16(buf, ATTR_DEV_NAME); wpabuf_put_be16(buf, nlen); wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); /* Update attribute length */ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); wpa_printf(MSG_DEBUG, "P2P: * Device Info"); }
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) { u8 *subelem; struct wpa_group *gsm = sm->group; size_t subelem_len, pad_len; const u8 *key; size_t key_len; u8 keybuf[32]; key_len = gsm->GTK_len; if (key_len > sizeof(keybuf)) return NULL; /* * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less * than 16 bytes. */ pad_len = key_len % 8; if (pad_len) pad_len = 8 - pad_len; if (key_len + pad_len < 16) pad_len += 8; if (pad_len) { os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len); os_memset(keybuf + key_len, 0, pad_len); keybuf[key_len] = 0xdd; key_len += pad_len; key = keybuf; } else key = gsm->GTK[gsm->GN - 1]; /* * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | * Key[5..32]. */ subelem_len = 13 + key_len + 8; subelem = os_zalloc(subelem_len); if (subelem == NULL) return NULL; subelem[0] = FTIE_SUBELEM_GTK; subelem[1] = 11 + key_len + 8; /* Key ID in B0-B1 of Key Info */ WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); subelem[4] = gsm->GTK_len; wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5); if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { os_free(subelem); return NULL; } *len = subelem_len; return subelem; }
static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, u8 minor_reason_code, const u8 *addr) { struct ieee80211_mgmt *mgmt; int ret; u8 *pos; if (hapd->driver->send_frame == NULL) return -1; mgmt = os_zalloc(sizeof(*mgmt) + 100); if (mgmt == NULL) return -1; mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor reason code %u (stype=%u (%s))", MAC2STR(addr), minor_reason_code, stype, fc2str(mgmt->frame_control)); os_memcpy(mgmt->da, addr, ETH_ALEN); os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); if (stype == WLAN_FC_STYPE_DEAUTH) { mgmt->u.deauth.reason_code = host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); } else { mgmt->u.disassoc.reason_code = host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); } *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 4 + 3 + 1; WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE); pos += 4; *pos++ = P2P_ATTR_MINOR_REASON_CODE; WPA_PUT_LE16(pos, 1); pos += 2; *pos++ = minor_reason_code; ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, pos - (u8 *) mgmt, 1); os_free(mgmt); return ret < 0 ? -1 : 0; }
static struct wpabuf * p2p_build_sd_query(u16 update_indic, struct wpabuf *tlvs) { struct wpabuf *buf; u8 *len_pos, *len_pos2; buf = wpabuf_alloc(1000 + wpabuf_len(tlvs)); if (buf == NULL) return NULL; wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ); wpabuf_put_u8(buf, 0); /* Dialog Token */ /* Advertisement Protocol IE */ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); wpabuf_put_u8(buf, 2); /* Length */ wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ /* Query Request */ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ /* NQP Query Request Frame */ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */ wpabuf_put_buf(buf, tlvs); WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); return buf; }
int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, size_t subelem_len) { u8 *pos = buf, *ielen; struct rsn_ftie *hdr; if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len + subelem_len) return -1; *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ielen = pos++; hdr = (struct rsn_ftie *) pos; os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); WPA_PUT_LE16(hdr->mic_control, 0); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN); /* Optional Parameters */ *pos++ = FTIE_SUBELEM_R1KH_ID; *pos++ = FT_R1KH_ID_LEN; os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN); pos += FT_R1KH_ID_LEN; if (r0kh_id) { *pos++ = FTIE_SUBELEM_R0KH_ID; *pos++ = r0kh_id_len; os_memcpy(pos, r0kh_id, r0kh_id_len); pos += r0kh_id_len; } if (subelem) { os_memcpy(pos, subelem, subelem_len); pos += subelem_len; } *ielen = pos - buf - 2; return pos - buf; }
static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, u16 status_code, u16 update_indic, const u8 *data, size_t len, u8 frag_id, u8 more, u16 total_len) { struct wpabuf *buf; u8 *len_pos; buf = wpabuf_alloc(1000 + len); if (buf == NULL) return NULL; wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP); wpabuf_put_u8(buf, dialog_token); wpabuf_put_le16(buf, status_code); wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0)); wpabuf_put_le16(buf, 0); /* Comeback Delay */ /* Advertisement Protocol IE */ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); wpabuf_put_u8(buf, 2); /* Length */ wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ /* Query Response */ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ if (frag_id == 0) { /* NQP Query Response Frame */ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ wpabuf_put_le16(buf, 3 + 1 + 2 + total_len); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); /* Service Update Indicator */ wpabuf_put_le16(buf, update_indic); } wpabuf_put_data(buf, data, len); WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); return buf; }
/** * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) */ static void encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t i, offset; u8 *pos; if (password_len > 256) return; memset(pw_block, 0, PWBLOCK_LEN); offset = (256 - password_len) * 2; for (i = 0; i < password_len; i++) pw_block[offset + i * 2] = password[i]; pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4(pw_block, PWBLOCK_LEN, password_hash, 16); }
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid) { u8 bitmap; *eid++ = WLAN_EID_VENDOR_SPECIFIC; *eid++ = 4 + 3 + 1; WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = P2P_OUI_TYPE; *eid++ = P2P_ATTR_MANAGEABILITY; WPA_PUT_LE16(eid, 1); eid += 2; bitmap = P2P_MAN_DEVICE_MANAGEMENT; if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION) bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED; bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL; *eid++ = bitmap; return eid; }
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid) { u8 conf; if (!hapd->conf->hs20) return eid; *eid++ = WLAN_EID_VENDOR_SPECIFIC; *eid++ = 7; WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = HS20_INDICATION_OUI_TYPE; conf = HS20_VERSION; /* Release Number */ conf |= HS20_ANQP_DOMAIN_ID_PRESENT; if (hapd->conf->disable_dgaf) conf |= HS20_DGAF_DISABLED; *eid++ = conf; WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id); eid += 2; return eid; }
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { u8 *group_info; struct wpabuf *p2p_subelems, *ie; struct p2p_group_member *m; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) extra += wpabuf_len(group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ p2p_subelems = wpabuf_alloc(500 + extra); if (p2p_subelems == NULL) return NULL; #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) wpabuf_put_buf(p2p_subelems, group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ p2p_group_add_common_ies(group, p2p_subelems); p2p_group_add_noa(p2p_subelems, group->noa); /* P2P Device Info */ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL); /* P2P Group Info */ group_info = wpabuf_put(p2p_subelems, 0); wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO); wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */ for (m = group->members; m; m = m->next) p2p_client_info(p2p_subelems, m); WPA_PUT_LE16(group_info + 1, (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3); ie = p2p_group_encaps_probe_resp(p2p_subelems); wpabuf_free(p2p_subelems); return ie; }
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { struct wpabuf *p2p_subelems, *ie; struct p2p_group_member *m; p2p_subelems = wpabuf_alloc(500); if (p2p_subelems == NULL) return NULL; p2p_group_add_common_ies(group, p2p_subelems); p2p_group_add_noa(p2p_subelems, group->noa); /* P2P Device Info */ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL); /* P2P Group Info: Only when at least one P2P Client is connected */ if (group->members) { u8 *group_info; group_info = wpabuf_put(p2p_subelems, 0); wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO); wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */ for (m = group->members; m; m = m->next) p2p_client_info(p2p_subelems, m); WPA_PUT_LE16(group_info + 1, (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3); } ie = p2p_group_encaps_probe_resp(p2p_subelems); wpabuf_free(p2p_subelems); #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) { struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); ie = wpabuf_concat(wfd, ie); } #endif /* CONFIG_WIFI_DISPLAY */ return ie; }
void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, struct p2p_channels *chan) { u8 *len; size_t i; /* Channel List */ wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); len = wpabuf_put(buf, 2); /* IE length to be filled */ wpabuf_put_data(buf, country, 3); /* Country String */ for (i = 0; i < chan->reg_classes; i++) { struct p2p_reg_class *c = &chan->reg_class[i]; wpabuf_put_u8(buf, c->reg_class); wpabuf_put_u8(buf, c->channels); wpabuf_put_data(buf, c->channel, c->channels); } /* Update attribute length */ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); wpa_printf(MSG_DEBUG, "P2P: * Channel List"); }
static int wpa_supplicant_process_smk_m2( struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, size_t extra_len, int ver) { struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; struct wpa_ie_data ie; int cipher; struct rsn_ie_hdr *hdr; u8 *pos; wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " "the current network"); return -1; } if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); return -1; } if (kde.rsn_ie == NULL || kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN) { wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " "SMK M2"); return -1; } wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, MAC2STR(kde.mac_addr)); if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " "M2"); return -1; } if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); return -1; } cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; if (cipher & WPA_CIPHER_CCMP) { wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); cipher = WPA_CIPHER_CCMP; } else if (cipher & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); cipher = WPA_CIPHER_TKIP; } else { wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, STK_MUI_SMK, STK_ERR_CPHR_NS, ver); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one; how to handle the case where both ends initiate at the * same time? */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); peerkey->rsnie_i_len = kde.rsn_ie_len; peerkey->cipher = cipher; #ifdef CONFIG_IEEE80211W if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_PSK_SHA256)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for PNonce"); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; /* Include only the selected cipher in pairwise cipher suite */ WPA_PUT_LE16(pos, 1); pos += 2; if (cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; hdr->len = (pos - peerkey->rsnie_p) - 2; peerkey->rsnie_p_len = pos - peerkey->rsnie_p; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_p, peerkey->rsnie_p_len); wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }