Exemplo n.º 1
0
struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
				   const u8 *extra, size_t extra_len)
{
	struct eap_hdr *eap;
	struct wpabuf *buf;

	if (msg == NULL)
		return NULL;

	eap = wpabuf_mhead(msg->buf);
	eap->length = host_to_be16(wpabuf_len(msg->buf));

#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
	if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
				       wpabuf_len(msg->buf),
				       (u8 *) wpabuf_mhead(msg->buf) +
				       msg->mac, extra, extra_len);
	} else
#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
	if (k_aut && msg->mac) {
		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
				wpabuf_len(msg->buf),
				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
				extra, extra_len);
	}

	buf = msg->buf;
	os_free(msg);
	return buf;
}
Exemplo n.º 2
0
/**
 * dh_derive_shared - Derive shared Diffie-Hellman key
 * @peer_public: Diffie-Hellman public value from peer
 * @own_private: Diffie-Hellman private key from dh_init()
 * @dh: Selected Diffie-Hellman group
 * Returns: Diffie-Hellman shared key
 */
struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
				 const struct wpabuf *own_private,
				 const struct dh_group *dh)
{
	struct wpabuf *shared;
	size_t shared_len;

	if (dh == NULL || peer_public == NULL || own_private == NULL)
		return NULL;

	shared_len = dh->prime_len;
	shared = wpabuf_alloc(shared_len);
	if (shared == NULL)
		return NULL;
	if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
			   wpabuf_head(own_private), wpabuf_len(own_private),
			   dh->prime, dh->prime_len,
			   wpabuf_mhead(shared), &shared_len) < 0) {
		wpabuf_free(shared);
		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
		return NULL;
	}
	wpabuf_put(shared, shared_len);
	wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);

	return shared;
}
Exemplo n.º 3
0
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, wpabuf_mhead(plain),
				      wpabuf_len(plain));
	wpabuf_free(plain);

	if (data->ssl.out_buf && 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.out_buf),
			   (int) data->ssl.out_used);
		if (wpabuf_resize(&data->ssl.out_buf, 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.out_buf, encr);
		wpabuf_free(encr);
	} else {
		wpabuf_free(data->ssl.out_buf);
		data->ssl.out_used = 0;
		data->ssl.out_buf = encr;
	}

	return 0;
}
Exemplo n.º 4
0
struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
{
	return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
				 FLAG_TNF_RFC2046, wifi_handover_type,
				 os_strlen(wifi_handover_type), NULL, 0,
				 wpabuf_mhead(buf), wpabuf_len(buf));
}
Exemplo n.º 5
0
static struct wpabuf * read_ufd(void *priv)
{
	struct wps_ufd_data *data = priv;
	struct wpabuf *buf;
	struct stat s;
	size_t file_size;

	if (fstat(data->ufd_fd, &s) < 0) {
		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
		return NULL;
	}

	file_size = s.st_size;
	buf = wpabuf_alloc(file_size);
	if (buf == NULL) {
		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
			   "buffer");
		return NULL;
	}

	if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
	    (int) file_size) {
		wpabuf_free(buf);
		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
		return NULL;
	}
	wpabuf_put(buf, file_size);
	return buf;
}
Exemplo n.º 6
0
void wpabuf_clear_free(struct wpabuf *buf)
{
	if (buf) {
		os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
		wpabuf_free(buf);
	}
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
void eap_update_len(struct wpabuf *msg)
{
	struct eap_hdr *hdr;
	hdr = wpabuf_mhead(msg);
	if (wpabuf_len(msg) < sizeof(*hdr))
		return;
	hdr->length = host_to_be16(wpabuf_len(msg));
}
Exemplo n.º 10
0
void ikev2_update_hdr(struct wpabuf *msg)
{
	struct ikev2_hdr *hdr;

	/* Update lenth field in HDR */
	hdr = wpabuf_mhead(msg);
	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
static int write_ufd(void *priv, struct wpabuf *buf)
{
	struct wps_ufd_data *data = priv;

	if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
	    (int) wpabuf_len(buf)) {
		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
		return -1;
	}
	return 0;
}
Exemplo n.º 14
0
void ext_password_free(struct wpabuf *pw)
{
	if (pw == NULL) {
		return;
	}
	os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
#ifdef __linux__
	if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
		wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s", strerror(errno));
	}
#endif							/* __linux__ */
	wpabuf_free(pw);
}
Exemplo n.º 15
0
struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
				   const u8 *extra, size_t extra_len)
{
	struct eap_hdr *eap;
	struct wpabuf *buf;

	if (msg == NULL)
		return NULL;

	eap = wpabuf_mhead(msg->buf);
	eap->length = host_to_be16(wpabuf_len(msg->buf));

	if (k_aut && msg->mac) {
		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
				wpabuf_len(msg->buf),
				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
				extra, extra_len);
	}

	buf = msg->buf;
	os_free(msg);
	return buf;
}
Exemplo n.º 16
0
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
					  size_t encr_len)
{
	struct wpabuf *decrypted;
	const size_t block_size = 16;
	size_t i;
	u8 pad;
	const u8 *pos;

	/* AES-128-CBC */
	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
	{
		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
		return NULL;
	}

	decrypted = wpabuf_alloc(encr_len - block_size);
	if (decrypted == NULL)
		return NULL;

	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
				wpabuf_len(decrypted))) {
		wpabuf_free(decrypted);
		return NULL;
	}

	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
			    decrypted);

	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
	pad = *pos;
	if (pad > wpabuf_len(decrypted)) {
		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
		wpabuf_free(decrypted);
		return NULL;
	}
	for (i = 0; i < pad; i++) {
		if (*pos-- != pad) {
			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
				   "string");
			wpabuf_free(decrypted);
			return NULL;
		}
	}
	decrypted->used -= pad;

	return decrypted;
}
Exemplo n.º 17
0
static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
				    struct eap_fast_tlv_parse *tlv,
				    struct wpabuf **resp)
{
	int mandatory, tlv_type, res;
	size_t len;
	u8 *pos, *end;

