Exemplo n.º 1
0
/* @ms: is the number of milliseconds to wait for data. Use zero for indefinite.
 *
 * This will receive record layer packets and add them to 
 * application_data_buffer and handshake_data_buffer.
 *
 * If the htype is not -1 then handshake timeouts
 * will be enforced.
 */
ssize_t
_gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type,
			gnutls_handshake_description_t htype,
			unsigned int ms)
{
	uint64 *packet_sequence;
	gnutls_datum_t ciphertext;
	mbuffer_st *bufel = NULL, *decrypted = NULL;
	gnutls_datum_t t;
	int ret;
	unsigned int empty_fragments = 0;
	record_parameters_st *record_params;
	record_state_st *record_state;
	struct tls_record_st record;

      begin:

	if (empty_fragments >
	    session->internals.priorities.max_empty_records) {
		gnutls_assert();
		return GNUTLS_E_TOO_MANY_EMPTY_PACKETS;
	}

	if (session->internals.read_eof != 0) {
		/* if we have already read an EOF
		 */
		return 0;
	} else if (session_is_valid(session) != 0
		   || session->internals.may_not_read != 0)
		return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);

	/* get the record state parameters */
	ret =
	    _gnutls_epoch_get(session, EPOCH_READ_CURRENT, &record_params);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* Safeguard against processing data with an incomplete cipher state. */
	if (!record_params->initialized)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	record_state = &record_params->read;

	/* receive headers */
	ret = recv_headers(session, record_params, type, htype, &record, &ms);
	if (ret < 0) {
		ret = gnutls_assert_val_fatal(ret);
		goto recv_error;
	}

	if (IS_DTLS(session))
		packet_sequence = &record.sequence;
	else
		packet_sequence = &record_state->sequence_number;

	/* Read the packet data and insert it to record_recv_buffer.
	 */
	ret =
	    _gnutls_io_read_buffered(session, record.packet_size,
				     record.type, &ms);
	if (ret != record.packet_size) {
		gnutls_assert();
		goto recv_error;
	}

	/* ok now we are sure that we have read all the data - so
	 * move on !
	 */
	ret = _mbuffer_linearize_align16(&session->internals.record_recv_buffer, 
		get_total_headers2(session, record_params));
	if (ret < 0)
		return gnutls_assert_val(ret);

	bufel =
	    _mbuffer_head_get_first(&session->internals.record_recv_buffer,
				    NULL);
	if (bufel == NULL)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	/* We allocate the maximum possible to allow few compressed bytes to expand to a
	 * full record. Moreover we add space for any pad and the MAC (in case
	 * they are encrypted).
	 */
	ret = max_decrypted_size(session) + MAX_PAD_SIZE + MAX_HASH_SIZE;
	decrypted = _mbuffer_alloc_align16(ret, 0);
	if (decrypted == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	_mbuffer_set_udata_size(decrypted, ret);
	ciphertext.data =
	    (uint8_t *) _mbuffer_get_udata_ptr(bufel) + record.header_size;
	ciphertext.size = record.length;

	/* decrypt the data we got. 
	 */
	t.data = _mbuffer_get_udata_ptr(decrypted);
	t.size = _mbuffer_get_udata_size(decrypted);
	ret =
	    _gnutls_decrypt(session, &ciphertext, &t,
			    record.type, record_params, packet_sequence);
	if (ret >= 0)
		_mbuffer_set_udata_size(decrypted, ret);

	_mbuffer_head_remove_bytes(&session->internals.record_recv_buffer,
				   record.header_size + record.length);
	if (ret < 0) {
		gnutls_assert();
		_gnutls_audit_log(session,
				  "Discarded message[%u] due to invalid decryption\n",
				  (unsigned int)
				  _gnutls_uint64touint32(packet_sequence));
		goto sanity_check_error;
	}

	/* check for duplicates. We check after the message
	 * is processed and authenticated to avoid someone
	 * messing with our windows.
	 */
	if (IS_DTLS(session)
	    && session->internals.no_replay_protection == 0) {
		ret = _dtls_record_check(record_params, packet_sequence);
		if (ret < 0) {
			_gnutls_record_log
			    ("REC[%p]: Discarded duplicate message[%u.%u]: %s\n",
			     session,
			     (unsigned int) record.sequence.i[0] * 256 +
			     (unsigned int) record.sequence.i[1],
			     (unsigned int)
			     _gnutls_uint64touint32(packet_sequence),
			     _gnutls_packet2str(record.type));
			goto sanity_check_error;
		}
		_gnutls_record_log
		    ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n",
		     session,
		     (unsigned int) record.sequence.i[0] * 256 +
		     (unsigned int) record.sequence.i[1],
		     (unsigned int)
		     _gnutls_uint64touint32(packet_sequence),
		     _gnutls_packet2str(record.type), record.type,
		     (int) _mbuffer_get_udata_size(decrypted));
	} else {
		_gnutls_record_log
		    ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n",
		     session,
		     (unsigned int)
		     _gnutls_uint64touint32(packet_sequence),
		     _gnutls_packet2str(record.type), record.type,
		     (int) _mbuffer_get_udata_size(decrypted));
	}

	/* increase sequence number 
	 */
	if (!IS_DTLS(session)
	    && sequence_increment(session,
				  &record_state->sequence_number) != 0) {
		session_invalidate(session);
		gnutls_assert();
		ret = GNUTLS_E_RECORD_LIMIT_REACHED;
		goto sanity_check_error;
	}

