Commit message: None
CVE: CVE-2008-1950
CWE: CWE-189
Vulnerability description: Integer signedness error in the _gnutls_ciphertext2compressed function in lib/gnutls_cipher.c in libgnutls in GnuTLS before 2.2.4 allows remote attackers to cause a denial of service (buffer over-read and crash) via a certain integer value in the Random field in an encrypted Client Hello message within a TLS record with an invalid Record Length, which leads to an invalid cipher padding length, aka GNUTLS-SA-2008-1-3.

Project: savannah

_gnutls_server_name_recv_params (gnutls_session_t session,
				 const opaque * data, size_t _data_size)
{
  int i;
  const unsigned char *p;
  uint16_t len, type;
  ssize_t data_size = _data_size;
  int server_names = 0;

  if (session->security_parameters.entity == GNUTLS_SERVER)
    {
      DECR_LENGTH_RET (data_size, 2, 0);
      len = _gnutls_read_uint16 (data);

      if (len != data_size)
	{
	  /* This is unexpected packet length, but
	   * just ignore it, for now.
	   */
	  gnutls_assert ();
	  return 0;
	}

      p = data + 2;

      /* Count all server_names in the packet. */
      while (data_size > 0)
	{
	  DECR_LENGTH_RET (data_size, 1, 0);
	  p++;

	  DECR_LEN (data_size, 2);
          len = _gnutls_read_uint16 (p);
          p += 2;
 
         if (len > 0)
           {
             DECR_LENGTH_RET (data_size, len, 0);
             server_names++;
             p += len;
           }
         else
           _gnutls_handshake_log
             ("HSK[%x]: Received zero size server name (under attack?)\n",
              session);
 
       }

      /* we cannot accept more server names.
       */
      if (server_names > MAX_SERVER_NAME_EXTENSIONS)
       {
         _gnutls_handshake_log
           ("HSK[%x]: Too many server names received (under attack?)\n",
            session);
         server_names = MAX_SERVER_NAME_EXTENSIONS;
        }
 
       session->security_parameters.extensions.server_names_size =

       if (server_names == 0)
        return 0;               /* no names found */
 
 
       p = data + 2;
       for (i = 0; i < server_names; i++)
			  server_names[i].name, p, len);
		  session->security_parameters.extensions.
		    server_names[i].name_length = len;
		  session->security_parameters.extensions.
		    server_names[i].type = GNUTLS_NAME_DNS;
		  break;
		}
	    }

Project: savannah

