int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) { u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN]; wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password"); if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) { wpa_printf(MSG_ERROR, "WPS: device password id " "generation error"); return -1; } wps->oob_dev_pw_id |= 0x0010; if (random_get_bytes(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) { wpa_printf(MSG_ERROR, "WPS: OOB device password " "generation error"); return -1; } wpa_snprintf_hex_uppercase( wpabuf_put(wps->oob_conf.dev_password, wpabuf_size(wps->oob_conf.dev_password)), wpabuf_size(wps->oob_conf.dev_password), dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); return wps_build_oob_dev_pw(msg, wps->oob_dev_pw_id, wps->dh_pubkey, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); }
int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, size_t noa_len) { if (noa == NULL) { wpabuf_free(group->noa); group->noa = NULL; } else { if (group->noa) { if (wpabuf_size(group->noa) >= noa_len) { group->noa->used = 0; wpabuf_put_data(group->noa, noa, noa_len); } else { wpabuf_free(group->noa); group->noa = NULL; } } if (!group->noa) { group->noa = wpabuf_alloc_copy(noa, noa_len); if (group->noa == NULL) return -1; } } group->beacon_update = 1; p2p_group_update_ies(group); return 0; }
static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) { int res; struct wpabuf *ad; wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); if (ad == NULL) return NULL; res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), wpabuf_size(ad)); wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(ad); return NULL; } wpabuf_put(ad, res); wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", res); return ad; }
static int fst_session_send_action(struct fst_session *s, Boolean old_iface, const void *payload, size_t size, const struct wpabuf *extra_buf) { size_t len; int res; struct wpabuf *buf; u8 action; struct fst_iface *iface = old_iface ? s->data.old_iface : s->data.new_iface; WPA_ASSERT(payload != NULL); WPA_ASSERT(size != 0); action = *(const u8 *) payload; WPA_ASSERT(action <= FST_ACTION_MAX_SUPPORTED); if (!iface) { fst_printf_session(s, MSG_ERROR, "no %s interface for FST Action '%s' sending", old_iface ? "old" : "new", fst_action_names[action]); return -1; } len = sizeof(u8) /* category */ + size; if (extra_buf) len += wpabuf_size(extra_buf); buf = wpabuf_alloc(len); if (!buf) { fst_printf_session(s, MSG_ERROR, "cannot allocate buffer of %zu bytes for FST Action '%s' sending", len, fst_action_names[action]); return -1; } wpabuf_put_u8(buf, WLAN_ACTION_FST); wpabuf_put_data(buf, payload, size); if (extra_buf) wpabuf_put_buf(buf, extra_buf); res = fst_iface_send_action(iface, old_iface ? s->data.old_peer_addr : s->data.new_peer_addr, buf); if (res < 0) fst_printf_siface(s, iface, MSG_ERROR, "failed to send FST Action '%s'", fst_action_names[action]); else fst_printf_siface(s, iface, MSG_DEBUG, "FST Action '%s' sent", fst_action_names[action]); wpabuf_free(buf); return res; }
struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { struct wpabuf *buf; int res; buf = wpabuf_alloc(wpabuf_len(in_data) + 300); if (buf == NULL) return NULL; res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { struct wpabuf *buf; int res; buf = wpabuf_alloc(wpabuf_len(in_data) + 300); if (buf == NULL) return NULL; res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; }
static int wps_parse_oob_dev_pwd(struct wps_context *wps, struct wpabuf *data) { struct oob_conf_data *oob_conf = &wps->oob_conf; struct wps_parse_attr attr; const u8 *pos; if (wps_parse_msg(data, &attr) < 0 || attr.oob_dev_password == NULL) { wpa_printf(MSG_ERROR, "WPS: OOB device password not found"); return -1; } pos = attr.oob_dev_password; oob_conf->pubkey_hash = wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN); if (oob_conf->pubkey_hash == NULL) { wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " "public key hash"); return -1; } pos += WPS_OOB_PUBKEY_HASH_LEN; wps->oob_dev_pw_id = WPA_GET_BE16(pos); pos += sizeof(wps->oob_dev_pw_id); oob_conf->dev_password = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); if (oob_conf->dev_password == NULL) { wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " "device password"); return -1; } wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password, wpabuf_size(oob_conf->dev_password)), wpabuf_size(oob_conf->dev_password), pos, WPS_OOB_DEVICE_PASSWORD_LEN); return 0; }
int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) { size_t hash_len; const u8 *addr[1]; u8 pubkey_hash[WPS_HASH_LEN]; u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN]; wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password"); addr[0] = wpabuf_head(wps->dh_pubkey); hash_len = wpabuf_len(wps->dh_pubkey); sha256_vector(1, addr, &hash_len, pubkey_hash); if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) { wpa_printf(MSG_ERROR, "WPS: device password id " "generation error"); return -1; } wps->oob_dev_pw_id |= 0x0010; if (random_get_bytes(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) { wpa_printf(MSG_ERROR, "WPS: OOB device password " "generation error"); return -1; } wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); wpabuf_put_be16(msg, wps->oob_dev_pw_id); wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); wpa_snprintf_hex_uppercase( wpabuf_put(wps->oob_conf.dev_password, wpabuf_size(wps->oob_conf.dev_password)), wpabuf_size(wps->oob_conf.dev_password), dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); return 0; }
struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { PRInt32 res; struct wpabuf *out; wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", (int) wpabuf_len(in_data)); if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) return NULL; os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = wpabuf_len(in_data); /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (out == NULL) return NULL; res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); if (res < 0) { wpabuf_free(out); return NULL; } wpabuf_put(out, res); return out; }
struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { ssize_t res; struct wpabuf *out; if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) wpabuf_len(conn->pull_buf)); wpabuf_free(conn->pull_buf); } conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) return NULL; conn->pull_buf_offset = wpabuf_head(conn->pull_buf); /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (out == NULL) return NULL; res = gnutls_record_recv(conn->session, wpabuf_mhead(out), wpabuf_size(out)); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(out); return NULL; } wpabuf_put(out, res); return out; }
static struct wpabuf * eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_pwd_data *data = priv; struct wpabuf *resp = NULL; const u8 *pos, *buf; size_t len; u16 tot_len = 0; u8 lm_exch; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); if ((pos == NULL) || (len < 1)) { wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " "len is %d", pos == NULL ? "NULL" : "not NULL", (int) len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = FALSE; lm_exch = *pos; pos++; /* skip over the bits and the exch */ len--; /* * we're fragmenting so send out the next fragment */ if (data->out_frag_pos) { /* * this should be an ACK */ if (len) wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " "not an ACK"); wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); /* * check if there are going to be more fragments */ len = wpabuf_len(data->outbuf) - data->out_frag_pos; if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { len = data->mtu - EAP_PWD_HDR_SIZE; EAP_PWD_SET_MORE_BIT(lm_exch); } resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE + len, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) { wpa_printf(MSG_INFO, "Unable to allocate memory for " "next fragment!"); return NULL; } wpabuf_put_u8(resp, lm_exch); buf = wpabuf_head_u8(data->outbuf); wpabuf_put_data(resp, buf + data->out_frag_pos, len); data->out_frag_pos += len; /* * this is the last fragment so get rid of the out buffer */ if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { wpabuf_free(data->outbuf); data->outbuf = NULL; data->out_frag_pos = 0; } wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", data->out_frag_pos == 0 ? "last" : "next", (int) len); return resp; } /* * see if this is a fragment that needs buffering * * if it's the first fragment there'll be a length field */ if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { tot_len = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " "total length = %d", tot_len); data->inbuf = wpabuf_alloc(tot_len); if (data->inbuf == NULL) { wpa_printf(MSG_INFO, "Out of memory to buffer " "fragments!"); return NULL; } pos += sizeof(u16); len -= sizeof(u16); } /* * buffer and ACK the fragment */ if (EAP_PWD_GET_MORE_BIT(lm_exch)) { data->in_frag_pos += len; if (data->in_frag_pos > wpabuf_size(data->inbuf)) { wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " "detected (%d vs. %d)!", (int) data->in_frag_pos, (int) wpabuf_len(data->inbuf)); wpabuf_free(data->inbuf); data->in_frag_pos = 0; return NULL; } wpabuf_put_data(data->inbuf, pos, len); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp != NULL) wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", (int) len); return resp; } /* * we're buffering and this is the last fragment */ if (data->in_frag_pos) { wpabuf_put_data(data->inbuf, pos, len); wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", (int) len); data->in_frag_pos += len; pos = wpabuf_head_u8(data->inbuf); len = data->in_frag_pos; } wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { case EAP_PWD_OPCODE_ID_EXCH: eap_pwd_perform_id_exchange(sm, data, ret, reqData, pos, len); break; case EAP_PWD_OPCODE_COMMIT_EXCH: eap_pwd_perform_commit_exchange(sm, data, ret, reqData, pos, len); break; case EAP_PWD_OPCODE_CONFIRM_EXCH: eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, pos, len); break; default: wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " "opcode %d", lm_exch); break; } /* * if we buffered the just processed input now's the time to free it */ if (data->in_frag_pos) { wpabuf_free(data->inbuf); data->in_frag_pos = 0; } if (data->outbuf == NULL) return NULL; /* generic failure */ /* * we have output! Do we need to fragment it? */ len = wpabuf_len(data->outbuf); if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, EAP_CODE_RESPONSE, eap_get_id(reqData)); /* * if so it's the first so include a length field */ EAP_PWD_SET_LENGTH_BIT(lm_exch); EAP_PWD_SET_MORE_BIT(lm_exch); tot_len = len; /* * keep the packet at the MTU */ len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " "length = %d", tot_len); } else { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE + len, EAP_CODE_RESPONSE, eap_get_id(reqData)); } if (resp == NULL) return NULL; wpabuf_put_u8(resp, lm_exch); if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { wpabuf_put_be16(resp, tot_len); data->out_frag_pos += len; } buf = wpabuf_head_u8(data->outbuf); wpabuf_put_data(resp, buf, len); /* * if we're not fragmenting then there's no need to carry this around */ if (data->out_frag_pos == 0) { wpabuf_free(data->outbuf); data->outbuf = NULL; data->out_frag_pos = 0; } return resp; }
static void eap_pwd_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_pwd_data *data = priv; const u8 *pos; size_t len; u8 lm_exch; u16 tot_len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); if ((pos == NULL) || (len < 1)) { wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d", (pos == NULL) ? "is NULL" : "is not NULL", (int) len); return; } lm_exch = *pos; pos++; /* skip over the bits and the exch */ len--; /* * if we're fragmenting then this should be an ACK with no data, * just return and continue fragmenting in the "build" section above */ if (data->out_frag_pos) { if (len > 1) wpa_printf(MSG_INFO, "EAP-pwd: Bad response! " "Fragmenting but not an ACK"); else wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from " "peer"); return; } /* * if we're receiving fragmented packets then we need to buffer... * * the first fragment has a total length */ if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { tot_len = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total " "length = %d", tot_len); if (tot_len > 15000) return; data->inbuf = wpabuf_alloc(tot_len); if (data->inbuf == NULL) { wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to " "buffer fragments!"); return; } pos += sizeof(u16); len -= sizeof(u16); } /* * the first and all intermediate fragments have the M bit set */ if (EAP_PWD_GET_MORE_BIT(lm_exch)) { if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) { wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow " "attack detected! (%d+%d > %d)", (int) data->in_frag_pos, (int) len, (int) wpabuf_size(data->inbuf)); eap_pwd_state(data, FAILURE); return; } wpabuf_put_data(data->inbuf, pos, len); data->in_frag_pos += len; wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment", (int) len); return; } /* * last fragment won't have the M bit set (but we're obviously * buffering fragments so that's how we know it's the last) */ if (data->in_frag_pos) { wpabuf_put_data(data->inbuf, pos, len); data->in_frag_pos += len; pos = wpabuf_head_u8(data->inbuf); len = data->in_frag_pos; wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", (int) len); } switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { case EAP_PWD_OPCODE_ID_EXCH: eap_pwd_process_id_resp(sm, data, pos, len); break; case EAP_PWD_OPCODE_COMMIT_EXCH: eap_pwd_process_commit_resp(sm, data, pos, len); break; case EAP_PWD_OPCODE_CONFIRM_EXCH: eap_pwd_process_confirm_resp(sm, data, pos, len); break; } /* * if we had been buffering fragments, here's a great place * to clean up */ if (data->in_frag_pos) { wpabuf_free(data->inbuf); data->inbuf = NULL; data->in_frag_pos = 0; } }