Example #1
0
/* This is a send function for the gnutls handshake 
 * protocol. Just makes sure that all data have been sent.
 *
 */
int
_gnutls_handshake_io_cache_int(gnutls_session_t session,
			       gnutls_handshake_description_t htype,
			       mbuffer_st * bufel)
{
	mbuffer_head_st *send_buffer;

	if (IS_DTLS(session)) {
		bufel->handshake_sequence =
		    session->internals.dtls.hsk_write_seq - 1;
	}

	send_buffer = &session->internals.handshake_send_buffer;

	/* ensure that our epoch does not get garbage collected
	 * before we send all queued messages with it */
	bufel->epoch =
	    (uint16_t) _gnutls_epoch_refcount_inc(session,
						  EPOCH_WRITE_CURRENT);
	bufel->htype = htype;
	if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
		bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
	else
		bufel->type = GNUTLS_HANDSHAKE;

	_mbuffer_enqueue(send_buffer, bufel);

	_gnutls_write_log
	    ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
	     _gnutls_handshake2str(bufel->htype), (int) bufel->msg.size,
	     (int) send_buffer->byte_length);

	return 0;
}
Example #2
0
/* Default (unencrypted) send.
 * For blocking sockets, always returns len or SECFailure, no short writes.
 * For non-blocking sockets:
 *   Returns positive count if any data was written, else returns SECFailure. 
 *   Short writes may occur.  Does not return SECWouldBlock.
 */
int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
{
    PRFileDesc *lower = ss->fd->lower;
    int sent = 0;

#if NSS_DISABLE_NAGLE_DELAYS
    /* Although this is overkill, we disable Nagle delays completely for 
    ** SSL sockets.
    */
    if (ss->opt.useSecurity && !ss->delayDisabled) {
	ssl_EnableNagleDelay(ss, PR_FALSE);   /* ignore error */
    	ss->delayDisabled = 1;
    }
#endif
    do {
	int rv = lower->methods->send(lower, (const void *)(buf + sent), 
	                              len - sent, flags, ss->wTimeout);
	if (rv < 0) {
	    PRErrorCode err = PR_GetError();
	    if (err == PR_WOULD_BLOCK_ERROR) {
		ss->lastWriteBlocked = 1;
		return sent ? sent : SECFailure;
	    }
	    ss->lastWriteBlocked = 0;
	    MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
	    /* Loser */
	    return rv;
	}
	sent += rv;
	
	if (IS_DTLS(ss) && (len > sent)) { 
	    /* We got a partial write so just return it */
	    return sent;
	}
    } while (len > sent);
Example #3
0
/* Checks if there are pending data in the record buffers. If there are
 * then it copies the data.
 */
static int
check_buffers (gnutls_session_t session, content_type_t type,
               uint8_t * data, int data_size, void* seq)
{
  if ((type == GNUTLS_APPLICATION_DATA ||
       type == GNUTLS_HANDSHAKE ||
       type == GNUTLS_CHANGE_CIPHER_SPEC)
      && _gnutls_record_buffer_get_size (session) > 0)
    {
      int ret;
      ret = _gnutls_record_buffer_get (type, session, data, data_size, seq);
      if (ret < 0)
        {
          if (IS_DTLS(session))
            {
              if (ret == GNUTLS_E_UNEXPECTED_PACKET)
                {
                  ret = GNUTLS_E_AGAIN;
                }
            }
          gnutls_assert ();
          return ret;
        }

      return ret;
    }

  return 0;
}
Example #4
0
static int
_gnutls_dumbfw_send_params(gnutls_session_t session,
			 gnutls_buffer_st * extdata)
{
	int total_size = 0, ret;
	uint8_t pad[257];
	unsigned pad_size;

	if (session->security_parameters.entity == GNUTLS_SERVER ||
	    session->internals.priorities.dumbfw == 0 ||
	    IS_DTLS(session) != 0 ||
	    (extdata->length < 256 || extdata->length >= 512)) {
		return 0;
	} else {
		/* 256 <= extdata->length < 512 */
		pad_size = 512 - extdata->length;
		memset(pad, 0, pad_size);

		ret =
		    gnutls_buffer_append_data(extdata, pad,
						       pad_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		total_size += pad_size;
	}

	return total_size;
}
Example #5
0
/* Here we check if the advertized version is the one we
 * negotiated in the handshake.
 */
inline static int
record_check_version (gnutls_session_t session,
                      gnutls_handshake_description_t htype, uint8_t version[2])
{
  if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO)
    {
      /* Reject hello packets with major version higher than 3.
       */
      if (!(IS_DTLS(session)) && version[0] > 3)
        {
          gnutls_assert ();
          _gnutls_record_log
            ("REC[%p]: INVALID VERSION PACKET: (%d) %d.%d\n", session,
             htype, version[0], version[1]);
          return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
        }
    }
  else if (htype != GNUTLS_HANDSHAKE_SERVER_HELLO &&
           gnutls_protocol_get_version (session) !=
           _gnutls_version_get (version[0], version[1]))
    {
      /* Reject record packets that have a different version than the
       * one negotiated. Note that this version is not protected by any
       * mac. I don't really think that this check serves any purpose.
       */
      gnutls_assert ();
      _gnutls_record_log ("REC[%p]: INVALID VERSION PACKET: (%d) %d.%d\n",
                          session, htype, version[0], version[1]);

      return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
    }

  return 0;
}
Example #6
0
/* Takes the size of the ClientHello, less the record header, and determines how
 * much padding is required. */
static unsigned int
ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
{
    unsigned int recordLength = 1 /* handshake message type */ +
                                3 /* handshake message length */ +
                                clientHelloLength;
    unsigned int extensionLen;

    /* Don't pad for DTLS, for SSLv3, or for renegotiation. */
    if (IS_DTLS(ss) ||
        ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 ||
        ss->firstHsDone) {
        return 0;
    }

    /* A padding extension may be included to ensure that the record containing
     * the ClientHello doesn't have a length between 256 and 511 bytes
     * (inclusive). Initial ClientHello records with such lengths trigger bugs
     * in F5 devices. */
    if (recordLength < 256 || recordLength >= 512) {
        return 0;
    }

    extensionLen = 512 - recordLength;
    /* Extensions take at least four bytes to encode. Always include at least
     * one byte of data if we are padding. Some servers will time out or
     * terminate the connection if the last ClientHello extension is empty. */
    if (extensionLen < 5) {
        extensionLen = 5;
    }

    return extensionLen - 4;
}
Example #7
0
int
_gnutls_epoch_alloc (gnutls_session_t session, uint16_t epoch,
                     record_parameters_st ** out)
{
  record_parameters_st **slot;

  _gnutls_record_log ("REC[%p]: Allocating epoch #%u\n", session, epoch);

  slot = epoch_get_slot (session, epoch);

  /* If slot out of range or not empty. */
  if (slot == NULL)
    return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);

  if (*slot != NULL)
    return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);

  *slot = gnutls_calloc (1, sizeof (record_parameters_st));
  if (*slot == NULL)
    return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

  (*slot)->epoch = epoch;
  (*slot)->cipher_algorithm = GNUTLS_CIPHER_UNKNOWN;
  (*slot)->mac_algorithm = GNUTLS_MAC_UNKNOWN;
  (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN;

  if (IS_DTLS (session))
    _gnutls_write_uint16 (epoch, UINT64DATA((*slot)->write.sequence_number));

  if (out != NULL)
    *out = *slot;

  return 0;
}
Example #8
0
/* Checks and retrieves any pending data in the application data record buffers.
 */
