Esempio n. 1
0
int
_gnutls_parse_extensions(gnutls_session_t session,
			 gnutls_ext_parse_type_t parse_type,
			 const uint8_t * data, int data_size)
{
	int next, ret;
	int pos = 0;
	uint16_t type;
	const uint8_t *sdata;
	gnutls_ext_recv_func ext_recv;
	uint16_t size;

#ifdef DEBUG
	int i;

	if (session->security_parameters.entity == GNUTLS_CLIENT)
		for (i = 0; i < session->internals.extensions_sent_size;
		     i++) {
			_gnutls_handshake_log
			    ("EXT[%d]: expecting extension '%s'\n",
			     session,
			     _gnutls_extension_get_name(session->internals.
							extensions_sent
							[i]));
		}
#endif

	DECR_LENGTH_RET(data_size, 2, 0);
	next = _gnutls_read_uint16(data);
	pos += 2;

	DECR_LENGTH_RET(data_size, next, 0);

	do {
		DECR_LENGTH_RET(next, 2, 0);
		type = _gnutls_read_uint16(&data[pos]);
		pos += 2;

		if ((ret =
		     _gnutls_extension_list_check(session, type)) < 0) {
			gnutls_assert();
			return ret;
		}

		DECR_LENGTH_RET(next, 2, 0);
		size = _gnutls_read_uint16(&data[pos]);
		pos += 2;

		DECR_LENGTH_RET(next, size, 0);
		sdata = &data[pos];
		pos += size;

		ext_recv = _gnutls_ext_func_recv(type, parse_type);
		if (ext_recv == NULL) {
			_gnutls_handshake_log
			    ("EXT[%p]: Found extension '%s/%d'\n", session,
			     _gnutls_extension_get_name(type), type);

			continue;
		}

		_gnutls_handshake_log
		    ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n",
		     session, _gnutls_extension_get_name(type), type,
		     size);

		if ((ret = ext_recv(session, sdata, size)) < 0) {
			gnutls_assert();
			return ret;
		}

	}
	while (next > 2);

	return 0;

}
int
_gnutls_gen_extensions(gnutls_session_t session,
		       gnutls_buffer_st * extdata,
		       gnutls_ext_parse_type_t parse_type)
{
	int size;
	int pos, size_pos, ret;
	size_t i, init_size = extdata->length;

	pos = extdata->length;	/* we will store length later on */

	ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	for (i = 0; i < extfunc_size; i++) {
		extension_entry_st *p = &extfunc[i];

		if (p->send_func == NULL)
			continue;

		if (parse_type != GNUTLS_EXT_ANY
		    && p->parse_type != parse_type)
			continue;

		/* ensure we are sending only what we received */
		if (session->security_parameters.entity == GNUTLS_SERVER) {
			if ((ret =
			     _gnutls_extension_list_check(session, p->type)) < 0) {
				continue;
			}
		}

		ret = _gnutls_buffer_append_prefix(extdata, 16, p->type);
		if (ret < 0)
			return gnutls_assert_val(ret);

		size_pos = extdata->length;
		ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
		if (ret < 0)
			return gnutls_assert_val(ret);

		size = p->send_func(session, extdata);
		/* returning GNUTLS_E_INT_RET_0 means to send an empty
		 * extension of this type.
		 */
		if (size > 0 || size == GNUTLS_E_INT_RET_0) {
			if (size == GNUTLS_E_INT_RET_0)
				size = 0;

			/* write the real size */
			_gnutls_write_uint16(size,
					     &extdata->data[size_pos]);

			/* add this extension to the extension list
			 */
			if (session->security_parameters.entity == GNUTLS_CLIENT)
				_gnutls_extension_list_add(session, p->type);

			_gnutls_handshake_log
			    ("EXT[%p]: Sending extension %s (%d bytes)\n",
			     session, p->name, size);
		} else if (size < 0) {
			gnutls_assert();
			return size;
		} else if (size == 0)
			extdata->length -= 4;	/* reset type and size */
	}

	/* remove any initial data, and the size of the header */
	size = extdata->length - init_size - 2;

	if (size > 0)
		_gnutls_write_uint16(size, &extdata->data[pos]);
	else if (size == 0)
		extdata->length -= 2;	/* the length bytes */

	return size;
}