Esempio n. 1
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);
    }
}
Esempio n. 2
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);
}
Esempio n. 3
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 */
static int
parse_record_buffered_msgs (gnutls_session_t session,
                               gnutls_handshake_description_t htype,
                               handshake_buffer_st * hsk)
{
  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 remain, append, header_size;

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

          /* if we have a half received message the complete it.
           */
          remain =  recv_buf[0].length -
                recv_buf[0].data.length;

          /* this is the rest of a previous message */
          if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > 0 && remain > 0)
            {
              if (msg.size <= remain)
                append = msg.size;
              else
                append = remain;
                  
              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 */
            {
              ret = parse_handshake_header(session, bufel, htype, &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 (cmp_hsk_types(htype, recv_buf[0].htype) == 0)
                { /* an unexpected packet */
                  hsk->htype = recv_buf[0].htype;
                  return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
                }

            }

          /* if packet is complete then return it
           */
          if (recv_buf[0].length ==
                recv_buf[0].data.length)
            {
              return get_last_packet(session, htype, hsk);
            }
          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, htype, &tmp);
              if (ret < 0)
                {
                  gnutls_assert();
                  _gnutls_audit_log("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("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 get_last_packet(session, htype, hsk);
    }
}