static int
check_packet_buffers(gnutls_session_t session, content_type_t type,
		     gnutls_packet_t *packet)
{
	if (_gnutls_record_buffer_get_size(session) > 0) {
		int ret;
		ret =
		    _gnutls_record_buffer_get_packet(type, session,
					      	     packet);
		if (ret < 0) {
			if (IS_DTLS(session)) {
				if (ret == GNUTLS_E_UNEXPECTED_PACKET) {
					ret = GNUTLS_E_AGAIN;
				}
			}
			gnutls_assert();
			return ret;
		}

		return ret;
	}

	*packet = NULL;
	return 0;
}
Example #9
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;
	}
}
Example #10
0
int
_gnutls_record_buffer_get_packet(content_type_t type, gnutls_session_t session, gnutls_packet_t *packet)
{
	mbuffer_st *bufel;

	bufel =
	    _mbuffer_head_pop_first(&session->internals.record_buffer);
	if (bufel == NULL)
		return
		    gnutls_assert_val
		    (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);

	if (type != bufel->type) {
		if (IS_DTLS(session))
			_gnutls_audit_log(session,
					  "Discarded unexpected %s (%d) packet (expecting: %s)\n",
					  _gnutls_packet2str(bufel->type),
					  (int) bufel->type,
					  _gnutls_packet2str(type));
		_mbuffer_head_remove_bytes(&session->internals.
					   record_buffer, bufel->msg.size);
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
	}

	*packet = bufel;

	return bufel->msg.size - bufel->mark;
}
Example #11
0
/* Checks whether there are received data within
 * a timeframe.
 *
 * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
 * on timeout and a negative error code on error.
 */
int _gnutls_io_check_recv(gnutls_session_t session, unsigned int ms)
{
	gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
	int ret = 0, err;

	if (unlikely
	    (session->internals.pull_timeout_func == gnutls_system_recv_timeout
	     && session->internals.pull_func != system_read)) {
		_gnutls_debug_log("The pull function has been replaced but not the pull timeout.");
		return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
	}

	reset_errno(session);

	ret = session->internals.pull_timeout_func(fd, ms);
	if (ret == -1) {
		err = get_errno(session);
		_gnutls_read_log
		    ("READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
		     (int) ret, fd, err, ms);
		return errno_to_gerr(err, IS_DTLS(session));
	}

	if (ret > 0)
		return 0;
	else
		return GNUTLS_E_TIMEDOUT;
}
/* returns ciphertext which contains the headers too. This also
 * calculates the size in the header field.
 * 
 * If random pad != 0 then the random pad data will be appended.
 */
