Ejemplo n.º 1
0
/* This is exactly like write_buffered, but will use two buffers to read
 * from.
 */
ssize_t
_gnutls_io_write_buffered2 (gnutls_session_t session,
                            const void *iptr, size_t n,
                            const void *iptr2, size_t n2)
{

    if (n == 0)
    {
        return _gnutls_io_write_buffered (session, iptr2, n2);
    }
    else
    {
        opaque *sptr;
        ssize_t ret;

        sptr = gnutls_alloca (n + n2);
        if (sptr == NULL)
        {
            gnutls_assert ();
            return GNUTLS_E_MEMORY_ERROR;
        }

        memcpy (sptr, iptr, n);
        memcpy (&sptr[n], iptr2, n2);

        ret = _gnutls_io_write_buffered (session, sptr, n + n2);
        gnutls_afree (sptr);

        return ret;
    }
}
Ejemplo n.º 2
0
/* This is the same as the _gnutls_x509_sign, but this one will decode
 * the ASN1_TYPE given, and sign the DER data. Actually used to get the DER
 * of the TBS and sign it on the fly.
 */
int
_gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
		       gnutls_digest_algorithm_t hash,
		       gnutls_x509_privkey_t signer,
		       gnutls_datum_t * signature)
{
  int result;
  opaque *buf;
  int buf_size;
  gnutls_datum_t tbs;

  buf_size = 0;
  asn1_der_coding (cert, tbs_name, NULL, &buf_size, NULL);

  buf = gnutls_alloca (buf_size);
  if (buf == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  result = asn1_der_coding (cert, tbs_name, buf, &buf_size, NULL);

  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      gnutls_afree (buf);
      return _gnutls_asn2err (result);
    }

  tbs.data = buf;
  tbs.size = buf_size;

  result = _gnutls_x509_sign (&tbs, hash, signer, signature);
  gnutls_afree (buf);

  return result;
}
Ejemplo n.º 3
0
/* This function is only used with berkeley style sockets.
 * Clears the peeked data (read with MSG_PEEK).
 */
int
_gnutls_io_clear_peeked_data (gnutls_session_t session)
{
    char *peekdata;
    int ret, sum;

    if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
        return 0;

    peekdata = gnutls_alloca (RCVLOWAT);
    if (peekdata == NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_MEMORY_ERROR;
    }

    /* this was already read by using MSG_PEEK - so it shouldn't fail */
    sum = 0;
    do
    {   /* we need this to finish now */
        ret = _gnutls_read (session, peekdata, RCVLOWAT - sum, 0);
        if (ret > 0)
            sum += ret;
    }
    while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN
            || sum < RCVLOWAT);

    gnutls_afree (peekdata);

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

    session->internals.have_peeked_data = 0;

    return 0;
}
Ejemplo n.º 4
0
/* Do PKCS-1 RSA encryption. 
 * params is modulus, public exp.
 */
