Beispiel #1
0
/* Apply the TLS PRF using the TLS/IA inner secret as keying material,
   where the seed is the client random concatenated with the server
   random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
   respectively).  LABEL and LABEL_SIZE is used as the label.  The
   result is placed in pre-allocated OUT of OUTSIZE length. */
static int
_gnutls_ia_prf (gnutls_session_t session,
		size_t label_size,
		const char *label,
		size_t extra_size,
		const char *extra, size_t outsize, opaque * out)
{
  int ret;
  opaque *seed;
  size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size;

  seed = gnutls_malloc (seedsize);
  if (!seed)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  memcpy (seed, session->security_parameters.server_random,
	  GNUTLS_RANDOM_SIZE);
  memcpy (seed + GNUTLS_RANDOM_SIZE,
	  session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
  memcpy (seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size);

  ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
		     GNUTLS_MASTER_SIZE,
		     label, label_size, seed, seedsize, outsize, out);

  gnutls_free (seed);

  return ret;
}
Beispiel #2
0
/**
 * gnutls_ia_verify_endphase:
 * @session: is a #gnutls_session_t structure.
 * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
 *
 * Verify TLS/IA end phase checksum data.  If verification fails, the
 * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
 * sie.
 *
 * This function is called when gnutls_ia_recv() return
 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
 *
 * Return value: Return 0 on successful verification, or an error
 * code.  If the checksum verification of the end phase message fails,
 * %GNUTLS_E_IA_VERIFY_FAILED is returned.
 **/
int
gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum)
{
  char local_checksum[CHECKSUM_SIZE];
  int client = session->security_parameters.entity == GNUTLS_CLIENT;
  const char *label = client ? server_finished_label : client_finished_label;
  int size_of_label = client ? sizeof (server_finished_label) :
    sizeof (client_finished_label);
  int ret;

  ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
		     GNUTLS_MASTER_SIZE,
		     label, size_of_label - 1,
		     "", 0, CHECKSUM_SIZE, local_checksum);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
    {
      ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
			       GNUTLS_A_INNER_APPLICATION_VERIFICATION);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      return GNUTLS_E_IA_VERIFY_FAILED;
    }

  return 0;
}
Beispiel #3
0
/**
 * gnutls_ia_endphase_send:
 * @session: is a #gnutls_session_t structure.
 * @final_p: Set iff this should signal the final phase.
 *
 * Send a TLS/IA end phase message.
 *
 * In the client, this should only be used to acknowledge an end phase
 * message sent by the server.
 *
 * In the server, this can be called instead of gnutls_ia_send() if
 * the server wishes to end an application phase.
 *
 * Return value: Return 0 on success, or an error code.
 **/
int
gnutls_ia_endphase_send (gnutls_session_t session, int final_p)
{
  opaque local_checksum[CHECKSUM_SIZE];
  int client = session->security_parameters.entity == GNUTLS_CLIENT;
  const char *label = client ? client_finished_label : server_finished_label;
  int size_of_label = client ? sizeof (client_finished_label) :
    sizeof (server_finished_label);
  ssize_t len;
  int ret;

  ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
		     GNUTLS_MASTER_SIZE, label, size_of_label - 1,
		     /* XXX specification unclear on seed. */
		     "", 0, CHECKSUM_SIZE, local_checksum);
  if (ret < 0)
    return ret;

  len = _gnutls_send_inner_application
    (session,
     final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
     GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);

  /* XXX  Instead of calling this function over and over...?
   * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
   *  len = _gnutls_io_write_flush(session);
   */

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

  return 0;
}
Beispiel #4
0
/* This function is to be called after handshake, when master_secret,
 *  client_random and server_random have been initialized. 
 * This function creates the keys and stores them into pending session.
 * (session->cipher_specs)
 */