int
_gnutls_encrypt (gnutls_session_t session, const opaque * headers,
                 size_t headers_size, const opaque * data,
                 size_t data_size, opaque * ciphertext,
                 size_t ciphertext_size, 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 = (opaque*)data;
      comp.size = data_size;
    }
  else
    {
      /* Here comp is allocated and must be 
       * freed.
       */
      free_comp = 1;
      
      comp.size = ciphertext_size - headers_size;
      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);
      if (ret < 0)
        {
          gnutls_free(comp.data);
          return gnutls_assert_val(ret);
        }
      
      comp.size = ret;
    }

  ret = compressed_to_ciphertext (session, &ciphertext[headers_size],
                                       ciphertext_size - headers_size,
                                       &comp, type, params);

  if (free_comp)
    gnutls_free(comp.data);

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

  /* copy the headers */
  memcpy (ciphertext, headers, headers_size);
  
  if(IS_DTLS(session))
    _gnutls_write_uint16 (ret, &ciphertext[11]);
  else
    _gnutls_write_uint16 (ret, &ciphertext[3]);

  return ret + headers_size;
}
Example #13
0
/* returns the last stored handshake packet.
 */
static int get_last_packet(gnutls_session_t session, gnutls_handshake_description_t htype,
  handshake_buffer_st * hsk)
{
handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;

  if (IS_DTLS(session))
    {
      if (session->internals.handshake_recv_buffer_size == 0 ||
        (session->internals.dtls.hsk_read_seq != recv_buf[LAST_ELEMENT].sequence))
        goto timeout;

      if (htype != recv_buf[LAST_ELEMENT].htype)
        {
          hsk->htype = recv_buf[LAST_ELEMENT].htype;
          return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
        }

      else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
        recv_buf[LAST_ELEMENT].end_offset == recv_buf[LAST_ELEMENT].length -1) || 
        recv_buf[LAST_ELEMENT].length == 0)
        {
          session->internals.dtls.hsk_read_seq++;
          _gnutls_handshake_buffer_move(hsk, &recv_buf[LAST_ELEMENT]);
          session->internals.handshake_recv_buffer_size--;
          return 0;
        }
      else
        goto timeout;
    }
  else /* TLS */
    {
      if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length == recv_buf[0].data.length)
        {
          if (cmp_hsk_types(htype, recv_buf[0].htype) == 0)
            {
              hsk->htype = recv_buf[LAST_ELEMENT].htype;
              return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
            }

          _gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
          session->internals.handshake_recv_buffer_size--;
          return 0;
        }
      else
        return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
    }

timeout:
  if (time(0)-session->internals.dtls.handshake_start_time > session->internals.dtls.total_timeout/1000) 
    return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
  else
    {
      if (session->internals.dtls.blocking != 0)
        millisleep(50);
        
      return gnutls_assert_val(GNUTLS_E_AGAIN);
    }
}
Example #14
0
/* Increments the sequence value
 */
inline static int
sequence_increment(gnutls_session_t session, uint64 * value)
{
	if (IS_DTLS(session)) {
		return _gnutls_uint48pp(value);
	} else {
		return _gnutls_uint64pp(value);
	}
}
Example #15
0
/* This function is like read. But it does not return -1 on error.
 * It does return gnutls_errno instead.
 *
 * Flags are only used if the default recv() function is being used.
 */
