Exemple #1
0
/* This function will check if the received record type is
 * the one we actually expect and adds it to the proper
 * buffer. The bufel will be deinitialized after calling
 * this function, even if it fails.
 */
static int
record_add_to_buffers (gnutls_session_t session,
                   struct tls_record_st *recv, content_type_t type,
                   gnutls_handshake_description_t htype, 
                   uint64* seq,
                   mbuffer_st* bufel)
{

  int ret;

  if ((recv->type == type)
      && (type == GNUTLS_APPLICATION_DATA ||
          type == GNUTLS_CHANGE_CIPHER_SPEC ||
          type == GNUTLS_HANDSHAKE))
    {
      _gnutls_record_buffer_put (session, type, seq, bufel);
      
      /* if we received application data as expected then we
       * deactivate the async timer */
      _dtls_async_timer_delete(session);
    }
  else
    {
      /* if the expected type is different than the received 
       */
      switch (recv->type)
        {
        case GNUTLS_ALERT:
          if (bufel->msg.size < 2)
            {
              ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
              goto unexpected_packet;
            }

          _gnutls_record_log
            ("REC[%p]: Alert[%d|%d] - %s - was received\n", session,
             bufel->msg.data[0], bufel->msg.data[1], gnutls_alert_get_name ((int) bufel->msg.data[1]));

          session->internals.last_alert = bufel->msg.data[1];

          /* if close notify is received and
           * the alert is not fatal
           */
          if (bufel->msg.data[1] == GNUTLS_A_CLOSE_NOTIFY && bufel->msg.data[0] != GNUTLS_AL_FATAL)
            {
              /* If we have been expecting for an alert do 
               */
              session->internals.read_eof = 1;
              ret = GNUTLS_E_SESSION_EOF;
              goto cleanup;
            }
          else
            {
              /* if the alert is FATAL or WARNING
               * return the apropriate message
               */

              gnutls_assert ();
              ret = GNUTLS_E_WARNING_ALERT_RECEIVED;
              if (bufel->msg.data[0] == GNUTLS_AL_FATAL)
                {
                  session_unresumable (session);
                  session_invalidate (session);
                  ret = gnutls_assert_val(GNUTLS_E_FATAL_ALERT_RECEIVED);
                }
              goto cleanup;
            }
          break;

        case GNUTLS_CHANGE_CIPHER_SPEC:
          if (!(IS_DTLS(session)))
            return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
            
          _gnutls_record_buffer_put (session, recv->type, seq, bufel);

          break;

#ifdef ENABLE_HEARTBEAT
        case GNUTLS_HEARTBEAT:
	    ret = _gnutls_heartbeat_handle (session, bufel);
	    goto cleanup;
#endif

        case GNUTLS_APPLICATION_DATA:
          if (session->internals.initial_negotiation_completed == 0)
            {
              ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
              goto unexpected_packet;
            }


          /* the got_application data is only returned
           * if expecting client hello (for rehandshake
           * reasons). Otherwise it is an unexpected packet
           */
          if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO
                                       && type == GNUTLS_HANDSHAKE))
            {
              /* even if data is unexpected put it into the buffer */
              if ((ret =
                   _gnutls_record_buffer_put (session, recv->type, seq,
                                              bufel)) < 0)
                {
                  gnutls_assert ();
                  goto cleanup;
                }

              return gnutls_assert_val(GNUTLS_E_GOT_APPLICATION_DATA);
            }
          else
            {
              ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
              goto unexpected_packet;
            }

          break;

        case GNUTLS_HANDSHAKE:
          /* In DTLS we might receive a handshake replay from the peer to indicate
           * the our last TLS handshake messages were not received.
           */
          if (IS_DTLS(session))
            {
              if (type == GNUTLS_CHANGE_CIPHER_SPEC)
                {
                  ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
                  goto unexpected_packet;
                }

              if (_dtls_is_async(session) && _dtls_async_timer_active(session))
                {
                  if (session->security_parameters.entity == GNUTLS_SERVER &&
                      bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO)
                    {
                      /* client requested rehandshake. Delete the timer */
                      _dtls_async_timer_delete(session);
                    }
                  else
                    {
                      session->internals.recv_state = RECV_STATE_DTLS_RETRANSMIT;
                      ret = _dtls_retransmit(session);
                      if (ret == 0) 
                        {
                          session->internals.recv_state = RECV_STATE_0;
                          ret = gnutls_assert_val(GNUTLS_E_AGAIN);
                          goto unexpected_packet;
                        }
                      goto cleanup;
                    }
                }
            }

          /* This is legal if HELLO_REQUEST is received - and we are a client.
           * If we are a server, a client may initiate a renegotiation at any time.
           */
          if (session->security_parameters.entity == GNUTLS_SERVER &&
              bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO)
            {
              gnutls_assert ();
              ret =
                _gnutls_record_buffer_put (session, recv->type, seq, bufel);
              if (ret < 0)
                {
                  gnutls_assert ();
                  goto cleanup;
                }
              return GNUTLS_E_REHANDSHAKE;
            }

          /* If we are already in a handshake then a Hello
           * Request is illegal. But here we don't really care
           * since this message will never make it up here.
           */

          /* So we accept it, if it is a Hello. If not, this will
           * fail and trigger flight retransmissions after some time. */
          ret = _gnutls_recv_hello_request (session, bufel->msg.data, bufel->msg.size);
          goto unexpected_packet;

          break;
        default:

          _gnutls_record_log
            ("REC[%p]: Received unexpected packet %d (%s) expecting %d (%s)\n",
             session, recv->type, _gnutls_packet2str(recv->type), type, _gnutls_packet2str(type));

          gnutls_assert ();
          ret = GNUTLS_E_UNEXPECTED_PACKET;
          goto unexpected_packet;
        }
    }

  return 0;