int
_gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext,
			   const gnutls_datum_t * plaintext,
			   mpi_t * params, unsigned params_len,
			   unsigned btype)
{
  unsigned int i, pad;
  int ret;
  mpi_t m, res;
  opaque *edata, *ps;
  size_t k, psize;
  size_t mod_bits;

  mod_bits = _gnutls_mpi_get_nbits (params[0]);
  k = mod_bits / 8;
  if (mod_bits % 8 != 0)
    k++;

  if (plaintext->size > k - 11)
    {
      gnutls_assert ();
      return GNUTLS_E_PK_ENCRYPTION_FAILED;
    }

  edata = gnutls_alloca (k);
  if (edata == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  /* EB = 00||BT||PS||00||D 
   * (use block type 'btype')
   */

  edata[0] = 0;
  edata[1] = btype;
  psize = k - 3 - plaintext->size;

  ps = &edata[2];
  switch (btype)
    {
    case 2:
      /* using public key */
      if (params_len < RSA_PUBLIC_PARAMS)
	{
	  gnutls_assert ();
	  gnutls_afree (edata);
	  return GNUTLS_E_INTERNAL_ERROR;
	}

      if (gc_pseudo_random (ps, psize) != GC_OK)
	{
	  gnutls_assert ();
	  gnutls_afree (edata);
	  return GNUTLS_E_RANDOM_FAILED;
	}
      for (i = 0; i < psize; i++)
	while (ps[i] == 0)
	  {
	    if (gc_pseudo_random (&ps[i], 1) != GC_OK)
	      {
		gnutls_assert ();
		gnutls_afree (edata);
		return GNUTLS_E_RANDOM_FAILED;
	      }
	  }
      break;
    case 1:
      /* using private key */

      if (params_len < RSA_PRIVATE_PARAMS)
	{
	  gnutls_assert ();
	  gnutls_afree (edata);
	  return GNUTLS_E_INTERNAL_ERROR;
	}

      for (i = 0; i < psize; i++)
	ps[i] = 0xff;
      break;
    default:
      gnutls_assert ();
      gnutls_afree (edata);
      return GNUTLS_E_INTERNAL_ERROR;
    }

  ps[psize] = 0;
  memcpy (&ps[psize + 1], plaintext->data, plaintext->size);

  if (_gnutls_mpi_scan_nz (&m, edata, &k) != 0)
    {
      gnutls_assert ();
      gnutls_afree (edata);
      return GNUTLS_E_MPI_SCAN_FAILED;
    }
  gnutls_afree (edata);

  if (btype == 2)		/* encrypt */
    ret = _gnutls_pk_encrypt (GCRY_PK_RSA, &res, m, params, params_len);
  else				/* sign */
    ret = _gnutls_pk_sign (GCRY_PK_RSA, &res, m, params, params_len);

  _gnutls_mpi_release (&m);

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

  _gnutls_mpi_print (NULL, &psize, res);

  if (psize < k)
    {
      /* padding psize */
      pad = k - psize;
      psize = k;
    }
  else if (psize == k)
    {
      pad = 0;
    }
  else
    {				/* psize > k !!! */
      /* This is an impossible situation */
      gnutls_assert ();
      _gnutls_mpi_release (&res);
      return GNUTLS_E_INTERNAL_ERROR;
    }

  ciphertext->data = gnutls_malloc (psize);
  if (ciphertext->data == NULL)
    {
      gnutls_assert ();
      _gnutls_mpi_release (&res);
      return GNUTLS_E_MEMORY_ERROR;
    }
  _gnutls_mpi_print (&ciphertext->data[pad], &psize, res);
  for (i = 0; i < pad; i++)
    ciphertext->data[i] = 0;

  ciphertext->size = k;

  _gnutls_mpi_release (&res);

  return 0;
}
Ejemplo n.º 5
0
/* Do PKCS-1 RSA decryption. 
 * params is modulus, public exp., private key
 * Can decrypt block type 1 and type 2 packets.
 */
int
_gnutls_pkcs1_rsa_decrypt (gnutls_datum_t * plaintext,
			   const gnutls_datum_t * ciphertext,
			   mpi_t * params, unsigned params_len,
			   unsigned btype)
{
  unsigned k, i;
  int ret;
  mpi_t c, res;
  opaque *edata;
  size_t esize, mod_bits;

  mod_bits = _gnutls_mpi_get_nbits (params[0]);
  k = mod_bits / 8;
  if (mod_bits % 8 != 0)
    k++;

  esize = ciphertext->size;

  if (esize != k)
    {
      gnutls_assert ();
      return GNUTLS_E_PK_DECRYPTION_FAILED;
    }

  if (_gnutls_mpi_scan_nz (&c, ciphertext->data, &esize) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MPI_SCAN_FAILED;
    }

  /* we can use btype to see if the private key is
   * available.
   */
  if (btype == 2)
    ret = _gnutls_pk_decrypt (GCRY_PK_RSA, &res, c, params, params_len);
  else
    {
      ret = _gnutls_pk_encrypt (GCRY_PK_RSA, &res, c, params, params_len);
    }
  _gnutls_mpi_release (&c);

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

  _gnutls_mpi_print (NULL, &esize, res);
  edata = gnutls_alloca (esize + 1);
  if (edata == NULL)
    {
      gnutls_assert ();
      _gnutls_mpi_release (&res);
      return GNUTLS_E_MEMORY_ERROR;
    }
  _gnutls_mpi_print (&edata[1], &esize, res);

  _gnutls_mpi_release (&res);

  /* EB = 00||BT||PS||00||D
   * (use block type 'btype')
   *
   * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to
   * avoid attacks similar to the one described by Bleichenbacher in:
   * "Chosen Ciphertext Attacks against Protocols Based on RSA
   * Encryption Standard PKCS #1".
   */


  edata[0] = 0;
  esize++;

  if (edata[0] != 0 || edata[1] != btype)
    {
      gnutls_assert ();
      gnutls_afree (edata);
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  ret = GNUTLS_E_DECRYPTION_FAILED;
  switch (btype)
    {
    case 2:
      for (i = 2; i < esize; i++)
	{
	  if (edata[i] == 0)
	    {
	      ret = 0;
	      break;
	    }
	}
      break;
    case 1:
      for (i = 2; i < esize; i++)
	{
	  if (edata[i] == 0 && i > 2)
	    {
	      ret = 0;
	      break;
	    }
	  if (edata[i] != 0xff)
	    {
	      _gnutls_handshake_log ("PKCS #1 padding error");
	      /* PKCS #1 padding error.  Don't use
		 GNUTLS_E_PKCS1_WRONG_PAD here.  */
	      break;
	    }
	}
      break;
    default:
      gnutls_assert ();
      gnutls_afree (edata);
      break;
    }
  i++;

  if (ret < 0)
    {
      gnutls_assert ();
      gnutls_afree (edata);
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  if (_gnutls_sset_datum (plaintext, &edata[i], esize - i) < 0)
    {
      gnutls_assert ();
      gnutls_afree (edata);
      return GNUTLS_E_MEMORY_ERROR;
    }

  gnutls_afree (edata);

  return 0;
}
Ejemplo n.º 6
0
/* A generic export function. Will export the given ASN.1 encoded data
 * to PEM or DER raw data.
 */
int
_gnutls_x509_export_int (ASN1_TYPE asn1_data,
			 gnutls_x509_crt_fmt_t format, char *pem_header,
			 int tmp_buf_size, unsigned char *output_data,
			 size_t * output_data_size)
{
  int result, len;
  if (tmp_buf_size == 0)
    tmp_buf_size = 16 * 1024;

  if (format == GNUTLS_X509_FMT_DER)
    {

      if (output_data == NULL)
	*output_data_size = 0;

      len = *output_data_size;

      if ((result =
	   asn1_der_coding (asn1_data, "", output_data, &len,
			    NULL)) != ASN1_SUCCESS)
	{
	  *output_data_size = len;
	  if (result == ASN1_MEM_ERROR)
	    {
	      return GNUTLS_E_SHORT_MEMORY_BUFFER;
	    }
	  gnutls_assert ();
	  return _gnutls_asn2err (result);
	}

      *output_data_size = len;

    }
  else
    {				/* PEM */
      opaque *tmp;
      opaque *out;

      len = tmp_buf_size;

      tmp = gnutls_alloca (len);
      if (tmp == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      if ((result =
	   asn1_der_coding (asn1_data, "", tmp, &len, NULL)) != ASN1_SUCCESS)
	{
	  gnutls_assert ();
	  if (result == ASN1_MEM_ERROR)
	    {
	      *output_data_size = B64FSIZE (strlen (pem_header), len) + 1;
	    }
	  gnutls_afree (tmp);
	  return _gnutls_asn2err (result);
	}

      result = _gnutls_fbase64_encode (pem_header, tmp, len, &out);

      gnutls_afree (tmp);

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

      if (result == 0)
	{			/* oooops */
	  gnutls_assert ();
	  return GNUTLS_E_INTERNAL_ERROR;
	}

      if ((unsigned) result > *output_data_size)
	{
	  gnutls_assert ();
	  gnutls_free (out);
	  *output_data_size = result;
	  return GNUTLS_E_SHORT_MEMORY_BUFFER;
	}

      *output_data_size = result;

      if (output_data)
	{
	  memcpy (output_data, out, result);

	  /* do not include the null character into output size.
	   */
	  *output_data_size = result - 1;
	}
      gnutls_free (out);

    }

  return 0;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
/* This function behaves exactly like write(). The only difference is
 * that it accepts, the gnutls_session_t and the content_type_t of data to
 * send (if called by the user the Content is specific)
 * It is intended to transfer data, under the current session.    
 *
 * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE.
 * This makes the function much easier to read, and more error resistant
 * (there were cases were the old function could mess everything up).
 * --nmav
 *
 * This function may accept a NULL pointer for data, and 0 for size, if
 * and only if the previous send was interrupted for some reason.
 *
 */
ssize_t
_gnutls_send_int (gnutls_session_t session, content_type_t type,
		  gnutls_handshake_description_t htype, const void *_data,
		  size_t sizeofdata)
{
  uint8_t *cipher;
  int cipher_size;
  int retval, ret;
  int data2send_size;
  uint8_t headers[5];
  const uint8_t *data = _data;
  int erecord_size = 0;
  opaque *erecord = NULL;

  /* Do not allow null pointer if the send buffer is empty.
   * If the previous send was interrupted then a null pointer is
   * ok, and means to resume.
   */
  if (session->internals.record_send_buffer.length == 0 &&
      (sizeofdata == 0 && _data == NULL))
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  if (type != GNUTLS_ALERT)	/* alert messages are sent anyway */
    if (session_is_valid (session) || session->internals.may_not_write != 0)
      {
	gnutls_assert ();
	return GNUTLS_E_INVALID_SESSION;
      }



  headers[0] = type;

  /* Use the default record version, if it is
   * set.
   */
  copy_record_version (session, htype, &headers[1]);


  _gnutls_record_log
    ("REC[%x]: Sending Packet[%d] %s(%d) with length: %d\n", session,
     (int) _gnutls_uint64touint32 (&session->connection_state.
				   write_sequence_number),
     _gnutls_packet2str (type), type, sizeofdata);

  if (sizeofdata > MAX_RECORD_SEND_SIZE)
    data2send_size = MAX_RECORD_SEND_SIZE;
  else
    data2send_size = sizeofdata;

  /* Only encrypt if we don't have data to send 
   * from the previous run. - probably interrupted.
   */
  if (session->internals.record_send_buffer.length > 0)
    {
      ret = _gnutls_io_write_flush (session);
      if (ret > 0)
	cipher_size = ret;
      else
	cipher_size = 0;

      cipher = NULL;

      retval = session->internals.record_send_buffer_user_size;
    }
  else
    {

      /* now proceed to packet encryption
       */
      cipher_size = data2send_size + MAX_RECORD_OVERHEAD;
      cipher = gnutls_malloc (cipher_size);
      if (cipher == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      cipher_size =
	_gnutls_encrypt (session, headers, RECORD_HEADER_SIZE, data,
			 data2send_size, cipher, cipher_size, type, 1);
      if (cipher_size <= 0)
	{
	  gnutls_assert ();
	  if (cipher_size == 0)
	    cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
	  gnutls_afree (erecord);
	  gnutls_free (cipher);
	  return cipher_size;	/* error */
	}

      retval = data2send_size;
      session->internals.record_send_buffer_user_size = data2send_size;

      /* increase sequence number
       */
      if (_gnutls_uint64pp
	  (&session->connection_state.write_sequence_number) != 0)
	{
	  session_invalidate (session);
	  gnutls_assert ();
	  gnutls_afree (erecord);
	  gnutls_free (cipher);
	  return GNUTLS_E_RECORD_LIMIT_REACHED;
	}

      ret =
	_gnutls_io_write_buffered2 (session, erecord, erecord_size,
				    cipher, cipher_size);
      gnutls_afree (erecord);
      gnutls_free (cipher);
    }

  if (ret != cipher_size + erecord_size)
    {
      if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
	{
	  /* If we have sent any data then just return
	   * the error value. Do not invalidate the session.
	   */
	  gnutls_assert ();
	  return ret;
	}

      if (ret > 0)
	{
	  gnutls_assert ();
	  ret = GNUTLS_E_INTERNAL_ERROR;
	}
      session_unresumable (session);
      session->internals.may_not_write = 1;
      gnutls_assert ();
      return ret;
    }

  session->internals.record_send_buffer_user_size = 0;

  _gnutls_record_log ("REC[%x]: Sent Packet[%d] %s(%d) with length: %d\n",
		      session,
		      (int) _gnutls_uint64touint32 (&session->
						    connection_state.
						    write_sequence_number),
		      _gnutls_packet2str (type), type, cipher_size);

  return retval;
}