Commit message: Fix GNUTLS-SA-2008-1 security vulnerabilities.
See http://www.gnu.org/software/gnutls/security.html for updates.
CVE: CVE-2008-1948
CWE: CWE-189
Vulnerability description: The _gnutls_server_name_recv_params function in lib/ext_server_name.c in libgnutls in gnutls-serv in GnuTLS before 2.2.4 does not properly calculate the number of Server Names in a TLS 1.0 Client Hello message during extension handling, which allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a zero value for the length of Server Names, which leads to a buffer overflow in session resumption data in the pack_security_parameters function, aka GNUTLS-SA-2008-1-1.

Project: gnutls
File: ext_server_name.c

_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 =
	server_names;
      if (server_names == 0)
	return 0;		/* no names found */


      p = data + 2;
      for (i = 0; i < server_names; i++)
	{
	  type = *p;
	  p++;

	  len = _gnutls_read_uint16 (p);
	  p += 2;

	  switch (type)
	    {
	    case 0:		/* NAME_DNS */
	      if (len <= MAX_SERVER_NAME_SIZE)
		{
		  memcpy (session->security_parameters.extensions.
			  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;
		}
	    }

	  /* move to next record */
	  p += len;
	}
    }
  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_recv_supplemental (gnutls_session_t session)
{
  uint8_t *data = NULL;
  int datalen = 0;
  int ret;

  _gnutls_debug_log ("EXT[%x]: Expecting supplemental data\n", session);

  ret = _gnutls_recv_handshake (session, &data, &datalen,
				GNUTLS_HANDSHAKE_SUPPLEMENTAL,
				OPTIONAL_PACKET);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  ret = _gnutls_parse_supplemental (session, data, datalen);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  gnutls_free (data);

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_handshake_client (gnutls_session_t session)
{
  int ret = 0;

#ifdef HANDSHAKE_DEBUG
  char buf[64];

  if (session->internals.resumed_security_parameters.session_id_size > 0)
    _gnutls_handshake_log ("HSK[%x]: Ask to resume: %s\n", session,
			   _gnutls_bin2hex (session->internals.
					    resumed_security_parameters.
					    session_id,
					    session->internals.
					    resumed_security_parameters.
					    session_id_size, buf,
					    sizeof (buf)));
#endif

  switch (STATE)
    {
    case STATE0:
    case STATE1:
      ret = _gnutls_send_hello (session, AGAIN (STATE1));
      STATE = STATE1;
      IMED_RET ("send hello", ret);

    case STATE2:
      /* receive the server hello */
      ret =
	_gnutls_recv_handshake (session, NULL, NULL,
				GNUTLS_HANDSHAKE_SERVER_HELLO,
				MANDATORY_PACKET);
      STATE = STATE2;
      IMED_RET ("recv hello", ret);

    case STATE70:
      if (session->security_parameters.extensions.do_recv_supplemental)
	{
	  ret = _gnutls_recv_supplemental (session);
	  STATE = STATE70;
	  IMED_RET ("recv supplemental", ret);
	}

    case STATE3:
      /* RECV CERTIFICATE */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_server_certificate (session);
      STATE = STATE3;
      IMED_RET ("recv server certificate", ret);

    case STATE4:
      /* receive the server key exchange */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_server_kx_message (session);
      STATE = STATE4;
      IMED_RET ("recv server kx message", ret);

    case STATE5:
      /* receive the server certificate request - if any 
       */

      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_server_certificate_request (session);
      STATE = STATE5;
      IMED_RET ("recv server certificate request message", ret);

    case STATE6:
      /* receive the server hello done */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret =
	  _gnutls_recv_handshake (session, NULL, NULL,
				  GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
				  MANDATORY_PACKET);
      STATE = STATE6;
      IMED_RET ("recv server hello done", ret);

    case STATE71:
      if (session->security_parameters.extensions.do_send_supplemental)
	{
	  ret = _gnutls_send_supplemental (session, AGAIN (STATE71));
	  STATE = STATE71;
	  IMED_RET ("send supplemental", ret);
	}

    case STATE7:
      /* send our certificate - if any and if requested
       */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_send_client_certificate (session, AGAIN (STATE7));
      STATE = STATE7;
      IMED_RET ("send client certificate", ret);

    case STATE8:
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_send_client_kx_message (session, AGAIN (STATE8));
      STATE = STATE8;
      IMED_RET ("send client kx", ret);

    case STATE9:
      /* send client certificate verify */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret =
	  _gnutls_send_client_certificate_verify (session, AGAIN (STATE9));
      STATE = STATE9;
      IMED_RET ("send client certificate verify", ret);

      STATE = STATE0;
    default:
      break;
    }


  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_recv_hello (gnutls_session_t session, opaque * data, int datalen)
{
  int ret;

  if (session->security_parameters.entity == GNUTLS_CLIENT)
    {
      ret = _gnutls_read_server_hello (session, data, datalen);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
    }
  else
    {				/* Server side reading a client hello */

      ret = _gnutls_read_client_hello (session, data, datalen);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
    }

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

gnutls_handshake_get_last_in (gnutls_session_t session)
{
  return session->internals.last_handshake_in;
}

Project: gnutls
File: gnutls_handshake.c

gnutls_handshake_set_max_packet_length (gnutls_session_t session, size_t max)
{
  session->internals.max_handshake_data_buffer_size = max;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_client_set_comp_method (gnutls_session_t session, opaque comp_method)
{
  int comp_methods_num;
  uint8_t *compression_methods;
  int i;

  comp_methods_num = _gnutls_supported_compression_methods (session,
							    &compression_methods);
  if (comp_methods_num < 0)
    {
      gnutls_assert ();
      return comp_methods_num;
    }

  for (i = 0; i < comp_methods_num; i++)
    {
      if (compression_methods[i] == comp_method)
	{
	  comp_methods_num = 0;
	  break;
	}
    }

  gnutls_free (compression_methods);

  if (comp_methods_num != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
    }

  session->internals.compression_method =
    _gnutls_compression_get_id (comp_method);


  return 0;
}

Project: gnutls
File: gnutls_handshake.c

gnutls_rehandshake (gnutls_session_t session)
{
  int ret;

  /* only server sends that handshake packet */
  if (session->security_parameters.entity == GNUTLS_CLIENT)
    return GNUTLS_E_INVALID_REQUEST;

  ret =
    _gnutls_send_empty_handshake (session, GNUTLS_HANDSHAKE_HELLO_REQUEST,
				  AGAIN (STATE50));
  STATE = STATE50;

  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }
  STATE = STATE0;

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_recv_handshake_final (gnutls_session_t session, int init)
{
  int ret = 0;
  uint8_t ch;

  switch (STATE)
    {
    case STATE0:
    case STATE30:
      ret = _gnutls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, 1);
      STATE = STATE30;
      if (ret <= 0)
	{
	  ERR ("recv ChangeCipherSpec", ret);
	  gnutls_assert ();
	  return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

      /* Initialize the connection session (start encryption) - in case of server */
      if (init == TRUE)
	{
	  ret = _gnutls_connection_state_init (session);
	  if (ret < 0)
	    {
	      gnutls_assert ();
	      return ret;
	    }
	}

      ret = _gnutls_read_connection_state_init (session);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

    case STATE31:
      ret = _gnutls_recv_finished (session);
      STATE = STATE31;
      if (ret < 0)
	{
	  ERR ("recv finished", ret);
	  gnutls_assert ();
	  return ret;
	}
      STATE = STATE0;
    default:
      break;
    }


  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_get_adv_version (gnutls_session_t session)
{
  return _gnutls_version_get (_gnutls_get_adv_version_major (session),
			      _gnutls_get_adv_version_minor (session));
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_send_hello (gnutls_session_t session, int again)
{
  int ret;

  if (session->security_parameters.entity == GNUTLS_CLIENT)
    {
      ret = _gnutls_send_client_hello (session, again);

    }
  else
    {				/* SERVER */
      ret = _gnutls_send_server_hello (session, again);
    }

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_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;
    }

  /* Note: SSL2_HEADERS == 1 */

  dataptr = session->internals.handshake_header_buffer.header;

  /* If we haven't already read the handshake headers.
   */
  if (session->internals.handshake_header_buffer.header_size < SSL2_HEADERS)
    {
      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;
    }

  if (session->internals.v2_hello == 0
      || type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
    {
      ret =
	_gnutls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE,
				       type,
				       &dataptr[session->
						internals.
						handshake_header_buffer.
						header_size],
				       HANDSHAKE_HEADER_SIZE -
				       session->internals.
				       handshake_header_buffer.header_size);
      if (ret <= 0)
	{
	  gnutls_assert ();
	  return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}
      if ((size_t) ret !=
	  HANDSHAKE_HEADER_SIZE -
	  session->internals.handshake_header_buffer.header_size)
	{
	  gnutls_assert ();
	  return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}
      *recv_type = dataptr[0];

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

      _gnutls_handshake_log ("HSK[%x]: %s was received [%ld bytes]\n",
			     session, _gnutls_handshake2str (dataptr[0]),
			     length32 + HANDSHAKE_HEADER_SIZE);

    }
  else
    {				/* v2 hello */
      length32 = session->internals.v2_hello - SSL2_HEADERS;	/* we've read the first byte */

      handshake_header_size = SSL2_HEADERS;	/* we've already read one byte */

      *recv_type = dataptr[0];

      _gnutls_handshake_log ("HSK[%x]: %s(v2) was received [%ld bytes]\n",
			     session, _gnutls_handshake2str (*recv_type),
			     length32 + handshake_header_size);

      if (*recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
	{			/* it should be one or nothing */
	  gnutls_assert ();
	  return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
	}
    }

  /* put the packet into the buffer */
  session->internals.handshake_header_buffer.header_size =
    handshake_header_size;
  session->internals.handshake_header_buffer.packet_length = length32;
  session->internals.handshake_header_buffer.recv_type = *recv_type;

  if (*recv_type != type)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
    }

  return length32;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_read_server_hello (gnutls_session_t session,
			   opaque * data, int datalen)
{
  uint8_t session_id_len = 0;
  int pos = 0;
  int ret = 0;
  gnutls_protocol_t version;
  int len = datalen;

  if (datalen < 38)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
    }

  _gnutls_handshake_log ("HSK[%x]: Server's version: %d.%d\n",
			 session, data[pos], data[pos + 1]);

  DECR_LEN (len, 2);
  version = _gnutls_version_get (data[pos], data[pos + 1]);
  if (_gnutls_version_is_supported (session, version) == 0)
    {
      gnutls_assert ();
      return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
    }
  else
    {
      _gnutls_set_current_version (session, version);
    }

  pos += 2;

  DECR_LEN (len, TLS_RANDOM_SIZE);
  _gnutls_set_server_random (session, &data[pos]);
  pos += TLS_RANDOM_SIZE;


  /* Read session ID
   */
  DECR_LEN (len, 1);
  session_id_len = data[pos++];

  if (len < session_id_len)
    {
      gnutls_assert ();
      return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
    }
  DECR_LEN (len, session_id_len);


  /* check if we are resuming and set the appropriate
   * values;
   */
  if (_gnutls_client_check_if_resuming
      (session, &data[pos], session_id_len) == 0)
    return 0;
  pos += session_id_len;


  /* Check if the given cipher suite is supported and copy
   * it to the session.
   */

  DECR_LEN (len, 2);
  ret = _gnutls_client_set_ciphersuite (session, &data[pos]);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }
  pos += 2;



  /* move to compression 
   */
  DECR_LEN (len, 1);

  ret = _gnutls_client_set_comp_method (session, data[pos++]);
  if (ret < 0)
    {
      gnutls_assert ();
      return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
    }

  /* Parse extensions.
   */
  if (version >= GNUTLS_TLS1)
    {
      ret = _gnutls_parse_extensions (session, EXTENSION_ANY, &data[pos], len);	/* len is the rest of the parsed length */
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
    }
  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_handshake_server (gnutls_session_t session)
{
  int ret = 0;

  switch (STATE)
    {
    case STATE0:
    case STATE1:
      ret =
	_gnutls_recv_handshake (session, NULL, NULL,
				GNUTLS_HANDSHAKE_CLIENT_HELLO,
				MANDATORY_PACKET);
      STATE = STATE1;
      IMED_RET ("recv hello", ret);

    case STATE2:
      ret = _gnutls_send_hello (session, AGAIN (STATE2));
      STATE = STATE2;
      IMED_RET ("send hello", ret);

    case STATE70:
      if (session->security_parameters.extensions.do_send_supplemental)
	{
	  ret = _gnutls_send_supplemental (session, AGAIN (STATE70));
	  STATE = STATE70;
	  IMED_RET ("send supplemental data", ret);
	}

      /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
    case STATE3:
      /* NOTE: these should not be send if we are resuming */

      if (session->internals.resumed == RESUME_FALSE)
	ret = _gnutls_send_server_certificate (session, AGAIN (STATE3));
      STATE = STATE3;
      IMED_RET ("send server certificate", ret);

    case STATE4:
      /* send server key exchange (A) */
      if (session->internals.resumed == RESUME_FALSE)
	ret = _gnutls_send_server_kx_message (session, AGAIN (STATE4));
      STATE = STATE4;
      IMED_RET ("send server kx", ret);

    case STATE5:
      /* Send certificate request - if requested to */
      if (session->internals.resumed == RESUME_FALSE)
	ret =
	  _gnutls_send_server_certificate_request (session, AGAIN (STATE5));
      STATE = STATE5;
      IMED_RET ("send server cert request", ret);

    case STATE6:
      /* send the server hello done */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret =
	  _gnutls_send_empty_handshake (session,
					GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
					AGAIN (STATE6));
      STATE = STATE6;
      IMED_RET ("send server hello done", ret);

    case STATE71:
      if (session->security_parameters.extensions.do_recv_supplemental)
	{
	  ret = _gnutls_recv_supplemental (session);
	  STATE = STATE71;
	  IMED_RET ("recv client supplemental", ret);
	}

      /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
    case STATE7:
      /* receive the client certificate message */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_client_certificate (session);
      STATE = STATE7;
      IMED_RET ("recv client certificate", ret);

    case STATE8:
      /* receive the client key exchange message */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_client_kx_message (session);
      STATE = STATE8;
      IMED_RET ("recv client kx", ret);

    case STATE9:
      /* receive the client certificate verify message */
      if (session->internals.resumed == RESUME_FALSE)	/* if we are not resuming */
	ret = _gnutls_recv_client_certificate_verify_message (session);
      STATE = STATE9;
      IMED_RET ("recv client certificate verify", ret);

      STATE = STATE0;		/* finished thus clear session */
    default:
      break;
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_send_server_hello (gnutls_session_t session, int again)
{
  opaque *data = NULL;
  opaque extdata[MAX_EXT_DATA_LENGTH];
  int extdatalen;
  int pos = 0;
  int datalen, ret = 0;
  uint8_t comp;
  opaque *SessionID = session->security_parameters.session_id;
  uint8_t session_id_len = session->security_parameters.session_id_size;
  opaque buf[2 * TLS_MAX_SESSION_ID_SIZE + 1];

  if (SessionID == NULL)
    session_id_len = 0;

  datalen = 0;

#ifdef ENABLE_SRP
  if (IS_SRP_KX
      (_gnutls_cipher_suite_get_kx_algo
       (&session->security_parameters.current_cipher_suite)))
    {
      /* While resuming we cannot check the username extension since it is
       * not available at this point. It will be copied on connection
       * state activation.
       */
      if (session->internals.resumed == RESUME_FALSE &&
	  session->security_parameters.extensions.srp_username[0] == 0)
	{
	  /* The peer didn't send a valid SRP extension with the
	   * SRP username. The draft requires that we send a fatal
	   * alert and abort.
	   */
	  gnutls_assert ();
	  ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
				   GNUTLS_A_UNKNOWN_PSK_IDENTITY);
	  if (ret < 0)
	    {
	      gnutls_assert ();
	      return ret;
	    }

	  return GNUTLS_E_ILLEGAL_SRP_USERNAME;
	}
    }
#endif

  if (again == 0)
    {
      datalen = 2 + session_id_len + 1 + TLS_RANDOM_SIZE + 3;
      extdatalen =
	_gnutls_gen_extensions (session, extdata, sizeof (extdata));

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

      data = gnutls_malloc (datalen + extdatalen);
      if (data == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      data[pos++] =
	_gnutls_version_get_major (session->security_parameters.version);
      data[pos++] =
	_gnutls_version_get_minor (session->security_parameters.version);

      memcpy (&data[pos],
	      session->security_parameters.server_random, TLS_RANDOM_SIZE);
      pos += TLS_RANDOM_SIZE;

      data[pos++] = session_id_len;
      if (session_id_len > 0)
	{
	  memcpy (&data[pos], SessionID, session_id_len);
	}
      pos += session_id_len;

      _gnutls_handshake_log ("HSK[%x]: SessionID: %s\n", session,
			     _gnutls_bin2hex (SessionID, session_id_len,
					      buf, sizeof (buf)));

      memcpy (&data[pos],
	      session->security_parameters.current_cipher_suite.suite, 2);
      pos += 2;

      comp =
	(uint8_t) _gnutls_compression_get_num (session->
					       internals.compression_method);
      data[pos++] = comp;


      if (extdatalen > 0)
	{
	  datalen += extdatalen;

	  memcpy (&data[pos], extdata, extdatalen);
	}
    }

  ret =
    _gnutls_send_handshake (session, data, datalen,
			    GNUTLS_HANDSHAKE_SERVER_HELLO);
  gnutls_free (data);

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_generate_session_id (opaque * session_id, uint8_t * len)
{
  *len = TLS_MAX_SESSION_ID_SIZE;
  int ret;

  ret = _gnutls_rnd (RND_NONCE, session_id, *len);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_client_check_if_resuming (gnutls_session_t session,
				  opaque * session_id, int session_id_len)
{
  opaque buf[2 * TLS_MAX_SESSION_ID_SIZE + 1];

  _gnutls_handshake_log ("HSK[%x]: SessionID length: %d\n", session,
			 session_id_len);
  _gnutls_handshake_log ("HSK[%x]: SessionID: %s\n", session,
			 _gnutls_bin2hex (session_id, session_id_len, buf,
					  sizeof (buf)));

  if (session_id_len > 0 &&
      session->internals.resumed_security_parameters.session_id_size ==
      session_id_len
      && memcmp (session_id,
		 session->internals.resumed_security_parameters.
		 session_id, session_id_len) == 0)
    {
      /* resume session */
      memcpy (session->internals.
	      resumed_security_parameters.server_random,
	      session->security_parameters.server_random, TLS_RANDOM_SIZE);
      memcpy (session->internals.
	      resumed_security_parameters.client_random,
	      session->security_parameters.client_random, TLS_RANDOM_SIZE);
      session->internals.resumed = RESUME_TRUE;	/* we are resuming */

      return 0;
    }
  else
    {
      /* keep the new session id */
      session->internals.resumed = RESUME_FALSE;	/* we are not resuming */
      session->security_parameters.session_id_size = session_id_len;
      memcpy (session->security_parameters.session_id,
	      session_id, session_id_len);

      return -1;
    }
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_send_client_hello (gnutls_session_t session, int again)
{
  opaque *data = NULL;
  int extdatalen;
  int pos = 0;
  int datalen = 0, ret = 0;
  opaque rnd[TLS_RANDOM_SIZE];
  gnutls_protocol_t hver;
  opaque extdata[MAX_EXT_DATA_LENGTH];

  opaque *SessionID =
    session->internals.resumed_security_parameters.session_id;
  uint8_t session_id_len =
    session->internals.resumed_security_parameters.session_id_size;

  if (SessionID == NULL)
    session_id_len = 0;
  else if (session_id_len == 0)
    SessionID = NULL;

  if (again == 0)
    {

      datalen = 2 + (session_id_len + 1) + TLS_RANDOM_SIZE;
      /* 2 for version, (4 for unix time + 28 for random bytes==TLS_RANDOM_SIZE) 
       */

      data = gnutls_malloc (datalen);
      if (data == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      /* if we are resuming a session then we set the
       * version number to the previously established.
       */
      if (SessionID == NULL)
	hver = _gnutls_version_max (session);
      else
	{			/* we are resuming a session */
	  hver = session->internals.resumed_security_parameters.version;
	}

      if (hver == GNUTLS_VERSION_UNKNOWN || hver == 0)
	{
	  gnutls_assert ();
	  gnutls_free (data);
	  return GNUTLS_E_INTERNAL_ERROR;
	}

      data[pos++] = _gnutls_version_get_major (hver);
      data[pos++] = _gnutls_version_get_minor (hver);

      /* Set the version we advertized as maximum 
       * (RSA uses it).
       */
      _gnutls_set_adv_version (session, hver);

      /* Some old implementations do not interoperate if we send a
       * different version in the record layer.
       * It seems they prefer to read the record's version
       * as the one we actually requested.
       * The proper behaviour is to use the one in the client hello 
       * handshake packet and ignore the one in the packet's record 
       * header.
       */
      _gnutls_set_current_version (session, hver);

      /* In order to know when this session was initiated.
       */
      session->security_parameters.timestamp = time (NULL);

      /* Generate random data 
       */
      _gnutls_tls_create_random (rnd);
      _gnutls_set_client_random (session, rnd);

      memcpy (&data[pos], rnd, TLS_RANDOM_SIZE);
      pos += TLS_RANDOM_SIZE;

      /* Copy the Session ID 
       */
      data[pos++] = session_id_len;

      if (session_id_len > 0)
	{
	  memcpy (&data[pos], SessionID, session_id_len);
	  pos += session_id_len;
	}


      /* Copy the ciphersuites.
       */
      extdatalen =
	_gnutls_copy_ciphersuites (session, extdata, sizeof (extdata));
      if (extdatalen > 0)
	{
	  datalen += extdatalen;
	  data = gnutls_realloc_fast (data, datalen);
	  if (data == NULL)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_MEMORY_ERROR;
	    }

	  memcpy (&data[pos], extdata, extdatalen);
	  pos += extdatalen;

	}
      else
	{
	  if (extdatalen == 0)
	    extdatalen = GNUTLS_E_INTERNAL_ERROR;
	  gnutls_free (data);
	  gnutls_assert ();
	  return extdatalen;
	}


      /* Copy the compression methods.
       */
      extdatalen =
	_gnutls_copy_comp_methods (session, extdata, sizeof (extdata));
      if (extdatalen > 0)
	{
	  datalen += extdatalen;
	  data = gnutls_realloc_fast (data, datalen);
	  if (data == NULL)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_MEMORY_ERROR;
	    }

	  memcpy (&data[pos], extdata, extdatalen);
	  pos += extdatalen;

	}
      else
	{
	  if (extdatalen == 0)
	    extdatalen = GNUTLS_E_INTERNAL_ERROR;
	  gnutls_free (data);
	  gnutls_assert ();
	  return extdatalen;
	}

      /* Generate and copy TLS extensions.
       */
      if (hver >= GNUTLS_TLS1)
	{
	  extdatalen =
	    _gnutls_gen_extensions (session, extdata, sizeof (extdata));

	  if (extdatalen > 0)
	    {
	      datalen += extdatalen;
	      data = gnutls_realloc_fast (data, datalen);
	      if (data == NULL)
		{
		  gnutls_assert ();
		  return GNUTLS_E_MEMORY_ERROR;
		}

	      memcpy (&data[pos], extdata, extdatalen);
	    }
	  else if (extdatalen < 0)
	    {
	      gnutls_assert ();
	      gnutls_free (data);
	      return extdatalen;
	    }
	}
    }

  ret =
    _gnutls_send_handshake (session, data, datalen,
			    GNUTLS_HANDSHAKE_CLIENT_HELLO);
  gnutls_free (data);

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_handshake_hash_init (gnutls_session_t session)
{

  if (session->internals.handshake_mac_handle_init == 0)
    {
      int ret =
	_gnutls_hash_init (&session->internals.handshake_mac_handle_md5, GNUTLS_MAC_MD5);

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

      ret = _gnutls_hash_init(&session->internals.handshake_mac_handle_sha, GNUTLS_MAC_SHA1);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}
	
      session->internals.handshake_mac_handle_init = 1;
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_copy_ciphersuites (gnutls_session_t session,
			   opaque * ret_data, size_t ret_data_size)
{
  int ret, i;
  cipher_suite_st *cipher_suites;
  uint16_t cipher_num;
  int datalen, pos;

  ret = _gnutls_supported_ciphersuites_sorted (session, &cipher_suites);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  /* Here we remove any ciphersuite that does not conform
   * the certificate requested, or to the
   * authentication requested (eg SRP).
   */
  ret =
    _gnutls_remove_unwanted_ciphersuites (session, &cipher_suites, ret, -1);
  if (ret < 0)
    {
      gnutls_assert ();
      gnutls_free (cipher_suites);
      return ret;
    }

  /* If no cipher suites were enabled.
   */
  if (ret == 0)
    {
      gnutls_assert ();
      gnutls_free (cipher_suites);
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  cipher_num = ret;

  cipher_num *= sizeof (uint16_t);	/* in order to get bytes */

  datalen = pos = 0;

  datalen += sizeof (uint16_t) + cipher_num;

  if ((size_t) datalen > ret_data_size)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  _gnutls_write_uint16 (cipher_num, ret_data);
  pos += 2;

  for (i = 0; i < (cipher_num / 2); i++)
    {
      memcpy (&ret_data[pos], cipher_suites[i].suite, 2);
      pos += 2;
    }
  gnutls_free (cipher_suites);

  return datalen;
}

Project: gnutls
File: gnutls_handshake.c

gnutls_handshake (gnutls_session_t session)
{
  int ret;

  if ((ret = _gnutls_handshake_hash_init (session)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  if (session->security_parameters.entity == GNUTLS_CLIENT)
    {
      ret = _gnutls_handshake_client (session);
    }
  else
    {
      ret = _gnutls_handshake_server (session);
    }
  if (ret < 0)
    {
      /* In the case of a rehandshake abort
       * we should reset the handshake's internal state.
       */
      if (_gnutls_abort_handshake (session, ret) == 0)
	STATE = STATE0;

      return ret;
    }

  ret = _gnutls_handshake_common (session);

  if (ret < 0)
    {
      if (_gnutls_abort_handshake (session, ret) == 0)
	STATE = STATE0;

      return ret;
    }

  STATE = STATE0;

  _gnutls_handshake_io_buffer_clear (session);
  _gnutls_handshake_internal_state_clear (session);

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_handshake_common (gnutls_session_t session)
{
  int ret = 0;

  /* send and recv the change cipher spec and finished messages */
  if ((session->internals.resumed == RESUME_TRUE
       && session->security_parameters.entity == GNUTLS_CLIENT)
      || (session->internals.resumed == RESUME_FALSE
	  && session->security_parameters.entity == GNUTLS_SERVER))
    {
      /* if we are a client resuming - or we are a server not resuming */

      ret = _gnutls_recv_handshake_final (session, TRUE);
      IMED_RET ("recv handshake final", ret);

      ret = _gnutls_send_handshake_final (session, FALSE);
      IMED_RET ("send handshake final", ret);
    }
  else
    {				/* if we are a client not resuming - or we are a server resuming */

      ret = _gnutls_send_handshake_final (session, TRUE);
      IMED_RET ("send handshake final 2", ret);

      ret = _gnutls_recv_handshake_final (session, FALSE);
      IMED_RET ("recv handshake final 2", ret);
    }

  if (session->security_parameters.entity == GNUTLS_SERVER)
    {
      /* in order to support session resuming */
      _gnutls_server_register_current_session (session);
    }

  /* clear handshake buffer */
  _gnutls_handshake_hash_buffers_clear (session);
  return ret;

}

Project: gnutls
File: gnutls_handshake.c

_gnutls_abort_handshake (gnutls_session_t session, int ret)
{
  if (((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&
       (gnutls_alert_get (session) == GNUTLS_A_NO_RENEGOTIATION))
      || ret == GNUTLS_E_GOT_APPLICATION_DATA)
    return 0;

  /* this doesn't matter */
  return GNUTLS_E_INTERNAL_ERROR;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_recv_hello_request (gnutls_session_t session, void *data,
			    uint32_t data_size)
{
  uint8_t type;

  if (session->security_parameters.entity == GNUTLS_SERVER)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET;
    }
  if (data_size < 1)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
    }
  type = ((uint8_t *) data)[0];
  if (type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
    return GNUTLS_E_REHANDSHAKE;
  else
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET;
    }
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_set_adv_version (gnutls_session_t session, gnutls_protocol_t ver)
{
  set_adv_version (session, _gnutls_version_get_major (ver),
		   _gnutls_version_get_minor (ver));
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_send_handshake_final (gnutls_session_t session, int init)
{
  int ret = 0;

  /* Send the CHANGE CIPHER SPEC PACKET */

  switch (STATE)
    {
    case STATE0:
    case STATE20:
      ret = _gnutls_send_change_cipher_spec (session, AGAIN (STATE20));
      STATE = STATE20;
      if (ret < 0)
	{
	  ERR ("send ChangeCipherSpec", ret);
	  gnutls_assert ();
	  return ret;
	}

      /* Initialize the connection session (start encryption) - in case of client 
       */
      if (init == TRUE)
	{
	  ret = _gnutls_connection_state_init (session);
	  if (ret < 0)
	    {
	      gnutls_assert ();
	      return ret;
	    }
	}

      ret = _gnutls_write_connection_state_init (session);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

    case STATE21:
      /* send the finished message */
      ret = _gnutls_send_finished (session, AGAIN (STATE21));
      STATE = STATE21;
      if (ret < 0)
	{
	  ERR ("send Finished", ret);
	  gnutls_assert ();
	  return ret;
	}

      STATE = STATE0;
    default:
      break;
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_handshake_hash_add_recvd (gnutls_session_t session,
				  gnutls_handshake_description_t recv_type,
				  opaque * header, uint16_t header_size,
				  opaque * dataptr, uint32_t datalen)
{
  int ret;

  /* The idea here is to hash the previous message we received,
   * and add the one we just received into the handshake_hash_buffer.
   */

  if ((ret = _gnutls_handshake_hash_pending (session)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  /* here we buffer the handshake messages - needed at Finished message */
  if (recv_type != GNUTLS_HANDSHAKE_HELLO_REQUEST)
    {

      if ((ret =
	   _gnutls_handshake_buffer_put (session, header, header_size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      if (datalen > 0)
	{
	  if ((ret =
	       _gnutls_handshake_buffer_put (session, dataptr, datalen)) < 0)
	    {
	      gnutls_assert ();
	      return ret;
	    }
	}
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
			int *datalen, gnutls_handshake_description_t type,
			Optional optional)
{
  int ret;
  uint32_t length32 = 0;
  opaque *dataptr = NULL;
  gnutls_handshake_description_t recv_type;

  ret = _gnutls_recv_handshake_header (session, type, &recv_type);
  if (ret < 0)
    {

      if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
	  && optional == OPTIONAL_PACKET)
	{
	  if (datalen != NULL)
	    *datalen = 0;
	  if (data != NULL)
	    *data = NULL;
	  return 0;		/* ok just ignore the packet */
	}

      return ret;
    }

  session->internals.last_handshake_in = recv_type;

  length32 = ret;

  if (length32 > 0)
    dataptr = gnutls_malloc (length32);
  else if (recv_type != GNUTLS_HANDSHAKE_SERVER_HELLO_DONE)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
    }

  if (dataptr == NULL && length32 > 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  if (datalen != NULL)
    *datalen = length32;

  if (length32 > 0)
    {
      ret =
	_gnutls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE,
				       type, dataptr, length32);
      if (ret <= 0)
	{
	  gnutls_assert ();
	  gnutls_free (dataptr);
	  return (ret == 0) ? GNUTLS_E_UNEXPECTED_PACKET_LENGTH : ret;
	}
    }

  if (data != NULL && length32 > 0)
    *data = dataptr;


  ret = _gnutls_handshake_hash_add_recvd (session, recv_type,
					  session->internals.
					  handshake_header_buffer.header,
					  session->internals.
					  handshake_header_buffer.
					  header_size, dataptr, length32);
  if (ret < 0)
    {
      gnutls_assert ();
      _gnutls_handshake_header_buffer_clear (session);
      return ret;
    }

  /* If we fail before this then we will reuse the handshake header
   * have have received above. if we get here the we clear the handshake
   * header we received.
   */
  _gnutls_handshake_header_buffer_clear (session);

  switch (recv_type)
    {
    case GNUTLS_HANDSHAKE_CLIENT_HELLO:
    case GNUTLS_HANDSHAKE_SERVER_HELLO:
      ret = _gnutls_recv_hello (session, dataptr, length32);
      /* dataptr is freed because the caller does not
       * need it */
      gnutls_free (dataptr);
      if (data != NULL)
	*data = NULL;
      break;
    case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
      if (length32 == 0)
	ret = 0;
      else
	ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
      break;
    case GNUTLS_HANDSHAKE_CERTIFICATE_PKT:
    case GNUTLS_HANDSHAKE_FINISHED:
    case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE:
    case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
    case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
    case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
    case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
      ret = length32;
      break;
    default:
      gnutls_assert ();
      gnutls_free (dataptr);
      if (data != NULL)
	*data = NULL;
      ret = GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
    }

  return ret;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_remove_unwanted_ciphersuites (gnutls_session_t session,
				      cipher_suite_st ** cipherSuites,
				      int numCipherSuites,
				      gnutls_pk_algorithm_t requested_pk_algo)
{

  int ret = 0;
  cipher_suite_st *newSuite, cs;
  int newSuiteSize = 0, i;
  gnutls_certificate_credentials_t cert_cred;
  gnutls_kx_algorithm_t kx;
  int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
  gnutls_kx_algorithm_t *alg = NULL;
  int alg_size = 0;

  /* if we should use a specific certificate, 
   * we should remove all algorithms that are not supported
   * by that certificate and are on the same authentication
   * method (CERTIFICATE).
   */

  cert_cred =
    (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key,
							 GNUTLS_CRD_CERTIFICATE,
							 NULL);

  /* If there are certificate credentials, find an appropriate certificate
   * or disable them;
   */
  if (session->security_parameters.entity == GNUTLS_SERVER
      && cert_cred != NULL)
    {
      ret = _gnutls_server_select_cert (session, requested_pk_algo);
      if (ret < 0)
	{
	  gnutls_assert ();
	  _gnutls_x509_log("Could not find an appropriate certificate: %s\n", gnutls_strerror(ret));
	  cert_cred = NULL;
	}
    }

  /* get all the key exchange algorithms that are 
   * supported by the X509 certificate parameters.
   */
  if ((ret =
       _gnutls_selected_cert_supported_kx (session, &alg, &alg_size)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  newSuite = gnutls_malloc (numCipherSuites * sizeof (cipher_suite_st));
  if (newSuite == NULL)
    {
      gnutls_assert ();
      gnutls_free (alg);
      return GNUTLS_E_MEMORY_ERROR;
    }

  /* now removes ciphersuites based on the KX algorithm
   */
  for (i = 0; i < numCipherSuites; i++)
    {
      int delete = 0;

      /* finds the key exchange algorithm in
       * the ciphersuite
       */
      kx = _gnutls_cipher_suite_get_kx_algo (&(*cipherSuites)[i]);

      /* if it is defined but had no credentials 
       */
      if (_gnutls_get_kx_cred (session, kx, NULL) == NULL)
	{
	  delete = 1;
	}
      else
	{
	  delete = 0;

	  if (server)
	    delete = check_server_params (session, kx, alg, alg_size);
	}

      /* These two SRP kx's are marked to require a CRD_CERTIFICATE,
	 (see cred_mappings in gnutls_algorithms.c), but it also
	 requires a SRP credential.  Don't use SRP kx unless we have a
	 SRP credential too.  */
      if (kx == GNUTLS_KX_SRP_RSA || kx == GNUTLS_KX_SRP_DSS)
	{
	  if (!_gnutls_get_cred (session->key, GNUTLS_CRD_SRP, NULL))
	    delete = 1;
	}

      memcpy (&cs.suite, &(*cipherSuites)[i].suite, 2);

      if (delete == 0)
	{

	  _gnutls_handshake_log ("HSK[%x]: Keeping ciphersuite: %s\n",
				 session,
				 _gnutls_cipher_suite_get_name (&cs));

	  memcpy (newSuite[newSuiteSize].suite, (*cipherSuites)[i].suite, 2);
	  newSuiteSize++;
	}
      else
	{
	  _gnutls_handshake_log ("HSK[%x]: Removing ciphersuite: %s\n",
				 session,
				 _gnutls_cipher_suite_get_name (&cs));

	}
    }

  gnutls_free (alg);
  gnutls_free (*cipherSuites);
  *cipherSuites = newSuite;

  ret = newSuiteSize;

  return ret;

}

Project: gnutls
File: gnutls_handshake.c

check_server_params (gnutls_session_t session,
		     gnutls_kx_algorithm_t kx,
		     gnutls_kx_algorithm_t * alg, int alg_size)
{
  int cred_type;
  gnutls_dh_params_t dh_params = NULL;
  gnutls_rsa_params_t rsa_params = NULL;
  int j;

  cred_type = _gnutls_map_kx_get_cred (kx, 1);

  /* Read the Diffie Hellman parameters, if any.
   */
  if (cred_type == GNUTLS_CRD_CERTIFICATE)
    {
      int delete;
      gnutls_certificate_credentials_t x509_cred =
	(gnutls_certificate_credentials_t) _gnutls_get_cred (session->key,
							     cred_type, NULL);

      if (x509_cred != NULL)
	{
	  dh_params =
	    _gnutls_get_dh_params (x509_cred->dh_params,
				   x509_cred->params_func, session);
	  rsa_params =
	    _gnutls_certificate_get_rsa_params (x509_cred->rsa_params,
						x509_cred->params_func,
						session);
	}

      /* Check also if the certificate supports the
       * KX method.
       */
      delete = 1;
      for (j = 0; j < alg_size; j++)
	{
	  if (alg[j] == kx)
	    {
	      delete = 0;
	      break;
	    }
	}

      if (delete == 1)
	return 1;

#ifdef ENABLE_ANON
    }
  else if (cred_type == GNUTLS_CRD_ANON)
    {
      gnutls_anon_server_credentials_t anon_cred =
	(gnutls_anon_server_credentials_t) _gnutls_get_cred (session->key,
							     cred_type, NULL);

      if (anon_cred != NULL)
	{
	  dh_params =
	    _gnutls_get_dh_params (anon_cred->dh_params,
				   anon_cred->params_func, session);
	}
#endif
#ifdef ENABLE_PSK
    }
  else if (cred_type == GNUTLS_CRD_PSK)
    {
      gnutls_psk_server_credentials_t psk_cred =
	(gnutls_psk_server_credentials_t) _gnutls_get_cred (session->key,
							    cred_type, NULL);

      if (psk_cred != NULL)
	{
	  dh_params =
	    _gnutls_get_dh_params (psk_cred->dh_params, psk_cred->params_func,
				   session);
	}
#endif
    }
  else
    return 0;			/* no need for params */


  /* If the key exchange method needs RSA or DH params,
   * but they are not set then remove it.
   */
  if (_gnutls_kx_needs_rsa_params (kx) != 0)
    {
      /* needs rsa params. */
      if (_gnutls_rsa_params_to_mpi (rsa_params) == NULL)
	{
	  gnutls_assert ();
	  return 1;
	}
    }

  if (_gnutls_kx_needs_dh_params (kx) != 0)
    {
      /* needs DH params. */
      if (_gnutls_dh_params_to_mpi (dh_params) == NULL)
	{
	  gnutls_assert ();
	  return 1;
	}
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_copy_comp_methods (gnutls_session_t session,
			   opaque * ret_data, size_t ret_data_size)
{
  int ret, i;
  uint8_t *compression_methods, comp_num;
  int datalen, pos;

  ret = _gnutls_supported_compression_methods (session, &compression_methods);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  comp_num = ret;

  datalen = pos = 0;
  datalen += comp_num + 1;

  if ((size_t) datalen > ret_data_size)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  ret_data[pos++] = comp_num;	/* put the number of compression methods */

  for (i = 0; i < comp_num; i++)
    {
      ret_data[pos++] = compression_methods[i];
    }

  gnutls_free (compression_methods);

  return datalen;
}

Project: gnutls
File: ext_server_name.c

_gnutls_server_name_send_params (gnutls_session_t session,
				 opaque * data, size_t _data_size)
{
  uint16_t len;
  opaque *p;
  unsigned i;
  ssize_t data_size = _data_size;
  int total_size = 0;

  /* this function sends the client extension data (dnsname) 
   */
  if (session->security_parameters.entity == GNUTLS_CLIENT)
    {

      if (session->security_parameters.extensions.server_names_size == 0)
	return 0;

      /* uint16_t 
       */
      total_size = 2;
      for (i = 0;
	   i < session->security_parameters.extensions.server_names_size; i++)
	{
	  /* count the total size 
	   */
	  len =
	    session->security_parameters.extensions.server_names[i].
	    name_length;

	  /* uint8_t + uint16_t + size 
	   */
	  total_size += 1 + 2 + len;
	}

      p = data;

      /* UINT16: write total size of all names 
       */
      DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER);
      _gnutls_write_uint16 (total_size - 2, p);
      p += 2;

      for (i = 0;
	   i < session->security_parameters.extensions.server_names_size; i++)
	{

	  switch (session->security_parameters.extensions.
		  server_names[i].type)
	    {
	    case GNUTLS_NAME_DNS:

	      len =
		session->security_parameters.extensions.
		server_names[i].name_length;
	      if (len == 0)
		break;

	      /* UINT8: type of this extension
	       * UINT16: size of the first name
	       * LEN: the actual server name.
	       */
	      DECR_LENGTH_RET (data_size, len + 3,
			       GNUTLS_E_SHORT_MEMORY_BUFFER);

	      *p = 0;		/* NAME_DNS type */
	      p++;

	      _gnutls_write_uint16 (len, p);
	      p += 2;

	      memcpy (p,
		      session->security_parameters.extensions.
		      server_names[i].name, len);
	      p += len;
	      break;
	    default:
	      gnutls_assert ();
	      return GNUTLS_E_INTERNAL_ERROR;
	    }
	}
    }

  return total_size;
}

Project: gnutls
File: ext_server_name.c

gnutls_server_name_get (gnutls_session_t session, void *data,
			size_t * data_length,
			unsigned int *type, unsigned int indx)
{
  char *_data = data;

  if (session->security_parameters.entity == GNUTLS_CLIENT)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  if (indx + 1 > session->security_parameters.extensions.server_names_size)
    {
      return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
    }

  *type = session->security_parameters.extensions.server_names[indx].type;

  if (*data_length >		/* greater since we need one extra byte for the null */
      session->security_parameters.extensions.server_names[indx].name_length)
    {
      *data_length =
	session->security_parameters.extensions.server_names[indx].
	name_length;
      memcpy (data,
	      session->security_parameters.extensions.server_names[indx].
	      name, *data_length);

      if (*type == GNUTLS_NAME_DNS)	/* null terminate */
	_data[(*data_length)] = 0;

    }
  else
    {
      *data_length =
	session->security_parameters.extensions.server_names[indx].
	name_length;
      return GNUTLS_E_SHORT_MEMORY_BUFFER;
    }

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_client_set_ciphersuite (gnutls_session_t session, opaque suite[2])
{
  uint8_t z;
  cipher_suite_st *cipher_suites;
  int cipher_suite_num;
  int i, err;

  z = 1;
  cipher_suite_num = _gnutls_supported_ciphersuites (session, &cipher_suites);
  if (cipher_suite_num < 0)
    {
      gnutls_assert ();
      return cipher_suite_num;
    }

  for (i = 0; i < cipher_suite_num; i++)
    {
      if (memcmp (&cipher_suites[i], suite, 2) == 0)
	{
	  z = 0;
	  break;
	}
    }

  gnutls_free (cipher_suites);

  if (z != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_UNKNOWN_CIPHER_SUITE;
    }

  memcpy (session->security_parameters.current_cipher_suite.suite, suite, 2);

  _gnutls_handshake_log ("HSK[%x]: Selected cipher suite: %s\n", session,
			 _gnutls_cipher_suite_get_name (&session->
							security_parameters.
							current_cipher_suite));


  /* check if the credentials (username, public key etc.) are ok.
   * Actually checks if they exist.
   */
  if (_gnutls_get_kx_cred
      (session, _gnutls_cipher_suite_get_kx_algo (&session->
						  security_parameters.
						  current_cipher_suite),
       &err) == NULL && err != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }


  /* set the mod_auth_st to the appropriate struct
   * according to the KX algorithm. This is needed since all the
   * handshake functions are read from there;
   */
  session->internals.auth_struct =
    _gnutls_kx_auth_struct (_gnutls_cipher_suite_get_kx_algo
			    (&session->security_parameters.
			     current_cipher_suite));

  if (session->internals.auth_struct == NULL)
    {

      _gnutls_handshake_log
	("HSK[%x]: Cannot find the appropriate handler for the KX algorithm\n",
	 session);
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }


  return 0;
}

Project: gnutls
File: gnutls_handshake.c

_gnutls_send_supplemental (gnutls_session_t session, int again)
{
  int ret = 0;

  _gnutls_debug_log ("EXT[%x]: Sending supplemental data\n", session);

  if (again)
    ret = _gnutls_send_handshake (session, NULL, 0,
				  GNUTLS_HANDSHAKE_SUPPLEMENTAL);
  else
    {
      gnutls_buffer buf;
      _gnutls_buffer_init (&buf);

      ret = _gnutls_gen_supplemental (session, &buf);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      ret = _gnutls_send_handshake (session, buf.data, buf.length,
				    GNUTLS_HANDSHAKE_SUPPLEMENTAL);
      _gnutls_buffer_clear (&buf);
    }

  return ret;
}

Project: gnutls
File: ext_server_name.c

gnutls_server_name_set (gnutls_session_t session,
			gnutls_server_name_type_t type,
			const void *name, size_t name_length)
{
  int server_names;

  if (session->security_parameters.entity == GNUTLS_SERVER)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  if (name_length > MAX_SERVER_NAME_SIZE)
    return GNUTLS_E_SHORT_MEMORY_BUFFER;

  server_names =
    session->security_parameters.extensions.server_names_size + 1;

  if (server_names > MAX_SERVER_NAME_EXTENSIONS)
    server_names = MAX_SERVER_NAME_EXTENSIONS;

  session->security_parameters.extensions.server_names[server_names -
						       1].type = type;
  memcpy (session->security_parameters.extensions.
	  server_names[server_names - 1].name, name, name_length);
  session->security_parameters.extensions.server_names[server_names -
						       1].name_length =
    name_length;

  session->security_parameters.extensions.server_names_size++;

  return 0;
}

Project: gnutls
File: gnutls_handshake.c

gnutls_handshake_get_last_out (gnutls_session_t session)
{
  return session->internals.last_handshake_out;
}