	os_memset(tlv, 0, sizeof(*tlv));

	/* Parse TLVs from the decrypted Phase 2 data */
	pos = wpabuf_mhead(decrypted);
	end = pos + wpabuf_len(decrypted);
	while (end - pos > 4) {
		mandatory = pos[0] & 0x80;
		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
		pos += 2;
		len = WPA_GET_BE16(pos);
		pos += 2;
		if (len > (size_t) (end - pos)) {
			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
			return -1;
		}
		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
			   "TLV type %d length %u%s",
			   tlv_type, (unsigned int) len,
			   mandatory ? " (mandatory)" : "");

		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
		if (res == -2)
			break;
		if (res < 0) {
			if (mandatory) {
				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
					   "mandatory TLV type %d", tlv_type);
				*resp = eap_fast_tlv_nak(0, tlv_type);
				break;
			} else {
				wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
					   "unknown optional TLV type %d",
					   tlv_type);
			}
		}

		pos += len;
	}

	return 0;
}
Exemplo n.º 18
0
static int write_nfc(void *priv, struct wpabuf *buf)
{
	struct wps_nfc_data *data = priv;
	struct wpabuf *wifi;
	int ret;

	wifi = ndef_build_wifi(buf);
	if (wifi == NULL) {
		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to wrap");
		return -1;
	}

	ret = data->oob_nfc_dev->write_func(wpabuf_mhead(wifi),
					    wpabuf_len(wifi));
	wpabuf_free(wifi);
	return ret;
}
Exemplo n.º 19
0
static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
					   struct eap_pax_data *data, u8 id)
{
	struct wpabuf *req;
	struct eap_pax_hdr *pax;
	u8 *pos;

	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");

	if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) {
		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
		data->state = FAILURE;
		return NULL;
	}

	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
			    sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
	if (req == NULL) {
		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
			   "request");
		data->state = FAILURE;
		return NULL;
	}

	pax = wpabuf_put(req, sizeof(*pax));
	pax->op_code = EAP_PAX_OP_STD_1;
	pax->flags = 0;
	pax->mac_id = data->mac_id;
	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;

	wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
	wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
		    data->rand.r.x, EAP_PAX_RAND_LEN);

	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
	eap_pax_mac(data->mac_id, (u8 *) "", 0,
		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
		    NULL, 0, NULL, 0, pos);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);

	return req;
}
Exemplo n.º 20
0
static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
					   struct eap_pax_data *data, u8 id)
{
	struct wpabuf *req;
	struct eap_pax_hdr *pax;
	u8 *pos;

	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");

	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
			    sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
	if (req == NULL) {
		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
			   "request");
		data->state = FAILURE;
		return NULL;
	}

	pax = wpabuf_put(req, sizeof(*pax));
	pax->op_code = EAP_PAX_OP_STD_3;
	pax->flags = 0;
	pax->mac_id = data->mac_id;
	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;

	wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
	eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
		    data->rand.r.y, EAP_PAX_RAND_LEN,
		    (u8 *) data->cid, data->cid_len, NULL, 0, pos);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
		    pos, EAP_PAX_MAC_LEN);
	pos += EAP_PAX_MAC_LEN;

	/* Optional ADE could be added here, if needed */

	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
		    NULL, 0, NULL, 0, pos);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);

	return req;
}
static int eap_fast_parse_tlvs(struct wpabuf *data,
			       struct eap_fast_tlv_parse *tlv)
{
	int mandatory, tlv_type, len, res;
	u8 *pos, *end;

