Exemple #1
0
/*-
 * _gnutls_openpgp_privkey_decrypt_data:
 * @key: Holds the key
 * @flags: (0) for now
 * @ciphertext: holds the data to be decrypted
 * @plaintext: will contain newly allocated plaintext
 *
 * This function will sign the given hash using the private key.  You
 * should use gnutls_openpgp_privkey_set_preferred_key_id() before
 * calling this function to set the subkey to use.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 -*/
int
_gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
                                     unsigned int flags,
                                     const gnutls_datum_t * ciphertext,
                                     gnutls_datum_t * plaintext)
{
  int result, i;
  gnutls_pk_params_st params;
  int pk_algorithm;
  uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
  char buf[2*GNUTLS_OPENPGP_KEYID_SIZE+1];

  if (key == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
  if (result == 0)
    {
      uint32_t kid[2];

      KEYID_IMPORT (kid, keyid);

      _gnutls_hard_log("Decrypting using PGP key ID %s\n", _gnutls_bin2hex(keyid, GNUTLS_OPENPGP_KEYID_SIZE, buf, sizeof(buf), NULL));

      result = _gnutls_openpgp_privkey_get_mpis (key, kid, &params);

      i = gnutls_openpgp_privkey_get_subkey_idx (key, keyid);

      pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, i, NULL);
    }
  else
    {
      _gnutls_hard_log("Decrypting using master PGP key\n");

      pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);

      result = _gnutls_openpgp_privkey_get_mpis (key, NULL, &params);

    }

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

  result = _gnutls_pk_decrypt (pk_algorithm, plaintext, ciphertext, &params);

  gnutls_pk_params_clear(&params);
  gnutls_pk_params_release(&params);

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

  return 0;
}
static unsigned email_matches(const gnutls_datum_t *name, const gnutls_datum_t *suffix)
{
	_gnutls_hard_log("matching %.*s with e-mail constraint %.*s\n", name->size, name->data,
		suffix->size, suffix->data);

	if (suffix->size == name->size && memcmp(suffix->data, name->data, suffix->size) == 0)
		return 1; /* match */

	return email_ends_with(name, suffix);
}
Exemple #3
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;
}
Exemple #4
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;
}
Exemple #5
0
int
_gnutls_fbase64_decode(const char *header, const uint8_t * data,
		       size_t data_size, gnutls_datum_t * result)
{
	int ret;
	static const char top[] = "-----BEGIN ";
	static const char bottom[] = "-----END ";
	uint8_t *rdata, *kdata;
	int rdata_size;
	char pem_header[128];

	_gnutls_str_cpy(pem_header, sizeof(pem_header), top);
	if (header != NULL)
		_gnutls_str_cat(pem_header, sizeof(pem_header), header);

	rdata = memmem(data, data_size, pem_header, strlen(pem_header));

	if (rdata == NULL) {
		gnutls_assert();
		_gnutls_hard_log("Could not find '%s'\n", pem_header);
		return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
	}

	data_size -= MEMSUB(rdata, data);

	if (data_size < 4 + strlen(bottom)) {
		gnutls_assert();
		return GNUTLS_E_BASE64_DECODING_ERROR;
	}

	kdata =
	    memmem(rdata + 1, data_size - 1, ENDSTR, sizeof(ENDSTR) - 1);
	/* allow CR as well.
	 */
	if (kdata == NULL) {
		gnutls_assert();
		_gnutls_hard_log("Could not find '%s'\n", ENDSTR);
		return GNUTLS_E_BASE64_DECODING_ERROR;
	}
	data_size -= strlen(ENDSTR);
	data_size -= MEMSUB(kdata, rdata);

	rdata = kdata + strlen(ENDSTR);

	/* position is now after the ---BEGIN--- headers */

	kdata = memmem(rdata, data_size, bottom, strlen(bottom));
	if (kdata == NULL) {
		gnutls_assert();
		return GNUTLS_E_BASE64_DECODING_ERROR;
	}

	/* position of kdata is before the ----END--- footer 
	 */
	rdata_size = MEMSUB(kdata, rdata);

	if (rdata_size < 4) {
		gnutls_assert();
		return GNUTLS_E_BASE64_DECODING_ERROR;
	}

	if ((ret = _gnutls_base64_decode(rdata, rdata_size, result)) < 0) {
		gnutls_assert();
		return GNUTLS_E_BASE64_DECODING_ERROR;
	}

	return ret;
}
Exemple #6
0
/* return A = g^a % N */
int
_gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data)
{
  size_t n_a;
  int ret;
  uint8_t *data_a;
  char *username, *password;
  char buf[64];
  gnutls_srp_client_credentials_t cred;


  cred = (gnutls_srp_client_credentials_t)
    _gnutls_get_cred (session->key, GNUTLS_CRD_SRP, NULL);

  if (cred == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  if (session->internals.srp_username == NULL)
    {
      username = cred->username;
      password = cred->password;
    }
  else
    {
      username = session->internals.srp_username;
      password = session->internals.srp_password;
    }

  if (username == NULL || password == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  /* calc A = g^a % N 
   */
  if (G == NULL || N == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  A = _gnutls_calc_srp_A (&_a, G, N);
  if (A == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  /* Rest of SRP calculations 
   */

  /* calculate u */
  session->key->u = _gnutls_calc_srp_u (A, B, N);
  if (session->key->u == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  _gnutls_dump_mpi ("SRP U: ", session->key->u);

  /* S = (B - g^x) ^ (a + u * x) % N */
  S = _gnutls_calc_srp_S2 (B, G, session->key->x, _a, session->key->u, N);
  if (S == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  _gnutls_dump_mpi ("SRP B: ", B);

  _gnutls_mpi_release (&_b);
  _gnutls_mpi_release (&V);
  _gnutls_mpi_release (&session->key->u);
  _gnutls_mpi_release (&B);

  ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY);
  _gnutls_mpi_release (&S);

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

  if (_gnutls_mpi_print (NULL, &n_a, A) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_PRINT_FAILED;
    }

  (*data) = gnutls_malloc (n_a + 2);
  if ((*data) == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  /* copy A */
  data_a = (*data);
  if (_gnutls_mpi_print (&data_a[2], &n_a, A) != 0)
    {
      gnutls_free (*data);
      return GNUTLS_E_MPI_PRINT_FAILED;
    }

  _gnutls_hard_log ("INT: SRP A[%d]: %s\n", n_a,
		    _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf)));

  _gnutls_mpi_release (&A);

  _gnutls_write_uint16 (n_a, data_a);

  return n_a + 2;
}
Exemple #7
0
/* Send the first key exchange message ( g, n, s) and append the verifier algorithm number 
 * Data is allocated by the caller, and should have data_size size.
 */
int
_gnutls_gen_srp_server_kx (gnutls_session_t session, opaque ** data)
{
  int ret;
  uint8_t *data_n, *data_s;
  uint8_t *data_g;
  char *username;
  SRP_PWD_ENTRY *pwd_entry;
  srp_server_auth_info_t info;
  ssize_t data_size;
  size_t n_b, tmp_size;
  char buf[64];
  uint8_t *data_b;

  if ((ret =
       _gnutls_auth_info_set (session, GNUTLS_CRD_SRP,
			      sizeof (srp_server_auth_info_st), 1)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  info = _gnutls_get_auth_info (session);
  username = info->username;

  _gnutls_str_cpy (username, MAX_SRP_USERNAME,
		   session->security_parameters.extensions.srp_username);

  ret = _gnutls_srp_pwd_read_entry (session, username, &pwd_entry);

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

  /* copy from pwd_entry to local variables (actually in session) */
  tmp_size = pwd_entry->g.size;
  if (_gnutls_mpi_scan_nz (&G, pwd_entry->g.data, &tmp_size) < 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_SCAN_FAILED;
    }

  tmp_size = pwd_entry->n.size;
  if (_gnutls_mpi_scan_nz (&N, pwd_entry->n.data, &tmp_size) < 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_SCAN_FAILED;
    }

  tmp_size = pwd_entry->v.size;
  if (_gnutls_mpi_scan_nz (&V, pwd_entry->v.data, &tmp_size) < 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_SCAN_FAILED;
    }

  /* Calculate:  B = (k*v + g^b) % N 
   */
  B = _gnutls_calc_srp_B (&_b, G, N, V);
  if (B == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  if (_gnutls_mpi_print (NULL, &n_b, B) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_PRINT_FAILED;
    }


  /* Allocate size to hold the N, g, s, B 
   */

  data_size = (pwd_entry->n.size + 2 + pwd_entry->g.size + 2 +
	       pwd_entry->salt.size + 1) + (n_b + 2);

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

  /* copy N (mod n) 
   */
  data_n = *data;
  _gnutls_write_datum16 (data_n, pwd_entry->n);


  /* copy G (generator) to data 
   */
  data_g = &data_n[2 + pwd_entry->n.size];
  _gnutls_write_datum16 (data_g, pwd_entry->g);


  /* copy the salt 
   */
  data_s = &data_g[2 + pwd_entry->g.size];
  _gnutls_write_datum8 (data_s, pwd_entry->salt);


  /* Copy the B value
   */

  data_b = &data_s[1 + pwd_entry->salt.size];
  if (_gnutls_mpi_print (&data_b[2], &n_b, B) != 0) 
    {
      gnutls_assert();
      return GNUTLS_E_MPI_PRINT_FAILED;
    }

  _gnutls_write_uint16 (n_b, data_b);

  _gnutls_hard_log ("INT: SRP B[%d]: %s\n", n_b,
		    _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf)));

  _gnutls_srp_entry_free (pwd_entry);

  return data_size;
}
Exemple #8
0
/**
 * gnutls_openpgp_privkey_sign_hash:
 * @key: Holds the key
 * @hash: holds the data to be signed
 * @signature: will contain newly allocated signature
 *
 * This function will sign the given hash using the private key.  You
 * should use gnutls_openpgp_privkey_set_preferred_key_id() before
 * calling this function to set the subkey to use.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Deprecated: Use gnutls_privkey_sign_hash() instead.
 */
int
gnutls_openpgp_privkey_sign_hash(gnutls_openpgp_privkey_t key,
				 const gnutls_datum_t * hash,
				 gnutls_datum_t * signature)
{
	int result;
	gnutls_pk_params_st params;
	int pk_algorithm;
	uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
	char buf[2 * GNUTLS_OPENPGP_KEYID_SIZE + 1];

	if (key == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	result = gnutls_openpgp_privkey_get_preferred_key_id(key, keyid);
	if (result == 0) {
		uint32_t kid[2];
		int idx;

		KEYID_IMPORT(kid, keyid);

		_gnutls_hard_log("Signing using PGP key ID %s\n",
				 _gnutls_bin2hex(keyid,
						 GNUTLS_OPENPGP_KEYID_SIZE,
						 buf, sizeof(buf), NULL));

		idx = gnutls_openpgp_privkey_get_subkey_idx(key, keyid);
		pk_algorithm =
		    gnutls_openpgp_privkey_get_subkey_pk_algorithm(key,
								   idx,
								   NULL);
		result =
		    _gnutls_openpgp_privkey_get_mpis(key, kid, &params);
	} else {
		_gnutls_hard_log("Signing using master PGP key\n");

		pk_algorithm =
		    gnutls_openpgp_privkey_get_pk_algorithm(key, NULL);
		result =
		    _gnutls_openpgp_privkey_get_mpis(key, NULL, &params);
	}

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


	result = _gnutls_pk_sign(pk_algorithm, signature, hash, &params);

	gnutls_pk_params_clear(&params);
	gnutls_pk_params_release(&params);

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

	return 0;
}
Exemple #9
0
/* This is the actual encryption 
 * Encrypts the given compressed datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int
compressed_to_ciphertext(gnutls_session_t session,
			 uint8_t * cipher_data, int cipher_size,
			 gnutls_datum_t * compressed,
			 size_t min_pad,
			 content_type_t type,
			 record_parameters_st * params)
{
	uint8_t pad;
	int length, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->write.cipher_state);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned block_algo = _gnutls_cipher_is_block(params->cipher);
	uint8_t *data_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher =
	    _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
	uint8_t nonce[MAX_CIPHER_BLOCK_SIZE];
	unsigned iv_size;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	preamble_size =
	    make_preamble(UINT64DATA
			  (params->write.sequence_number),
			  type, compressed->size, ver, preamble);

	/* Calculate the encrypted length (padding etc.)
	 */
	if (block_algo == CIPHER_BLOCK) {
		/* Call _gnutls_rnd() once. Get data used for the IV
		 */
		ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
		if (ret < 0)
			return gnutls_assert_val(ret);

		pad = min_pad;

		length =
		    calc_enc_length_block(session, ver, compressed->size,
					  tag_size, &pad, auth_cipher,
					  blocksize);
	} else {
		pad = 0;
		length =
		    calc_enc_length_stream(session, compressed->size,
					   tag_size, auth_cipher);
	}

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

	/* copy the encrypted data to cipher_data.
	 */
	if (cipher_size < length)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	data_ptr = cipher_data;

	if (explicit_iv) {	/* TLS 1.1 or later */
		if (block_algo == CIPHER_BLOCK) {
			/* copy the random IV.
			 */
			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
		} else if (auth_cipher) {
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (params->write.IV.data == NULL
			    || params->write.IV.size !=
			    AEAD_IMPLICIT_DATA_SIZE)
				return
				    gnutls_assert_val
				    (GNUTLS_E_INTERNAL_ERROR);

			/* Instead of generating a new nonce on every packet, we use the
			 * write.sequence_number (It is a MAY on RFC 5288).
			 */
			memcpy(nonce, params->write.IV.data,
			       params->write.IV.size);
			memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE],
			       UINT64DATA(params->write.sequence_number),
			       8);

			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, nonce,
						  AEAD_IMPLICIT_DATA_SIZE +
						  AEAD_EXPLICIT_DATA_SIZE);

			/* copy the explicit part */
			memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE],
			       AEAD_EXPLICIT_DATA_SIZE);

			data_ptr += AEAD_EXPLICIT_DATA_SIZE;
			cipher_data += AEAD_EXPLICIT_DATA_SIZE;
		} else if (iv_size > 0)
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state,
						  UINT64DATA(params->write.
							     sequence_number),
						  8);
	} else {
		/* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
		 */
		if (auth_cipher)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
		else if (block_algo == CIPHER_STREAM && iv_size > 0)
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state,
						  UINT64DATA(params->write.
							     sequence_number),
						  8);
	}

	_gnutls_auth_cipher_set_mac_nonce(&params->write.cipher_state,
					  UINT64DATA(params->write.
						     sequence_number), 8);

	/* add the authenticate data */
	ret =
	    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
					 preamble, preamble_size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* Actual encryption.
	 */
	ret =
	    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
					     compressed->data,
					     compressed->size, cipher_data,
					     cipher_size, pad);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return length;
}
Exemple #10
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;
}
Exemple #11
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;
}
Exemple #12
0
/* This is the actual encryption 
 * Encrypts the given compressed datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int
compressed_to_ciphertext(gnutls_session_t session,
			 uint8_t * cipher_data, int cipher_size,
			 gnutls_datum_t * compressed,
			 size_t min_pad,
			 content_type_t type,
			 record_parameters_st * params)
{
	uint8_t pad;
	int length, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->write.cipher_state);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned algo_type = _gnutls_cipher_type(params->cipher);
	uint8_t *data_ptr, *full_cipher_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher =
	    _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
	uint8_t nonce[MAX_CIPHER_BLOCK_SIZE];
	unsigned imp_iv_size = 0, exp_iv_size = 0;
	bool etm = 0;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (algo_type == CIPHER_BLOCK && params->etm != 0)
		etm = 1;

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	/* Calculate the encrypted length (padding etc.)
	 */
	if (algo_type == CIPHER_BLOCK) {
		/* Call _gnutls_rnd() once. Get data used for the IV
		 */
		ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
		if (ret < 0)
			return gnutls_assert_val(ret);

		pad = min_pad;

		length =
		    calc_enc_length_block(session, ver, compressed->size,
					  tag_size, &pad, auth_cipher,
					  blocksize, etm);
	} else { /* AEAD + STREAM */
		imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);
		exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher);

		pad = 0;
		length =
		    calc_enc_length_stream(session, compressed->size,
					   tag_size, auth_cipher, exp_iv_size);
	}

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

	/* copy the encrypted data to cipher_data.
	 */
	if (cipher_size < length)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	data_ptr = cipher_data;
	full_cipher_ptr = data_ptr;

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		if (algo_type == CIPHER_BLOCK && explicit_iv != 0) {
			/* copy the random IV.
			 */
			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
		}

	} else { /* AEAD */
		/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
		 */
		if (params->write.IV.data == NULL
		    || params->write.IV.size !=
		    imp_iv_size)
			return
			    gnutls_assert_val
			    (GNUTLS_E_INTERNAL_ERROR);

		/* Instead of generating a new nonce on every packet, we use the
		 * write.sequence_number (It is a MAY on RFC 5288), and safer
		 * as it will never reuse a value.
		 */
		memcpy(nonce, params->write.IV.data,
		       params->write.IV.size);
		memcpy(&nonce[imp_iv_size],
		       UINT64DATA(params->write.sequence_number),
		       8);

		/* copy the explicit part */
		memcpy(data_ptr, &nonce[imp_iv_size],
		       exp_iv_size);

		data_ptr += exp_iv_size;
		cipher_data += exp_iv_size;
	}

	if (etm)
		ret = length-tag_size;
	else
		ret = compressed->size;

	preamble_size =
	    make_preamble(UINT64DATA(params->write.sequence_number),
			  type, ret, ver, preamble);

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		/* add the authenticated data */
		ret =
		    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
					 preamble, preamble_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		if (etm && explicit_iv) {
			/* In EtM we need to hash the IV as well */
			ret =
			    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
						 full_cipher_ptr, blocksize);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}

		/* Actual encryption.
		 */
		ret =
		    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
						     compressed->data,
						     compressed->size, cipher_data,
						     cipher_size, pad);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else { /* AEAD */
		ret = _gnutls_aead_cipher_encrypt(&params->write.cipher_state.cipher,
						  nonce, imp_iv_size + exp_iv_size,
						  preamble, preamble_size,
						  tag_size,
						  compressed->data, compressed->size,
						  cipher_data, cipher_size);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	return length;
}
Exemple #13
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;
}
/* This is the actual encryption 
 * Encrypts the given compressed datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int
compressed_to_ciphertext (gnutls_session_t session,
                               opaque * cipher_data, int cipher_size,
                               gnutls_datum_t *compressed,
                               content_type_t type, 
                               record_parameters_st * params)
{
  uint8_t * tag_ptr = NULL;
  uint8_t pad;
  int length, length_to_encrypt, ret;
  opaque preamble[MAX_PREAMBLE_SIZE];
  int preamble_size;
  int tag_size = _gnutls_auth_cipher_tag_len (&params->write.cipher_state);
  int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);
  unsigned block_algo =
    _gnutls_cipher_is_block (params->cipher_algorithm);
  opaque *data_ptr;
  int ver = gnutls_protocol_get_version (session);
  int explicit_iv = _gnutls_version_has_explicit_iv (session->security_parameters.version);
  int auth_cipher = _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
  int random_pad;
  
  /* We don't use long padding if requested or if we are in DTLS.
   */
  if (session->internals.priorities.no_padding == 0 && (!IS_DTLS(session)))
    random_pad = 1;
  else
    random_pad = 0;
  
  _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
    session, gnutls_cipher_get_name(params->cipher_algorithm), gnutls_mac_get_name(params->mac_algorithm),
    (unsigned int)params->epoch);

  preamble_size =
    make_preamble (UINT64DATA
                   (params->write.sequence_number),
                   type, compressed->size, ver, preamble);

  /* Calculate the encrypted length (padding etc.)
   */
  length_to_encrypt = length =
    calc_enc_length (session, compressed->size, tag_size, &pad,
                     random_pad, block_algo, auth_cipher, blocksize);
  if (length < 0)
    {
      return gnutls_assert_val(length);
    }

  /* copy the encrypted data to cipher_data.
   */
  if (cipher_size < length)
    {
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
    }

  data_ptr = cipher_data;

  if (explicit_iv)
    {

      if (block_algo == CIPHER_BLOCK)
        {
          /* copy the random IV.
           */
          ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
          if (ret < 0)
            return gnutls_assert_val(ret);

          _gnutls_auth_cipher_setiv(&params->write.cipher_state, data_ptr, blocksize);

          data_ptr += blocksize;
          cipher_data += blocksize;
          length_to_encrypt -= blocksize;
        }
      else if (auth_cipher)
        {
          uint8_t nonce[blocksize];

          /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
           */
          if (params->write.IV.data == NULL || params->write.IV.size != AEAD_IMPLICIT_DATA_SIZE)
            return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

          /* Instead of generating a new nonce on every packet, we use the
           * write.sequence_number (It is a MAY on RFC 5288).
           */
          memcpy(nonce, params->write.IV.data, params->write.IV.size);
          memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], UINT64DATA(params->write.sequence_number), 8);

          _gnutls_auth_cipher_setiv(&params->write.cipher_state, nonce, AEAD_IMPLICIT_DATA_SIZE+AEAD_EXPLICIT_DATA_SIZE);

          /* copy the explicit part */
          memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], AEAD_EXPLICIT_DATA_SIZE);

          data_ptr += AEAD_EXPLICIT_DATA_SIZE;
          cipher_data += AEAD_EXPLICIT_DATA_SIZE;
          /* In AEAD ciphers we don't encrypt the tag 
           */
          length_to_encrypt -= AEAD_EXPLICIT_DATA_SIZE + tag_size;
        }
    }
  else
    {
      /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
       */
      if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
    }

  memcpy (data_ptr, compressed->data, compressed->size);
  data_ptr += compressed->size;

  if (tag_size > 0)
    {
      tag_ptr = data_ptr;
      data_ptr += tag_size;
    }
  if (block_algo == CIPHER_BLOCK && pad > 0)
    {
      memset (data_ptr, pad - 1, pad);
    }

  /* add the authenticate data */
  _gnutls_auth_cipher_add_auth(&params->write.cipher_state, preamble, preamble_size);

  /* Actual encryption (inplace).
   */
  ret =
    _gnutls_auth_cipher_encrypt_tag (&params->write.cipher_state,
      cipher_data, length_to_encrypt, tag_ptr, tag_size, compressed->size);
  if (ret < 0)
    return gnutls_assert_val(ret);

  return length;
}
Exemple #15
0
static int
compressed_to_ciphertext_new(gnutls_session_t session,
			     uint8_t * cipher_data, int cipher_size,
			     gnutls_datum_t * compressed,
			     size_t min_pad,
			     content_type_t type,
			     record_parameters_st * params)
{
	uint16_t pad = min_pad;
	int length, length_to_encrypt, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->write.cipher_state);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned block_algo = _gnutls_cipher_is_block(params->cipher);
	uint8_t *data_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher =
	    _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
	uint8_t nonce[MAX_CIPHER_BLOCK_SIZE];
	unsigned iv_size, final_cipher_size;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	/* Call _gnutls_rnd() once. Get data used for the IV
	 */
	ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* cipher_data points to the start of data to be encrypted */
	data_ptr = cipher_data;

	length_to_encrypt = length = 0;

	if (explicit_iv) {
		if (block_algo == CIPHER_BLOCK) {
			/* copy the random IV.
			 */
			DECR_LEN(cipher_size, blocksize);

			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
			length += blocksize;
		} else if (auth_cipher) {
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (params->write.IV.data == NULL
			    || params->write.IV.size !=
			    AEAD_IMPLICIT_DATA_SIZE)
				return
				    gnutls_assert_val
				    (GNUTLS_E_INTERNAL_ERROR);

			/* Instead of generating a new nonce on every packet, we use the
			 * write.sequence_number (It is a MAY on RFC 5288).
			 */
			memcpy(nonce, params->write.IV.data,
			       params->write.IV.size);
			memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE],
			       UINT64DATA(params->write.sequence_number),
			       8);

			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, nonce,
						  AEAD_IMPLICIT_DATA_SIZE +
						  AEAD_EXPLICIT_DATA_SIZE);

			/* copy the explicit part */
			DECR_LEN(cipher_size, AEAD_EXPLICIT_DATA_SIZE);
			memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE],
			       AEAD_EXPLICIT_DATA_SIZE);

			data_ptr += AEAD_EXPLICIT_DATA_SIZE;
			cipher_data += AEAD_EXPLICIT_DATA_SIZE;
			length += AEAD_EXPLICIT_DATA_SIZE;
		} else if (iv_size > 0)
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state,
						  UINT64DATA(params->write.
							     sequence_number),
						  8);
	} else {
		/* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
		 */
		if (auth_cipher)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
	}

	DECR_LEN(cipher_size, 2);

	if (block_algo == CIPHER_BLOCK) {	/* make pad a multiple of blocksize */
		unsigned t =
		    (2 + pad + compressed->size + tag_size) % blocksize;
		if (t > 0) {
			pad += blocksize - t;
		}
	}

	_gnutls_write_uint16(pad, data_ptr);
	data_ptr += 2;
	length_to_encrypt += 2;
	length += 2;
	final_cipher_size = cipher_size;

	if (pad > 0) {
		unsigned t;

		t = cipher_size - compressed->size;
		if (pad > t) {
			if (block_algo == CIPHER_BLOCK) {
				if (pad <= blocksize)
					return
					    gnutls_assert_val
					    (GNUTLS_E_INVALID_REQUEST);

				pad -= blocksize * ((pad - t) / blocksize);
			} else
				pad = t;
		}

		DECR_LEN(cipher_size, pad);

		memset(data_ptr, 0, pad);
		data_ptr += pad;
		length_to_encrypt += pad;
		length += pad;
	}

	DECR_LEN(cipher_size, compressed->size);

	memcpy(data_ptr, compressed->data, compressed->size);
	data_ptr += compressed->size;
	length_to_encrypt += compressed->size;
	length += compressed->size;

	if (tag_size > 0) {
		DECR_LEN(cipher_size, tag_size);

		data_ptr += tag_size;

		/* In AEAD ciphers we don't encrypt the tag 
		 */
		length += tag_size;
	}

	preamble_size =
	    make_preamble(UINT64DATA
			  (params->write.sequence_number),
			  type, compressed->size + 2 + pad, ver, preamble);

	_gnutls_auth_cipher_set_mac_nonce(&params->write.cipher_state,
					  UINT64DATA(params->write.
						     sequence_number), 8);
	/* add the authenticated data */
	ret =
	    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
					 preamble, preamble_size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* Actual encryption (inplace).
	 */
	ret =
	    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
					     cipher_data,
					     length_to_encrypt,
					     cipher_data,
					     final_cipher_size, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return length;
}
Exemple #16
0
void _gnutls_mpi_log(const char *prefix, bigint_t a)
{
	size_t binlen = 0;
	void *binbuf;
	size_t hexlen;
	char *hexbuf;
	int res;

	if (_gnutls_log_level < 2)
		return;

	res = _gnutls_mpi_print(a, NULL, &binlen);
	if (res < 0 && res != GNUTLS_E_SHORT_MEMORY_BUFFER) {
		gnutls_assert();
		_gnutls_hard_log("MPI: %s can't print value (%d/%d)\n",
				 prefix, res, (int) binlen);
		return;
	}

	if (binlen > 1024 * 1024) {
		gnutls_assert();
		_gnutls_hard_log("MPI: %s too large mpi (%d)\n", prefix,
				 (int) binlen);
		return;
	}

	binbuf = gnutls_malloc(binlen);
	if (!binbuf) {
		gnutls_assert();
		_gnutls_hard_log("MPI: %s out of memory (%d)\n", prefix,
				 (int) binlen);
		return;
	}

	res = _gnutls_mpi_print(a, binbuf, &binlen);
	if (res != 0) {
		gnutls_assert();
		_gnutls_hard_log("MPI: %s can't print value (%d/%d)\n",
				 prefix, res, (int) binlen);
		gnutls_free(binbuf);
		return;
	}

	hexlen = 2 * binlen + 1;
	hexbuf = gnutls_malloc(hexlen);

	if (!hexbuf) {
		gnutls_assert();
		_gnutls_hard_log("MPI: %s out of memory (hex %d)\n",
				 prefix, (int) hexlen);
		gnutls_free(binbuf);
		return;
	}

	_gnutls_bin2hex(binbuf, binlen, hexbuf, hexlen, NULL);

	_gnutls_hard_log("MPI: length: %d\n\t%s%s\n", (int) binlen, prefix,
			 hexbuf);

	gnutls_free(hexbuf);
	gnutls_free(binbuf);
}
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;
}
Exemple #18
0
static int
encrypt_packet_tls13(gnutls_session_t session,
		     uint8_t *cipher_data, size_t cipher_size,
		     gnutls_datum_t *plain,
		     size_t pad_size,
		     uint8_t type,
		     record_parameters_st *params)
{
	int ret;
	unsigned int tag_size = params->write.aead_tag_size;
	const version_entry_st *ver = get_version(session);
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	unsigned iv_size = 0;
	ssize_t max, total;
	uint8_t aad[5];
	giovec_t auth_iov[1];
	giovec_t iov[2];

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	iv_size = params->write.iv_size;

	if (params->cipher->id == GNUTLS_CIPHER_NULL) {
		if (cipher_size < plain->size+1)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
		memcpy(cipher_data, plain->data, plain->size);
		return plain->size;
	}

	if (unlikely(iv_size < 8))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	memcpy(nonce, params->write.iv, iv_size);
	memxor(&nonce[iv_size-8], UINT64DATA(params->write.sequence_number), 8);

	max = MAX_RECORD_SEND_SIZE(session);

	/* make TLS 1.3 form of data */
	total = plain->size + 1 + pad_size;

	/* check whether padding would exceed max */
	if (total > max) {
		if (unlikely(max < (ssize_t)plain->size+1))
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		pad_size = max - plain->size - 1;
		total = max;
	}

	/* create authenticated data header */
	aad[0] = GNUTLS_APPLICATION_DATA;
	aad[1] = 0x03;
	aad[2] = 0x03;
	_gnutls_write_uint16(total+tag_size, &aad[3]);

	auth_iov[0].iov_base = aad;
	auth_iov[0].iov_len = sizeof(aad);

	iov[0].iov_base = plain->data;
	iov[0].iov_len = plain->size;

	if (pad_size || (session->internals.flags & GNUTLS_SAFE_PADDING_CHECK)) {
		uint8_t *pad = gnutls_calloc(1, 1+pad_size);
		if (pad == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		pad[0] = type;

		iov[1].iov_base = pad;
		iov[1].iov_len = 1+pad_size;

		ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
						  nonce, iv_size,
						  auth_iov, 1,
						  tag_size,
						  iov, 2,
						  cipher_data, &cipher_size);
		gnutls_free(pad);
	} else {
		iov[1].iov_base = &type;
		iov[1].iov_len = 1;

		ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
						  nonce, iv_size,
						  auth_iov, 1,
						  tag_size,
						  iov, 2,
						  cipher_data, &cipher_size);
	}

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

	return cipher_size;
}