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