示例#1
0
文件: alert.c 项目: GostCrypt/GnuTLS
/**
 * gnutls_alert_send:
 * @session: is a #gnutls_session_t type.
 * @level: is the level of the alert
 * @desc: is the alert description
 *
 * This function will send an alert to the peer in order to inform
 * him of something important (eg. his Certificate could not be verified).
 * If the alert level is Fatal then the peer is expected to close the
 * connection, otherwise he may ignore the alert and continue.
 *
 * The error code of the underlying record send function will be
 * returned, so you may also receive %GNUTLS_E_INTERRUPTED or
 * %GNUTLS_E_AGAIN as well.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
 *   an error code is returned.
 **/
int
gnutls_alert_send(gnutls_session_t session, gnutls_alert_level_t level,
		  gnutls_alert_description_t desc)
{
	uint8_t data[2];
	int ret;
	const char *name;

	data[0] = (uint8_t) level;
	data[1] = (uint8_t) desc;

	name = gnutls_alert_get_name((int) data[1]);
	if (name == NULL)
		name = "(unknown)";
	_gnutls_record_log("REC: Sending Alert[%d|%d] - %s\n", data[0],
			   data[1], name);

	if ((ret =
	     _gnutls_send_int(session, GNUTLS_ALERT, -1,
			      EPOCH_WRITE_CURRENT, data, 2,
			      MBUFFER_FLUSH)) >= 0)
		return 0;
	else
		return ret;
}
示例#2
0
/* Send TLS/IA data.  If data==NULL && sizeofdata==NULL, then the last
   send was interrupted for some reason, and then we try to send it
   again.  Returns the number of bytes sent, or an error code.  If
   this return E_AGAIN and E_INTERRUPTED, call this function again
   with data==NULL&&sizeofdata=0NULL until it returns successfully. */
static ssize_t
_gnutls_send_inner_application (gnutls_session_t session,
				gnutls_ia_apptype_t msg_type,
				const char *data, size_t sizeofdata)
{
  opaque *p = NULL;
  size_t plen = 0;
  ssize_t len;

  if (data != NULL)
    {
      plen = sizeofdata + 4;
      p = gnutls_malloc (plen);
      if (!p)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      *(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
      _gnutls_write_uint24 (sizeofdata, p + 1);
      memcpy (p + 4, data, sizeofdata);
    }

  len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);

  if (p)
    gnutls_free (p);

  return len;
}
示例#3
0
/**
 * gnutls_record_send:
 * @session: is a #gnutls_session_t structure.
 * @data: contains the data to send
 * @data_size: is the length of the data
 *
 * This function has the similar semantics with send().  The only
 * difference is that it accepts a GnuTLS session, and uses different
 * error codes.
 * Note that if the send buffer is full, send() will block this
 * function.  See the send() documentation for more information.  
 *
 * You can replace the default push function which is send(), by using
 * gnutls_transport_set_push_function().
 *
 * If the EINTR is returned by the internal push function 
 * then %GNUTLS_E_INTERRUPTED will be returned. If
 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must
 * call this function again, with the exact same parameters; alternatively
 * you could provide a %NULL pointer for data, and 0 for
 * size. cf. gnutls_record_get_direction(). 
 *
 * Note that in DTLS this function will return the %GNUTLS_E_LARGE_PACKET
 * error code if the send data exceed the data MTU value - as returned
 * by gnutls_dtls_get_data_mtu(). The errno value EMSGSIZE
 * also maps to %GNUTLS_E_LARGE_PACKET. 
 * Note that since 3.2.13 this function can be called under cork in DTLS
 * mode, and will refuse to send data over the MTU size by returning
 * %GNUTLS_E_LARGE_PACKET.
 *
 * Returns: The number of bytes sent, or a negative error code.  The
 *   number of bytes sent might be less than @data_size.  The maximum
 *   number of bytes this function can send in a single call depends
 *   on the negotiated maximum record size.
 **/