static int
_gnutls_set_keys (gnutls_session_t session, record_parameters_st * params,
                  int hash_size, int IV_size, int key_size, int export_flag)
{
  /* FIXME: This function is too long
   */
  opaque rnd[2 * GNUTLS_RANDOM_SIZE];
  opaque rrnd[2 * GNUTLS_RANDOM_SIZE];
  int pos, ret;
  int block_size;
  char buf[65];
  /* avoid using malloc */
  opaque key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE +
                   2 * MAX_CIPHER_BLOCK_SIZE];
  record_state_st *client_write, *server_write;

  client_write =
    session->security_parameters.entity ==
    GNUTLS_CLIENT ? &params->write : &params->read;
  server_write =
    session->security_parameters.entity ==
    GNUTLS_SERVER ? &params->write : &params->read;

  block_size = 2 * hash_size + 2 * key_size;
  if (export_flag == 0)
    block_size += 2 * IV_size;

  memcpy (rnd, session->security_parameters.server_random,
          GNUTLS_RANDOM_SIZE);
  memcpy (&rnd[GNUTLS_RANDOM_SIZE],
          session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);

  memcpy (rrnd, session->security_parameters.client_random,
          GNUTLS_RANDOM_SIZE);
  memcpy (&rrnd[GNUTLS_RANDOM_SIZE],
          session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);

  if (session->security_parameters.version == GNUTLS_SSL3)
    {                           /* SSL 3 */
      ret =
        _gnutls_ssl3_generate_random
        (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd,
         2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
    }
  else
    {                           /* TLS 1.0 */
      ret =
        _gnutls_PRF (session, session->security_parameters.master_secret,
                     GNUTLS_MASTER_SIZE, keyexp, keyexp_length,
                     rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
    }

  if (ret < 0)
    return gnutls_assert_val (ret);

  _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
                    _gnutls_bin2hex (key_block, block_size, buf,
                                     sizeof (buf), NULL));

  pos = 0;
  if (hash_size > 0)
    {

      if (_gnutls_sset_datum
          (&client_write->mac_secret, &key_block[pos], hash_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      pos += hash_size;

      if (_gnutls_sset_datum
          (&server_write->mac_secret, &key_block[pos], hash_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      pos += hash_size;
    }

  if (key_size > 0)
    {
      opaque key1[EXPORT_FINAL_KEY_SIZE];
      opaque key2[EXPORT_FINAL_KEY_SIZE];
      opaque *client_write_key, *server_write_key;
      int client_write_key_size, server_write_key_size;

      if (export_flag == 0)
        {
          client_write_key = &key_block[pos];
          client_write_key_size = key_size;

          pos += key_size;

          server_write_key = &key_block[pos];
          server_write_key_size = key_size;

          pos += key_size;

        }
      else
        {                       /* export */
          client_write_key = key1;
          server_write_key = key2;

          /* generate the final keys */

          if (session->security_parameters.version == GNUTLS_SSL3)
            {                   /* SSL 3 */
              ret =
                _gnutls_ssl3_hash_md5 (&key_block[pos],
                                       key_size, rrnd,
                                       2 * GNUTLS_RANDOM_SIZE,
                                       EXPORT_FINAL_KEY_SIZE,
                                       client_write_key);

            }
          else
            {                   /* TLS 1.0 */
              ret =
                _gnutls_PRF (session, &key_block[pos], key_size,
                             cliwrite, cliwrite_length,
                             rrnd,
                             2 * GNUTLS_RANDOM_SIZE,
                             EXPORT_FINAL_KEY_SIZE, client_write_key);
            }

          if (ret < 0)
            return gnutls_assert_val (ret);

          client_write_key_size = EXPORT_FINAL_KEY_SIZE;
          pos += key_size;

          if (session->security_parameters.version == GNUTLS_SSL3)
            {                   /* SSL 3 */
              ret =
                _gnutls_ssl3_hash_md5 (&key_block[pos], key_size,
                                       rnd, 2 * GNUTLS_RANDOM_SIZE,
                                       EXPORT_FINAL_KEY_SIZE,
                                       server_write_key);
            }
          else
            {                   /* TLS 1.0 */
              ret =
                _gnutls_PRF (session, &key_block[pos], key_size,
                             servwrite, servwrite_length,
                             rrnd, 2 * GNUTLS_RANDOM_SIZE,
                             EXPORT_FINAL_KEY_SIZE, server_write_key);
            }

          if (ret < 0)
            return gnutls_assert_val (ret);

          server_write_key_size = EXPORT_FINAL_KEY_SIZE;
          pos += key_size;
        }

      if (_gnutls_sset_datum
          (&client_write->key, client_write_key, client_write_key_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n",
                        client_write_key_size,
                        _gnutls_bin2hex (client_write_key,
                                         client_write_key_size, buf,
                                         sizeof (buf), NULL));

      if (_gnutls_sset_datum
          (&server_write->key, server_write_key, server_write_key_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n",
                        server_write_key_size,
                        _gnutls_bin2hex (server_write_key,
                                         server_write_key_size, buf,
                                         sizeof (buf), NULL));

    }


  /* IV generation in export and non export ciphers.
   */
  if (IV_size > 0 && export_flag == 0)
    {
      if (_gnutls_sset_datum
          (&client_write->IV, &key_block[pos], IV_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      pos += IV_size;

      if (_gnutls_sset_datum
          (&server_write->IV, &key_block[pos], IV_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      pos += IV_size;

    }
  else if (IV_size > 0 && export_flag != 0)
    {
      opaque iv_block[MAX_CIPHER_BLOCK_SIZE * 2];

      if (session->security_parameters.version == GNUTLS_SSL3)
        {                       /* SSL 3 */
          ret = _gnutls_ssl3_hash_md5 ("", 0,
                                       rrnd, GNUTLS_RANDOM_SIZE * 2,
                                       IV_size, iv_block);

          if (ret < 0)
            return gnutls_assert_val (ret);


          ret = _gnutls_ssl3_hash_md5 ("", 0, rnd,
                                       GNUTLS_RANDOM_SIZE * 2,
                                       IV_size, &iv_block[IV_size]);

        }
      else
        {                       /* TLS 1.0 */
          ret = _gnutls_PRF (session, "", 0,
                             ivblock, ivblock_length, rrnd,
                             2 * GNUTLS_RANDOM_SIZE, IV_size * 2, iv_block);
        }

      if (ret < 0)
        return gnutls_assert_val (ret);

      if (_gnutls_sset_datum (&client_write->IV, iv_block, IV_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);

      if (_gnutls_sset_datum
          (&server_write->IV, &iv_block[IV_size], IV_size) < 0)
        return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
    }

  return 0;
}
Beispiel #5
0
static int
generate_normal_master (gnutls_session_t session, int keep_premaster)
{
    int ret = 0;
    char buf[512];

    _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size,
                      _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf,
                                       sizeof (buf)));
    _gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32,
                      _gnutls_bin2hex (session->
                                       security_parameters.client_random, 32,
                                       buf, sizeof (buf)));
    _gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32,
                      _gnutls_bin2hex (session->
                                       security_parameters.server_random, 32,
                                       buf, sizeof (buf)));

    if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
    {
        opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1];

        memcpy (rnd, session->security_parameters.client_random,
                GNUTLS_RANDOM_SIZE);
        memcpy (&rnd[GNUTLS_RANDOM_SIZE],
                session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);

        ret =
            _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size,
                                          rnd, 2 * GNUTLS_RANDOM_SIZE,
                                          GNUTLS_MASTER_SIZE,
                                          session->
                                          security_parameters.master_secret);

    }
    else if (session->security_parameters.extensions.oprfi_client_len > 0 &&
             session->security_parameters.extensions.oprfi_server_len > 0)
    {
        opaque *rnd;
        size_t rndlen = 2 * GNUTLS_RANDOM_SIZE;

        rndlen += session->security_parameters.extensions.oprfi_client_len;
        rndlen += session->security_parameters.extensions.oprfi_server_len;

        rnd = gnutls_malloc (rndlen + 1);
        if (!rnd)
        {
            gnutls_assert ();
            return GNUTLS_E_MEMORY_ERROR;
        }

        _gnutls_hard_log ("INT: CLIENT OPRFI[%d]: %s\n",
                          session->security_parameters.extensions.
                          oprfi_server_len,
                          _gnutls_bin2hex (session->
                                           security_parameters.extensions.
                                           oprfi_client,
                                           session->
                                           security_parameters.extensions.
                                           oprfi_client_len, buf,
                                           sizeof (buf)));
        _gnutls_hard_log ("INT: SERVER OPRFI[%d]: %s\n",
                          session->security_parameters.extensions.
                          oprfi_server_len,
                          _gnutls_bin2hex (session->
                                           security_parameters.extensions.
                                           oprfi_server,
                                           session->
                                           security_parameters.extensions.
                                           oprfi_server_len, buf,
                                           sizeof (buf)));

        memcpy (rnd, session->security_parameters.client_random,
                GNUTLS_RANDOM_SIZE);
        memcpy (rnd + GNUTLS_RANDOM_SIZE,
                session->security_parameters.extensions.oprfi_client,
                session->security_parameters.extensions.oprfi_client_len);
        memcpy (rnd + GNUTLS_RANDOM_SIZE +
                session->security_parameters.extensions.oprfi_client_len,
                session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
        memcpy (rnd + GNUTLS_RANDOM_SIZE +
                session->security_parameters.extensions.oprfi_client_len +
                GNUTLS_RANDOM_SIZE,
                session->security_parameters.extensions.oprfi_server,
                session->security_parameters.extensions.oprfi_server_len);

        ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size,
                           MASTER_SECRET, strlen (MASTER_SECRET),
                           rnd, rndlen, GNUTLS_MASTER_SIZE,
                           session->security_parameters.master_secret);

        gnutls_free (rnd);
    }
    else
    {
        opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1];

        memcpy (rnd, session->security_parameters.client_random,
                GNUTLS_RANDOM_SIZE);
        memcpy (&rnd[GNUTLS_RANDOM_SIZE],
                session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);

        ret =
            _gnutls_PRF (session, PREMASTER.data, PREMASTER.size,
                         MASTER_SECRET, strlen (MASTER_SECRET),
                         rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE,
                         session->security_parameters.master_secret);
    }

    /* TLS/IA inner secret is derived from the master secret. */
    memcpy (session->security_parameters.inner_secret,
            session->security_parameters.master_secret, GNUTLS_MASTER_SIZE);

    if (!keep_premaster)
        _gnutls_free_datum (&PREMASTER);

    if (ret < 0)
        return ret;

    _gnutls_hard_log ("INT: MASTER SECRET: %s\n",
                      _gnutls_bin2hex (session->
                                       security_parameters.master_secret,
                                       GNUTLS_MASTER_SIZE, buf, sizeof (buf)));

    return ret;
}
static int
generate_normal_master (gnutls_session_t session, int keep_premaster)
{
  int ret = 0;
  char buf[512];

  _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size,
                    _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf,
                                     sizeof (buf), NULL));
  _gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32,
                    _gnutls_bin2hex (session->
                                     security_parameters.client_random, 32,
                                     buf, sizeof (buf), NULL));
  _gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32,
                    _gnutls_bin2hex (session->
                                     security_parameters.server_random, 32,
                                     buf, sizeof (buf), NULL));

  if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
    {
      opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1];

      memcpy (rnd, session->security_parameters.client_random,
              GNUTLS_RANDOM_SIZE);
      memcpy (&rnd[GNUTLS_RANDOM_SIZE],
              session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);

      ret =
        _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size,
                                      rnd, 2 * GNUTLS_RANDOM_SIZE,
                                      GNUTLS_MASTER_SIZE,
                                      session->
                                      security_parameters.master_secret);

    }
  else
    {
      opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1];

      memcpy (rnd, session->security_parameters.client_random,
              GNUTLS_RANDOM_SIZE);
      memcpy (&rnd[GNUTLS_RANDOM_SIZE],
              session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);

      ret =
        _gnutls_PRF (session, PREMASTER.data, PREMASTER.size,
                     MASTER_SECRET, MASTER_SECRET_SIZE,
                     rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE,
                     session->security_parameters.master_secret);
    }

  if (!keep_premaster)
    _gnutls_free_datum (&PREMASTER);

  if (ret < 0)
    return ret;

  _gnutls_hard_log ("INT: MASTER SECRET: %s\n",
                    _gnutls_bin2hex (session->
                                     security_parameters.master_secret,
                                     GNUTLS_MASTER_SIZE, buf, sizeof (buf),
                                     NULL));

  return ret;
}
Beispiel #7
0
/* here we generate the TLS Master secret.
 */