	os_memset(tlv, 0, sizeof(*tlv));

	pos = wpabuf_mhead(data);
	end = pos + wpabuf_len(data);
	while (pos + 4 < end) {
		mandatory = pos[0] & 0x80;
		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
		pos += 2;
		len = WPA_GET_BE16(pos);
		pos += 2;
		if (pos + len > end) {
			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
			return -1;
		}
		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
			   "TLV type %d length %d%s",
			   tlv_type, len, mandatory ? " (mandatory)" : "");

		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
		if (res == -2)
			break;
		if (res < 0) {
			if (mandatory) {
				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
					   "mandatory TLV type %d", tlv_type);
				/* TODO: generate Nak TLV */
				break;
			} else {
				wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
					   "unknown optional TLV type %d",
					   tlv_type);
			}
		}

		pos += len;
	}

	return 0;
}
/**
 * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 * @data: Data for TLS processing
 * @in_data: Message received from the server
 * @in_decrypted: Buffer for returning a pointer to the decrypted message
 * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
 */
int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
			 const struct wpabuf *in_data,
			 struct wpabuf **in_decrypted)
{
	int res;
	const u8 *msg;
	size_t msg_len, buf_len;
	int need_more_input;

	msg = eap_peer_tls_data_reassemble(data, wpabuf_head(in_data),
					   wpabuf_len(in_data), &msg_len,
					   &need_more_input);
	if (msg == NULL)
		return need_more_input ? 1 : -1;

	buf_len = wpabuf_len(in_data);
	if (data->tls_in_total > buf_len)
		buf_len = data->tls_in_total;
	/*
	 * 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.
	 */
	buf_len += 500;
	buf_len *= 3;
	*in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1);
	if (*in_decrypted == NULL) {
		eap_peer_tls_reset_input(data);
		wpa_printf(MSG_WARNING, "SSL: Failed to allocate memory for "
			   "decryption");
		return -1;
	}

	res = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg, msg_len,
				     wpabuf_mhead(*in_decrypted), buf_len);
	eap_peer_tls_reset_input(data);
	if (res < 0) {
		wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
		return -1;
	}
	wpabuf_put(*in_decrypted, res);
	return 0;
}
Exemplo n.º 23
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;

	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;
}
Exemplo n.º 24
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;
}
static struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp,
						u32 avp_code, int mandatory)
{
	struct wpabuf *avp;
	u8 *pos;

	avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4);
	if (avp == NULL) {
		wpabuf_free(resp);
		return NULL;
	}

	pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory,
			       wpabuf_len(resp));
	os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp));
	pos += wpabuf_len(resp);
	AVP_PAD((const u8 *) wpabuf_head(avp), pos);
	wpabuf_free(resp);
	wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp));
	return avp;
}
Exemplo n.º 26
0
static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
					  int (*filter)(struct ndef_record *))
{
	struct ndef_record record;
	int len = wpabuf_len(buf);
	u8 *data = wpabuf_mhead(buf);

	while (len > 0) {
		if (ndef_parse_record(data, len, &record) < 0) {
			wpa_printf(MSG_ERROR, "NDEF : Failed to parse");
			return NULL;
		}
		if (filter == NULL || filter(&record))
			return wpabuf_alloc_copy(record.payload,
						 record.payload_length);
		data += record.total_length;
		len -= record.total_length;
	}
	wpa_printf(MSG_ERROR, "NDEF : Record not found");
	return NULL;
}
Exemplo n.º 27
0
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;
}
Exemplo n.º 28
0
static void wps_er_process_wlanevent(struct wps_er_ap *ap,
				     struct wpabuf *event)
{
	u8 *data;
	u8 wlan_event_type;
	u8 wlan_event_mac[ETH_ALEN];
	struct wpabuf msg;

	wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
		    wpabuf_head(event), wpabuf_len(event));
	if (wpabuf_len(event) < 1 + 17) {
		wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
		return;
	}

	data = wpabuf_mhead(event);
	wlan_event_type = data[0];
	if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
		wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
			   "WLANEvent");
		return;
	}

	wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));

	switch (wlan_event_type) {
	case 1:
		wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
		break;
	case 2:
		wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
		break;
	default:
		wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
			   wlan_event_type);
		break;
	}
}
Exemplo n.º 29
0
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;
}
Exemplo n.º 30
0
static int eap_peap_phase2_request(struct eap_sm *sm,
				   struct eap_peap_data *data,
				   struct eap_method_ret *ret,
				   struct wpabuf *req,
				   struct wpabuf **resp)
{
	struct eap_hdr *hdr = wpabuf_mhead(req);
	size_t len = be_to_host16(hdr->length);
	u8 *pos;
	struct eap_method_ret iret;
	struct eap_peer_config *config = eap_get_config(sm);

	if (len <= sizeof(struct eap_hdr)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
			   "Phase 2 request (len=%lu)", (unsigned long) len);
		return -1;
	}
	pos = (u8 *) (hdr + 1);
	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
	switch (*pos) {
	case EAP_TYPE_IDENTITY:
		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
		break;
	case EAP_TYPE_TLV:
		os_memset(&iret, 0, sizeof(iret));
		if (eap_tlv_process(sm, data, &iret, req, resp,
				    data->phase2_eap_started &&
				    !data->phase2_eap_success)) {
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		if (iret.methodState == METHOD_DONE ||
		    iret.methodState == METHOD_MAY_CONT) {
			ret->methodState = iret.methodState;
			ret->decision = iret.decision;
			data->phase2_success = 1;
		}
		break;
	case EAP_TYPE_EXPANDED:
#ifdef EAP_TNC
		if (data->soh) {
			const u8 *epos;
			size_t eleft;

			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
						req, &eleft);
			if (epos) {
				struct wpabuf *buf;
				wpa_printf(MSG_DEBUG,
					   "EAP-PEAP: SoH EAP Extensions");
				buf = tncc_process_soh_request(data->soh,
							       epos, eleft);
				if (buf) {
					*resp = eap_msg_alloc(
						EAP_VENDOR_MICROSOFT, 0x21,
						wpabuf_len(buf),
						EAP_CODE_RESPONSE,
						hdr->identifier);
					if (*resp == NULL) {
						ret->methodState = METHOD_DONE;
						ret->decision = DECISION_FAIL;
						return -1;
					}
					wpabuf_put_buf(*resp, buf);
					wpabuf_free(buf);
					break;
				}
			}
		}
#endif /* EAP_TNC */
		/* fall through */
	default:
		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
		    data->phase2_type.method == EAP_TYPE_NONE) {
			size_t i;
			for (i = 0; i < data->num_phase2_types; i++) {
				if (data->phase2_types[i].vendor !=
				    EAP_VENDOR_IETF ||
				    data->phase2_types[i].method != *pos)
					continue;

				data->phase2_type.vendor =
					data->phase2_types[i].vendor;
				data->phase2_type.method =
					data->phase2_types[i].method;
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
					   "Phase 2 EAP vendor %d method %d",
					   data->phase2_type.vendor,
					   data->phase2_type.method);
				break;
			}
		}
		if (*pos != data->phase2_type.method ||
		    *pos == EAP_TYPE_NONE) {
			if (eap_peer_tls_phase2_nak(data->phase2_types,
						    data->num_phase2_types,
						    hdr, resp))
				return -1;
			return 0;
		}

		if (data->phase2_priv == NULL) {
			data->phase2_method = eap_peer_get_eap_method(
				data->phase2_type.vendor,
				data->phase2_type.method);
			if (data->phase2_method) {
				sm->init_phase2 = 1;
				data->phase2_priv =
					data->phase2_method->init(sm);
				sm->init_phase2 = 0;
			}
		}
		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
				   "Phase 2 EAP method %d", *pos);
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		data->phase2_eap_started = 1;
		os_memset(&iret, 0, sizeof(iret));
		*resp = data->phase2_method->process(sm, data->phase2_priv,
						     &iret, req);
		if ((iret.methodState == METHOD_DONE ||
		     iret.methodState == METHOD_MAY_CONT) &&
		    (iret.decision == DECISION_UNCOND_SUCC ||
		     iret.decision == DECISION_COND_SUCC)) {
			data->phase2_eap_success = 1;
			data->phase2_success = 1;
		}
		break;
	}

	if (*resp == NULL &&
	    (config->pending_req_identity || config->pending_req_password ||
	     config->pending_req_otp || config->pending_req_new_password)) {
		wpabuf_free(data->pending_phase2_req);
		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
	}

	return 0;
}