Beispiel #1
0
/**
 * gnutls_pkcs12_verify_mac:
 * @pkcs12: should contain a gnutls_pkcs12_t type
 * @pass: The password for the MAC
 *
 * This function will verify the MAC for the PKCS12 structure.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
{
	uint8_t key[MAX_HASH_SIZE];
	char oid[MAX_OID_SIZE];
	int result;
	unsigned int iter;
	int len;
	mac_hd_st td1;
	gnutls_datum_t tmp = { NULL, 0 }, salt = {
	NULL, 0};
	uint8_t mac_output[MAX_HASH_SIZE];
	uint8_t mac_output_orig[MAX_HASH_SIZE];
	gnutls_mac_algorithm_t algo;
	unsigned mac_len, key_len;
	const mac_entry_st *entry;
#if ENABLE_GOST
	int gost_retry = 0;
#endif

	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 */
	}

	len = sizeof(oid);
	result =
	    asn1_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm",
			    oid, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	algo = gnutls_oid_to_digest(oid);
	if (algo == GNUTLS_MAC_UNKNOWN) {
 unknown_mac:
		gnutls_assert();
		return GNUTLS_E_UNKNOWN_HASH_ALGORITHM;
	}

	entry = mac_to_entry(algo);
	if (entry == NULL)
		goto unknown_mac;

	mac_len = _gnutls_mac_get_algo_len(entry);
	key_len = mac_len;

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

	/* Generate the key.
	 */
	result = _gnutls_pkcs12_string_to_key(entry, 3 /*MAC*/,
					      salt.data, salt.size,
					      iter, pass,
					      key_len, 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;
	}

#if ENABLE_GOST
	/* GOST PKCS#12 files use either PKCS#12 scheme or proprietary
	 * HMAC-based scheme to generate MAC key. */
pkcs12_try_gost:
#endif

	/* MAC the data
	 */
	result = _gnutls_mac_init(&td1, entry, key, key_len);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	_gnutls_mac(&td1, tmp.data, tmp.size);

	_gnutls_mac_deinit(&td1, mac_output);

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

	if ((unsigned)len != mac_len ||
	    memcmp(mac_output_orig, mac_output, len) != 0) {

#if ENABLE_GOST
		/* It is possible that GOST files use proprietary
		 * key generation scheme */
		if (!gost_retry &&
		    (algo == GNUTLS_MAC_GOSTR_94 ||
		     algo == GNUTLS_MAC_STREEBOG_256 ||
		     algo == GNUTLS_MAC_STREEBOG_512)) {
			gost_retry = 1;
			key_len = 32;
			result = _gnutls_pkcs12_gost_string_to_key(algo,
								   salt.data,
								   salt.size,
								   iter,
								   pass,
								   key_len,
								   key);
			if (result < 0) {
				gnutls_assert();
				goto cleanup;
			}

			goto pkcs12_try_gost;
		}
#endif

		gnutls_assert();
		result = GNUTLS_E_MAC_VERIFY_FAILED;
		goto cleanup;
	}

	result = 0;
 cleanup:
	_gnutls_free_datum(&tmp);
	_gnutls_free_datum(&salt);
	return result;
}
Beispiel #2
0
/**
 * gnutls_pkcs12_mac_info:
 * @pkcs12: A pkcs12 type
 * @mac: the MAC algorithm used as %gnutls_mac_algorithm_t
 * @salt: the salt used for string to key (if non-NULL then @salt_size initially holds its size)
 * @salt_size: string to key salt size
 * @iter_count: string to key iteration count
 * @oid: if non-NULL it will contain an allocated null-terminated variable with the OID
 *
 * This function will provide information on the MAC algorithm used
 * in a PKCS #12 structure. If the structure algorithms
 * are unknown the code %GNUTLS_E_UNKNOWN_HASH_ALGORITHM will be returned,
 * and only @oid, will be set. That is, @oid will be set on structures
 * with a MAC whether supported or not. It must be deinitialized using gnutls_free().
 * The other variables are only set on supported structures.
 *
 * Returns: %GNUTLS_E_INVALID_REQUEST if the provided structure doesn't contain a MAC,
 *  %GNUTLS_E_UNKNOWN_HASH_ALGORITHM if the structure's MAC isn't supported, or
 *  another negative error code in case of a failure. Zero on success.
 **/