static ssize_t
_gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
	      size_t size, gnutls_pull_func pull_func)
{
  if (IS_DTLS (session))
    /* Size is not passed, since a whole datagram will be read. */
    return _gnutls_dgram_read (session, bufel, pull_func);
  else
    return _gnutls_stream_read (session, bufel, size, pull_func);
}
Example #16
0
PRInt32
tls13_SendShortHeaderXtn(const sslSocket *ss,
                         TLSExtensionData *xtnData,
                         PRBool append, PRUint32 maxBytes)
{
    PRUint32 extension_len = 2 + 2; /* Type + length (0). */

    if (!ss->opt.enableShortHeaders) {
        return 0;
    }

    /* Presently this is incompatible with 0-RTT. We will fix if
     * it becomes more than an experiment. */
    if (ss->opt.enable0RttData) {
        return 0;
    }

    if (IS_DTLS(ss)) {
        return 0;
    }

    /* Don't send this if TLS 1.3 isn't at least possible. */
    if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
        /* This should only happen on the client. */
        PORT_Assert(!ss->sec.isServer);
        return 0;
    }

    SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension",
                SSL_GETPID(), ss->fd));

    if (maxBytes < extension_len) {
        PORT_Assert(0);
        return 0;
    }

    if (append) {
        SECStatus rv;

        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2);
        if (rv != SECSuccess)
            return -1;

        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
        if (rv != SECSuccess)
            return -1;

        xtnData->advertised[xtnData->numAdvertised++] =
            ssl_tls13_short_header_xtn;
    }

    return extension_len;
}
Example #17
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);
}
Example #18
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);
}
Example #19
0
int
_gnutls_record_buffer_get(content_type_t type,
			  gnutls_session_t session, uint8_t * data,
			  size_t length, uint8_t seq[8])
{
	gnutls_datum_t msg;
	mbuffer_st *bufel;

	if (length == 0 || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	bufel =
	    _mbuffer_head_get_first(&session->internals.record_buffer,
				    &msg);
	if (bufel == NULL)
		return
		    gnutls_assert_val
		    (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);

	if (type != bufel->type) {
		if (IS_DTLS(session))
			_gnutls_audit_log(session,
					  "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
					  _gnutls_packet2str(bufel->type),
					  (int) bufel->type,
					  _gnutls_packet2str(type),
					  (int) type);
		else
			_gnutls_debug_log("received unexpected packet: %s(%d)\n",
						_gnutls_packet2str(bufel->type), (int)bufel->type);

		_mbuffer_head_remove_bytes(&session->internals.
					   record_buffer, msg.size);
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
	}

	if (msg.size <= length)
		length = msg.size;

	if (seq)
		memcpy(seq, bufel->record_sequence.i, 8);

	memcpy(data, msg.data, length);
	_mbuffer_head_remove_bytes(&session->internals.record_buffer,
				   length);

	return length;
}
Example #20
0
SECStatus
tls13_HandleShortHeaderXtn(
    const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
    SECItem *data)
{
    SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension",
                SSL_GETPID(), ss->fd));

    /* The client might have asked for this, but we didn't negotiate TLS 1.3. */
    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
        return SECSuccess;
    }

    /* Presently this is incompatible with 0-RTT. We will fix if
     * it becomes more than an experiment. */
    if (ss->opt.enable0RttData) {
        return SECSuccess;
    }

    if (IS_DTLS(ss)) {
        PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
        return SECFailure;
    }

    if (data->len) {
        PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
        return SECFailure;
    }

    if (!ss->opt.enableShortHeaders) {
        /* Ignore. */
        return SECSuccess;
    }

    /* Keep track of negotiated extensions. */
    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;

    if (ss->sec.isServer) {
        SECStatus rv;

        rv = ssl3_RegisterExtensionSender(ss, xtnData,
                                          ssl_tls13_short_header_xtn,
                                          tls13_SendShortHeaderXtn);
        if (rv != SECSuccess) {
            return SECFailure;
        }
    }

    return SECSuccess;
}
Example #21
0
int
_gnutls_supported_compression_methods(gnutls_session_t session,
				      uint8_t * comp, size_t comp_size)
{
	unsigned int i, j;
	int tmp;

	if (comp_size < SUPPORTED_COMPRESSION_METHODS)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++) {
		if (IS_DTLS(session) && session->internals.priorities.compression.priority[i] != GNUTLS_COMP_NULL) {
			gnutls_assert();
			continue;
		}

		tmp =
		    _gnutls_compression_get_num(session->
						internals.priorities.
						compression.priority[i]);

		/* remove private compression algorithms, if requested.
		 */
		if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO &&
				  session->internals.enable_private == 0))
		{
			gnutls_assert();
			continue;
		}

		comp[j] = (uint8_t) tmp;
		j++;
	}

	if (j == 0) {
		gnutls_assert();
		return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
	}
	return j;
}
Example #22
0
/* @total: The sum of the data in giovec
 */
