Exemple #1
0
static inline void
mac_hash (digest_hd_st * td, void *data, int data_size, int ver)
{
  if (ver == GNUTLS_SSL3)
    {                           /* SSL 3.0 */
      _gnutls_hash (td, data, data_size);
    }
  else
    {
      _gnutls_hmac (td, data, data_size);
    }
}
Exemple #2
0
/**
 * gnutls_pkcs12_verify_mac:
 * @pkcs12: should contain a gnutls_pkcs12_t structure
 * @pass: The password for the MAC
 *
 * This function will verify the MAC for the PKCS12 structure.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs12_verify_mac (gnutls_pkcs12_t pkcs12, const char *pass)
{
  opaque key[20];
  int result;
  unsigned int iter;
  int len;
  digest_hd_st td1;
  gnutls_datum_t tmp = { NULL, 0 }, salt =
  {
  NULL, 0};
  opaque sha_mac[20];
  opaque sha_mac_orig[20];

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

  /* read the iterations
   */

  result =
    _gnutls_x509_read_uint (pkcs12->pkcs12, "macData.iterations", &iter);
  if (result < 0)
    {
      iter = 1;			/* the default */
    }


  /* Read the salt from the structure.
   */
  result =
    _gnutls_x509_read_value (pkcs12->pkcs12, "macData.macSalt", &salt, 0);
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  /* Generate the key.
   */
  result = _gnutls_pkcs12_string_to_key (3 /*MAC*/, salt.data, salt.size,
					 iter, pass, sizeof (key), key);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  _gnutls_free_datum (&salt);

  /* Get the data to be MACed
   */
  result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, NULL, &tmp);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  /* MAC the data
   */
  result = _gnutls_hmac_init (&td1, GNUTLS_MAC_SHA1, key, sizeof (key));
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  _gnutls_hmac (&td1, tmp.data, tmp.size);
  _gnutls_free_datum (&tmp);

  _gnutls_hmac_deinit (&td1, sha_mac);

  len = sizeof (sha_mac_orig);
  result =
    asn1_read_value (pkcs12->pkcs12, "macData.mac.digest", sha_mac_orig,
		     &len);
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  if (memcmp (sha_mac_orig, sha_mac, sizeof (sha_mac)) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_MAC_VERIFY_FAILED;
    }

  return 0;

cleanup:
  _gnutls_free_datum (&tmp);
  _gnutls_free_datum (&salt);
  return result;
}
Exemple #3
0
/**
 * gnutls_pkcs12_generate_mac:
 * @pkcs12: should contain a gnutls_pkcs12_t structure
 * @pass: The password for the MAC
 *
 * This function will generate a MAC for the PKCS12 structure.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs12_generate_mac (gnutls_pkcs12_t pkcs12, const char *pass)
{
  opaque salt[8], key[20];
  int result;
  const int iter = 1;
  digest_hd_st td1;
  gnutls_datum_t tmp = { NULL, 0 };
  opaque sha_mac[20];

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

  /* Generate the salt.
   */
  result = _gnutls_rnd (GNUTLS_RND_NONCE, salt, sizeof (salt));
  if (result < 0)
    {
      gnutls_assert ();
      return result;
    }

  /* Write the salt into the structure.
   */
  result =
    asn1_write_value (pkcs12->pkcs12, "macData.macSalt", salt, sizeof (salt));
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  /* write the iterations
   */

  if (iter > 1)
    {
      result =
	_gnutls_x509_write_uint32 (pkcs12->pkcs12, "macData.iterations",
				   iter);
      if (result < 0)
	{
	  gnutls_assert ();
	  goto cleanup;
	}
    }

  /* Generate the key.
   */
  result = _gnutls_pkcs12_string_to_key (3 /*MAC*/, salt, sizeof (salt),
					 iter, pass, sizeof (key), key);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  /* Get the data to be MACed
   */
  result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, NULL, &tmp);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  /* MAC the data
   */
  result = _gnutls_hmac_init (&td1, GNUTLS_MAC_SHA1, key, sizeof (key));
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  _gnutls_hmac (&td1, tmp.data, tmp.size);
  _gnutls_free_datum (&tmp);

  _gnutls_hmac_deinit (&td1, sha_mac);


  result =
    asn1_write_value (pkcs12->pkcs12, "macData.mac.digest", sha_mac,
		      sizeof (sha_mac));
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  result =
    asn1_write_value (pkcs12->pkcs12,
		      "macData.mac.digestAlgorithm.parameters", NULL, 0);
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  result =
    asn1_write_value (pkcs12->pkcs12,
		      "macData.mac.digestAlgorithm.algorithm", HASH_OID_SHA1,
		      1);
  if (result != ASN1_SUCCESS)
    {
      gnutls_assert ();
      result = _gnutls_asn2err (result);
      goto cleanup;
    }

  return 0;