int
gnutls_pkcs12_mac_info(gnutls_pkcs12_t pkcs12, unsigned int *mac,
	void *salt, unsigned int *salt_size, unsigned int *iter_count, char **oid)
{
	int ret;
	gnutls_datum_t tmp = { NULL, 0 }, dsalt = {
	NULL, 0};
	gnutls_mac_algorithm_t algo;

	if (oid)
		*oid = NULL;

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

	ret =
	    _gnutls_x509_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm",
				    &tmp);
	if (ret < 0) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (oid) {
		*oid = (char*)tmp.data;
	}

	algo = gnutls_oid_to_digest((char*)tmp.data);
	if (algo == GNUTLS_MAC_UNKNOWN || mac_to_entry(algo) == NULL) {
		gnutls_assert();
		return GNUTLS_E_UNKNOWN_HASH_ALGORITHM;
	}

	if (oid) {
		tmp.data = NULL;
	}

	if (mac) {
		*mac = algo;
	}

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

	if (salt) {
		/* Read the salt from the structure.
		 */
		ret =
		    _gnutls_x509_read_null_value(pkcs12->pkcs12, "macData.macSalt",
					    &dsalt);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		if (*salt_size >= (unsigned)dsalt.size) {
			*salt_size = dsalt.size;
			if (dsalt.size > 0)
				memcpy(salt, dsalt.data, dsalt.size);
		} else {
			*salt_size = dsalt.size;
			ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
			goto cleanup;
		}
	}

	ret = 0;
 cleanup:
	_gnutls_free_datum(&tmp);
	_gnutls_free_datum(&dsalt);
	return ret;

}
Beispiel #3
0
/**
 * gnutls_decode_ber_digest_info:
 * @info: an RSA BER encoded DigestInfo structure
 * @hash: will contain the hash algorithm of the structure
 * @digest: will contain the hash output of the structure
 * @digest_size: will contain the hash size of the structure; initially must hold the maximum size of @digest
 *
 * This function will parse an RSA PKCS#1 1.5 DigestInfo structure
 * and report the hash algorithm used as well as the digest data.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
 *   an error code is returned.
 *
 * Since: 3.5.0
 *
 **/
int
gnutls_decode_ber_digest_info(const gnutls_datum_t * info,
		       gnutls_digest_algorithm_t * hash,
		       unsigned char * digest, unsigned int *digest_size)
{
	ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
	int result;
	char str[MAX(MAX_OID_SIZE, MAX_HASH_SIZE)];
	int len;

	if ((result = asn1_create_element(_gnutls_get_gnutls_asn(),
					  "GNUTLS.DigestInfo",
					  &dinfo)) != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_der_decoding(&dinfo, info->data, info->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&dinfo);
		return _gnutls_asn2err(result);
	}

	len = sizeof(str) - 1;
	result =
	    asn1_read_value(dinfo, "digestAlgorithm.algorithm", str, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&dinfo);
		return _gnutls_asn2err(result);
	}

	*hash = gnutls_oid_to_digest(str);

	if (*hash == GNUTLS_DIG_UNKNOWN) {

		_gnutls_debug_log("verify.c: HASH OID: %s\n", str);

		gnutls_assert();
		asn1_delete_structure(&dinfo);
		return GNUTLS_E_UNKNOWN_HASH_ALGORITHM;
	}

	len = sizeof(str) - 1;
	result =
	    asn1_read_value(dinfo, "digestAlgorithm.parameters", str,
			    &len);
	/* To avoid permitting garbage in the parameters field, either the
	   parameters field is not present, or it contains 0x05 0x00. */
	if (!(result == ASN1_ELEMENT_NOT_FOUND ||
	      (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE &&
	       memcmp(str, ASN1_NULL, ASN1_NULL_SIZE) == 0))) {
		gnutls_assert();
		asn1_delete_structure(&dinfo);
		return GNUTLS_E_ASN1_GENERIC_ERROR;
	}

	len = *digest_size;
	result = asn1_read_value(dinfo, "digest", digest, &len);

	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		*digest_size = len;
		asn1_delete_structure(&dinfo);
		return _gnutls_asn2err(result);
	}

	*digest_size = len;
	asn1_delete_structure(&dinfo);

	return 0;
}