static ssize_t
_gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
	       unsigned giovec_cnt, unsigned total)
{
	int i;
	bool is_dtls = IS_DTLS(session);
	unsigned no_writev = 0;
	gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;

	reset_errno(session);

	if (session->internals.vec_push_func != NULL) {
		if (is_dtls && giovec_cnt > 1) {
			if (total > session->internals.dtls.mtu) {
				no_writev = 1;
			}
		}

		if (no_writev == 0) {
			i = session->internals.vec_push_func(fd, giovec, giovec_cnt);
		} else {
			i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 1);
		}
	} else if (session->internals.push_func != NULL) {
		i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
	} else
		return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);

	if (i == -1) {
		int err = get_errno(session);
		_gnutls_debug_log("WRITE: %d returned from %p, errno: %d\n",
				  i, fd, err);

		return errno_to_gerr(err, is_dtls);
	}
	return i;
}
Example #23
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 */
ssize_t
_gnutls_handshake_io_recv_int (gnutls_session_t session,
                               gnutls_handshake_description_t htype,
                               handshake_buffer_st * hsk)
{
  int ret;

  ret = get_last_packet(session, htype, hsk);
  if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
    {
      return gnutls_assert_val(ret);
    }

  /* try using the already existing records before
   * trying to receive.
   */
  ret = parse_record_buffered_msgs(session, htype, hsk);
  if (IS_DTLS(session))
    {
      if (ret >= 0)
        return ret;
    }
  else
    {
      if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && ret < 0) || ret >= 0)
        return gnutls_assert_val(ret);
    }

  /* if we don't have a complete message waiting for us, try 
   * receiving more */
  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype);
  if (ret < 0)
    return gnutls_assert_val_fatal(ret);

  return parse_record_buffered_msgs(session, htype, hsk); 
}
Example #24
0
/* Caller must hold the SpecWriteLock. */
SECStatus
ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
{
    ssl3CipherSpec *spec;

    PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));

    spec = ssl_CreateCipherSpec(ss, dir);
    if (!spec) {
        return SECFailure;
    }

    /* Set default versions.  This value will be used to generate and send
     * alerts if a version is not negotiated.  These values are overridden when
     * sending a ClientHello and when a version is negotiated. */
    spec->version = SSL_LIBRARY_VERSION_TLS_1_0;
    spec->recordVersion = IS_DTLS(ss)
                              ? SSL_LIBRARY_VERSION_DTLS_1_0_WIRE
                              : SSL_LIBRARY_VERSION_TLS_1_0;
    spec->cipherDef = &ssl_bulk_cipher_defs[cipher_null];
    PORT_Assert(spec->cipherDef->cipher == cipher_null);
    spec->macDef = &ssl_mac_defs[ssl_mac_null];
    PORT_Assert(spec->macDef->mac == ssl_mac_null);
    spec->cipher = Null_Cipher;

    spec->phase = "cleartext";
    dtls_InitRecvdRecords(&spec->recvdRecords);

    ssl_SaveCipherSpec(ss, spec);
    if (dir == CipherSpecRead) {
        ss->ssl3.crSpec = spec;
    } else {
        ss->ssl3.cwSpec = spec;
    }
    return SECSuccess;
}
Example #25
0
static int
parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
		       handshake_buffer_st * hsk)
{
	uint8_t *dataptr = NULL;	/* for realloc */
	size_t handshake_header_size =
	    HANDSHAKE_HEADER_SIZE(session), data_size, frag_size;

	/* Note: SSL2_HEADERS == 1 */
	if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	dataptr = _mbuffer_get_udata_ptr(bufel);

	/* if reading a client hello of SSLv2 */
#ifdef ENABLE_SSL2
	if (unlikely
	    (!IS_DTLS(session)
	     && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
		handshake_header_size = SSL2_HEADERS;	/* we've already read one byte */

		frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;	/* we've read the first byte */

		if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
			return
			    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);

		hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;

		hsk->sequence = 0;
		hsk->start_offset = 0;
		hsk->length = frag_size;
	} else
#endif
	{	/* TLS or DTLS handshake headers */


		hsk->rtype = hsk->htype = dataptr[0];

		/* we do not use DECR_LEN because we know
		 * that the packet has enough data.
		 */
		hsk->length = _gnutls_read_uint24(&dataptr[1]);

		if (IS_DTLS(session)) {
			hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
			hsk->start_offset =
			    _gnutls_read_uint24(&dataptr[6]);
			frag_size =
			    _gnutls_read_uint24(&dataptr[9]);
		} else {
			hsk->sequence = 0;
			hsk->start_offset = 0;
			frag_size =
			    MIN((_mbuffer_get_udata_size(bufel) -
				 handshake_header_size), hsk->length);
		}

		/* TLS1.3: distinguish server hello versus hello retry request.
		 * The epitome of slick protocol design. */
		if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) {
			if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE &&
			    memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
				hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
			}
		}
	}
	data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;

	if (frag_size > 0)
		hsk->end_offset = hsk->start_offset + frag_size - 1;
	else
		hsk->end_offset = 0;

	_gnutls_handshake_log
	    ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
	     session, _gnutls_handshake2str(hsk->htype),
	     (unsigned) hsk->htype, (int) hsk->length, (int) data_size,
	     hsk->start_offset, (int) frag_size,
	     (int) hsk->sequence);

	hsk->header_size = handshake_header_size;
	memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
	       handshake_header_size);

	if (hsk->length > 0 && (frag_size > data_size ||
				(frag_size > 0 &&
				 hsk->end_offset >= hsk->length))) {
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
	}
	else if (hsk->length == 0 && hsk->end_offset != 0
		 && hsk->start_offset != 0)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	return handshake_header_size;
}
Example #26
0
/* 
 * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
 *
 * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
 * It does return gnutls_errno instead.
 * This function reads data from the socket and keeps them in a buffer, of up to
 * max_record_recv_size. 
 *
 * This is not a general purpose function. It returns EXACTLY the data requested,
 * which are stored in a local (in the session) buffer.
 *
 * If the @ms parameter is non zero then this function will return before
 * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
 *
 */