static int
generate_normal_master(gnutls_session_t session,
		       gnutls_datum_t * premaster, int keep_premaster)
{
	int ret = 0;
	char buf[512];

	_gnutls_hard_log("INT: PREMASTER SECRET[%d]: %s\n",
			 premaster->size, _gnutls_bin2hex(premaster->data,
							  premaster->size,
							  buf, sizeof(buf),
							  NULL));
	_gnutls_hard_log("INT: CLIENT RANDOM[%d]: %s\n", 32,
			 _gnutls_bin2hex(session->security_parameters.
					 client_random, 32, buf,
					 sizeof(buf), NULL));
	_gnutls_hard_log("INT: SERVER RANDOM[%d]: %s\n", 32,
			 _gnutls_bin2hex(session->security_parameters.
					 server_random, 32, buf,
					 sizeof(buf), NULL));

	if (session->security_parameters.ext_master_secret == 0) {
		uint8_t rnd[2 * GNUTLS_RANDOM_SIZE + 1];
		memcpy(rnd, session->security_parameters.client_random,
		       GNUTLS_RANDOM_SIZE);
		memcpy(&rnd[GNUTLS_RANDOM_SIZE],
		       session->security_parameters.server_random,
		       GNUTLS_RANDOM_SIZE);

#ifdef ENABLE_SSL3
		if (get_num_version(session) == GNUTLS_SSL3) {
			ret =
			    _gnutls_ssl3_generate_random(premaster->data,
							 premaster->size, rnd,
							 2 * GNUTLS_RANDOM_SIZE,
							 GNUTLS_MASTER_SIZE,
							 session->security_parameters.
							 master_secret);
		} else
#endif
			ret =
			    _gnutls_PRF(session, premaster->data, premaster->size,
					MASTER_SECRET, MASTER_SECRET_SIZE,
					rnd, 2 * GNUTLS_RANDOM_SIZE,
					GNUTLS_MASTER_SIZE,
					session->security_parameters.
					master_secret);
	} else {
		gnutls_datum_t shash = {NULL, 0};

		/* draft-ietf-tls-session-hash-02 */
		ret = _gnutls_handshake_get_session_hash(session, &shash);
		if (ret < 0)
			return gnutls_assert_val(ret);
#ifdef ENABLE_SSL3
		if (get_num_version(session) == GNUTLS_SSL3)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
#endif

		ret =
		    _gnutls_PRF(session, premaster->data, premaster->size,
				EXT_MASTER_SECRET, EXT_MASTER_SECRET_SIZE,
				shash.data, shash.size,
				GNUTLS_MASTER_SIZE,
				session->security_parameters.
				master_secret);

		gnutls_free(shash.data);
	}

	write_nss_key_log(session, premaster);

	if (!keep_premaster)
		_gnutls_free_temp_key_datum(premaster);

	if (ret < 0)
		return ret;

	_gnutls_hard_log("INT: MASTER SECRET: %s\n",
			 _gnutls_bin2hex(session->security_parameters.
					 master_secret, GNUTLS_MASTER_SIZE,
					 buf, sizeof(buf), NULL));

	return ret;
}
Beispiel #8
0
/* This function is to be called after handshake, when master_secret,
 *  client_random and server_random have been initialized. 
 * This function creates the keys and stores them into pending session.
 * (session->cipher_specs)
 */