ssize_t
gnutls_record_send(gnutls_session_t session, const void *data,
		   size_t data_size)
{
	if (session->internals.record_flush_mode == RECORD_FLUSH) {
		return _gnutls_send_int(session, GNUTLS_APPLICATION_DATA,
					-1, EPOCH_WRITE_CURRENT, data,
					data_size, MBUFFER_FLUSH);
	} else {		/* GNUTLS_CORKED */

		int ret;

		if (IS_DTLS(session)) {
			if (data_size + session->internals.record_presend_buffer.length >
				gnutls_dtls_get_data_mtu(session)) {
				return gnutls_assert_val(GNUTLS_E_LARGE_PACKET);
			}
		}

		ret =
		    _gnutls_buffer_append_data(&session->internals.
					       record_presend_buffer, data,
					       data_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		return data_size;
	}
}
示例#4
0
/**
  * gnutls_record_send - sends to the peer the specified data
  * @session: is a #gnutls_session_t structure.
  * @data: contains the data to send
  * @sizeofdata: is the length of the data
  *
  * This function has the similar semantics with send(). The only
  * difference is that is accepts a GNUTLS session, and uses different
  * error codes.
  *
  * Note that if the send buffer is full, send() will block this
  * function.  See the send() documentation for full information.  You
  * can replace the default push function by using
  * gnutls_transport_set_ptr2() with a call to send() with a
  * MSG_DONTWAIT flag if blocking is a problem.
  *
  * If the EINTR is returned by the internal push function (the
  * default is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
  * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must
  * call this function again, with the same parameters; alternatively
  * you could provide a %NULL pointer for data, and 0 for
  * size. cf. gnutls_record_get_direction().
  *
  * Returns the number of bytes sent, or a negative error code. The
  * number of bytes sent might be less than @sizeofdata. The maximum
  * number of bytes this function can send in a single call depends on
  * the negotiated maximum record size.
  **/
ssize_t
gnutls_record_send (gnutls_session_t session, const void *data,
		    size_t sizeofdata)
{
  return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data,
			   sizeofdata);
}
示例#5
0
/**
 * gnutls_record_send:
 * @session: is a #gnutls_session_t structure.
 * @data: contains the data to send
 * @data_size: is the length of the data
 *
 * This function has the similar semantics with send().  The only
 * difference is that it accepts a GnuTLS session, and uses different
 * error codes.
 * Note that if the send buffer is full, send() will block this
 * function.  See the send() documentation for full information.  You
 * can replace the default push function by using
 * gnutls_transport_set_ptr2() with a call to send() with a
 * MSG_DONTWAIT flag if blocking is a problem.
 * If the EINTR is returned by the internal push function (the
 * default is send()) then %GNUTLS_E_INTERRUPTED will be returned. If
 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must
 * call this function again, with the same parameters; alternatively
 * you could provide a %NULL pointer for data, and 0 for
 * size. cf. gnutls_record_get_direction(). The errno value EMSGSIZE
 * maps to %GNUTLS_E_LARGE_PACKET.
 *
 * Returns: The number of bytes sent, or a negative error code.  The
 *   number of bytes sent might be less than @data_size.  The maximum
 *   number of bytes this function can send in a single call depends
 *   on the negotiated maximum record size.
 **/
ssize_t
gnutls_record_send (gnutls_session_t session, const void *data,
                    size_t data_size)
{
  return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1,
                           EPOCH_WRITE_CURRENT, data, data_size,
                           MBUFFER_FLUSH);
}
示例#6
0
/* This function writes the data that are left in the
 * Handshake write buffer (ie. because the previous write was
 * interrupted.
 *
 */
