Пример #1
0
/* This is exactly like write_buffered, but will use two buffers to read
 * from.
 */
ssize_t
_gnutls_io_write_buffered2 (gnutls_session_t session,
                            const void *iptr, size_t n,
                            const void *iptr2, size_t n2)
{

    if (n == 0)
    {
        return _gnutls_io_write_buffered (session, iptr2, n2);
    }
    else
    {
        opaque *sptr;
        ssize_t ret;

        sptr = gnutls_alloca (n + n2);
        if (sptr == NULL)
        {
            gnutls_assert ();
            return GNUTLS_E_MEMORY_ERROR;
        }

        memcpy (sptr, iptr, n);
        memcpy (&sptr[n], iptr2, n2);

        ret = _gnutls_io_write_buffered (session, sptr, n + n2);
        gnutls_afree (sptr);

        return ret;
    }
}
Пример #2
0
/* This function writes the data that are left in the
 * TLS write buffer (ie. because the previous write was
 * interrupted.
 */
ssize_t
_gnutls_io_write_flush (gnutls_session_t session)
{
    ssize_t ret;

    if (session->internals.record_send_buffer.length == 0)
        return 0;			/* done */

    ret = _gnutls_io_write_buffered (session, NULL, 0);
    _gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", ret,
                       session->internals.record_send_buffer.length);

    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
/* 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.    
 *
 * 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_int (gnutls_session_t session, content_type_t type,
                  gnutls_handshake_description_t htype,
                  unsigned int epoch_rel, const void *_data,
                  size_t sizeofdata, unsigned int mflags)
{
  mbuffer_st *bufel;
  ssize_t cipher_size;
  int retval, ret;
  int data2send_size;
  uint8_t headers[5];
  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)
    {
      gnutls_assert ();
      return ret;
    }

  /* Safeguard against processing data with an incomplete cipher state. */
  if (!record_params->initialized)
    {
      gnutls_assert ();
      return 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 &&
      (sizeofdata == 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;
      }

  headers[0] = type;

  /* Use the default record version, if it is
   * set.
   */
  copy_record_version (session, htype, &headers[1]);


  _gnutls_record_log
    ("REC[%p]: Sending Packet[%d] %s(%d) with length: %d\n", session,
     (int) _gnutls_uint64touint32 (&record_state->sequence_number),
     _gnutls_packet2str (type), type, (int) sizeofdata);

  if (sizeofdata > MAX_RECORD_SEND_SIZE)
    data2send_size = MAX_RECORD_SEND_SIZE;
  else
    data2send_size = sizeofdata;

  /* 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
    {

      /* now proceed to packet encryption
       */
      cipher_size = data2send_size + MAX_RECORD_OVERHEAD;
      bufel = _mbuffer_alloc (cipher_size, cipher_size);
      if (bufel == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
        }

      cipher_size =
        _gnutls_encrypt (session, headers, RECORD_HEADER_SIZE, data,
                         data2send_size, _mbuffer_get_udata_ptr (bufel),
                         cipher_size, type,
                         (session->internals.priorities.no_padding ==
                          0) ? 1 : 0, record_params);
      if (cipher_size <= 0)
        {
          gnutls_assert ();
          if (cipher_size == 0)
            cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
          gnutls_free (bufel);
          return cipher_size;   /* error */
        }

      retval = data2send_size;
      session->internals.record_send_buffer_user_size = data2send_size;

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

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

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

      if (ret > 0)
        {
          gnutls_assert ();
          ret = GNUTLS_E_INTERNAL_ERROR;
        }
      session_unresumable (session);
      session->internals.may_not_write = 1;
      gnutls_assert ();
      return ret;
    }

  session->internals.record_send_buffer_user_size = 0;

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

  return retval;
}