int
_gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size,
		  int key_size, int export_flag)
{

/* FIXME: This function is too long
 */
  opaque *key_block;
  opaque rnd[2 * TLS_RANDOM_SIZE];
  opaque rrnd[2 * TLS_RANDOM_SIZE];
  int pos, ret;
  int block_size;
  char buf[65];

  if (session->cipher_specs.generated_keys != 0)
    {
      /* keys have already been generated.
       * reset generated_keys and exit normally.
       */
      session->cipher_specs.generated_keys = 0;
      return 0;
    }

  block_size = 2 * hash_size + 2 * key_size;
  if (export_flag == 0)
    block_size += 2 * IV_size;

  key_block = gnutls_secure_malloc (block_size);
  if (key_block == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  memcpy (rnd, session->security_parameters.server_random, TLS_RANDOM_SIZE);
  memcpy (&rnd[TLS_RANDOM_SIZE],
	  session->security_parameters.client_random, TLS_RANDOM_SIZE);

  memcpy (rrnd, session->security_parameters.client_random, TLS_RANDOM_SIZE);
  memcpy (&rrnd[TLS_RANDOM_SIZE],
	  session->security_parameters.server_random, TLS_RANDOM_SIZE);

  if (session->security_parameters.version == GNUTLS_SSL3)
    {				/* SSL 3 */
      ret =
	_gnutls_ssl3_generate_random (session->
				      security_parameters.
				      master_secret,
				      TLS_MASTER_SIZE, rnd,
				      2 * TLS_RANDOM_SIZE,
				      block_size, key_block);
    }
  else
    {				/* TLS 1.0 */
      ret =
	_gnutls_PRF (session, session->security_parameters.master_secret,
		     TLS_MASTER_SIZE, keyexp, keyexp_length,
		     rnd, 2 * TLS_RANDOM_SIZE, block_size, key_block);
    }

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

  _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
		    _gnutls_bin2hex (key_block, block_size, buf,
				     sizeof (buf)));

  pos = 0;
  if (hash_size > 0)
    {
      if (_gnutls_sset_datum
	  (&session->cipher_specs.client_write_mac_secret,
	   &key_block[pos], hash_size) < 0)
	{
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}
      pos += hash_size;

      if (_gnutls_sset_datum
	  (&session->cipher_specs.server_write_mac_secret,
	   &key_block[pos], hash_size) < 0)
	{
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}
      pos += hash_size;
    }

  if (key_size > 0)
    {
      opaque *client_write_key, *server_write_key;
      int client_write_key_size, server_write_key_size;
      int free_keys = 0;

      if (export_flag == 0)
	{
	  client_write_key = &key_block[pos];
	  client_write_key_size = key_size;

	  pos += key_size;

	  server_write_key = &key_block[pos];
	  server_write_key_size = key_size;

	  pos += key_size;

	}
      else
	{			/* export */
	  free_keys = 1;

	  client_write_key = gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE);
	  if (client_write_key == NULL)
	    {
	      gnutls_assert ();
	      gnutls_free (key_block);
	      return GNUTLS_E_MEMORY_ERROR;
	    }

	  server_write_key = gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE);
	  if (server_write_key == NULL)
	    {
	      gnutls_assert ();
	      gnutls_free (key_block);
	      gnutls_free (client_write_key);
	      return GNUTLS_E_MEMORY_ERROR;
	    }

	  /* generate the final keys */

	  if (session->security_parameters.version == GNUTLS_SSL3)
	    {			/* SSL 3 */
	      ret =
		_gnutls_ssl3_hash_md5 (&key_block[pos],
				       key_size, rrnd,
				       2 * TLS_RANDOM_SIZE,
				       EXPORT_FINAL_KEY_SIZE,
				       client_write_key);

	    }
	  else
	    {			/* TLS 1.0 */
	      ret =
		_gnutls_PRF (session, &key_block[pos], key_size,
			     cliwrite, cliwrite_length,
			     rrnd,
			     2 * TLS_RANDOM_SIZE,
			     EXPORT_FINAL_KEY_SIZE, client_write_key);
	    }

	  if (ret < 0)
	    {
	      gnutls_assert ();
	      gnutls_free (key_block);
	      gnutls_free (server_write_key);
	      gnutls_free (client_write_key);
	      return ret;
	    }

	  client_write_key_size = EXPORT_FINAL_KEY_SIZE;
	  pos += key_size;

	  if (session->security_parameters.version == GNUTLS_SSL3)
	    {			/* SSL 3 */
	      ret =
		_gnutls_ssl3_hash_md5 (&key_block[pos], key_size,
				       rnd, 2 * TLS_RANDOM_SIZE,
				       EXPORT_FINAL_KEY_SIZE,
				       server_write_key);
	    }
	  else
	    {			/* TLS 1.0 */
	      ret =
		_gnutls_PRF (session, &key_block[pos], key_size,
			     servwrite, servwrite_length,
			     rrnd, 2 * TLS_RANDOM_SIZE,
			     EXPORT_FINAL_KEY_SIZE, server_write_key);
	    }

	  if (ret < 0)
	    {
	      gnutls_assert ();
	      gnutls_free (key_block);
	      gnutls_free (server_write_key);
	      gnutls_free (client_write_key);
	      return ret;
	    }

	  server_write_key_size = EXPORT_FINAL_KEY_SIZE;
	  pos += key_size;
	}

      if (_gnutls_sset_datum
	  (&session->cipher_specs.client_write_key,
	   client_write_key, client_write_key_size) < 0)
	{
	  gnutls_free (key_block);
	  gnutls_free (server_write_key);
	  gnutls_free (client_write_key);
	  return GNUTLS_E_MEMORY_ERROR;
	}
      _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n",
			client_write_key_size,
			_gnutls_bin2hex (client_write_key,
					 client_write_key_size, buf,
					 sizeof (buf)));

      if (_gnutls_sset_datum
	  (&session->cipher_specs.server_write_key,
	   server_write_key, server_write_key_size) < 0)
	{
	  gnutls_free (key_block);
	  gnutls_free (server_write_key);
	  gnutls_free (client_write_key);
	  return GNUTLS_E_MEMORY_ERROR;
	}

      _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n",
			server_write_key_size,
			_gnutls_bin2hex (server_write_key,
					 server_write_key_size, buf,
					 sizeof (buf)));

      if (free_keys != 0)
	{
	  gnutls_free (server_write_key);
	  gnutls_free (client_write_key);
	}
    }


  /* IV generation in export and non export ciphers.
   */
  if (IV_size > 0 && export_flag == 0)
    {
      if (_gnutls_sset_datum
	  (&session->cipher_specs.client_write_IV, &key_block[pos],
	   IV_size) < 0)
	{
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}
      pos += IV_size;

      if (_gnutls_sset_datum
	  (&session->cipher_specs.server_write_IV, &key_block[pos],
	   IV_size) < 0)
	{
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}
      pos += IV_size;

    }
  else if (IV_size > 0 && export_flag != 0)
    {
      opaque *iv_block = gnutls_alloca (IV_size * 2);
      if (iv_block == NULL)
	{
	  gnutls_assert ();
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}

      if (session->security_parameters.version == GNUTLS_SSL3)
	{			/* SSL 3 */
	  ret = _gnutls_ssl3_hash_md5 ("", 0,
				       rrnd, TLS_RANDOM_SIZE * 2,
				       IV_size, iv_block);

	  if (ret < 0)
	    {
	      gnutls_assert ();
	      gnutls_free (key_block);
	      gnutls_afree (iv_block);
	      return ret;
	    }

	  ret = _gnutls_ssl3_hash_md5 ("", 0, rnd,
				       TLS_RANDOM_SIZE * 2,
				       IV_size, &iv_block[IV_size]);

	}
      else
	{			/* TLS 1.0 */
	  ret = _gnutls_PRF (session, "", 0,
			     ivblock, ivblock_length, rrnd,
			     2 * TLS_RANDOM_SIZE, IV_size * 2, iv_block);
	}

      if (ret < 0)
	{
	  gnutls_assert ();
	  gnutls_afree (iv_block);
	  gnutls_free (key_block);
	  return ret;
	}

      if (_gnutls_sset_datum
	  (&session->cipher_specs.client_write_IV, iv_block, IV_size) < 0)
	{
	  gnutls_afree (iv_block);
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}

      if (_gnutls_sset_datum
	  (&session->cipher_specs.server_write_IV,
	   &iv_block[IV_size], IV_size) < 0)
	{
	  gnutls_afree (iv_block);
	  gnutls_free (key_block);
	  return GNUTLS_E_MEMORY_ERROR;
	}

      gnutls_afree (iv_block);
    }

  gnutls_free (key_block);

  session->cipher_specs.generated_keys = 1;

  return 0;
}
Beispiel #9
0
/* This function is to be called after handshake, when master_secret,
 *  client_random and server_random have been initialized. 
 * This function creates the keys and stores them into pending session.
 * (session->cipher_specs)
 */
