Пример #1
0
/* returns ciphertext which contains the headers too. This also
 * calculates the size in the header field.
 * 
 */
int
_gnutls_encrypt(gnutls_session_t session,
		const uint8_t *data, size_t data_size,
		size_t min_pad,
		mbuffer_st *bufel,
		content_type_t type, record_parameters_st *params)
{
	gnutls_datum_t plaintext;
	const version_entry_st *vers = get_version(session);
	int ret;

	plaintext.data = (uint8_t *) data;
	plaintext.size = data_size;

	if (vers && vers->tls13_sem) {
		/* it fills the header, as it is included in the authenticated
		 * data of the AEAD cipher. */
		ret =
		    encrypt_packet_tls13(session,
					 _mbuffer_get_udata_ptr(bufel),
					 _mbuffer_get_udata_size(bufel),
					 &plaintext, min_pad, type,
					 params);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else {
		ret =
		    encrypt_packet(session,
				   _mbuffer_get_udata_ptr(bufel),
				   _mbuffer_get_udata_size
				   (bufel), &plaintext, min_pad, type,
				   params);
		if (ret < 0)
			return gnutls_assert_val(ret);

	}

	if (IS_DTLS(session))
		_gnutls_write_uint16(ret,
				     ((uint8_t *)
				      _mbuffer_get_uhead_ptr(bufel)) + 11);
	else
		_gnutls_write_uint16(ret,
				     ((uint8_t *)
				      _mbuffer_get_uhead_ptr(bufel)) + 3);

	_mbuffer_set_udata_size(bufel, ret);
	_mbuffer_set_uhead_size(bufel, 0);

	return _mbuffer_get_udata_size(bufel);
}
Пример #2
0
/* This function fragments and transmits a previously buffered
 * outgoing message. It accepts mtu_data which is a buffer to
 * be reused (should be set to NULL initially).
 */
static inline int
transmit_message (gnutls_session_t session,
		  mbuffer_st *bufel, uint8_t **buf)
{
  uint8_t *data, *mtu_data;
  int ret = 0;
  unsigned int offset, frag_len, data_size;
  const unsigned int mtu = gnutls_dtls_get_data_mtu(session) - DTLS_HANDSHAKE_HEADER_SIZE;

  if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC)
    {
      _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d)\n",
			session, bufel->handshake_sequence,
			_gnutls_handshake2str (bufel->htype),
			bufel->htype);

      return _gnutls_send_int (session, bufel->type, -1,
        bufel->epoch, 
        _mbuffer_get_uhead_ptr(bufel), 
        _mbuffer_get_uhead_size(bufel), 0);
    }

  if (*buf == NULL) *buf = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
  if (*buf == NULL)
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

  mtu_data = *buf;

  data = _mbuffer_get_udata_ptr( bufel);
  data_size = _mbuffer_get_udata_size(bufel);

  /* Write fixed headers
   */

  /* Handshake type */
  mtu_data[0] = (uint8_t) bufel->htype;

  /* Total length */
  _gnutls_write_uint24 (data_size, &mtu_data[1]);

  /* Handshake sequence */
  _gnutls_write_uint16 (bufel->handshake_sequence, &mtu_data[4]);

  /* Chop up and send handshake message into mtu-size pieces. */
  for (offset=0; offset <= data_size; offset += mtu)
    {
      /* Calculate fragment length */
      if(offset + mtu > data_size)
        frag_len = data_size - offset;
      else
        frag_len = mtu;

      /* Fragment offset */
      _gnutls_write_uint24 (offset, &mtu_data[6]);

      /* Fragment length */
      _gnutls_write_uint24 (frag_len, &mtu_data[9]);

      memcpy (&mtu_data[DTLS_HANDSHAKE_HEADER_SIZE], data+offset, frag_len);

      _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
			"length: %u, offset: %u, fragment length: %u\n",
			session, bufel->handshake_sequence,
			_gnutls_handshake2str (bufel->htype),
			bufel->htype, data_size, offset, frag_len);

      ret = _gnutls_send_int (session, bufel->type, bufel->htype, 
        bufel->epoch, mtu_data, DTLS_HANDSHAKE_HEADER_SIZE + frag_len, 0);
      if (ret < 0)
        {
          gnutls_assert();
          break;
        }
   }

  return ret;
}
Пример #3
0
/* This function behaves exactly like write(). The only difference is
 * that it accepts, the gnutls_session_t and the content_type_t of data to
 * send (if called by the user the Content is specific)
 * It is intended to transfer data, under the current session.    
 *
 * @type: The content type to send
 * @htype: If this is a handshake message then the handshake type
 * @epoch_rel: %EPOCH_READ_* or %EPOCH_WRITE_*
 * @data: the data to be sent
 * @data_size: the size of the @data
 * @target_length: @data_size + minimum required padding
 * @mflags: zero or %MBUFFER_FLUSH
 *
 * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE.
 * This makes the function much easier to read, and more error resistant
 * (there were cases were the old function could mess everything up).
 * --nmav
 *
 * This function may accept a NULL pointer for data, and 0 for size, if
 * and only if the previous send was interrupted for some reason.
 *
 */
