Example #1
0
/* Read a v2 client hello. Some browsers still use that beast!
 * However they set their version to 3.0 or 3.1.
 */
int
_gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data,
			     unsigned int datalen)
{
	uint16_t session_id_len = 0;
	int pos = 0;
	int ret = 0, sret = 0;
	uint16_t sizeOfSuites;
	gnutls_protocol_t adv_version;
	uint8_t rnd[GNUTLS_RANDOM_SIZE];
	int len = datalen;
	uint16_t challenge;
	uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE];

	DECR_LEN(len, 2);

	_gnutls_handshake_log
	    ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
	     data[pos], data[pos + 1]);

	set_adv_version(session, data[pos], data[pos + 1]);

	adv_version = _gnutls_version_get(data[pos], data[pos + 1]);

	ret = _gnutls_negotiate_version(session, adv_version);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	pos += 2;

	/* Read uint16_t cipher_spec_length */
	DECR_LEN(len, 2);
	sizeOfSuites = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	/* read session id length */
	DECR_LEN(len, 2);
	session_id_len = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	/* read challenge length */
	DECR_LEN(len, 2);
	challenge = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
	}

	/* call the user hello callback
	 */
	ret = _gnutls_user_hello_func(session, adv_version);
	if (ret < 0) {
		if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
			sret = GNUTLS_E_INT_RET_0;
		} else {
			gnutls_assert();
			return ret;
		}
	}

	/* find an appropriate cipher suite */

	DECR_LEN(len, sizeOfSuites);
	ret =
	    _gnutls_handshake_select_v2_suite(session, &data[pos],
					      sizeOfSuites);

	pos += sizeOfSuites;
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	/* check if the credentials (username, public key etc.) are ok
	 */
	if (_gnutls_get_kx_cred
	    (session,
	     _gnutls_cipher_suite_get_kx_algo(session->security_parameters.
					      cipher_suite)) == NULL) {
		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.
				    cipher_suite));
	if (session->internals.auth_struct == NULL) {

		_gnutls_handshake_log
		    ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
		     session);

		gnutls_assert();
		return GNUTLS_E_INTERNAL_ERROR;
	}

	/* read random new values -skip session id for now */
	DECR_LEN(len, session_id_len);	/* skip session id for now */
	memcpy(session_id, &data[pos], session_id_len);
	pos += session_id_len;

	DECR_LEN(len, challenge);
	memset(rnd, 0, GNUTLS_RANDOM_SIZE);

	memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos],
	       challenge);

	ret = _gnutls_set_client_random(session, rnd);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* generate server random value */
	ret = _gnutls_set_server_random(session, NULL);
	if (ret < 0)
		return gnutls_assert_val(ret);

	session->security_parameters.timestamp = gnutls_time(NULL);


	/* RESUME SESSION */

	DECR_LEN(len, session_id_len);
	ret =
	    _gnutls_server_restore_session(session, session_id,
					   session_id_len);

	if (ret == 0) {		/* resumed! */
		/* get the new random values */
		memcpy(session->internals.resumed_security_parameters.
		       server_random,
		       session->security_parameters.server_random,
		       GNUTLS_RANDOM_SIZE);
		memcpy(session->internals.resumed_security_parameters.
		       client_random,
		       session->security_parameters.client_random,
		       GNUTLS_RANDOM_SIZE);

		session->internals.resumed = RESUME_TRUE;
		return 0;
	} else {
		_gnutls_generate_session_id(session->security_parameters.
					    session_id,
					    &session->security_parameters.
					    session_id_size);
		session->internals.resumed = RESUME_FALSE;
	}

	_gnutls_epoch_set_compression(session, EPOCH_NEXT,
				      GNUTLS_COMP_NULL);
	session->security_parameters.compression_method = GNUTLS_COMP_NULL;

	return sret;
}
Example #2
0
/*
 * Return zero if session tickets haven't been enabled.
 */
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
{
	uint8_t *p;
	int data_size;
	gnutls_buffer_st buf;
	uint16_t ticket_len;
	int ret;
	session_ticket_ext_st *priv = NULL;
	gnutls_ext_priv_data_t epriv;

	if (session->internals.flags & GNUTLS_NO_TICKETS)
		return 0;
	if (!session->internals.session_ticket_renew)
		return 0;

	/* This is the last flight and peer cannot be sure
	 * we have received it unless we notify him. So we
	 * wait for a message and retransmit if needed. */
	if (IS_DTLS(session) && !_dtls_is_async(session)) {
		unsigned have;
		mbuffer_st *bufel = NULL;

		have = gnutls_record_check_pending(session) +
		       record_check_unprocessed(session);

		if (have != 0) {
			bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL);
		}

		if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
			ret = _dtls_wait_and_retransmit(session);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}
	}

	ret = _gnutls_recv_handshake(session,
				     GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
				     0, &buf);
	if (ret < 0)
		return gnutls_assert_val_fatal(ret);

	p = buf.data;
	data_size = buf.length;

	DECR_LENGTH_COM(data_size, 4, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	/* skip over lifetime hint */
	p += 4;

	DECR_LENGTH_COM(data_size, 2, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	ticket_len = _gnutls_read_uint16(p);
	p += 2;

	DECR_LENGTH_COM(data_size, ticket_len, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);

	priv = gnutls_calloc(1, sizeof(*priv));
	if (!priv) {
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto error;
	}
	priv->session_ticket =
	    gnutls_realloc_fast(priv->session_ticket, ticket_len);
	if (!priv->session_ticket) {
		gnutls_free(priv);
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto error;
	}
	memcpy(priv->session_ticket, p, ticket_len);
	priv->session_ticket_len = ticket_len;
	epriv = priv;

	/* Discard the current session ID.  (RFC5077 3.4) */
	ret =
	    _gnutls_generate_session_id(session->security_parameters.
					session_id,
					&session->security_parameters.
					session_id_size);
	if (ret < 0) {
		gnutls_assert();
		session_ticket_deinit_data(epriv);
		ret = GNUTLS_E_INTERNAL_ERROR;
		goto error;
	}
	ret = 0;

	_gnutls_handshake_log
		    ("HSK[%p]: received session ticket\n", session);
	session->internals.hsk_flags |= HSK_TICKET_RECEIVED;

	_gnutls_hello_ext_set_priv(session,
			GNUTLS_EXTENSION_SESSION_TICKET,
			epriv);

      error:
	_gnutls_buffer_clear(&buf);

	return ret;
}
Example #3
0
/* Read a v2 client hello. Some browsers still use that beast!
 * However they set their version to 3.0 or 3.1.
 */
int
_gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data,
			      int datalen)
{
  uint16_t session_id_len = 0;
  int pos = 0;
  int ret = 0;
  uint16_t sizeOfSuites;
  gnutls_protocol_t version;
  opaque rnd[TLS_RANDOM_SIZE];
  int len = datalen;
  int err;
  uint16_t challenge;
  opaque session_id[TLS_MAX_SESSION_ID_SIZE];
  gnutls_protocol_t ver;

  /* we only want to get here once - only in client hello */
  session->internals.v2_hello = 0;

  DECR_LEN (len, 2);

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

  set_adv_version (session, data[pos], data[pos + 1]);

  version = _gnutls_version_get (data[pos], data[pos + 1]);

  /* if we do not support that version  
   */
  if (_gnutls_version_is_supported (session, version) == 0)
    {
      ver = _gnutls_version_lowest (session);
    }
  else
    {
      ver = version;
    }

  _gnutls_set_current_version (session, ver);

  pos += 2;


  /* Read uint16_t cipher_spec_length */
  DECR_LEN (len, 2);
  sizeOfSuites = _gnutls_read_uint16 (&data[pos]);
  pos += 2;

  /* read session id length */
  DECR_LEN (len, 2);
  session_id_len = _gnutls_read_uint16 (&data[pos]);
  pos += 2;

  if (session_id_len > TLS_MAX_SESSION_ID_SIZE)
    {
      gnutls_assert ();
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
    }

  /* read challenge length */
  DECR_LEN (len, 2);
  challenge = _gnutls_read_uint16 (&data[pos]);
  pos += 2;

  if (challenge < 16 || challenge > TLS_RANDOM_SIZE)
    {
      gnutls_assert ();
      return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
    }

  /* find an appropriate cipher suite */

  DECR_LEN (len, sizeOfSuites);
  ret = _gnutls_handshake_select_v2_suite (session, &data[pos], sizeOfSuites);

  pos += sizeOfSuites;
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  /* check if the credentials (username, public key etc.) are ok
   */
  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]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
	 session);

      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }



  /* read random new values -skip session id for now */
  DECR_LEN (len, session_id_len);	/* skip session id for now */
  memcpy (session_id, &data[pos], session_id_len);
  pos += session_id_len;

  DECR_LEN (len, challenge);
  memset (rnd, 0, TLS_RANDOM_SIZE);

  memcpy (&rnd[TLS_RANDOM_SIZE - challenge], &data[pos], challenge);

  _gnutls_set_client_random (session, rnd);

  /* generate server random value */

  _gnutls_tls_create_random (rnd);
  _gnutls_set_server_random (session, rnd);

  session->security_parameters.timestamp = time (NULL);


  /* RESUME SESSION */

  DECR_LEN (len, session_id_len);
  ret = _gnutls_server_restore_session (session, session_id, session_id_len);

  if (ret == 0)
    {				/* resumed! */
      /* get the new random values */
      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;
      return 0;
    }
  else
    {
      _gnutls_generate_session_id (session->security_parameters.
				   session_id,
				   &session->security_parameters.
				   session_id_size);
      session->internals.resumed = RESUME_FALSE;
    }

  session->internals.compression_method = GNUTLS_COMP_NULL;

  return 0;
}
Example #4
0
/*
 * Return zero if session tickets haven't been enabled.
 */
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
{
	mbuffer_st *bufel = NULL;
	uint8_t *data = NULL, *p;
	int data_size = 0;
	int ret;
	gnutls_datum_t state = { NULL, 0 };
	uint16_t epoch_saved = session->security_parameters.epoch_write;
	gnutls_datum_t ticket_data;

	if (again == 0) {
		if (session->internals.flags & GNUTLS_NO_TICKETS)
			return 0;
		if (!session->internals.session_ticket_renew)
			return 0;

		_gnutls_handshake_log
		    ("HSK[%p]: sending session ticket\n", session);

		/* XXX: Temporarily set write algorithms to be used.
		   _gnutls_write_connection_state_init() does this job, but it also
		   triggers encryption, while NewSessionTicket should not be
		   encrypted in the record layer. */
		ret =
		    _gnutls_epoch_set_keys(session,
					   session->security_parameters.
					   epoch_next, 0);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		/* Under TLS1.2 with session tickets, the session ID is used for different
		 * purposes than the TLS1.0 session ID. Ensure that there is an internally
		 * set value which the server will see on the original and resumed sessions */
		if (session->internals.resumed != RESUME_TRUE) {
			ret = _gnutls_generate_session_id(session->security_parameters.
							  session_id,
							  &session->security_parameters.
							  session_id_size);
			if (ret < 0) {
				gnutls_assert();
				return ret;
			}
		}

		session->security_parameters.epoch_write =
		    session->security_parameters.epoch_next;

		/* Pack security parameters. */
		ret = _gnutls_session_pack(session, &state);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		/* Generate an encrypted ticket */
		ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data);
		session->security_parameters.epoch_write = epoch_saved;
		_gnutls_free_datum(&state);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		bufel =
		    _gnutls_handshake_alloc(session, 
					    4 + 2 + ticket_data.size);
		if (!bufel) {
			gnutls_assert();
			_gnutls_free_datum(&ticket_data);
			return GNUTLS_E_MEMORY_ERROR;
		}

		data = _mbuffer_get_udata_ptr(bufel);
		p = data;

		_gnutls_write_uint32(session->internals.expire_time, p);
		p += 4;

		_gnutls_write_uint16(ticket_data.size, p);
		p += 2;

		memcpy(p, ticket_data.data, ticket_data.size);
		p += ticket_data.size;

		_gnutls_free_datum(&ticket_data);

		data_size = p - data;

		session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
	}
	return _gnutls_send_handshake(session, data_size ? bufel : NULL,
				      GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
}
Example #5
0
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
{
    uint8_t *p;
    int data_size;
    gnutls_buffer_st buf;
    uint16_t ticket_len;
    int ret;
    session_ticket_ext_st *priv = NULL;
    extension_priv_data_t epriv;

    ret =
        _gnutls_ext_get_session_data(session,
                                     GNUTLS_EXTENSION_SESSION_TICKET,
                                     &epriv);
    if (ret < 0) {
        gnutls_assert();
        return 0;
    }
    priv = epriv;

    if (!priv->session_ticket_renew)
        return 0;

    /* This is the last flight and peer cannot be sure
     * we have received it unless we notify him. So we
     * wait for a message and retransmit if needed. */
    if (IS_DTLS(session) && !_dtls_is_async(session) &&
            (gnutls_record_check_pending(session) +
             record_check_unprocessed(session)) == 0) {
        ret = _dtls_wait_and_retransmit(session);
        if (ret < 0)
            return gnutls_assert_val(ret);
    }

    ret = _gnutls_recv_handshake(session,
                                 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
                                 0, &buf);
    if (ret < 0)
        return gnutls_assert_val_fatal(ret);

    p = buf.data;
    data_size = buf.length;

    DECR_LENGTH_COM(data_size, 4, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    /* skip over lifetime hint */
    p += 4;

    DECR_LENGTH_COM(data_size, 2, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    ticket_len = _gnutls_read_uint16(p);
    p += 2;

    DECR_LENGTH_COM(data_size, ticket_len, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    priv->session_ticket =
        gnutls_realloc_fast(priv->session_ticket, ticket_len);
    if (!priv->session_ticket) {
        gnutls_assert();
        ret = GNUTLS_E_MEMORY_ERROR;
        goto error;
    }
    memcpy(priv->session_ticket, p, ticket_len);
    priv->session_ticket_len = ticket_len;

    /* Discard the current session ID.  (RFC5077 3.4) */
    ret =
        _gnutls_generate_session_id(session->security_parameters.
                                    session_id,
                                    &session->security_parameters.
                                    session_id_size);
    if (ret < 0) {
        gnutls_assert();
        gnutls_free(priv->session_ticket);
        priv->session_ticket = NULL;
        ret = GNUTLS_E_INTERNAL_ERROR;
        goto error;
    }
    ret = 0;

error:
    _gnutls_buffer_clear(&buf);

    return ret;
}