static int
_gnutls_set_keys(gnutls_session_t session, record_parameters_st * params,
		 int hash_size, int IV_size, int key_size)
{
	/* FIXME: This function is too long
	 */
	uint8_t rnd[2 * GNUTLS_RANDOM_SIZE];
	uint8_t rrnd[2 * GNUTLS_RANDOM_SIZE];
	int pos, ret;
	int block_size;
	char buf[65];
	/* avoid using malloc */
	uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE +
			  2 * MAX_CIPHER_BLOCK_SIZE];
	record_state_st *client_write, *server_write;

	if (session->security_parameters.entity == GNUTLS_CLIENT) {
		client_write = &params->write;
		server_write = &params->read;
	} else {
		client_write = &params->read;
		server_write = &params->write;
	}

	block_size = 2 * hash_size + 2 * key_size;
	block_size += 2 * IV_size;

	memcpy(rnd, session->security_parameters.server_random,
	       GNUTLS_RANDOM_SIZE);
	memcpy(&rnd[GNUTLS_RANDOM_SIZE],
	       session->security_parameters.client_random,
	       GNUTLS_RANDOM_SIZE);

	memcpy(rrnd, session->security_parameters.client_random,
	       GNUTLS_RANDOM_SIZE);
	memcpy(&rrnd[GNUTLS_RANDOM_SIZE],
	       session->security_parameters.server_random,
	       GNUTLS_RANDOM_SIZE);

	if (get_num_version(session) == GNUTLS_SSL3) {	/* SSL 3 */
		ret =
		    _gnutls_ssl3_generate_random
		    (session->security_parameters.master_secret,
		     GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE,
		     block_size, key_block);
	} else {		/* TLS 1.0 */
		ret =
		    _gnutls_PRF(session,
				session->security_parameters.master_secret,
				GNUTLS_MASTER_SIZE, keyexp, keyexp_length,
				rnd, 2 * GNUTLS_RANDOM_SIZE, block_size,
				key_block);
	}

	if (ret < 0)
		return gnutls_assert_val(ret);

	_gnutls_hard_log("INT: KEY BLOCK[%d]: %s\n", block_size,
			 _gnutls_bin2hex(key_block, block_size, buf,
					 sizeof(buf), NULL));

	pos = 0;
	if (hash_size > 0) {

		if (_gnutls_set_datum
		    (&client_write->mac_secret, &key_block[pos],
		     hash_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		pos += hash_size;

		if (_gnutls_set_datum
		    (&server_write->mac_secret, &key_block[pos],
		     hash_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		pos += hash_size;
	}

	if (key_size > 0) {
		uint8_t *client_write_key, *server_write_key;
		int client_write_key_size, server_write_key_size;

		client_write_key = &key_block[pos];
		client_write_key_size = key_size;

		pos += key_size;

		server_write_key = &key_block[pos];
		server_write_key_size = key_size;

		pos += key_size;

		if (_gnutls_set_datum
		    (&client_write->key, client_write_key,
		     client_write_key_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		_gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n",
				 client_write_key_size,
				 _gnutls_bin2hex(client_write_key,
						 client_write_key_size,
						 buf, sizeof(buf), NULL));

		if (_gnutls_set_datum
		    (&server_write->key, server_write_key,
		     server_write_key_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		_gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n",
				 server_write_key_size,
				 _gnutls_bin2hex(server_write_key,
						 server_write_key_size,
						 buf, sizeof(buf), NULL));

	}

	/* IV generation in export and non export ciphers.
	 */
	if (IV_size > 0) {
		if (_gnutls_set_datum
		    (&client_write->IV, &key_block[pos], IV_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		pos += IV_size;

		if (_gnutls_set_datum
		    (&server_write->IV, &key_block[pos], IV_size) < 0)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);


		_gnutls_hard_log("INT: CLIENT WRITE IV [%d]: %s\n",
				 client_write->IV.size,
				 _gnutls_bin2hex(client_write->IV.data,
						 client_write->IV.size,
						 buf, sizeof(buf), NULL));

		_gnutls_hard_log("INT: SERVER WRITE IV [%d]: %s\n",
				 server_write->IV.size,
				 _gnutls_bin2hex(server_write->IV.data,
						 server_write->IV.size,
						 buf, sizeof(buf), NULL));
	}

	return 0;
}