void p2p_group_update_ies(struct p2p_group *group) { struct wpabuf *beacon_ie; struct wpabuf *probe_resp_ie; #ifdef CONFIG_WIFI_DISPLAY wifi_display_group_update(group); #endif /* CONFIG_WIFI_DISPLAY */ probe_resp_ie = p2p_group_build_probe_resp_ie(group); if (probe_resp_ie == NULL) return; wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE", probe_resp_ie); if (group->beacon_update) { beacon_ie = p2p_group_build_beacon_ie(group); if (beacon_ie) group->beacon_update = 0; wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE", beacon_ie); } else beacon_ie = NULL; group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie); }
/** * offchannel_send_action_tx_status - TX status callback * @wpa_s: Pointer to wpa_supplicant data * @dst: Destination MAC address of the transmitted Action frame * @data: Transmitted frame payload * @data_len: Length of @data in bytes * @result: TX status * * This function is called whenever the driver indicates a TX status event for * a frame sent by offchannel_send_action() using wpa_drv_send_action(). */ void offchannel_send_action_tx_status( struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { if (wpa_s->pending_action_tx == NULL) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "no pending operation"); return; } if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "unknown destination address"); return; } /* Accept report only if the contents of the frame matches */ if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 || os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx)) != 0) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "mismatching contents with pending frame"); wpa_hexdump(MSG_MSGDUMP, "TX status frame data", data, data_len); wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", wpa_s->pending_action_tx); return; } wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame (dst=" MACSTR " pending_action_tx=%p)", MAC2STR(dst), wpa_s->pending_action_tx); wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p", result, wpa_s->pending_action_tx_status_cb); if (wpa_s->pending_action_tx_status_cb) { wpa_s->pending_action_tx_status_cb( wpa_s, wpa_s->pending_action_freq, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, data, data_len, result); } #ifdef CONFIG_P2P if (wpa_s->p2p_long_listen > 0) { /* Continue the listen */ wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state"); wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen); } #endif /* CONFIG_P2P */ }
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; }
/** * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) * @data: IEs from the message * @len: Length of data buffer in octets * @msg: Buffer for returning parsed attributes * Returns: 0 on success, -1 on failure * * Note: Caller is responsible for clearing the msg data structure before * calling this function. * * Note: Caller must free temporary memory allocations by calling * p2p_parse_free() when the parsed data is not needed anymore. */ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) { struct ieee802_11_elems elems; ieee802_11_parse_elems(data, len, &elems, 0); if (elems.ds_params && elems.ds_params_len >= 1) msg->ds_params = elems.ds_params; if (elems.ssid) msg->ssid = elems.ssid - 2; msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, WPS_DEV_OUI_WFA); if (msg->wps_attributes && p2p_parse_wps_ie(msg->wps_attributes, msg)) { p2p_parse_free(msg); return -1; } msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, P2P_IE_VENDOR_TYPE); if (msg->p2p_attributes && p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); if (msg->p2p_attributes) wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", msg->p2p_attributes); p2p_parse_free(msg); return -1; } return 0; }
static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data) { struct wpabuf *msg, *plain; const u8 *secret; size_t secret_len; secret = data->get_shared_secret(data->cb_ctx, data->IDr, data->IDr_len, &secret_len); if (secret == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Could not get shared secret - " "use fake value"); /* RFC 5106, Sect. 7: * Use a random key to fake AUTH generation in order to prevent * probing of user identities. */ data->unknown_user = 1; os_free(data->shared_secret); data->shared_secret = os_zalloc(16); if (data->shared_secret == NULL) return NULL; data->shared_secret_len = 16; if (os_get_random(data->shared_secret, 16)) return NULL; } else { os_free(data->shared_secret); data->shared_secret = os_zalloc(secret_len); if (data->shared_secret == NULL) return NULL; os_memcpy(data->shared_secret, secret, secret_len); data->shared_secret_len = secret_len; } /* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); plain = wpabuf_alloc(data->IDr_len + 1000); if (plain == NULL) { wpabuf_free(msg); return NULL; } if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 1, msg, plain, IKEV2_PAYLOAD_IDi)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); return msg; }
int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p, size_t p2p_len, struct p2p_message *msg) { os_memset(msg, 0, sizeof(*msg)); msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len); if (msg->wps_attributes && p2p_parse_wps_ie(msg->wps_attributes, msg)) { p2p_parse_free(msg); return -1; } msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len); if (msg->p2p_attributes && p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); if (msg->p2p_attributes) wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", msg->p2p_attributes); p2p_parse_free(msg); return -1; } return 0; }
static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap, const u8 *addr, struct wpabuf *msg) { struct wps_parse_attr attr; wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from " MACSTR, MAC2STR(addr)); wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " "(TLVs from Probe Request)", msg); if (wps_validate_probe_req(msg, addr) < 0) { wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied " "Probe Request frame from " MACSTR, MAC2STR(addr)); return; } if (wps_parse_msg(msg, &attr) < 0) { wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " "WLANEvent message"); return; } wps_er_add_sta_data(ap, addr, &attr, 1); wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0); }
/** * wps_init - Initialize WPS Registration protocol data * @cfg: WPS configuration * Returns: Pointer to allocated data or %NULL on failure * * This function is used to initialize WPS data for a registration protocol * instance (i.e., each run of registration protocol as a Registrar of * Enrollee. The caller is responsible for freeing this data after the * registration run has been completed by calling wps_deinit(). */ struct wps_data * wps_init(const struct wps_config *cfg) { struct wps_data *data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->wps = cfg->wps; data->registrar = cfg->registrar; if (cfg->registrar) { os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); } else { os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); } if (cfg->pin) { data->dev_pw_id = DEV_PW_DEFAULT; data->dev_password = os_malloc(cfg->pin_len); if (data->dev_password == NULL) { os_free(data); return NULL; } os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); data->dev_password_len = cfg->pin_len; } data->pbc = cfg->pbc; if (cfg->pbc) { /* Use special PIN '00000000' for PBC */ data->dev_pw_id = DEV_PW_PUSHBUTTON; os_free(data->dev_password); data->dev_password = os_malloc(8); if (data->dev_password == NULL) { os_free(data); return NULL; } os_memset(data->dev_password, '0', 8); data->dev_password_len = 8; } data->state = data->registrar ? RECV_M1 : SEND_M1; if (cfg->assoc_wps_ie) { struct wps_parse_attr attr; wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", cfg->assoc_wps_ie); if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " "from (Re)AssocReq"); } else if (attr.request_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " "in (Re)AssocReq WPS IE"); } else { wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " "in (Re)AssocReq WPS IE): %d", *attr.request_type); data->request_type = *attr.request_type; } } return data; }
static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) { struct wpabuf *msg, *plain; /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); plain = wpabuf_alloc(data->IDr_len + 1000); if (plain == NULL) { wpabuf_free(msg); return NULL; } if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 0, msg, plain, IKEV2_PAYLOAD_IDr)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); data->state = IKEV2_DONE; return msg; }
static int ikev2_process_ker(struct ikev2_initiator_data *data, const u8 *ker, size_t ker_len) { u16 group; /* * Key Exchange Payload: * DH Group # (16 bits) * RESERVED (16 bits) * Key Exchange Data (Diffie-Hellman public value) */ if (ker == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr not received"); return -1; } if (ker_len < 4 + 96) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Too show Key Exchange Payload"); return -1; } group = WPA_GET_BE16(ker); asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr DH Group #%u", group); if (group != data->proposal.dh) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match " "with the selected proposal (%u)", group, data->proposal.dh); return -1; } if (data->dh == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Unsupported DH group"); return -1; } /* RFC 4306, Section 3.4: * The length of DH public value MUST be equal to the lenght of the * prime modulus. */ if (ker_len - 4 != data->dh->prime_len) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Invalid DH public value length " "%ld (expected %ld)", (long) (ker_len - 4), (long) data->dh->prime_len); return -1; } wpabuf_free(data->r_dh_public); data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4); if (data->r_dh_public == NULL) return -1; wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value", data->r_dh_public); return 0; }
static int ikev2_process_kei(struct ikev2_responder_data *data, const u8 *kei, size_t kei_len) { u16 group; /* * Key Exchange Payload: * DH Group # (16 bits) * RESERVED (16 bits) * Key Exchange Data (Diffie-Hellman public value) */ if (kei == NULL) { wpa_printf(MSG_INFO, "IKEV2: KEi not received"); return -1; } if (kei_len < 4 + 96) { wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload"); return -1; } group = WPA_GET_BE16(kei); wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); if (group != data->proposal.dh) { wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " "with the selected proposal (%u)", group, data->proposal.dh); /* Reject message with Notify payload of type * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ data->error_type = INVALID_KE_PAYLOAD; data->state = NOTIFY; return -1; } if (data->dh == NULL) { wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); return -1; } /* RFC 4306, Section 3.4: * The length of DH public value MUST be equal to the length of the * prime modulus. */ if (kei_len - 4 != data->dh->prime_len) { wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " "%ld (expected %ld)", (long)(kei_len - 4), (long)data->dh->prime_len); return -1; } wpabuf_free(data->i_dh_public); data->i_dh_public = wpabuf_alloc(kei_len - 4); if (data->i_dh_public == NULL) { return -1; } wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", data->i_dh_public); return 0; }
/** * dh_init - Initialize Diffie-Hellman handshake * @dh: Selected Diffie-Hellman group * @priv: Pointer for returning Diffie-Hellman private key * Returns: Diffie-Hellman public value */ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv) { struct wpabuf *pv; size_t pv_len; int retval = 1; if (dh == NULL) return NULL; wpabuf_free(*priv); *priv = wpabuf_alloc(dh->prime_len); if (*priv == NULL) return NULL; if(get_dh_small()) { /* Use small DH secret (1) to reduce calculation time on AP */ if(!memset(wpabuf_put(*priv, 1), 1, 1)) retval = 0; } else { if(os_get_random(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) retval = 0; } if(!retval) { wpabuf_free(*priv); *priv = NULL; return NULL; } if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { /* Make sure private value is smaller than prime */ *(wpabuf_mhead_u8(*priv)) = 0; } wpa_hexdump_buf_key(/*MSG_INFO*/ MSG_DEBUG, "DH: private value", *priv); pv_len = dh->prime_len; pv = wpabuf_alloc(pv_len); if (pv == NULL) return NULL; if (crypto_mod_exp(dh->generator, dh->generator_len, wpabuf_head(*priv), wpabuf_len(*priv), dh->prime, dh->prime_len, wpabuf_mhead(pv), &pv_len) < 0) { wpabuf_free(pv); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; } wpabuf_put(pv, pv_len); wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); return pv; }
int eap_eke_auth(struct eap_eke_session *sess, const char *label, const struct wpabuf *msgs, u8 *auth) { wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label); wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth", sess->ka, sess->auth_len); wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs); return eap_eke_prf(sess->prf, sess->ka, sess->auth_len, (const u8 *) label, os_strlen(label), wpabuf_head(msgs), wpabuf_len(msgs), auth); }
static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, const struct eap_hdr *req, const struct wpabuf *in_data, struct wpabuf **out_data) { struct wpabuf *in_decrypted; int res; wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" " Phase 2", (unsigned long) wpabuf_len(in_data)); if (data->pending_phase2_req) { wpa_printf(MSG_DEBUG, "EAP-FAST: Pending Phase 2 request - " "skip decryption and use old data"); /* Clear TLS reassembly state. */ eap_peer_tls_reset_input(&data->ssl); in_decrypted = data->pending_phase2_req; data->pending_phase2_req = NULL; goto continue_req; } if (wpabuf_len(in_data) == 0) { /* Received TLS ACK - requesting more fragments */ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, data->fast_version, req->identifier, NULL, out_data); } res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); if (res) return res; continue_req: wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)", in_decrypted); if (wpabuf_len(in_decrypted) < 4) { wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " "TLV frame (len=%lu)", (unsigned long) wpabuf_len(in_decrypted)); wpabuf_free(in_decrypted); return -1; } res = eap_fast_process_decrypted(sm, data, ret, req, in_decrypted, out_data); wpabuf_free(in_decrypted); return res; }
static void gas_serv_req_local_processing(struct hostapd_data *hapd, const u8 *sa, u8 dialog_token, struct anqp_query_info *qi) { struct wpabuf *buf, *tx_buf; buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, qi->home_realm_query, qi->home_realm_query_len); wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", buf); if (!buf) return; if (wpabuf_len(buf) > hapd->gas_frag_limit || hapd->conf->gas_comeback_delay) { struct gas_dialog_info *di; u16 comeback_delay = 1; if (hapd->conf->gas_comeback_delay) { /* Testing - allow overriding of the delay value */ comeback_delay = hapd->conf->gas_comeback_delay; } wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " "initial response - use GAS comeback"); di = gas_dialog_create(hapd, sa, dialog_token); if (!di) { wpa_printf(MSG_INFO, "ANQP: Could not create dialog " "for " MACSTR " (dialog token %u)", MAC2STR(sa), dialog_token); wpabuf_free(buf); return; } di->sd_resp = buf; di->sd_resp_pos = 0; tx_buf = gas_anqp_build_initial_resp_buf( dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, NULL); } else { wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); tx_buf = gas_anqp_build_initial_resp_buf( dialog_token, WLAN_STATUS_SUCCESS, 0, buf); wpabuf_free(buf); } if (!tx_buf) return; hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, wpabuf_head(tx_buf), wpabuf_len(tx_buf)); wpabuf_free(tx_buf); }
static void p2p_group_update_ies(struct p2p_group *group) { struct wpabuf *beacon_ie; struct wpabuf *probe_resp_ie; probe_resp_ie = p2p_group_build_probe_resp_ie(group); if (probe_resp_ie == NULL) return; wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE", probe_resp_ie); if (group->beacon_update) { beacon_ie = p2p_group_build_beacon_ie(group); if (beacon_ie) group->beacon_update = 0; wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE", beacon_ie); } else beacon_ie = NULL; group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie); }
int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos, size_t len) { struct wpabuf *buf; u8 op, current, chan; u8 *ie_len; int res; /* * Assume 20 MHz channel for now. * TODO: Use the secondary channel and VHT channel width that will be * used after association. */ if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, ¤t, &chan) == NUM_HOSTAPD_MODES) return 0; /* * Need 3 bytes for EID, length, and current operating class, plus * 1 byte for every other supported operating class. */ buf = wpabuf_alloc(global_op_class_size + 3); if (!buf) return 0; wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES); /* Will set the length later, putting a placeholder */ ie_len = wpabuf_put(buf, 1); wpabuf_put_u8(buf, current); for (op = 0; global_op_class[op].op_class; op++) { if (wpas_op_class_supported(wpa_s, &global_op_class[op])) wpabuf_put_u8(buf, global_op_class[op].op_class); } *ie_len = wpabuf_len(buf) - 2; if (*ie_len < 2 || wpabuf_len(buf) > len) { wpa_printf(MSG_ERROR, "Failed to add supported operating classes IE"); res = 0; } else { os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf)); res = wpabuf_len(buf); wpa_hexdump_buf(MSG_DEBUG, "MBO: Added supported operating classes IE", buf); } wpabuf_free(buf); return res; }
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *pubkey; wpa_printf(MSG_DEBUG, "WPS: * Public Key"); wpabuf_free(wps->dh_privkey); if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) { wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys"); wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey); wps->dh_ctx = wps->wps->dh_ctx; wps->wps->dh_ctx = NULL; pubkey = wpabuf_dup(wps->wps->dh_pubkey); #ifdef CONFIG_WPS_NFC } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap && wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) { wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys"); wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey); pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey); wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey); #endif /* CONFIG_WPS_NFC */ } else { wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); wps->dh_privkey = NULL; dh5_free(wps->dh_ctx); wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey); pubkey = wpabuf_zeropad(pubkey, 192); } if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " "Diffie-Hellman handshake"); wpabuf_free(pubkey); return -1; } wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey); wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); wpabuf_put_be16(msg, wpabuf_len(pubkey)); wpabuf_put_buf(msg, pubkey); if (wps->registrar) { wpabuf_free(wps->dh_pubkey_r); wps->dh_pubkey_r = pubkey; } else { wpabuf_free(wps->dh_pubkey_e); wps->dh_pubkey_e = pubkey; } return 0; }
int upnp_er_set_selected_registrar(struct wps_registrar *reg, struct subscription *s, const struct wpabuf *msg) { struct wps_parse_attr attr; wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes", msg); if (wps_validate_upnp_set_selected_registrar(msg) < 0) return -1; if (wps_parse_msg(msg, &attr) < 0) return -1; s->reg = reg; eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL); os_memset(s->authorized_macs, 0, sizeof(s->authorized_macs)); if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) { wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable " "Selected Registrar"); s->selected_registrar = 0; } else { s->selected_registrar = 1; s->dev_password_id = attr.dev_password_id ? WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT; s->config_methods = attr.sel_reg_config_methods ? WPA_GET_BE16(attr.sel_reg_config_methods) : -1; if (attr.authorized_macs) { int count = attr.authorized_macs_len / ETH_ALEN; if (count > WPS_MAX_AUTHORIZED_MACS) count = WPS_MAX_AUTHORIZED_MACS; os_memcpy(s->authorized_macs, attr.authorized_macs, count * ETH_ALEN); } else if (!attr.version2) { #ifdef CONFIG_WPS2 wpa_printf(MSG_DEBUG, "WPS: Add broadcast " "AuthorizedMACs for WPS 1.0 ER"); os_memset(s->authorized_macs, 0xff, ETH_ALEN); #endif /* CONFIG_WPS2 */ } eloop_register_timeout(WPS_PBC_WALK_TIME, 0, upnp_er_set_selected_timeout, s, NULL); } wps_registrar_selected_registrar_changed(reg); return 0; }
static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) { struct wpabuf *msg; msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); if (msg == NULL) return NULL; if (data->last_msg == LAST_MSG_SA_AUTH) { /* HDR, SK{N} */ struct wpabuf *plain = wpabuf_alloc(100); if (plain == NULL) { wpabuf_free(msg); return NULL; } ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); if (ikev2_build_notification(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 0, msg, plain, IKEV2_PAYLOAD_NOTIFICATION)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); data->state = IKEV2_FAILED; } else { /* HDR, N */ ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_NOTIFICATION, 0); if (ikev2_build_notification(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { wpabuf_free(msg); return NULL; } data->state = SA_INIT; } ikev2_update_hdr(msg); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", msg); return msg; }
static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd, const struct wpabuf *wps) { struct wps_parse_attr attr; wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); if (wps_parse_msg(wps, &attr)) { wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); return -1; } if (attr.oob_dev_password) return hostapd_wps_add_nfc_password_token(hapd, &attr); wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); return -1; }
/** * dh_init - Initialize Diffie-Hellman handshake * @dh: Selected Diffie-Hellman group * @priv: Pointer for returning Diffie-Hellman private key * Returns: Diffie-Hellman public value */ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv) { struct wpabuf *pv; size_t pv_len; if (dh == NULL) return NULL; wpabuf_free(*priv); *priv = wpabuf_alloc(dh->prime_len); if (*priv == NULL) return NULL; if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) { wpabuf_free(*priv); *priv = NULL; return NULL; } if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { /* Make sure private value is smaller than prime */ *(wpabuf_mhead_u8(*priv)) = 0; } wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); pv_len = dh->prime_len; pv = wpabuf_alloc(pv_len); if (pv == NULL) return NULL; if (crypto_mod_exp(dh->generator, dh->generator_len, wpabuf_head(*priv), wpabuf_len(*priv), dh->prime, dh->prime_len, wpabuf_mhead(pv), &pv_len) < 0) { wpabuf_free(pv); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; } wpabuf_put(pv, pv_len); wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); return pv; }
/** * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) * @data: IEs from the message * @len: Length of data buffer in octets * @msg: Buffer for returning parsed attributes * Returns: 0 on success, -1 on failure * * Note: Caller is responsible for clearing the msg data structure before * calling this function. * * Note: Caller must free temporary memory allocations by calling * p2p_parse_free() when the parsed data is not needed anymore. */ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) { struct ieee802_11_elems elems; ieee802_11_parse_elems(data, len, &elems, 0); if (elems.ds_params) msg->ds_params = elems.ds_params; if (elems.ssid) msg->ssid = elems.ssid - 2; msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, WPS_DEV_OUI_WFA); if (msg->wps_attributes && p2p_parse_wps_ie(msg->wps_attributes, msg)) { p2p_parse_free(msg); return -1; } msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, P2P_IE_VENDOR_TYPE); if (msg->p2p_attributes && p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); if (msg->p2p_attributes) wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", msg->p2p_attributes); p2p_parse_free(msg); return -1; } #ifdef CONFIG_WIFI_DISPLAY if (elems.wfd) { msg->wfd_subelems = ieee802_11_vendor_ie_concat( data, len, WFD_IE_VENDOR_TYPE); } #endif /* CONFIG_WIFI_DISPLAY */ msg->pref_freq_list = elems.pref_freq_list; msg->pref_freq_list_len = elems.pref_freq_list_len; return 0; }
static int eap_fast_encrypt_response(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *resp, u8 identifier, struct wpabuf **out_data) { if (resp == NULL) return 0; wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data", resp); if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, data->fast_version, identifier, resp, out_data)) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 " "frame"); } wpabuf_free(resp); return 0; }
static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr, struct wpabuf *msg) { struct wps_parse_attr attr; struct wps_er_sta *sta; wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR, MAC2STR(addr)); wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " "(TLVs from EAP-WSC)", msg); if (wps_parse_msg(msg, &attr) < 0) { wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " "WLANEvent message"); return; } sta = wps_er_add_sta_data(ap, addr, &attr, 0); if (sta == NULL) return; if (attr.msg_type && *attr.msg_type == WPS_M1) wps_er_sta_start(sta, msg); else if (sta->wps) { enum wsc_op_code op_code = WSC_MSG; if (attr.msg_type) { switch (*attr.msg_type) { case WPS_WSC_ACK: op_code = WSC_ACK; break; case WPS_WSC_NACK: op_code = WSC_NACK; break; case WPS_WSC_DONE: op_code = WSC_Done; break; } } wps_er_sta_process(sta, msg, op_code); } }
int upnp_er_set_selected_registrar(struct wps_registrar *reg, struct subscription *s, const struct wpabuf *msg) { struct wps_parse_attr attr; wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes", msg); if (wps_parse_msg(msg, &attr) < 0) return -1; if (!wps_version_supported(attr.version)) { wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar " "version 0x%x", attr.version ? *attr.version : 0); return -1; } s->reg = reg; eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL); if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) { wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable " "Selected Registrar"); s->selected_registrar = 0; } else { s->selected_registrar = 1; s->dev_password_id = attr.dev_password_id ? WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT; s->config_methods = attr.sel_reg_config_methods ? WPA_GET_BE16(attr.sel_reg_config_methods) : -1; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, upnp_er_set_selected_timeout, s, NULL); } wps_registrar_selected_registrar_changed(reg); return 0; }
int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey) { struct wpabuf *priv = NULL, *pub = NULL; void *dh_ctx; dh_ctx = dh5_init(&priv, &pub); if (dh_ctx == NULL) return -1; pub = wpabuf_zeropad(pub, 192); if (pub == NULL) { wpabuf_free(priv); return -1; } wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub); dh5_free(dh_ctx); wpabuf_free(*pubkey); *pubkey = pub; wpabuf_free(*privkey); *privkey = priv; return 0; }
static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data) { struct wpabuf *msg; /* build IKE_SA_INIT: HDR, SAi, KEi, Ni */ if (os_get_random(data->i_spi, IKEV2_SPI_LEN)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", data->i_spi, IKEV2_SPI_LEN); data->i_nonce_len = IKEV2_NONCE_MIN_LEN; if (os_get_random(data->i_nonce, data->i_nonce_len)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len); msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) || ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { wpabuf_free(msg); return NULL; } ikev2_update_hdr(msg); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); wpabuf_free(data->i_sign_msg); data->i_sign_msg = wpabuf_dup(msg); return msg; }
static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, const struct eap_hdr *req, const struct wpabuf *in_data, struct wpabuf **out_data) { struct wpabuf *in_decrypted = NULL; int res, skip_change = 0; struct eap_hdr *hdr, *rhdr; struct wpabuf *resp = NULL; size_t len; wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" " Phase 2", (unsigned long) wpabuf_len(in_data)); if (data->pending_phase2_req) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " "skip decryption and use old data"); /* Clear TLS reassembly state. */ eap_peer_tls_reset_input(&data->ssl); in_decrypted = data->pending_phase2_req; data->pending_phase2_req = NULL; skip_change = 1; goto continue_req; } if (wpabuf_len(in_data) == 0 && sm->workaround && data->phase2_success) { /* * Cisco ACS seems to be using TLS ACK to terminate * EAP-PEAPv0/GTC. Try to reply with TLS ACK. */ wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " "expected data - acknowledge with TLS ACK since " "Phase 2 has been completed"); ret->decision = DECISION_COND_SUCC; ret->methodState = METHOD_DONE; return 1; } else if (wpabuf_len(in_data) == 0) { /* Received TLS ACK - requesting more fragments */ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, data->peap_version, req->identifier, NULL, out_data); } res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); if (res) return res; continue_req: wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); hdr = wpabuf_mhead(in_decrypted); if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && be_to_host16(hdr->length) == 5 && eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { /* At least FreeRADIUS seems to send full EAP header with * EAP Request Identity */ skip_change = 1; } if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && eap_get_type(in_decrypted) == EAP_TYPE_TLV) { skip_change = 1; } if (data->peap_version == 0 && !skip_change) { struct eap_hdr *nhdr; struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + wpabuf_len(in_decrypted)); if (nmsg == NULL) { wpabuf_free(in_decrypted); return 0; } nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); wpabuf_put_buf(nmsg, in_decrypted); nhdr->code = req->code; nhdr->identifier = req->identifier; nhdr->length = host_to_be16(sizeof(struct eap_hdr) + wpabuf_len(in_decrypted)); wpabuf_free(in_decrypted); in_decrypted = nmsg; } if (data->peap_version >= 2) { struct eap_tlv_hdr *tlv; struct wpabuf *nmsg; if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " "EAP TLV"); wpabuf_free(in_decrypted); return 0; } tlv = wpabuf_mhead(in_decrypted); if ((be_to_host16(tlv->tlv_type) & 0x3fff) != EAP_TLV_EAP_PAYLOAD_TLV) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); wpabuf_free(in_decrypted); return 0; } if (sizeof(*tlv) + be_to_host16(tlv->length) > wpabuf_len(in_decrypted)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " "length"); wpabuf_free(in_decrypted); return 0; } hdr = (struct eap_hdr *) (tlv + 1); if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " "EAP packet in EAP TLV"); wpabuf_free(in_decrypted); return 0; } nmsg = wpabuf_alloc(be_to_host16(hdr->length)); if (nmsg == NULL) { wpabuf_free(in_decrypted); return 0; } wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); wpabuf_free(in_decrypted); in_decrypted = nmsg; } hdr = wpabuf_mhead(in_decrypted); if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " "EAP frame (len=%lu)", (unsigned long) wpabuf_len(in_decrypted)); wpabuf_free(in_decrypted); return 0; } len = be_to_host16(hdr->length); if (len > wpabuf_len(in_decrypted)) { wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " "Phase 2 EAP frame (len=%lu hdr->length=%lu)", (unsigned long) wpabuf_len(in_decrypted), (unsigned long) len); wpabuf_free(in_decrypted); return 0; } if (len < wpabuf_len(in_decrypted)) { wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " "shorter length than full decrypted data " "(%lu < %lu)", (unsigned long) len, (unsigned long) wpabuf_len(in_decrypted)); } wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " "identifier=%d length=%lu", hdr->code, hdr->identifier, (unsigned long) len); switch (hdr->code) { case EAP_CODE_REQUEST: if (eap_peap_phase2_request(sm, data, ret, in_decrypted, &resp)) { wpabuf_free(in_decrypted); wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " "processing failed"); return 0; } break; case EAP_CODE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); if (data->peap_version == 1) { /* EAP-Success within TLS tunnel is used to indicate * shutdown of the TLS channel. The authentication has * been completed. */ if (data->phase2_eap_started && !data->phase2_eap_success) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " "Success used to indicate success, " "but Phase 2 EAP was not yet " "completed successfully"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; wpabuf_free(in_decrypted); return 0; } wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " "EAP-Success within TLS tunnel - " "authentication completed"); ret->decision = DECISION_UNCOND_SUCC; ret->methodState = METHOD_DONE; data->phase2_success = 1; if (data->peap_outer_success == 2) { wpabuf_free(in_decrypted); wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " "to finish authentication"); return 1; } else if (data->peap_outer_success == 1) { /* Reply with EAP-Success within the TLS * channel to complete the authentication. */ resp = wpabuf_alloc(sizeof(struct eap_hdr)); if (resp) { rhdr = wpabuf_put(resp, sizeof(*rhdr)); rhdr->code = EAP_CODE_SUCCESS; rhdr->identifier = hdr->identifier; rhdr->length = host_to_be16(sizeof(*rhdr)); } } else { /* No EAP-Success expected for Phase 1 (outer, * unencrypted auth), so force EAP state * machine to SUCCESS state. */ sm->peap_done = TRUE; } } else { /* FIX: ? */ } break; case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); ret->decision = DECISION_FAIL; ret->methodState = METHOD_MAY_CONT; ret->allowNotifications = FALSE; /* Reply with EAP-Failure within the TLS channel to complete * failure reporting. */ resp = wpabuf_alloc(sizeof(struct eap_hdr)); if (resp) { rhdr = wpabuf_put(resp, sizeof(*rhdr)); rhdr->code = EAP_CODE_FAILURE; rhdr->identifier = hdr->identifier; rhdr->length = host_to_be16(sizeof(*rhdr)); } break; default: wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); break; } wpabuf_free(in_decrypted); if (resp) { int skip_change2 = 0; struct wpabuf *rmsg, buf; wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", resp); /* PEAP version changes */ if (data->peap_version >= 2) { resp = eap_peapv2_tlv_eap_payload(resp); if (resp == NULL) return -1; } if (wpabuf_len(resp) >= 5 && wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && eap_get_type(resp) == EAP_TYPE_TLV) skip_change2 = 1; rmsg = resp; if (data->peap_version == 0 && !skip_change2) { wpabuf_set(&buf, wpabuf_head_u8(resp) + sizeof(struct eap_hdr), wpabuf_len(resp) - sizeof(struct eap_hdr)); rmsg = &buf; } if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, data->peap_version, req->identifier, rmsg, out_data)) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " "a Phase 2 frame"); } wpabuf_free(resp); } return 0; }
static int gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa, const u8 *bssid, int freq, u8 dialog_token, const u8 *data, size_t len) { const u8 *pos, *end, *adv_proto, *query_req; u8 adv_proto_len; u16 query_req_len; struct gas_server_handler *handler; struct wpabuf *resp; wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame", data, len); pos = data; end = data + len; if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) { wpa_printf(MSG_DEBUG, "GAS: No Advertisement Protocol element found"); return -1; } pos++; adv_proto_len = *pos++; if (end - pos < adv_proto_len || adv_proto_len < 2) { wpa_printf(MSG_DEBUG, "GAS: Truncated Advertisement Protocol element"); return -1; } adv_proto = pos; pos += adv_proto_len; wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element", adv_proto, adv_proto_len); if (end - pos < 2) { wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field"); return -1; } query_req_len = WPA_GET_LE16(pos); pos += 2; if (end - pos < query_req_len) { wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field"); return -1; } query_req = pos; pos += query_req_len; wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request", query_req, query_req_len); if (pos < end) { wpa_hexdump(MSG_MSGDUMP, "GAS: Ignored extra data after Query Request field", pos, end - pos); } dl_list_for_each(handler, &gas->handlers, struct gas_server_handler, list) { if (adv_proto_len < 1 + handler->adv_proto_id_len || os_memcmp(adv_proto + 1, handler->adv_proto_id, handler->adv_proto_id_len) != 0) continue; wpa_printf(MSG_DEBUG, "GAS: Calling handler for the requested Advertisement Protocol ID"); resp = handler->req_cb(handler->ctx, sa, query_req, query_req_len); wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler", resp); gas_server_send_resp(gas, handler, sa, freq, dialog_token, resp); return 0; } wpa_printf(MSG_DEBUG, "GAS: No registered handler for the requested Advertisement Protocol ID"); return -1; }