ssize_t
_gnutls_handshake_io_write_flush (gnutls_session_t session)
{
  mbuffer_head_st *const send_buffer =
    &session->internals.handshake_send_buffer;
  gnutls_datum_t msg;
  int ret;
  uint16_t epoch;
  ssize_t total = 0;
  mbuffer_st *cur;

  _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
                     (int) send_buffer->byte_length);

  if (IS_DTLS(session))
    return _dtls_transmit(session);

  for (cur = _mbuffer_head_get_first (send_buffer, &msg);
       cur != NULL; cur = _mbuffer_head_get_first (send_buffer, &msg))
    {
      epoch = cur->epoch;

      ret = _gnutls_send_int (session, cur->type,
                              cur->htype,
                              epoch,
                              msg.data, msg.size, 0);

      if (ret >= 0)
        {
          total += ret;
          
          ret = _mbuffer_head_remove_bytes (send_buffer, ret);
          if (ret == 1)
            _gnutls_epoch_refcount_dec(session, epoch);

          _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
                             ret, (int) send_buffer->byte_length);

        }
      else
        {
          _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
                             ret, (int) send_buffer->byte_length);

          gnutls_assert ();
          return ret;
        }
    }

  return _gnutls_io_write_flush (session);
}
示例#7
0
/* This function is to be called if the handshake was successfully 
 * completed. This sends a Change Cipher Spec packet to the peer.
 */
ssize_t
_gnutls_send_change_cipher_spec (gnutls_session_t session, int again)
{
  static const opaque data[1] = { GNUTLS_TYPE_CHANGE_CIPHER_SPEC };

  _gnutls_handshake_log ("REC[%x]: Sent ChangeCipherSpec\n", session);

  if (again == 0)
    return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1);
  else
    {
      return _gnutls_io_write_flush (session);
    }
}
示例#8
0
/**
 * gnutls_record_send:
 * @session: is a #gnutls_session_t structure.
 * @data: contains the data to send
 * @data_size: is the length of the data
 *
 * This function has the similar semantics with send().  The only
 * difference is that it accepts a GnuTLS session, and uses different
 * error codes.
 * Note that if the send buffer is full, send() will block this
 * function.  See the send() documentation for full information.  You
 * can replace the default push function by using
 * gnutls_transport_set_ptr2() with a call to send() with a
 * MSG_DONTWAIT flag if blocking is a problem.
 * If the EINTR is returned by the internal push function (the
 * default is send()) then %GNUTLS_E_INTERRUPTED will be returned. If
 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must
 * call this function again, with the same parameters; alternatively
 * you could provide a %NULL pointer for data, and 0 for
 * size. cf. gnutls_record_get_direction(). 
 *
 * Note that in DTLS this function will return the %GNUTLS_E_LARGE_PACKET
 * error code if the send data exceed the data MTU value - as returned
 * by gnutls_dtls_get_data_mtu(). The errno value EMSGSIZE
 * also maps to %GNUTLS_E_LARGE_PACKET.
 *
 * Returns: The number of bytes sent, or a negative error code.  The
 *   number of bytes sent might be less than @data_size.  The maximum
 *   number of bytes this function can send in a single call depends
 *   on the negotiated maximum record size.
 **/
ssize_t
gnutls_record_send (gnutls_session_t session, const void *data,
                    size_t data_size)
{
  if (session->internals.record_flush_mode == RECORD_FLUSH)
    {
      return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1,
                               EPOCH_WRITE_CURRENT, data, data_size,
                               MBUFFER_FLUSH);
    }
  else /* GNUTLS_CORKED */
    {
      int ret;

      ret = _gnutls_buffer_append_data(&session->internals.record_presend_buffer, data, data_size);
      if (ret < 0)
        return gnutls_assert_val(ret);
      
      return data_size;
    }
}
示例#9
0
/*
 * Sends heartbeat data.
 */