ssize_t
_gnutls_io_read_buffered(gnutls_session_t session, size_t total,
			 content_type_t recv_type, unsigned int *ms)
{
	ssize_t ret;
	size_t min;
	mbuffer_st *bufel = NULL;
	size_t recvdata, readsize;

	if (total > max_record_recv_size(session) || total == 0) {
		gnutls_assert();
		return GNUTLS_E_RECORD_OVERFLOW;
	}

	/* calculate the actual size, ie. get the minimum of the
	 * buffered data and the requested data.
	 */
	min =
	    MIN(session->internals.record_recv_buffer.byte_length, total);
	if (min > 0) {
		/* if we have enough buffered data
		 * then just return them.
		 */
		if (min == total) {
			return min;
		}
	}

	/* min is over zero. recvdata is the data we must
	 * receive in order to return the requested data.
	 */
	recvdata = total - min;
	readsize = recvdata;

	/* Check if the previously read data plus the new data to
	 * receive are longer than the maximum receive buffer size.
	 */
	if ((session->internals.record_recv_buffer.byte_length +
	     recvdata) > max_record_recv_size(session)) {
		gnutls_assert();	/* internal error */
		return GNUTLS_E_INVALID_REQUEST;
	}

	/* READ DATA
	 */
	if (readsize > 0) {
		ret =
		    _gnutls_read(session, &bufel, readsize,
				 session->internals.pull_func, ms);

		/* return immediately if we got an interrupt or eagain
		 * error.
		 */
		if (ret < 0) {
			return gnutls_assert_val(ret);
		}

		if (ret == 0)	/* EOF */
			return gnutls_assert_val(0);

		/* copy fresh data to our buffer.
		 */
		_gnutls_read_log
		    ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
		     (int) session->internals.record_recv_buffer.
		     byte_length, (int) ret);
		_gnutls_read_log("RB: Requested %d bytes\n", (int) total);

		_mbuffer_enqueue(&session->internals.record_recv_buffer,
				 bufel);

		if (IS_DTLS(session))
			ret =
			    MIN(total,
				session->internals.record_recv_buffer.
				byte_length);
		else
			ret =
			    session->internals.record_recv_buffer.
			    byte_length;

		if ((ret > 0) && ((size_t) ret < total))	/* Short Read */
			return gnutls_assert_val(GNUTLS_E_AGAIN);
		else
			return ret;
	} else
		return gnutls_assert_val(0);
}
Example #27
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 */
ssize_t
_gnutls_handshake_io_recv_int(gnutls_session_t session,
			      gnutls_handshake_description_t htype,
			      handshake_buffer_st * hsk,
			      unsigned int optional)
{
	int ret;
	unsigned int tleft = 0;
	int retries = 7;

	ret = get_last_packet(session, htype, hsk, optional);
	if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED &&
	    ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
	    ret != GNUTLS_E_INT_CHECK_AGAIN) {
		return gnutls_assert_val(ret);
	}

	/* try using the already existing records before
	 * trying to receive.
	 */
	ret = _gnutls_parse_record_buffered_msgs(session);

	if (ret == 0) {
		ret = get_last_packet(session, htype, hsk, optional);
	}

	if (IS_DTLS(session)) {
		if (ret >= 0)
			return ret;
	} else {
		if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
		     && ret < 0) || ret >= 0)
			return gnutls_assert_val(ret);
	}

	if (htype != (gnutls_handshake_description_t) -1) {
		ret = handshake_remaining_time(session);
		if (ret < 0)
			return gnutls_assert_val(ret);
		tleft = ret;
	}

	do {
		/* if we don't have a complete message waiting for us, try 
		 * receiving more */
		ret =
		    _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
					    tleft);
		if (ret < 0)
			return gnutls_assert_val_fatal(ret);

		ret = _gnutls_parse_record_buffered_msgs(session);
		if (ret == 0) {
			ret = get_last_packet(session, htype, hsk, optional);
		}
		/* we put an upper limit (retries) to the number of partial handshake
		 * messages in a record packet. */
	} while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);

	if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
		ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
	}

	return ret;
}
Example #28
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 *
 * htype is the next handshake packet expected.
 */