/* (originally for) TLS 1.0 CBC protection. 
 * Actually this code is called if we just received
 * an empty packet. An empty TLS packet is usually
 * sent to protect some vulnerabilities in the CBC mode.
 * In that case we go to the beginning and start reading
 * the next packet.
 */
	if (_mbuffer_get_udata_size(decrypted) == 0) {
		_mbuffer_xfree(&decrypted);
		empty_fragments++;
		goto begin;
	}

	if (record.v2) {
		decrypted->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
	} else {
		uint8_t *p = _mbuffer_get_udata_ptr(decrypted);
		decrypted->htype = p[0];
	}

	ret =
	    record_add_to_buffers(session, &record, type, htype,
				  packet_sequence, decrypted);

	/* decrypted is now either deinitialized or buffered somewhere else */

	if (ret < 0)
		return gnutls_assert_val(ret);

	return ret;

      discard:
	session->internals.dtls.packets_dropped++;

	/* discard the whole received fragment. */
	bufel =
	    _mbuffer_head_pop_first(&session->internals.
				    record_recv_buffer);
	_mbuffer_xfree(&bufel);
	return gnutls_assert_val(GNUTLS_E_AGAIN);

      sanity_check_error:
	if (IS_DTLS(session)) {
		session->internals.dtls.packets_dropped++;
		ret = gnutls_assert_val(GNUTLS_E_AGAIN);
		goto cleanup;
	}

	session_unresumable(session);
	session_invalidate(session);

      cleanup:
	_mbuffer_xfree(&decrypted);
	return ret;

      recv_error:
	if (ret < 0
	    && (gnutls_error_is_fatal(ret) == 0
		|| ret == GNUTLS_E_TIMEDOUT))
		return ret;

	if (type == GNUTLS_ALERT) {	/* we were expecting close notify */
		session_invalidate(session);
		gnutls_assert();
		return 0;
	}

	if (IS_DTLS(session) && (ret == GNUTLS_E_DECRYPTION_FAILED ||
		ret == GNUTLS_E_UNSUPPORTED_VERSION_PACKET ||
		ret == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
		ret == GNUTLS_E_UNEXPECTED_PACKET ||
		ret == GNUTLS_E_ERROR_IN_FINISHED_PACKET ||
		ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)) {
		goto discard;
	}

	session_invalidate(session);
	session_unresumable(session);

	if (ret == 0)
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	else
		return ret;
}
Exemplo n.º 2
0
static int
decrypt_packet_tls13(gnutls_session_t session,
		     gnutls_datum_t *ciphertext,
		     gnutls_datum_t *plain,
		     content_type_t *type, record_parameters_st *params,
		     gnutls_uint64 *sequence)
{
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	size_t length, length_to_decrypt;
	int ret;
	const version_entry_st *ver = get_version(session);
	unsigned int tag_size = params->read.aead_tag_size;
	unsigned iv_size;
	unsigned j;
	volatile unsigned length_set;
	uint8_t aad[5];

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (params->cipher->id == GNUTLS_CIPHER_NULL) {
		if (plain->size < ciphertext->size)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		length = ciphertext->size;
		memcpy(plain->data, ciphertext->data, length);

		return length;
	}

	iv_size = _gnutls_cipher_get_iv_size(params->cipher);

	/* The way AEAD ciphers are defined in RFC5246, it allows
	 * only stream ciphers.
	 */
	if (unlikely(ciphertext->size < tag_size))
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	if (unlikely(params->read.iv_size != iv_size || iv_size < 8))
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	memcpy(nonce, params->read.iv, params->read.iv_size);
	memxor(&nonce[iv_size-8], UINT64DATA(*sequence), 8);

	length =
	    ciphertext->size - tag_size;

	length_to_decrypt = ciphertext->size;

	if (unlikely
	    ((unsigned) length_to_decrypt > plain->size)) {
			_gnutls_audit_log(session,
				  "Received %u bytes, while expecting less than %u\n",
				  (unsigned int) length_to_decrypt,
				  (unsigned int) plain->size);
		return
		    gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
	}

	aad[0] = GNUTLS_APPLICATION_DATA;
	aad[1] = 0x03;
	aad[2] = 0x03;
	_gnutls_write_uint16(ciphertext->size, &aad[3]);

	ret = gnutls_aead_cipher_decrypt(&params->read.ctx.aead,
					 nonce, iv_size,
					 aad, sizeof(aad),
					 tag_size,
					 ciphertext->data, length_to_decrypt,
					 plain->data, &length);
	if (unlikely(ret < 0))
		return gnutls_assert_val(ret);

	/* 1 octet for content type */
	if (length > max_decrypted_size(session) + 1) {
		_gnutls_audit_log
		    (session, "Received packet with illegal length: %u\n",
		     (unsigned int) length);

		return gnutls_assert_val(GNUTLS_E_RECORD_OVERFLOW);
	}

	length_set = 0;

	/* now figure the actual data size. We intentionally iterate through all data,
	 * to avoid leaking the padding length due to timing differences in processing.
	 */
	for (j=length;j>0;j--) {
		if (plain->data[j-1]!=0 && length_set == 0) {
			*type = plain->data[j-1];
			length = j-1;
			length_set = 1;
			if (!(session->internals.flags & GNUTLS_SAFE_PADDING_CHECK))
				break;
		}
	}

	if (!length_set)
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	return length;
}