unexpected_packet:
  if (IS_DTLS(session) && ret != GNUTLS_E_REHANDSHAKE)
    {
      _mbuffer_xfree(&bufel);
      RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, ret);
    }

cleanup:
  _mbuffer_xfree(&bufel);
  return ret;

}
Exemple #2
0
/* This function will check if the received record type is
 * the one we actually expect.
 */
static int
record_check_type (gnutls_session_t session,
                   content_type_t recv_type, content_type_t type,
                   gnutls_handshake_description_t htype, opaque * data,
                   int data_size)
{

  int ret;

  if ((recv_type == type)
      && (type == GNUTLS_APPLICATION_DATA ||
          type == GNUTLS_HANDSHAKE || type == GNUTLS_INNER_APPLICATION))
    {
      _gnutls_record_buffer_put (type, session, (void *) data, data_size);
    }
  else
    {
      switch (recv_type)
        {
        case GNUTLS_ALERT:

          _gnutls_record_log
            ("REC[%p]: Alert[%d|%d] - %s - was received\n", session,
             data[0], data[1], gnutls_alert_get_name ((int) data[1]));

          session->internals.last_alert = data[1];

          /* if close notify is received and
           * the alert is not fatal
           */
          if (data[1] == GNUTLS_A_CLOSE_NOTIFY && data[0] != GNUTLS_AL_FATAL)
            {
              /* If we have been expecting for an alert do 
               */
              session->internals.read_eof = 1;
              return GNUTLS_E_INT_RET_0;        /* EOF */
            }
          else
            {

              /* if the alert is FATAL or WARNING
               * return the apropriate message
               */

              gnutls_assert ();
              ret = GNUTLS_E_WARNING_ALERT_RECEIVED;
              if (data[0] == GNUTLS_AL_FATAL)
                {
                  session_unresumable (session);
                  session_invalidate (session);
                  ret = GNUTLS_E_FATAL_ALERT_RECEIVED;
                }

              return ret;
            }
          break;

        case GNUTLS_CHANGE_CIPHER_SPEC:
          /* this packet is now handled in the recv_int()
           * function
           */
          gnutls_assert ();

          return GNUTLS_E_UNEXPECTED_PACKET;

        case GNUTLS_APPLICATION_DATA:
          if (session->internals.initial_negotiation_completed == 0)
            {
              return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
            }

          /* even if data is unexpected put it into the buffer */
          if ((ret =
               _gnutls_record_buffer_put (recv_type, session,
                                          (void *) data, data_size)) < 0)
            {
              gnutls_assert ();
              return ret;
            }

          /* the got_application data is only returned
           * if expecting client hello (for rehandshake
           * reasons). Otherwise it is an unexpected packet
           */
          if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO
                                       && type == GNUTLS_HANDSHAKE))
            return GNUTLS_E_GOT_APPLICATION_DATA;
          else
            {
              gnutls_assert ();
              return GNUTLS_E_UNEXPECTED_PACKET;
            }

          break;
        case GNUTLS_HANDSHAKE:
          /* This is legal if HELLO_REQUEST is received - and we are a client.
           * If we are a server, a client may initiate a renegotiation at any time.
           */
          if (session->security_parameters.entity == GNUTLS_SERVER)
            {
              gnutls_assert ();
              ret =
                _gnutls_record_buffer_put (recv_type, session, (void *) data,
                                           data_size);
              if (ret < 0)
                {
                  gnutls_assert ();
                  return ret;
                }
              return GNUTLS_E_REHANDSHAKE;
            }

          /* If we are already in a handshake then a Hello
           * Request is illegal. But here we don't really care
           * since this message will never make it up here.
           */

          /* So we accept it */
          return _gnutls_recv_hello_request (session, data, data_size);

          break;
        case GNUTLS_INNER_APPLICATION:
          /* even if data is unexpected put it into the buffer */
          if ((ret = _gnutls_record_buffer_put (recv_type, session,
                                                (void *) data,
                                                data_size)) < 0)
            {
              gnutls_assert ();
              return ret;
            }
          gnutls_assert ();
          return GNUTLS_E_UNEXPECTED_PACKET;
          break;
        default:

          _gnutls_record_log
            ("REC[%p]: Received Unknown packet %d expecting %d\n",
             session, recv_type, type);

          gnutls_assert ();
          return GNUTLS_E_INTERNAL_ERROR;
        }
    }

  return 0;

}