ssize_t
_gnutls_send_tlen_int (gnutls_session_t session, content_type_t type,
		gnutls_handshake_description_t htype,
		unsigned int epoch_rel, const void *_data,
		size_t data_size, size_t target_length, unsigned int mflags)
{
  mbuffer_st *bufel;
  ssize_t cipher_size;
  int retval, ret;
  int send_data_size;
  uint8_t *headers;
  int header_size;
  const uint8_t *data = _data;
  record_parameters_st *record_params;
  record_state_st *record_state;

  ret = _gnutls_epoch_get (session, epoch_rel, &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_INVALID_REQUEST);

  record_state = &record_params->write;

  /* Do not allow null pointer if the send buffer is empty.
   * If the previous send was interrupted then a null pointer is
   * ok, and means to resume.
   */
  if (session->internals.record_send_buffer.byte_length == 0 &&
      (data_size == 0 && _data == NULL))
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  if (type != GNUTLS_ALERT)     /* alert messages are sent anyway */
    if (session_is_valid (session) || session->internals.may_not_write != 0)
      {
        gnutls_assert ();
        return GNUTLS_E_INVALID_SESSION;
      }


  if (data_size > MAX_USER_SEND_SIZE(session))
    {
      if (IS_DTLS(session))
        return gnutls_assert_val(GNUTLS_E_LARGE_PACKET);

      send_data_size = MAX_USER_SEND_SIZE(session);
    }
  else
    send_data_size = data_size;
  
  /* Only encrypt if we don't have data to send 
   * from the previous run. - probably interrupted.
   */
  if (mflags != 0 && session->internals.record_send_buffer.byte_length > 0)
    {
      ret = _gnutls_io_write_flush (session);
      if (ret > 0)
        cipher_size = ret;
      else
        cipher_size = 0;

      retval = session->internals.record_send_buffer_user_size;
    }
  else
    {
      if (unlikely((send_data_size == 0 && target_length == 0)))
        return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

      /* now proceed to packet encryption
       */
      cipher_size = MAX_RECORD_SEND_SIZE(session);
      bufel = _mbuffer_alloc (0, cipher_size+CIPHER_SLACK_SIZE);
      if (bufel == NULL)
        return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

      headers = _mbuffer_get_uhead_ptr(bufel);
      headers[0] = type;
      /* Use the default record version, if it is
       * set. */
      copy_record_version (session, htype, &headers[1]);
      header_size = RECORD_HEADER_SIZE(session);
      /* Adjust header length and add sequence for DTLS */
      if (IS_DTLS(session))
        memcpy(&headers[3], &record_state->sequence_number.i, 8);

      _gnutls_record_log
        ("REC[%p]: Preparing Packet %s(%d) with length: %d and target length: %d\n", session,
         _gnutls_packet2str (type), type, (int) data_size, (int) target_length);

      _mbuffer_set_udata_size(bufel, cipher_size);
      _mbuffer_set_uhead_size(bufel, header_size);

      ret =
        _gnutls_encrypt (session, 
                         data, send_data_size, target_length, 
                         bufel, type, record_params);
      if (ret <= 0)
        {
          gnutls_assert ();
          if (ret == 0)
            ret = GNUTLS_E_ENCRYPTION_FAILED;
          gnutls_free (bufel);
          return ret;   /* error */
        }

      cipher_size = _mbuffer_get_udata_size(bufel);
      retval = send_data_size;
      session->internals.record_send_buffer_user_size = send_data_size;

      /* increase sequence number
       */
      if (sequence_increment (session, &record_state->sequence_number) != 0)
        {
          session_invalidate (session);
          gnutls_free (bufel);
          return gnutls_assert_val(GNUTLS_E_RECORD_LIMIT_REACHED);
        }

      ret = _gnutls_io_write_buffered (session, bufel, mflags);
    }

  if (ret != cipher_size)
    {
      /* If we have sent any data then just return
       * the error value. Do not invalidate the session.
       */
      if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
        return gnutls_assert_val(ret);

      if (ret > 0)
        ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

      session_unresumable (session);
      session->internals.may_not_write = 1;
      return gnutls_assert_val(ret);
    }

  session->internals.record_send_buffer_user_size = 0;

  _gnutls_record_log ("REC[%p]: Sent Packet[%d] %s(%d) in epoch %d and length: %d\n",
                      session,
                      (unsigned int)
                      _gnutls_uint64touint32
                      (&record_state->sequence_number),
                      _gnutls_packet2str (type), type, 
                      (int) record_params->epoch,
                      (int) cipher_size);

  return retval;
}
Пример #4
0
/* returns ciphertext which contains the headers too. This also
 * calculates the size in the header field.
 * 
 */