static int
heartbeat_send_data(gnutls_session_t session, const void *data,
		    size_t data_size, uint8_t type)
{
	int ret, pos;
	uint8_t *response;

	response = gnutls_malloc(1 + 2 + data_size + DEFAULT_PAYLOAD_SIZE);
	if (response == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	pos = 0;
	response[pos++] = type;

	_gnutls_write_uint16(data_size, &response[pos]);
	pos += 2;

	memcpy(&response[pos], data, data_size);
	pos += data_size;

	ret =
	    gnutls_rnd(GNUTLS_RND_NONCE, &response[pos],
		       DEFAULT_PAYLOAD_SIZE);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}
	pos += DEFAULT_PAYLOAD_SIZE;

	ret =
	    _gnutls_send_int(session, GNUTLS_HEARTBEAT, -1,
			     EPOCH_WRITE_CURRENT, response, pos,
			     MBUFFER_FLUSH);

      cleanup:
	gnutls_free(response);
	return ret;
}
示例#10
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;
}
示例#11
0
/* This is a send function for the gnutls handshake
 * protocol. Just makes sure that all data have been sent.
 */
ssize_t
_gnutls_handshake_io_send_int (gnutls_session_t session,
                               content_type_t type,
                               gnutls_handshake_description_t htype,
                               const void *iptr, size_t n)
{
    size_t left;
    ssize_t ret = 0;
    const opaque *ptr;
    ssize_t retval = 0;

    ptr = iptr;

    if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL
            && n == 0)
    {
        /* resuming previously interrupted write
         */
        gnutls_assert ();
        ret =
            _gnutls_buffer_get (&session->internals.handshake_send_buffer,
                                &ptr, &n);
        if (ret < 0)
        {
            gnutls_assert ();
            return retval;
        }

        type = session->internals.handshake_send_buffer_type;
        htype = session->internals.handshake_send_buffer_htype;

    }
    else if (session->internals.handshake_send_buffer.length > 0)
    {
        gnutls_assert ();
        return GNUTLS_E_INTERNAL_ERROR;
    }
#ifdef WRITE_DEBUG
    else
    {
        size_t sum = 0, x, j;

        _gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
                           gnutls_transport_get_ptr (session));
        for (x = 0; x < ((n) / 16) + 1; x++)
        {
            if (sum > n)
                break;

            _gnutls_write_log ("%.4x - ", x);
            for (j = 0; j < 16; j++)
            {
                if (sum < n)
                {
                    _gnutls_write_log ("%.2x ", ((unsigned char *) ptr)[sum++]);
                }
                else
                    break;
            }
            _gnutls_write_log ("\n");
        }
        _gnutls_write_log ("\n");
    }
#endif

    if (n == 0)
    {   /* if we have no data to send */
        gnutls_assert ();
        return 0;
    }
    else if (ptr == NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_INTERNAL_ERROR;
    }


    left = n;
    while (left > 0)
    {
        ret = _gnutls_send_int (session, type, htype, &ptr[n - left], left);

        if (ret <= 0)
        {
            if (ret == 0)
            {
                gnutls_assert ();
                ret = GNUTLS_E_INTERNAL_ERROR;
            }

            if (left > 0
                    && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN))
            {
                gnutls_assert ();

                retval =
                    _gnutls_buffer_insert (&session->internals.
                                           handshake_send_buffer,
                                           &ptr[n - left], left);
                if (retval < 0)
                {
                    gnutls_assert ();
                    return retval;
                }

                session->internals.handshake_send_buffer_prev_size += n - left;

                session->internals.handshake_send_buffer_type = type;
                session->internals.handshake_send_buffer_htype = htype;

            }
            else
            {
                session->internals.handshake_send_buffer_prev_size = 0;
                session->internals.handshake_send_buffer.length = 0;
            }

            gnutls_assert ();
            return ret;
        }
        left -= ret;
    }

    retval = n + session->internals.handshake_send_buffer_prev_size;

    session->internals.handshake_send_buffer.length = 0;
    session->internals.handshake_send_buffer_prev_size = 0;

    return retval;

}