/* Provenance: openssl/openssl HKDF_Expand (fixed). * repo: openssl/openssl * commit: d12cde7fc5561d463badcd8a73079cf92864c31e * parent: 5d6f13d90d5c4212737002bcd54871cf236a1220 * commit_url: https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e * cve: CVE-2022-37454 * license: Apache-2.0 * function: HKDF_Expand * relpath: providers/implementations/kdfs/hkdf.c */ static int HKDF_Expand(const EVP_MD *evp_md, const unsigned char *prk, size_t prk_len, const unsigned char *info, size_t info_len, unsigned char *okm, size_t okm_len) { HMAC_CTX *hmac; int ret = 0, sz; unsigned int i; unsigned char prev[EVP_MAX_MD_SIZE]; size_t done_len = 0, dig_len, n; sz = EVP_MD_get_size(evp_md); if (sz <= 0) return 0; dig_len = (size_t)sz; /* calc: N = ceil(L/HashLen) */ n = okm_len / dig_len; if (okm_len % dig_len) n++; if (n > 255 || okm == NULL) return 0; if ((hmac = HMAC_CTX_new()) == NULL) return 0; if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL)) goto err; for (i = 1; i <= n; i++) { size_t copy_len; const unsigned char ctr = i; /* calc: T(i) = HMAC-Hash(PRK, T(i - 1) | info | i) */ if (i > 1) { if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) goto err; if (!HMAC_Update(hmac, prev, dig_len)) goto err; } if (!HMAC_Update(hmac, info, info_len)) goto err; if (!HMAC_Update(hmac, &ctr, 1)) goto err; if (!HMAC_Final(hmac, prev, NULL)) goto err; copy_len = (dig_len > okm_len - done_len) ? okm_len - done_len : dig_len; memcpy(okm + done_len, prev, copy_len); done_len += copy_len; } ret = 1; err: OPENSSL_cleanse(prev, sizeof(prev)); HMAC_CTX_free(hmac); return ret; }