int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
{
	gnutls_datum_t msg;
	mbuffer_st *bufel = NULL, *prev = NULL;
	int ret;
	size_t data_size;
	handshake_buffer_st *recv_buf =
	    session->internals.handshake_recv_buffer;

	bufel =
	    _mbuffer_head_get_first(&session->internals.record_buffer,
				    &msg);
	if (bufel == NULL)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;

	if (!IS_DTLS(session)) {
		ssize_t append, header_size;

		do {
			if (bufel->type != GNUTLS_HANDSHAKE)
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_PACKET);

			if (unlikely
			    (session->internals.handshake_recv_buffer_size == 0 &&
			     msg.size < HANDSHAKE_HEADER_SIZE(session) &&
			     session->internals.handshake_header_recv_buffer.byte_length <
			     HANDSHAKE_HEADER_SIZE(session) - msg.size)) {
				bufel = _mbuffer_head_pop_first(&session->internals.record_buffer);
				_mbuffer_enqueue(&session->internals.handshake_header_recv_buffer,
						 bufel);
				break;
			} else if (session->internals.handshake_recv_buffer_size >
				   0 && recv_buf[0].length > recv_buf[0].data.length) {
				/* this is the rest of a previous message */
				append = MIN(msg.size,
					     recv_buf[0].length -
					     recv_buf[0].data.length);

				ret =
				    _gnutls_buffer_append_data(&recv_buf
							       [0].data,
							       msg.data,
							       append);
				if (ret < 0)
					return gnutls_assert_val(ret);

				_mbuffer_head_remove_bytes(&session->
							   internals.
							   record_buffer,
							   append);
			} else {	/* received new message */
				if (unlikely
				    (session->internals.
				     handshake_header_recv_buffer.length > 0)) {
					bufel = _mbuffer_head_pop_first(&session->internals.
									record_buffer);
					_mbuffer_enqueue(&session->internals.
							 handshake_header_recv_buffer,
							 bufel);
					ret = _mbuffer_linearize_align16(&session->internals.
									 handshake_header_recv_buffer,
									 get_total_headers(session));
					if (ret < 0)
						return gnutls_assert_val(ret);
					bufel = _mbuffer_head_pop_first(&session->internals.
									handshake_header_recv_buffer);
					_mbuffer_head_push_first(&session->internals.
								 record_buffer,
								 bufel);
				}

				ret =
				    parse_handshake_header(session, bufel,
							   &recv_buf[0]);
				if (ret < 0)
					return gnutls_assert_val(ret);

				header_size = ret;
				session->internals.
				    handshake_recv_buffer_size = 1;

				_mbuffer_set_uhead_size(bufel,
							header_size);

				data_size =
				    MIN(recv_buf[0].length,
					_mbuffer_get_udata_size(bufel));
				ret =
				    _gnutls_buffer_append_data(&recv_buf
							       [0].data,
							       _mbuffer_get_udata_ptr
							       (bufel),
							       data_size);
				if (ret < 0)
					return gnutls_assert_val(ret);
				_mbuffer_set_uhead_size(bufel, 0);
				_mbuffer_head_remove_bytes(&session->
							   internals.
							   record_buffer,
							   data_size +
							   header_size);
			}

			/* if packet is complete then return it
			 */
			if (recv_buf[0].length == recv_buf[0].data.length) {
				return 0;
			}
			bufel =
			    _mbuffer_head_get_first(&session->internals.
						    record_buffer, &msg);
		}
		while (bufel != NULL);

		/* if we are here it means that the received packets were not
		 * enough to complete the handshake packet.
		 */
		return gnutls_assert_val(GNUTLS_E_AGAIN);
	} else {		/* DTLS */

		handshake_buffer_st tmp;

		do {
			/* we now 
			 * 0. parse headers
			 * 1. insert to handshake_recv_buffer
			 * 2. sort handshake_recv_buffer on sequence numbers
			 * 3. return first packet if completed or GNUTLS_E_AGAIN.
			 */
			do {
				if (bufel->type != GNUTLS_HANDSHAKE) {
					gnutls_assert();
					goto next;	/* ignore packet */
				}

				_gnutls_handshake_buffer_init(&tmp);

				ret =
				    parse_handshake_header(session, bufel,
							   &tmp);
				if (ret < 0) {
					gnutls_assert();
					_gnutls_audit_log(session,
							  "Invalid handshake packet headers. Discarding.\n");
					break;
				}

				_mbuffer_consume(&session->internals.
						 record_buffer, bufel,
						 ret);

				data_size =
				    MIN(tmp.length,
					tmp.end_offset - tmp.start_offset +
					1);

				ret =
				    _gnutls_buffer_append_data(&tmp.data,
							       _mbuffer_get_udata_ptr
							       (bufel),
							       data_size);
				if (ret < 0)
					return gnutls_assert_val(ret);

				_mbuffer_consume(&session->internals.
						 record_buffer, bufel,
						 data_size);

				ret =
				    merge_handshake_packet(session, &tmp);
				if (ret < 0)
					return gnutls_assert_val(ret);

			}
			while (_mbuffer_get_udata_size(bufel) > 0);

			prev = bufel;
			bufel =
			    _mbuffer_dequeue(&session->internals.
					     record_buffer, bufel);

			_mbuffer_xfree(&prev);
			continue;

		      next:
			bufel = _mbuffer_head_get_next(bufel, NULL);
		}
		while (bufel != NULL);

		/* sort in descending order */
		if (session->internals.handshake_recv_buffer_size > 1)
			qsort(recv_buf,
			      session->internals.
			      handshake_recv_buffer_size,
			      sizeof(recv_buf[0]), handshake_compare);

		while (session->internals.handshake_recv_buffer_size > 0 &&
		       recv_buf[LAST_ELEMENT].sequence <
		       session->internals.dtls.hsk_read_seq) {
			_gnutls_audit_log(session,
					  "Discarded replayed handshake packet with sequence %d\n",
					  recv_buf[LAST_ELEMENT].sequence);
			_gnutls_handshake_buffer_clear(&recv_buf
						       [LAST_ELEMENT]);
			session->internals.handshake_recv_buffer_size--;
		}

		return 0;
	}
}
Example #29
0
/* returns the last stored handshake packet.
 */