_gnutls_ciphertext2compressed (gnutls_session_t session,
			       opaque * compress_data,
			       int compress_size,
			       gnutls_datum_t ciphertext, uint8_t type)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length;
  digest_hd_st td;
  uint16_t blocksize;
  int ret, i, pad_failed = 0;
  uint8_t major, minor;
  gnutls_protocol_t ver;
  int hash_size =
    _gnutls_hash_get_algo_len (session->security_parameters.
			       read_mac_algorithm);

  ver = gnutls_protocol_get_version (session);
  minor = _gnutls_version_get_minor (ver);
  major = _gnutls_version_get_major (ver);

  blocksize = _gnutls_cipher_get_block_size (session->security_parameters.
					     read_bulk_cipher_algorithm);

  /* initialize MAC 
   */
  ret = mac_init (&td, session->security_parameters.read_mac_algorithm,
		 session->connection_state.read_mac_secret.data,
		 session->connection_state.read_mac_secret.size, ver);

  if (ret < 0
      && session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      gnutls_assert ();
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
  if (ciphertext.size < (unsigned) blocksize + hash_size)
    {
      _gnutls_record_log
       ("REC[%x]: Short record length %d < %d + %d (under attack?)\n",
        session, ciphertext.size, blocksize, hash_size);
      gnutls_assert ();
      return GNUTLS_E_DECRYPTION_FAILED;
    }
 
   /* actual decryption (inplace)
    */
	{
	  gnutls_assert ();
	  return ret;
	}

      length = ciphertext.size - hash_size;

      break;
    case CIPHER_BLOCK:
      if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
	{
	  gnutls_assert ();
	  return GNUTLS_E_DECRYPTION_FAILED;
	}

      if ((ret = _gnutls_cipher_decrypt (&session->connection_state.
					 read_cipher_state,
					 ciphertext.data,
					 ciphertext.size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      /* ignore the IV in TLS 1.1.
       */
      if (session->security_parameters.version >= GNUTLS_TLS1_1)
	{
	  ciphertext.size -= blocksize;
	  ciphertext.data += blocksize;

	  if (ciphertext.size == 0)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_DECRYPTION_FAILED;
	    }
	}

      pad = ciphertext.data[ciphertext.size - 1] + 1;	/* pad */

      length = ciphertext.size - hash_size - pad;

      if (pad > ciphertext.size - hash_size)
	{
	  gnutls_assert ();
 
       pad = ciphertext.data[ciphertext.size - 1] + 1;  /* pad */
 
      if ((int)pad > (int)ciphertext.size - hash_size)
        {
          gnutls_assert ();
          /* We do not fail here. We check below for the
       */
      if (ver >= GNUTLS_TLS1 && pad_failed == 0)
          pad_failed = GNUTLS_E_DECRYPTION_FAILED;
        }
 
      length = ciphertext.size - hash_size - pad;

       /* Check the pading bytes (TLS 1.x)
        */
       if (ver >= GNUTLS_TLS1 && pad_failed == 0)
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  if (length < 0)
    length = 0;
  c_length = _gnutls_conv_uint16 ((uint16_t) length);

  /* Pass the type, version, length and compressed through
   * MAC.
   */
  if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      _gnutls_hmac (&td,
		    UINT64DATA (session->connection_state.
				read_sequence_number), 8);

      _gnutls_hmac (&td, &type, 1);
      if (ver >= GNUTLS_TLS1)
	{			/* TLS 1.x */
	  _gnutls_hmac (&td, &major, 1);
	  _gnutls_hmac (&td, &minor, 1);
	}
      _gnutls_hmac (&td, &c_length, 2);

      if (length > 0)
	_gnutls_hmac (&td, ciphertext.data, length);

      mac_deinit (&td, MAC, ver);
    }

  /* This one was introduced to avoid a timing attack against the TLS
   * 1.0 protocol.
   */
  if (pad_failed != 0)
    return pad_failed;

  /* HMAC was not the same. 
   */
  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  /* copy the decrypted stuff to compress_data.
   */
  if (compress_size < length)
    {
      gnutls_assert ();
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }
  memcpy (compress_data, ciphertext.data, length);

  return length;
}

Project: savannah

_gnutls_recv_handshake_header (gnutls_session_t session,
			       gnutls_handshake_description_t type,
			       gnutls_handshake_description_t * recv_type)
{
  int ret;
  uint32_t length32 = 0;
  uint8_t *dataptr = NULL;	/* for realloc */
  size_t handshake_header_size = HANDSHAKE_HEADER_SIZE;

  /* if we have data into the buffer then return them, do not read the next packet.
   * In order to return we need a full TLS handshake header, or in case of a version 2
   * packet, then we return the first byte.
   */
  if (session->internals.handshake_header_buffer.header_size ==
      handshake_header_size || (session->internals.v2_hello != 0
				&& type == GNUTLS_HANDSHAKE_CLIENT_HELLO
				&& session->internals.
				handshake_header_buffer.packet_length > 0))
    {
 
       *recv_type = session->internals.handshake_header_buffer.recv_type;
 
      if (*recv_type != type)
       {
         gnutls_assert ();
         _gnutls_handshake_log
           ("HSK[%x]: Handshake type mismatch (under attack?)\n", session);
         return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
       }

       return session->internals.handshake_header_buffer.packet_length;
     }
      ret =
	_gnutls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE,
				       type, dataptr, SSL2_HEADERS);

      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      /* The case ret==0 is caught here.
       */
      if (ret != SSL2_HEADERS)
	{
	  gnutls_assert ();
	  return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}
      session->internals.handshake_header_buffer.header_size = SSL2_HEADERS;
    }