cleanup:
  _gnutls_free_datum (&tmp);
  return result;
}
Exemple #4
0
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
 * Returns the actual compressed packet size.
 */
int
_gnutls_ciphertext2compressed (gnutls_session_t session,
			       opaque * compress_data,
			       int compress_size,
			       gnutls_datum_t ciphertext, uint8_t type)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length;
  digest_hd_st td;
  uint16_t blocksize;
  int ret, i, pad_failed = 0;
  uint8_t major, minor;
  gnutls_protocol_t ver;
  int hash_size =
    _gnutls_hash_get_algo_len (session->security_parameters.
			       read_mac_algorithm);

  ver = gnutls_protocol_get_version (session);
  minor = _gnutls_version_get_minor (ver);
  major = _gnutls_version_get_major (ver);

  blocksize =
    _gnutls_cipher_get_block_size (session->security_parameters.
				   read_bulk_cipher_algorithm);

  /* initialize MAC 
   */
  ret = mac_init (&td, session->security_parameters.read_mac_algorithm,
		  session->connection_state.read_mac_secret.data,
		  session->connection_state.read_mac_secret.size, ver);

  if (ret < 0
      && session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  /* actual decryption (inplace)
   */
  switch (_gnutls_cipher_is_block
	  (session->security_parameters.read_bulk_cipher_algorithm))
    {
    case CIPHER_STREAM:
      if ((ret =
	   _gnutls_cipher_decrypt (&session->connection_state.
				   read_cipher_state, ciphertext.data,
				   ciphertext.size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      length = ciphertext.size - hash_size;

      break;
    case CIPHER_BLOCK:
      if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
	{
	  gnutls_assert ();
	  return GNUTLS_E_DECRYPTION_FAILED;
	}

      if ((ret =
	   _gnutls_cipher_decrypt (&session->connection_state.
				   read_cipher_state, ciphertext.data,
				   ciphertext.size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      /* ignore the IV in TLS 1.1.
       */
      if (session->security_parameters.version >= GNUTLS_TLS1_1)
	{
	  ciphertext.size -= blocksize;
	  ciphertext.data += blocksize;

	  if (ciphertext.size == 0)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_DECRYPTION_FAILED;
	    }
	}

      pad = ciphertext.data[ciphertext.size - 1] + 1;	/* pad */

      if ((int) pad > (int) ciphertext.size - hash_size)
	{
	  gnutls_assert ();
	  _gnutls_record_log
	    ("REC[%x]: Short record length %d > %d - %d (under attack?)\n",
	     session, pad, ciphertext.size, hash_size);
	  /* We do not fail here. We check below for the
	   * the pad_failed. If zero means success.
	   */
	  pad_failed = GNUTLS_E_DECRYPTION_FAILED;
	}

      length = ciphertext.size - hash_size - pad;

      /* Check the pading bytes (TLS 1.x)
       */
      if (ver >= GNUTLS_TLS1 && pad_failed == 0)
	for (i = 2; i < pad; i++)
	  {
	    if (ciphertext.data[ciphertext.size - i] !=
		ciphertext.data[ciphertext.size - 1])
	      pad_failed = GNUTLS_E_DECRYPTION_FAILED;
	  }
      break;
    default:
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  if (length < 0)
    length = 0;
  c_length = _gnutls_conv_uint16 ((uint16_t) length);

  /* Pass the type, version, length and compressed through
   * MAC.
   */
  if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      _gnutls_hmac (&td,
		    UINT64DATA (session->connection_state.
				read_sequence_number), 8);

      _gnutls_hmac (&td, &type, 1);
      if (ver >= GNUTLS_TLS1)
	{			/* TLS 1.x */
	  _gnutls_hmac (&td, &major, 1);
	  _gnutls_hmac (&td, &minor, 1);
	}
      _gnutls_hmac (&td, &c_length, 2);

      if (length > 0)
	_gnutls_hmac (&td, ciphertext.data, length);

      mac_deinit (&td, MAC, ver);
    }

  /* This one was introduced to avoid a timing attack against the TLS
   * 1.0 protocol.
   */
  if (pad_failed != 0)
    return pad_failed;

  /* HMAC was not the same. 
   */
  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  /* copy the decrypted stuff to compress_data.
   */
  if (compress_size < length)
    {
      gnutls_assert ();
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }
  memcpy (compress_data, ciphertext.data, length);

  return length;
}
Exemple #5
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.
 */
int
_gnutls_compressed2ciphertext (gnutls_session_t session,
			       opaque * cipher_data, int cipher_size,
			       gnutls_datum_t compressed,
			       content_type_t _type, int random_pad)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length, ret;
  digest_hd_st td;
  uint8_t type = _type;
  uint8_t major, minor;
  int hash_size =
    _gnutls_hash_get_algo_len (session->security_parameters.
			       write_mac_algorithm);
  gnutls_protocol_t ver;
  int blocksize =
    _gnutls_cipher_get_block_size (session->security_parameters.
				   write_bulk_cipher_algorithm);
  cipher_type_t block_algo =
    _gnutls_cipher_is_block (session->security_parameters.
			     write_bulk_cipher_algorithm);
  opaque *data_ptr;


  ver = gnutls_protocol_get_version (session);
  minor = _gnutls_version_get_minor (ver);
  major = _gnutls_version_get_major (ver);


  /* Initialize MAC */
  ret = mac_init (&td, session->security_parameters.write_mac_algorithm,
		  session->connection_state.write_mac_secret.data,
		  session->connection_state.write_mac_secret.size, ver);

  if (ret < 0
      && session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL)
    {
      gnutls_assert ();
      return ret;
    }

  c_length = _gnutls_conv_uint16 (compressed.size);

  if (session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL)
    {				/* actually when the algorithm in not the NULL one */
      _gnutls_hmac (&td,
		    UINT64DATA (session->connection_state.
				write_sequence_number), 8);

      _gnutls_hmac (&td, &type, 1);
      if (ver >= GNUTLS_TLS1)
	{			/* TLS 1.0 or higher */
	  _gnutls_hmac (&td, &major, 1);
	  _gnutls_hmac (&td, &minor, 1);
	}
      _gnutls_hmac (&td, &c_length, 2);
      _gnutls_hmac (&td, compressed.data, compressed.size);
      mac_deinit (&td, MAC, ver);
    }


  /* Calculate the encrypted length (padding etc.)
   */
  length =
    calc_enc_length (session, compressed.size, hash_size, &pad,
		     random_pad, block_algo, blocksize);
  if (length < 0)
    {
      gnutls_assert ();
      return length;
    }

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

  data_ptr = cipher_data;
  if (block_algo == CIPHER_BLOCK &&
      session->security_parameters.version >= GNUTLS_TLS1_1)
    {
      /* copy the random IV.
       */
      ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      data_ptr += blocksize;
    }

  memcpy (data_ptr, compressed.data, compressed.size);
  data_ptr += compressed.size;

  if (hash_size > 0)
    {
      memcpy (data_ptr, MAC, hash_size);
      data_ptr += hash_size;
    }
  if (block_algo == CIPHER_BLOCK && pad > 0)
    {
      memset (data_ptr, pad - 1, pad);
    }


  /* Actual encryption (inplace).
   */
  ret =
    _gnutls_cipher_encrypt (&session->connection_state.write_cipher_state,
			    cipher_data, length);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return length;
}