static int get_last_packet(gnutls_session_t session,
			   gnutls_handshake_description_t htype,
			   handshake_buffer_st * hsk,
			   unsigned int optional)
{
	handshake_buffer_st *recv_buf =
	    session->internals.handshake_recv_buffer;

	if (IS_DTLS(session)) {
		if (session->internals.handshake_recv_buffer_size == 0 ||
		    (session->internals.dtls.hsk_read_seq !=
		     recv_buf[LAST_ELEMENT].sequence))
			goto timeout;

		if (htype != recv_buf[LAST_ELEMENT].htype) {
			if (optional == 0)
				_gnutls_audit_log(session,
						  "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
						  _gnutls_handshake2str
						  (recv_buf[0].htype),
						  (int) recv_buf[0].htype,
						  _gnutls_handshake2str
						  (htype), (int) htype);

			return
			    gnutls_assert_val
			    (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
		}

		else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
			  recv_buf[LAST_ELEMENT].end_offset ==
			  recv_buf[LAST_ELEMENT].length - 1)
			 || recv_buf[LAST_ELEMENT].length == 0) {
			session->internals.dtls.hsk_read_seq++;
			_gnutls_handshake_buffer_move(hsk,
						      &recv_buf
						      [LAST_ELEMENT]);
			session->internals.handshake_recv_buffer_size--;
			return 0;
		} else {
			/* if we don't have a complete handshake message, but we
			 * have queued data waiting, try again to reconstruct the
			 * handshake packet, using the queued */
			if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
			    record_check_unprocessed(session) > 0)
				return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
			else
				goto timeout;
		}
	} else {		/* TLS */

		if (session->internals.handshake_recv_buffer_size > 0
		    && recv_buf[0].length == recv_buf[0].data.length) {
			if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
			}

			_gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
			session->internals.handshake_recv_buffer_size--;
			return 0;
		} else
			return
			    gnutls_assert_val
			    (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
	}

      timeout:
	RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
}
Example #30
0
static int
parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
		       handshake_buffer_st * hsk)
{
	uint8_t *dataptr = NULL;	/* for realloc */
	size_t handshake_header_size =
	    HANDSHAKE_HEADER_SIZE(session), data_size;

	/* Note: SSL2_HEADERS == 1 */
	if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	dataptr = _mbuffer_get_udata_ptr(bufel);

	/* if reading a client hello of SSLv2 */
#ifdef ENABLE_SSL2
	if (unlikely
	    (!IS_DTLS(session)
	     && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
		handshake_header_size = SSL2_HEADERS;	/* we've already read one byte */

		hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size;	/* we've read the first byte */

		if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
			return
			    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);

		hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;

		hsk->sequence = 0;
		hsk->start_offset = 0;
		hsk->end_offset = hsk->length;
	} else
#endif
	{		/* TLS or DTLS handshake headers */


		hsk->htype = dataptr[0];

		/* we do not use DECR_LEN because we know
		 * that the packet has enough data.
		 */
		hsk->length = _gnutls_read_uint24(&dataptr[1]);
		handshake_header_size = HANDSHAKE_HEADER_SIZE(session);

		if (IS_DTLS(session)) {
			hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
			hsk->start_offset =
			    _gnutls_read_uint24(&dataptr[6]);
			hsk->end_offset =
			    hsk->start_offset +
			    _gnutls_read_uint24(&dataptr[9]);
		} else {
			hsk->sequence = 0;
			hsk->start_offset = 0;
			hsk->end_offset =
			    MIN((_mbuffer_get_udata_size(bufel) -
				 handshake_header_size), hsk->length);
		}
	}
	data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;

	/* make the length offset */
	if (hsk->end_offset > 0)
		hsk->end_offset--;

	_gnutls_handshake_log
	    ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
	     session, _gnutls_handshake2str(hsk->htype),
	     (unsigned) hsk->htype, (int) hsk->length, (int) data_size,
	     hsk->start_offset, hsk->end_offset - hsk->start_offset + 1,
	     (int) hsk->sequence);

	hsk->header_size = handshake_header_size;
	memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
	       handshake_header_size);

	if (hsk->length > 0 &&
	    (hsk->end_offset - hsk->start_offset >= data_size))
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	if (hsk->length > 0 && (hsk->start_offset >= hsk->end_offset ||
				hsk->end_offset - hsk->start_offset >=
				data_size
				|| hsk->end_offset >= hsk->length))
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
	else if (hsk->length == 0 && hsk->end_offset != 0
		 && hsk->start_offset != 0)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	return handshake_header_size;
}