int
_gnutls_encrypt(gnutls_session_t session,
		const uint8_t * data, size_t data_size,
		size_t min_pad,
		mbuffer_st * bufel,
		content_type_t type, record_parameters_st * params)
{
	gnutls_datum_t comp;
	int free_comp = 0;
	int ret;

	if (data_size == 0 || is_write_comp_null(params) == 0) {
		comp.data = (uint8_t *) data;
		comp.size = data_size;
	} else {
		/* Here comp is allocated and must be 
		 * freed.
		 */
		free_comp = 1;

		comp.size = _mbuffer_get_udata_size(bufel);
		comp.data = gnutls_malloc(comp.size);
		if (comp.data == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		ret =
		    _gnutls_compress(&params->write.compression_state,
				     data, data_size, comp.data, comp.size,
				     session->internals.priorities.
				     stateless_compression);
		if (ret < 0) {
			gnutls_free(comp.data);
			return gnutls_assert_val(ret);
		}

		comp.size = ret;
	}

	ret =
	    compressed_to_ciphertext(session,
				     _mbuffer_get_udata_ptr(bufel),
				     _mbuffer_get_udata_size
				     (bufel), &comp, min_pad, type,
				     params);
	if (free_comp)
		gnutls_free(comp.data);

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

	if (IS_DTLS(session))
		_gnutls_write_uint16(ret,
				     ((uint8_t *)
				      _mbuffer_get_uhead_ptr(bufel)) + 11);
	else
		_gnutls_write_uint16(ret,
				     ((uint8_t *)
				      _mbuffer_get_uhead_ptr(bufel)) + 3);

	_mbuffer_set_udata_size(bufel, ret);
	_mbuffer_set_uhead_size(bufel, 0);

	return _mbuffer_get_udata_size(bufel);
}