static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ #ifdef CONFIG_INTERWORKING if (wpa_s->conf->interworking && wpabuf_resize(&extra_ie, 100) == 0) wpas_add_interworking_elements(wpa_s, extra_ie); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s, &req_type); if (wps) { struct wpabuf *wps_ie; wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) wpabuf_put_buf(extra_ie, wps_ie); wpabuf_free(wps_ie); } } #ifdef CONFIG_P2P if (wps) { size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); if (wpabuf_resize(&extra_ie, ielen) == 0) wpas_p2p_scan_ie(wpa_s, extra_ie); } #endif /* CONFIG_P2P */ #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) wpas_hs20_add_indication(extra_ie); #endif /* CONFIG_HS20 */ return extra_ie; }
static int eap_fast_encrypt_phase2(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *plain, int piggyback) { struct wpabuf *encr; wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", plain); encr = eap_server_tls_encrypt(sm, &data->ssl, plain); wpabuf_free(plain); if (data->ssl.tls_out && piggyback) { wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data " "(len=%d) with last Phase 1 Message (len=%d " "used=%d)", (int) wpabuf_len(encr), (int) wpabuf_len(data->ssl.tls_out), (int) data->ssl.tls_out_pos); if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize " "output buffer"); wpabuf_free(encr); return -1; } wpabuf_put_buf(data->ssl.tls_out, encr); wpabuf_free(encr); } else { wpabuf_free(data->ssl.tls_out); data->ssl.tls_out_pos = 0; data->ssl.tls_out = encr; } return 0; }
u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value, const u8 *data, size_t len) { int attr_len = 4 + len; int pad_len; u8 *start; if (msg == NULL) return NULL; pad_len = (4 - attr_len % 4) % 4; attr_len += pad_len; if (wpabuf_resize(&msg->buf, attr_len)) return NULL; start = wpabuf_put(msg->buf, 0); wpabuf_put_u8(msg->buf, attr); wpabuf_put_u8(msg->buf, attr_len / 4); wpabuf_put_be16(msg->buf, value); if (data) wpabuf_put_data(msg->buf, data, len); else wpabuf_put(msg->buf, len); if (pad_len) os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); return start; }
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, const u8 *data, size_t data_len) { size_t buf_needed; struct radius_attr_hdr *attr; if (data_len > RADIUS_MAX_ATTR_LEN) { printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", (unsigned long) data_len); return NULL; } buf_needed = sizeof(*attr) + data_len; if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ if (wpabuf_resize(&msg->buf, buf_needed) < 0) return NULL; msg->hdr = wpabuf_mhead(msg->buf); } attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); attr->type = type; attr->length = sizeof(*attr) + data_len; wpabuf_put_data(msg->buf, data, data_len); if (radius_msg_add_attr_to_array(msg, attr)) return NULL; return attr; }
static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len) { if (!data || !len) return 0; if (wpabuf_resize(dst, len) != 0) return -1; wpabuf_put_data(*dst, data, len); return 0; }
static int add_buf(struct wpabuf **dst, const struct wpabuf *src) { if (!src) return 0; if (wpabuf_resize(dst, wpabuf_len(src)) != 0) return -1; wpabuf_put_buf(*dst, src); return 0; }
static int eap_peapv2_start_phase2(struct eap_sm *sm, struct eap_peap_data *data) { struct wpabuf *buf, *buf2; int res; wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " "payload in the same message"); eap_peap_state(data, PHASE1_ID2); if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) return -1; /* TODO: which Id to use here? */ buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); if (buf == NULL) return -1; buf2 = eap_peapv2_tlv_eap_payload(buf); if (buf2 == NULL) return -1; wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); buf = wpabuf_alloc(data->ssl.tls_out_limit); if (buf == NULL) { wpabuf_free(buf2); return -1; } res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, wpabuf_head(buf2), wpabuf_len(buf2), wpabuf_put(buf, 0), data->ssl.tls_out_limit); wpabuf_free(buf2); if (res < 0) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " "data"); wpabuf_free(buf); return -1; } wpabuf_put(buf, res); wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", buf); /* Append TLS data into the pending buffer after the Server Finished */ if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) { wpabuf_free(buf); return -1; } wpabuf_put_buf(data->ssl.out_buf, buf); wpabuf_free(buf); return 0; }
/** * eap_peer_tls_reassemble_fragment - Reassemble a received fragment * @data: Data for TLS processing * @in_data: Next incoming TLS segment * Returns: 0 on success, 1 if more data is needed for the full message, or * -1 on error */ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, const struct wpabuf *in_data) { size_t tls_in_len, in_len; tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; in_len = in_data ? wpabuf_len(in_data) : 0; if (tls_in_len + in_len == 0) { /* No message data received?! */ wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " "tls_in_left=%lu tls_in_len=%lu in_len=%lu", (unsigned long) data->tls_in_left, (unsigned long) tls_in_len, (unsigned long) in_len); eap_peer_tls_reset_input(data); return -1; } if (tls_in_len + in_len > 65536) { /* * Limit length to avoid rogue servers from causing large * memory allocations. */ wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " "64 kB)"); eap_peer_tls_reset_input(data); return -1; } if (in_len > data->tls_in_left) { /* Sender is doing something odd - reject message */ wpa_printf(MSG_INFO, "SSL: more data than TLS message length " "indicated"); eap_peer_tls_reset_input(data); return -1; } if (wpabuf_resize(&data->tls_in, in_len) < 0) { wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " "data"); eap_peer_tls_reset_input(data); return -1; } if (in_data) wpabuf_put_buf(data->tls_in, in_data); data->tls_in_left -= in_len; if (data->tls_in_left > 0) { wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " "data", (unsigned long) data->tls_in_left); return 1; } return 0; }
static int gas_query_append(struct gas_query_pending *query, const u8 *data, size_t len) { if (wpabuf_resize(&query->resp, len) < 0) { wpa_printf(MSG_DEBUG, "GAS: No memory to store the response"); return -1; } wpabuf_put_data(query->resp, data, len); return 0; }
void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf **extra_ie) { /* EID + 0-length (wildcard) mesh-id */ size_t ielen = 2; if (wpabuf_resize(extra_ie, ielen) == 0) { wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID); wpabuf_put_u8(*extra_ie, 0); } }
static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *) ptr; if (wpabuf_resize(&conn->push_buf, len) < 0) { errno = ENOMEM; return -1; } wpabuf_put_data(conn->push_buf, buf, len); return len; }
static int eap_aka_add_id_msg(struct eap_aka_data *data, const struct wpabuf *msg) { if (msg == NULL) return -1; if (data->id_msgs == NULL) { data->id_msgs = wpabuf_dup(msg); return data->id_msgs == NULL ? -1 : 0; } if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) return -1; wpabuf_put_buf(data->id_msgs, msg); return 0; }
static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm, struct eap_eke_data *data, u8 id) { struct wpabuf *msg; u8 pub[EAP_EKE_MAX_DH_LEN]; wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit"); if (sm->user == NULL || sm->user->password == NULL) { wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured"); eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); return eap_eke_build_failure(data, id); } if (eap_eke_derive_key(&data->sess, sm->user->password, sm->user->password_len, sm->server_id, sm->server_id_len, data->peerid, data->peerid_len, data->key) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len, EAP_EKE_COMMIT); if (msg == NULL) { eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } /* * y_s = g ^ x_s (mod p) * x_s = random number 2 .. p-1 * temp = prf(0+, password) * key = prf+(temp, ID_S | ID_P) * DHComponent_S = Encr(key, y_s) */ if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } if (eap_eke_dhcomp(&data->sess, data->key, pub, wpabuf_put(msg, data->sess.dhcomp_len)) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); wpabuf_free(msg); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) { wpabuf_free(msg); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } wpabuf_put_buf(data->msgs, msg); return msg; }
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf **beacon_ret, struct wpabuf **proberesp_ret, struct wpabuf **assocresp_ret) { struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL; u8 buf[200], *pos; *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; pos = buf; pos = hostapd_eid_time_adv(hapd, pos); if (add_buf_data(&beacon, buf, pos - buf) < 0) goto fail; pos = hostapd_eid_time_zone(hapd, pos); if (add_buf_data(&proberesp, buf, pos - buf) < 0) goto fail; pos = buf; pos = hostapd_eid_ext_capab(hapd, pos); if (add_buf_data(&assocresp, buf, pos - buf) < 0) goto fail; pos = hostapd_eid_interworking(hapd, pos); pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0) goto fail; #ifdef CONFIG_FST if (add_buf(&beacon, hapd->iface->fst_ies) < 0 || add_buf(&proberesp, hapd->iface->fst_ies) < 0 || add_buf(&assocresp, hapd->iface->fst_ies) < 0) goto fail; #endif /* CONFIG_FST */ #ifdef CONFIG_FILS pos = hostapd_eid_fils_indic(hapd, buf, 0); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0) goto fail; #endif /* CONFIG_FILS */ if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 || add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0) goto fail; #ifdef CONFIG_P2P if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 || add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0) goto fail; #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { if (wpabuf_resize(&beacon, 100) == 0) { u8 *start, *p; start = wpabuf_put(beacon, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(beacon, p - start); } if (wpabuf_resize(&proberesp, 100) == 0) { u8 *start, *p; start = wpabuf_put(proberesp, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(proberesp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WPS if (hapd->conf->wps_state) { struct wpabuf *a = wps_build_assoc_resp_ie(); add_buf(&assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { if (wpabuf_resize(&assocresp, 100) == 0) { u8 *start, *p; start = wpabuf_put(assocresp, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(assocresp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WIFI_DISPLAY if (hapd->p2p_group) { struct wpabuf *a; a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS); add_buf(&assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_HS20 pos = hostapd_eid_hs20_indication(hapd, buf); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0) goto fail; pos = hostapd_eid_osen(hapd, buf); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0) goto fail; #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO if (hapd->conf->mbo_enabled || hapd->enable_oce) { pos = hostapd_eid_mbo(hapd, buf, sizeof(buf)); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0 || add_buf_data(&assocresp, buf, pos - buf) < 0) goto fail; } #endif /* CONFIG_MBO */ add_buf(&beacon, hapd->conf->vendor_elements); add_buf(&proberesp, hapd->conf->vendor_elements); add_buf(&assocresp, hapd->conf->assocresp_elements); *beacon_ret = beacon; *proberesp_ret = proberesp; *assocresp_ret = assocresp; return 0; fail: wpabuf_free(beacon); wpabuf_free(proberesp); wpabuf_free(assocresp); return -1; }
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; enum scan_req_type scan_req = NORMAL_SCAN_REQ; int ret; struct wpabuf *extra_ie = NULL; struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; size_t max_ssids; enum wpa_states prev_state; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); return; } if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } if (!wpa_supplicant_enabled_networks(wpa_s) && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); #ifdef CONFIG_P2P wpa_s->sta_scan_pending = 0; #endif /* CONFIG_P2P */ return; } if (wpa_s->conf->ap_scan != 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; wpas_notify_ap_scan_changed(wpa_s); } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { if (wpa_s->sta_scan_pending && wpas_p2p_in_progress(wpa_s) == 2 && wpa_s->global->p2p_cb_on_scan_complete) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " "mode scan during P2P search"); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); return; } } #endif /* CONFIG_P2P */ if (wpa_s->conf->ap_scan == 2) max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } scan_req = wpa_s->scan_req; wpa_s->scan_req = NORMAL_SCAN_REQ; os_memset(¶ms, 0, sizeof(params)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); /* * If autoscan has set its own scanning parameters */ if (wpa_s->autoscan_params != NULL) { scan_params = wpa_s->autoscan_params; goto scan; } if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; } wpa_s->connect_without_scan = NULL; if (ssid) { wpa_printf(MSG_DEBUG, "Start a pre-selected network " "without scan step"); wpa_supplicant_associate(wpa_s, NULL, ssid); return; } } #ifdef CONFIG_P2P if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && wpa_s->go_params) { wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during " "P2P group formation"); params.ssids[0].ssid = wpa_s->go_params->ssid; params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; params.num_ssids = 1; goto ssid_list_set; } #endif /* CONFIG_P2P */ /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid) && ssid->scan_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids + 1 >= max_ssids) break; } ssid = ssid->next; if (ssid == start) break; if (ssid == NULL && max_ssids > 1 && start != wpa_s->conf->ssid) ssid = wpa_s->conf->ssid; } for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { if (wpas_network_disabled(wpa_s, tssid)) continue; if ((params.freqs || !freqs_set) && tssid->scan_freq) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { os_free(params.freqs); params.freqs = NULL; } freqs_set = 1; } int_array_sort_unique(params.freqs); } if (ssid && max_ssids == 1) { /* * If the driver is limited to 1 SSID at a time interleave * wildcard SSID scans with specific SSID scans to avoid * waiting a long time for a wildcard scan. */ if (!wpa_s->prev_scan_wildcard) { params.ssids[0].ssid = NULL; params.ssids[0].ssid_len = 0; wpa_s->prev_scan_wildcard = 1; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " "wildcard SSID (Interleave with specific)"); } else { wpa_s->prev_scan_ssid = ssid; wpa_s->prev_scan_wildcard = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific SSID: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } } else if (ssid) { /* max_ssids > 1 */ wpa_s->prev_scan_ssid = ssid; wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } #ifdef CONFIG_P2P ssid_list_set: #endif /* CONFIG_P2P */ wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) wpas_hs20_add_indication(extra_ie); #endif /* CONFIG_HS20 */ if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); params.freqs = wpa_s->next_scan_freqs; } else os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning || (wpa_s->show_group_started && wpa_s->go_params)) { /* * The interface may not yet be in P2P mode, so we have to * explicitly request P2P probe to disable CCK rates. */ params.p2p_probe = 1; } #endif /* CONFIG_P2P */ scan_params = ¶ms; scan: #ifdef CONFIG_P2P /* * If the driver does not support multi-channel concurrency and a * virtual interface that shares the same radio with the wpa_s interface * is operating there may not be need to scan other channels apart from * the current operating channel on the other virtual interface. Filter * out other channels in case we are trying to find a connection for a * station interface when we are not configured to prefer station * connection and a concurrent operation is already in process. */ if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ && !scan_params->freqs && !params.freqs && wpas_is_p2p_prioritized(wpa_s) && !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && non_p2p_network_enabled(wpa_s)) { int freq = shared_vif_oper_freq(wpa_s); if (freq > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current " "operating channel (%d MHz) since driver does " "not support multi-channel concurrency", freq); params.freqs = os_zalloc(sizeof(int) * 2); if (params.freqs) params.freqs[0] = freq; scan_params->freqs = params.freqs; } } #endif /* CONFIG_P2P */ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } else { wpa_s->scan_for_connection = 0; } }
static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, struct eap_eke_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { struct wpabuf *resp; const u8 *pos, *end, *dhcomp; size_t prot_len; u8 *rpos; u8 key[EAP_EKE_MAX_KEY_LEN]; u8 pub[EAP_EKE_MAX_DH_LEN]; const u8 *password; size_t password_len; u8 id = eap_get_id(reqData); if (data->state != COMMIT) { wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PROTO_ERROR); } wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PASSWD_NOT_FOUND); } pos = payload; end = payload + payload_len; if (pos + data->sess.dhcomp_len > end) { wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PROTO_ERROR); } wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", pos, data->sess.dhcomp_len); dhcomp = pos; pos += data->sess.dhcomp_len; wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); /* * temp = prf(0+, password) * key = prf+(temp, ID_S | ID_P) */ if (eap_eke_derive_key(&data->sess, password, password_len, data->serverid, data->serverid_len, data->peerid, data->peerid_len, key) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } /* * y_p = g ^ x_p (mod p) * x_p = random number 2 .. p-1 */ if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } if (eap_eke_derive_ke_ki(&data->sess, data->serverid, data->serverid_len, data->peerid, data->peerid_len) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); resp = eap_eke_build_msg(data, id, data->sess.dhcomp_len + data->sess.pnonce_len, EAP_EKE_COMMIT); if (resp == NULL) { os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } /* DHComponent_P = Encr(key, y_p) */ rpos = wpabuf_put(resp, data->sess.dhcomp_len); if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { wpabuf_free(resp); wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } os_memset(key, 0, sizeof(key)); wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", rpos, data->sess.dhcomp_len); if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", data->nonce_p, data->sess.nonce_len); prot_len = wpabuf_tailroom(resp); if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, wpabuf_put(resp, 0), &prot_len) < 0) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", wpabuf_put(resp, 0), prot_len); wpabuf_put(resp, prot_len); /* TODO: CBValue */ if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) < 0) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpabuf_put_buf(data->msgs, reqData); wpabuf_put_buf(data->msgs, resp); eap_eke_state(data, CONFIRM); return resp; }
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int scan_req = 0, ret; struct wpabuf *extra_ie; struct wpa_driver_scan_params params; size_t max_ssids; enum wpa_states prev_state; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); return; } if (wpa_s->disconnected && !wpa_s->scan_req) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } if (!wpa_supplicant_enabled_networks(wpa_s->conf) && !wpa_s->scan_req) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } if (wpa_s->conf->ap_scan != 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; wpas_notify_ap_scan_changed(wpa_s); } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { if (wpa_s->sta_scan_pending && wpas_p2p_in_progress(wpa_s) == 2 && wpa_s->global->p2p_cb_on_scan_complete) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " "mode scan during P2P search"); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); return; } } #endif /* CONFIG_P2P */ if (wpa_s->conf->ap_scan == 2) max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } scan_req = wpa_s->scan_req; wpa_s->scan_req = 0; os_memset(¶ms, 0, sizeof(params)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); if (scan_req != 2 && wpa_s->connect_without_scan) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; } wpa_s->connect_without_scan = NULL; if (ssid) { wpa_printf(MSG_DEBUG, "Start a pre-selected network " "without scan step"); wpa_supplicant_associate(wpa_s, NULL, ssid); return; } } /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; #ifndef ANDROID } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; #endif } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled && ssid->scan_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids + 1 >= max_ssids) break; } ssid = ssid->next; if (ssid == start) break; if (ssid == NULL && max_ssids > 1 && start != wpa_s->conf->ssid) ssid = wpa_s->conf->ssid; } for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { if (tssid->disabled) continue; if ((params.freqs || !freqs_set) && tssid->scan_freq) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { os_free(params.freqs); params.freqs = NULL; } freqs_set = 1; } int_array_sort_unique(params.freqs); } if (ssid && max_ssids == 1) { /* * If the driver is limited to 1 SSID at a time interleave * wildcard SSID scans with specific SSID scans to avoid * waiting a long time for a wildcard scan. */ if (!wpa_s->prev_scan_wildcard) { params.ssids[0].ssid = NULL; params.ssids[0].ssid_len = 0; wpa_s->prev_scan_wildcard = 1; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " "wildcard SSID (Interleave with specific)"); } else { wpa_s->prev_scan_ssid = ssid; wpa_s->prev_scan_wildcard = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific SSID: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } } else if (ssid) { /* max_ssids > 1 */ wpa_s->prev_scan_ssid = ssid; wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0) wpas_hs20_add_indication(extra_ie); #endif /* CONFIG_HS20 */ if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); params.freqs = wpa_s->next_scan_freqs; } else os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning) { /* * The interface may not yet be in P2P mode, so we have to * explicitly request P2P probe to disable CCK rates. */ params.p2p_probe = 1; } #endif /* CONFIG_P2P */ ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } }
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf **beacon_ret, struct wpabuf **proberesp_ret, struct wpabuf **assocresp_ret) { struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL; u8 buf[200], *pos; *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; pos = buf; pos = hostapd_eid_time_adv(hapd, pos); if (pos != buf) { if (wpabuf_resize(&beacon, pos - buf) != 0) goto fail; wpabuf_put_data(beacon, buf, pos - buf); } pos = hostapd_eid_time_zone(hapd, pos); if (pos != buf) { if (wpabuf_resize(&proberesp, pos - buf) != 0) goto fail; wpabuf_put_data(proberesp, buf, pos - buf); } pos = buf; pos = hostapd_eid_ext_capab(hapd, pos); if (pos != buf) { if (wpabuf_resize(&assocresp, pos - buf) != 0) goto fail; wpabuf_put_data(assocresp, buf, pos - buf); } pos = hostapd_eid_interworking(hapd, pos); pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); if (pos != buf) { if (wpabuf_resize(&beacon, pos - buf) != 0) goto fail; wpabuf_put_data(beacon, buf, pos - buf); if (wpabuf_resize(&proberesp, pos - buf) != 0) goto fail; wpabuf_put_data(proberesp, buf, pos - buf); } if (hapd->wps_beacon_ie) { if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) < 0) goto fail; wpabuf_put_buf(beacon, hapd->wps_beacon_ie); } if (hapd->wps_probe_resp_ie) { if (wpabuf_resize(&proberesp, wpabuf_len(hapd->wps_probe_resp_ie)) < 0) goto fail; wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); } #ifdef CONFIG_P2P if (hapd->p2p_beacon_ie) { if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) < 0) goto fail; wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); } if (hapd->p2p_probe_resp_ie) { if (wpabuf_resize(&proberesp, wpabuf_len(hapd->p2p_probe_resp_ie)) < 0) goto fail; wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { if (wpabuf_resize(&beacon, 100) == 0) { u8 *start, *p; start = wpabuf_put(beacon, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(beacon, p - start); } if (wpabuf_resize(&proberesp, 100) == 0) { u8 *start, *p; start = wpabuf_put(proberesp, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(proberesp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WPS2 if (hapd->conf->wps_state) { struct wpabuf *a = wps_build_assoc_resp_ie(); if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) wpabuf_put_buf(assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WPS2 */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { if (wpabuf_resize(&assocresp, 100) == 0) { u8 *start, *p; start = wpabuf_put(assocresp, 0); p = hostapd_eid_p2p_manage(hapd, start); wpabuf_put(assocresp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WIFI_DISPLAY if (hapd->p2p_group) { struct wpabuf *a; a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS); if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) wpabuf_put_buf(assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_HS20 pos = buf; pos = hostapd_eid_hs20_indication(hapd, pos); if (pos != buf) { if (wpabuf_resize(&beacon, pos - buf) != 0) goto fail; wpabuf_put_data(beacon, buf, pos - buf); if (wpabuf_resize(&proberesp, pos - buf) != 0) goto fail; wpabuf_put_data(proberesp, buf, pos - buf); } #endif /* CONFIG_HS20 */ *beacon_ret = beacon; *proberesp_ret = proberesp; *assocresp_ret = assocresp; return 0; fail: wpabuf_free(beacon); wpabuf_free(proberesp); wpabuf_free(assocresp); return -1; }
/** * tlsv1_client_decrypt - Decrypt data from TLS tunnel * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Pointer to input buffer (encrypted TLS data) * @in_len: Input buffer length * @need_more_data: Set to 1 if more data would be needed to complete * processing * Returns: Decrypted data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to * receive data from the encrypted tunnel. */ struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, int *need_more_data) { const u8 *in_end, *pos; int used; u8 alert, *out_pos, ct; size_t olen; struct wpabuf *buf = NULL; if (need_more_data) *need_more_data = 0; if (conn->partial_input) { if (wpabuf_resize(&conn->partial_input, in_len) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for pending record"); alert = TLS_ALERT_INTERNAL_ERROR; goto fail; } wpabuf_put_data(conn->partial_input, in_data, in_len); in_data = wpabuf_head(conn->partial_input); in_len = wpabuf_len(conn->partial_input); } pos = in_data; in_end = in_data + in_len; while (pos < in_end) { ct = pos[0]; if (wpabuf_resize(&buf, in_end - pos) < 0) { alert = TLS_ALERT_INTERNAL_ERROR; goto fail; } out_pos = wpabuf_put(buf, 0); olen = wpabuf_tailroom(buf); used = tlsv1_record_receive(&conn->rl, pos, in_end - pos, out_pos, &olen, &alert); if (used < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " "failed"); goto fail; } if (used == 0) { struct wpabuf *partial; wpa_printf(MSG_DEBUG, "TLSv1: Need more data"); partial = wpabuf_alloc_copy(pos, in_end - pos); wpabuf_free(conn->partial_input); conn->partial_input = partial; if (conn->partial_input == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to " "allocate memory for pending " "record"); alert = TLS_ALERT_INTERNAL_ERROR; goto fail; } if (need_more_data) *need_more_data = 1; return buf; } if (ct == TLS_CONTENT_TYPE_ALERT) { if (olen < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Alert " "underflow"); alert = TLS_ALERT_DECODE_ERROR; goto fail; } wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", out_pos[0], out_pos[1]); if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) { /* Continue processing */ pos += used; continue; } alert = out_pos[1]; goto fail; } if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " "0x%x when decrypting application data", pos[0]); alert = TLS_ALERT_UNEXPECTED_MESSAGE; goto fail; } wpabuf_put(buf, olen); pos += used; } wpabuf_free(conn->partial_input); conn->partial_input = NULL; return buf; fail: wpabuf_free(buf); wpabuf_free(conn->partial_input); conn->partial_input = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); return NULL; }
/** * tlsv1_client_handshake - Process TLS handshake * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Input data from TLS peer * @in_len: Input data length * @out_len: Length of the output buffer. * @appl_data: Pointer to application data pointer, or %NULL if dropped * @appl_data_len: Pointer to variable that is set to appl_data length * @need_more_data: Set to 1 if more data would be needed to complete * processing * Returns: Pointer to output data, %NULL on failure */ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, size_t *out_len, u8 **appl_data, size_t *appl_data_len, int *need_more_data) { const u8 *pos, *end; u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct; size_t in_msg_len; int no_appl_data; int used; if (need_more_data) *need_more_data = 0; if (conn->state == CLIENT_HELLO) { if (in_len) return NULL; return tls_send_client_hello(conn, out_len); } if (conn->partial_input) { if (wpabuf_resize(&conn->partial_input, in_len) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for pending record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); goto failed; } wpabuf_put_data(conn->partial_input, in_data, in_len); in_data = wpabuf_head(conn->partial_input); in_len = wpabuf_len(conn->partial_input); } if (in_data == NULL || in_len == 0) return NULL; pos = in_data; end = in_data + in_len; in_msg = os_malloc(in_len); if (in_msg == NULL) return NULL; /* Each received packet may include multiple records */ while (pos < end) { in_msg_len = in_len; used = tlsv1_record_receive(&conn->rl, pos, end - pos, in_msg, &in_msg_len, &alert); if (used < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Processing received " "record failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); goto failed; } if (used == 0) { struct wpabuf *partial; wpa_printf(MSG_DEBUG, "TLSv1: Need more data"); partial = wpabuf_alloc_copy(pos, end - pos); wpabuf_free(conn->partial_input); conn->partial_input = partial; if (conn->partial_input == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to " "allocate memory for pending " "record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); goto failed; } os_free(in_msg); if (need_more_data) *need_more_data = 1; return NULL; } ct = pos[0]; in_pos = in_msg; in_end = in_msg + in_msg_len; /* Each received record may include multiple messages of the * same ContentType. */ while (in_pos < in_end) { in_msg_len = in_end - in_pos; if (tlsv1_client_process_handshake(conn, ct, in_pos, &in_msg_len, appl_data, appl_data_len) < 0) goto failed; in_pos += in_msg_len; } pos += used; } os_free(in_msg); in_msg = NULL; no_appl_data = appl_data == NULL || *appl_data == NULL; msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data); failed: os_free(in_msg); if (conn->alert_level) { wpabuf_free(conn->partial_input); conn->partial_input = NULL; conn->state = FAILED; os_free(msg); msg = tlsv1_client_send_alert(conn, conn->alert_level, conn->alert_description, out_len); } else if (msg == NULL) { msg = os_zalloc(1); *out_len = 0; } if (need_more_data == NULL || !(*need_more_data)) { wpabuf_free(conn->partial_input); conn->partial_input = NULL; } return msg; }
static void eap_eke_process_commit(struct eap_sm *sm, struct eap_eke_data *data, const struct wpabuf *respData, const u8 *payload, size_t payloadlen) { const u8 *pos, *end, *dhcomp, *pnonce; size_t decrypt_len; wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit"); if (data->state != COMMIT) { eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } pos = payload; end = payload + payloadlen; if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) { wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", pos, data->sess.dhcomp_len); dhcomp = pos; pos += data->sess.dhcomp_len; wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len); pnonce = pos; pos += data->sess.pnonce_len; wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } if (eap_eke_derive_ke_ki(&data->sess, sm->server_id, sm->server_id_len, data->peerid, data->peerid_len) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } decrypt_len = sizeof(data->nonce_p); if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len, data->nonce_p, &decrypt_len) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P"); eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); return; } if (decrypt_len < (size_t) data->sess.nonce_len) { wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P"); eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); return; } wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", data->nonce_p, data->sess.nonce_len); if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } wpabuf_put_buf(data->msgs, respData); eap_eke_state(data, CONFIRM); }
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int scan_req = 0, ret; struct wpabuf *wps_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ struct wpa_driver_scan_params params; size_t max_ssids; enum wpa_states prev_state; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); return; } if (wpa_s->disconnected && !wpa_s->scan_req) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } if (!wpa_supplicant_enabled_networks(wpa_s->conf) && !wpa_s->scan_req) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } if (wpa_s->conf->ap_scan != 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; wpas_notify_ap_scan_changed(wpa_s); } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || wpa_s->conf->ap_scan == 2) max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s->conf, &req_type); #endif /* CONFIG_WPS */ scan_req = wpa_s->scan_req; wpa_s->scan_req = 0; os_memset(¶ms, 0, sizeof(params)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 || wpa_s->connect_without_scan)) { wpa_s->connect_without_scan = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled && ssid->scan_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids + 1 >= max_ssids) break; } ssid = ssid->next; if (ssid == start) break; if (ssid == NULL && max_ssids > 1 && start != wpa_s->conf->ssid) ssid = wpa_s->conf->ssid; } for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { if (tssid->disabled) continue; if ((params.freqs || !freqs_set) && tssid->scan_freq) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { os_free(params.freqs); params.freqs = NULL; } freqs_set = 1; } int_array_sort_unique(params.freqs); } if (ssid) { wpa_s->prev_scan_ssid = ssid; if (max_ssids > 1) { wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific " "SSID(s)"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } #ifdef CONFIG_P2P wpa_s->wps->dev.p2p = 1; if (!wps) { wps = 1; req_type = WPS_REQ_ENROLLEE_INFO; } if (params.freqs == NULL && wpa_s->p2p_in_provisioning && wpa_s->go_params) { /* Optimize provisioning state scan based on GO information */ if (wpa_s->p2p_in_provisioning < 5 && wpa_s->go_params->freq > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO " "preferred frequency %d MHz", wpa_s->go_params->freq); params.freqs = os_zalloc(2 * sizeof(int)); if (params.freqs) params.freqs[0] = wpa_s->go_params->freq; } else if (wpa_s->p2p_in_provisioning < 8 && wpa_s->go_params->freq_list[0]) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common " "channels"); int_array_concat(¶ms.freqs, wpa_s->go_params->freq_list); if (params.freqs) int_array_sort_unique(params.freqs); } wpa_s->p2p_in_provisioning++; } #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { /* * Optimize post-provisioning scan based on channel used * during provisioning. */ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " "that was used during provisioning", wpa_s->wps_freq); params.freqs = os_zalloc(2 * sizeof(int)); if (params.freqs) params.freqs[0] = wpa_s->wps_freq; wpa_s->after_wps--; } if (wps) { wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL, wpa_s->wps->config_methods); if (wps_ie) { params.extra_ies = wpabuf_head(wps_ie); params.extra_ies_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P if (wps_ie) { if (wpabuf_resize(&wps_ie, 100) == 0) { wpas_p2p_scan_ie(wpa_s, wps_ie); params.extra_ies = wpabuf_head(wps_ie); params.extra_ies_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_P2P */ if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); params.freqs = wpa_s->next_scan_freqs; } else os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); wpabuf_free(wps_ie); os_free(params.freqs); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); wpa_supplicant_req_scan(wpa_s, 1, 0); } }
void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 status_code; u8 frag_id; u8 more_frags; u16 comeback_delay; u16 slen; wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from " MACSTR, MAC2STR(sa)); return; } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)", MAC2STR(sa), (int) len); if (len < 6 + 2) { p2p_dbg(p2p, "Too short GAS Comeback Response frame"); return; } dialog_token = *pos++; /* TODO: check dialog_token match */ status_code = WPA_GET_LE16(pos); pos += 2; frag_id = *pos & 0x7f; more_frags = (*pos & 0x80) >> 7; pos++; comeback_delay = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d " "comeback_delay=%u", dialog_token, status_code, frag_id, more_frags, comeback_delay); /* TODO: check frag_id match */ if (status_code) { p2p_dbg(p2p, "Service Discovery failed: status code %u", status_code); return; } if (*pos != WLAN_EID_ADV_PROTO) { p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { p2p_dbg(p2p, "Invalid IE in GAS Comeback Response"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Response */ if (pos + 2 > end) { p2p_dbg(p2p, "Too short Query Response"); return; } slen = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "Query Response Length: %d", slen); if (pos + slen > end) { p2p_dbg(p2p, "Not enough Query Response data"); return; } if (slen == 0) { p2p_dbg(p2p, "No Query Response data"); return; } end = pos + slen; if (p2p->sd_rx_resp) { /* * ANQP header is only included in the first fragment; rest of * the fragments start with continue TLVs. */ goto skip_nqp_header; } /* ANQP Query Response */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "ANQP Query Response length: %u", slen); if (slen < 3 + 1) { p2p_dbg(p2p, "Invalid ANQP Query Response length"); return; } if (pos + 4 > end) return; if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", WPA_GET_BE32(pos)); return; } pos += 4; if (pos + 2 > end) return; p2p->sd_rx_update_indic = WPA_GET_LE16(pos); p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic); pos += 2; skip_nqp_header: if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) return; wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); p2p_dbg(p2p, "Current SD reassembly buffer length: %u", (unsigned int) wpabuf_len(p2p->sd_rx_resp)); if (more_frags) { p2p_dbg(p2p, "More fragments remains"); /* TODO: what would be a good size limit? */ if (wpabuf_len(p2p->sd_rx_resp) > 64000) { wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; p2p_dbg(p2p, "Too long SD response - drop it"); return; } p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); return; } p2p->sd_peer = NULL; if (p2p->sd_query) { if (!p2p->sd_query->for_all_peers) { struct p2p_sd_query *q; p2p_dbg(p2p, "Remove completed SD query %p", p2p->sd_query); q = p2p->sd_query; p2p_unlink_sd_query(p2p, p2p->sd_query); p2p_free_sd_query(q); } p2p->sd_query = NULL; } if (p2p->cfg->sd_response) p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, p2p->sd_rx_update_indic, wpabuf_head(p2p->sd_rx_resp), wpabuf_len(p2p->sd_rx_resp)); wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; p2p_continue_find(p2p); }
static void eap_eke_process_identity(struct eap_sm *sm, struct eap_eke_data *data, const struct wpabuf *respData, const u8 *payload, size_t payloadlen) { const u8 *pos, *end; int i; wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity"); if (data->state != IDENTITY) { eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } pos = payload; end = payload + payloadlen; if (pos + 2 + 4 + 1 > end) { wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload"); eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } if (*pos != 1) { wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)", *pos); eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } pos += 2; if (!supported_proposal(pos)) { wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)", pos[0], pos[1], pos[2], pos[3]); eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); return; } wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)", pos[0], pos[1], pos[2], pos[3]); if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) < 0) { eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } pos += 4; data->peerid_type = *pos++; os_free(data->peerid); data->peerid = os_memdup(pos, end - pos); if (data->peerid == NULL) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid"); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } data->peerid_len = end - pos; wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type); wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity", data->peerid, data->peerid_len); if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) { wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database"); eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); return; } for (i = 0; i < EAP_MAX_METHODS; i++) { if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && sm->user->methods[i].method == EAP_TYPE_EKE) break; } if (i == EAP_MAX_METHODS) { wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE"); eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); return; } if (sm->user->password == NULL || sm->user->password_len == 0) { wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer"); eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); return; } if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return; } wpabuf_put_buf(data->msgs, respData); eap_eke_state(data, COMMIT); }