Path: blob/main/crypto/openssl/providers/implementations/rands/drbg_hmac.c
48383 views
/*1* Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <stdlib.h>10#include <string.h>11#include <openssl/crypto.h>12#include <openssl/err.h>13#include <openssl/rand.h>14#include <openssl/proverr.h>15#include "internal/thread_once.h"16#include "prov/providercommon.h"17#include "prov/implementations.h"18#include "prov/provider_ctx.h"19#include "prov/hmac_drbg.h"20#include "drbg_local.h"21#include "crypto/evp.h"22#include "crypto/evp/evp_local.h"23#include "internal/provider.h"2425static OSSL_FUNC_rand_newctx_fn drbg_hmac_new_wrapper;26static OSSL_FUNC_rand_freectx_fn drbg_hmac_free;27static OSSL_FUNC_rand_instantiate_fn drbg_hmac_instantiate_wrapper;28static OSSL_FUNC_rand_uninstantiate_fn drbg_hmac_uninstantiate_wrapper;29static OSSL_FUNC_rand_generate_fn drbg_hmac_generate_wrapper;30static OSSL_FUNC_rand_reseed_fn drbg_hmac_reseed_wrapper;31static OSSL_FUNC_rand_settable_ctx_params_fn drbg_hmac_settable_ctx_params;32static OSSL_FUNC_rand_set_ctx_params_fn drbg_hmac_set_ctx_params;33static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_hmac_gettable_ctx_params;34static OSSL_FUNC_rand_get_ctx_params_fn drbg_hmac_get_ctx_params;35static OSSL_FUNC_rand_verify_zeroization_fn drbg_hmac_verify_zeroization;3637static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]);3839/*40* Called twice by SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process.41*42* hmac is an object that holds the input/output Key and Value (K and V).43* inbyte is 0x00 on the first call and 0x01 on the second call.44* in1, in2, in3 are optional inputs that can be NULL.45* in1len, in2len, in3len are the lengths of the input buffers.46*47* The returned K,V is:48* hmac->K = HMAC(hmac->K, hmac->V || inbyte || [in1] || [in2] || [in3])49* hmac->V = HMAC(hmac->K, hmac->V)50*51* Returns zero if an error occurs otherwise it returns 1.52*/53static int do_hmac(PROV_DRBG_HMAC *hmac, unsigned char inbyte,54const unsigned char *in1, size_t in1len,55const unsigned char *in2, size_t in2len,56const unsigned char *in3, size_t in3len)57{58EVP_MAC_CTX *ctx = hmac->ctx;5960if (!EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL)61/* K = HMAC(K, V || inbyte || [in1] || [in2] || [in3]) */62|| !EVP_MAC_update(ctx, hmac->V, hmac->blocklen)63|| !EVP_MAC_update(ctx, &inbyte, 1)64|| !(in1 == NULL || in1len == 0 || EVP_MAC_update(ctx, in1, in1len))65|| !(in2 == NULL || in2len == 0 || EVP_MAC_update(ctx, in2, in2len))66|| !(in3 == NULL || in3len == 0 || EVP_MAC_update(ctx, in3, in3len))67|| !EVP_MAC_final(ctx, hmac->K, NULL, sizeof(hmac->K)))68return 0;6970/* V = HMAC(K, V) */71return EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL)72&& EVP_MAC_update(ctx, hmac->V, hmac->blocklen)73&& EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V));74}7576/*77* SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process78*79*80* Updates the drbg objects Key(K) and Value(V) using the following algorithm:81* K,V = do_hmac(hmac, 0, in1, in2, in3)82* if (any input is not NULL)83* K,V = do_hmac(hmac, 1, in1, in2, in3)84*85* where in1, in2, in3 are optional input buffers that can be NULL.86* in1len, in2len, in3len are the lengths of the input buffers.87*88* Returns zero if an error occurs otherwise it returns 1.89*/90static int drbg_hmac_update(PROV_DRBG_HMAC *hmac,91const unsigned char *in1, size_t in1len,92const unsigned char *in2, size_t in2len,93const unsigned char *in3, size_t in3len)94{95/* (Steps 1-2) K = HMAC(K, V||0x00||provided_data). V = HMAC(K,V) */96if (!do_hmac(hmac, 0x00, in1, in1len, in2, in2len, in3, in3len))97return 0;98/* (Step 3) If provided_data == NULL then return (K,V) */99if (in1len == 0 && in2len == 0 && in3len == 0)100return 1;101/* (Steps 4-5) K = HMAC(K, V||0x01||provided_data). V = HMAC(K,V) */102return do_hmac(hmac, 0x01, in1, in1len, in2, in2len, in3, in3len);103}104105/*106* SP800-90Ar1 10.1.2.3 HMAC_DRBG_Instantiate_Process:107*108* This sets the drbg Key (K) to all zeros, and Value (V) to all 1's.109* and then calls (K,V) = drbg_hmac_update() with input parameters:110* ent = entropy data (Can be NULL) of length ent_len.111* nonce = nonce data (Can be NULL) of length nonce_len.112* pstr = personalization data (Can be NULL) of length pstr_len.113*114* Returns zero if an error occurs otherwise it returns 1.115*/116int ossl_drbg_hmac_init(PROV_DRBG_HMAC *hmac,117const unsigned char *ent, size_t ent_len,118const unsigned char *nonce, size_t nonce_len,119const unsigned char *pstr, size_t pstr_len)120{121if (hmac->ctx == NULL) {122ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC);123return 0;124}125126/* (Step 2) Key = 0x00 00...00 */127memset(hmac->K, 0x00, hmac->blocklen);128/* (Step 3) V = 0x01 01...01 */129memset(hmac->V, 0x01, hmac->blocklen);130/* (Step 4) (K,V) = HMAC_DRBG_Update(entropy||nonce||pers string, K, V) */131return drbg_hmac_update(hmac, ent, ent_len, nonce, nonce_len, pstr,132pstr_len);133}134static int drbg_hmac_instantiate(PROV_DRBG *drbg,135const unsigned char *ent, size_t ent_len,136const unsigned char *nonce, size_t nonce_len,137const unsigned char *pstr, size_t pstr_len)138{139return ossl_drbg_hmac_init((PROV_DRBG_HMAC *)drbg->data, ent, ent_len,140nonce, nonce_len, pstr, pstr_len);141}142143static int drbg_hmac_instantiate_wrapper(void *vdrbg, unsigned int strength,144int prediction_resistance,145const unsigned char *pstr,146size_t pstr_len,147const OSSL_PARAM params[])148{149PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;150int ret = 0;151152if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))153return 0;154155if (!ossl_prov_is_running()156|| !drbg_hmac_set_ctx_params_locked(drbg, params))157goto err;158ret = ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,159pstr, pstr_len);160err:161if (drbg->lock != NULL)162CRYPTO_THREAD_unlock(drbg->lock);163return ret;164}165166167/*168* SP800-90Ar1 10.1.2.4 HMAC_DRBG_Reseed_Process:169*170* Reseeds the drbg's Key (K) and Value (V) by calling171* (K,V) = drbg_hmac_update() with the following input parameters:172* ent = entropy input data (Can be NULL) of length ent_len.173* adin = additional input data (Can be NULL) of length adin_len.174*175* Returns zero if an error occurs otherwise it returns 1.176*/177static int drbg_hmac_reseed(PROV_DRBG *drbg,178const unsigned char *ent, size_t ent_len,179const unsigned char *adin, size_t adin_len)180{181PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data;182183/* (Step 2) (K,V) = HMAC_DRBG_Update(entropy||additional_input, K, V) */184return drbg_hmac_update(hmac, ent, ent_len, adin, adin_len, NULL, 0);185}186187static int drbg_hmac_reseed_wrapper(void *vdrbg, int prediction_resistance,188const unsigned char *ent, size_t ent_len,189const unsigned char *adin, size_t adin_len)190{191PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;192193return ossl_prov_drbg_reseed(drbg, prediction_resistance, ent, ent_len,194adin, adin_len);195}196197/*198* SP800-90Ar1 10.1.2.5 HMAC_DRBG_Generate_Process:199*200* Generates pseudo random bytes and updates the internal K,V for the drbg.201* out is a buffer to fill with outlen bytes of pseudo random data.202* adin is an additional_input string of size adin_len that may be NULL.203*204* Returns zero if an error occurs otherwise it returns 1.205*/206int ossl_drbg_hmac_generate(PROV_DRBG_HMAC *hmac,207unsigned char *out, size_t outlen,208const unsigned char *adin, size_t adin_len)209{210EVP_MAC_CTX *ctx = hmac->ctx;211const unsigned char *temp = hmac->V;212213/* (Step 2) if adin != NULL then (K,V) = HMAC_DRBG_Update(adin, K, V) */214if (adin != NULL215&& adin_len > 0216&& !drbg_hmac_update(hmac, adin, adin_len, NULL, 0, NULL, 0))217return 0;218219/*220* (Steps 3-5) temp = NULL221* while (len(temp) < outlen) {222* V = HMAC(K, V)223* temp = temp || V224* }225*/226for (;;) {227if (!EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL)228|| !EVP_MAC_update(ctx, temp, hmac->blocklen))229return 0;230231if (outlen > hmac->blocklen) {232if (!EVP_MAC_final(ctx, out, NULL, outlen))233return 0;234temp = out;235} else {236if (!EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V)))237return 0;238memcpy(out, hmac->V, outlen);239break;240}241out += hmac->blocklen;242outlen -= hmac->blocklen;243}244/* (Step 6) (K,V) = HMAC_DRBG_Update(adin, K, V) */245if (!drbg_hmac_update(hmac, adin, adin_len, NULL, 0, NULL, 0))246return 0;247248return 1;249}250251static int drbg_hmac_generate(PROV_DRBG *drbg,252unsigned char *out, size_t outlen,253const unsigned char *adin, size_t adin_len)254{255return ossl_drbg_hmac_generate((PROV_DRBG_HMAC *)drbg->data, out, outlen,256adin, adin_len);257}258259static int drbg_hmac_generate_wrapper(void *vdrbg,260unsigned char *out, size_t outlen, unsigned int strength,261int prediction_resistance, const unsigned char *adin, size_t adin_len)262{263PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;264265return ossl_prov_drbg_generate(drbg, out, outlen, strength,266prediction_resistance, adin, adin_len);267}268269static int drbg_hmac_uninstantiate(PROV_DRBG *drbg)270{271PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data;272273OPENSSL_cleanse(hmac->K, sizeof(hmac->K));274OPENSSL_cleanse(hmac->V, sizeof(hmac->V));275return ossl_prov_drbg_uninstantiate(drbg);276}277278static int drbg_hmac_uninstantiate_wrapper(void *vdrbg)279{280PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;281int ret;282283if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))284return 0;285286ret = drbg_hmac_uninstantiate(drbg);287288if (drbg->lock != NULL)289CRYPTO_THREAD_unlock(drbg->lock);290291return ret;292}293294static int drbg_hmac_verify_zeroization(void *vdrbg)295{296PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;297PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data;298int ret = 0;299300if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))301return 0;302303PROV_DRBG_VERIFY_ZEROIZATION(hmac->K);304PROV_DRBG_VERIFY_ZEROIZATION(hmac->V);305306ret = 1;307err:308if (drbg->lock != NULL)309CRYPTO_THREAD_unlock(drbg->lock);310return ret;311}312313static int drbg_hmac_new(PROV_DRBG *drbg)314{315PROV_DRBG_HMAC *hmac;316317hmac = OPENSSL_secure_zalloc(sizeof(*hmac));318if (hmac == NULL)319return 0;320321OSSL_FIPS_IND_INIT(drbg)322323drbg->data = hmac;324/* See SP800-57 Part1 Rev4 5.6.1 Table 3 */325drbg->max_entropylen = DRBG_MAX_LENGTH;326drbg->max_noncelen = DRBG_MAX_LENGTH;327drbg->max_perslen = DRBG_MAX_LENGTH;328drbg->max_adinlen = DRBG_MAX_LENGTH;329330/* Maximum number of bits per request = 2^19 = 2^16 bytes */331drbg->max_request = 1 << 16;332return 1;333}334335static void *drbg_hmac_new_wrapper(void *provctx, void *parent,336const OSSL_DISPATCH *parent_dispatch)337{338return ossl_rand_drbg_new(provctx, parent, parent_dispatch,339&drbg_hmac_new, &drbg_hmac_free,340&drbg_hmac_instantiate, &drbg_hmac_uninstantiate,341&drbg_hmac_reseed, &drbg_hmac_generate);342}343344static void drbg_hmac_free(void *vdrbg)345{346PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;347PROV_DRBG_HMAC *hmac;348349if (drbg != NULL && (hmac = (PROV_DRBG_HMAC *)drbg->data) != NULL) {350EVP_MAC_CTX_free(hmac->ctx);351ossl_prov_digest_reset(&hmac->digest);352OPENSSL_secure_clear_free(hmac, sizeof(*hmac));353}354ossl_rand_drbg_free(drbg);355}356357static int drbg_hmac_get_ctx_params(void *vdrbg, OSSL_PARAM params[])358{359PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;360PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data;361const char *name;362const EVP_MD *md;363OSSL_PARAM *p;364int ret = 0, complete = 0;365366if (!ossl_drbg_get_ctx_params_no_lock(drbg, params, &complete))367return 0;368369if (complete)370return 1;371372if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))373return 0;374375p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAC);376if (p != NULL) {377if (hmac->ctx == NULL)378goto err;379name = EVP_MAC_get0_name(EVP_MAC_CTX_get0_mac(hmac->ctx));380if (!OSSL_PARAM_set_utf8_string(p, name))381goto err;382}383384p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_DIGEST);385if (p != NULL) {386md = ossl_prov_digest_md(&hmac->digest);387if (md == NULL || !OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md)))388goto err;389}390391ret = ossl_drbg_get_ctx_params(drbg, params);392err:393if (drbg->lock != NULL)394CRYPTO_THREAD_unlock(drbg->lock);395396return ret;397}398399static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx,400ossl_unused void *p_ctx)401{402static const OSSL_PARAM known_gettable_ctx_params[] = {403OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0),404OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0),405OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON,406OSSL_FIPS_IND_GETTABLE_CTX_PARAM()407OSSL_PARAM_END408};409return known_gettable_ctx_params;410}411412static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[],413OSSL_LIB_CTX *libctx,414EVP_MAC_CTX **macctx,415EVP_MD **digest)416{417OSSL_PROVIDER *prov = NULL;418const OSSL_PARAM *p;419EVP_MD *md = NULL;420EVP_MAC *mac = NULL;421int ret = 0;422423if (macctx == NULL || digest == NULL)424return 0;425426if ((p = OSSL_PARAM_locate_const(params,427OSSL_PROV_PARAM_CORE_PROV_NAME)) == NULL)428return 0;429if (p->data_type != OSSL_PARAM_UTF8_STRING)430return 0;431if ((prov = ossl_provider_find(libctx, (const char *)p->data, 1)) == NULL)432return 0;433434p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST);435if (p) {436if (p->data_type != OSSL_PARAM_UTF8_STRING)437goto done;438439md = evp_digest_fetch_from_prov(prov, (const char *)p->data, NULL);440if (md) {441EVP_MD_free(*digest);442*digest = md;443} else {444goto done;445}446}447448p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_MAC);449if (p == NULL) {450ret = 1;451goto done;452}453454if (p->data_type != OSSL_PARAM_UTF8_STRING)455goto done;456457EVP_MAC_CTX_free(*macctx);458*macctx = NULL;459460mac = evp_mac_fetch_from_prov(prov, (const char *)p->data, NULL);461if (mac) {462*macctx = EVP_MAC_CTX_new(mac);463/* The context holds on to the MAC */464EVP_MAC_free(mac);465ret = 1;466}467468done:469ossl_provider_free(prov);470return ret;471}472473static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[])474{475PROV_DRBG *ctx = (PROV_DRBG *)vctx;476PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)ctx->data;477OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);478EVP_MD *prov_md = NULL;479const EVP_MD *md;480int md_size;481482if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params,483OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK))484return 0;485486/* try to fetch mac and digest from provider */487(void)ERR_set_mark();488if (!drbg_fetch_algs_from_prov(params, libctx, &hmac->ctx, &prov_md)) {489(void)ERR_pop_to_mark();490/* fall back to full implementation search */491if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx))492return 0;493494if (!ossl_prov_macctx_load_from_params(&hmac->ctx, params,495NULL, NULL, NULL, libctx))496return 0;497} else {498(void)ERR_clear_last_mark();499if (prov_md)500ossl_prov_digest_set_md(&hmac->digest, prov_md);501}502503md = ossl_prov_digest_md(&hmac->digest);504if (md != NULL && !ossl_drbg_verify_digest(ctx, libctx, md))505return 0; /* Error already raised for us */506507if (md != NULL && hmac->ctx != NULL) {508/* These are taken from SP 800-90 10.1 Table 2 */509md_size = EVP_MD_get_size(md);510if (md_size <= 0)511return 0;512hmac->blocklen = (size_t)md_size;513/* See SP800-57 Part1 Rev4 5.6.1 Table 3 */514ctx->strength = 64 * (int)(hmac->blocklen >> 3);515if (ctx->strength > 256)516ctx->strength = 256;517ctx->seedlen = hmac->blocklen;518ctx->min_entropylen = ctx->strength / 8;519ctx->min_noncelen = ctx->min_entropylen / 2;520}521522return ossl_drbg_set_ctx_params(ctx, params);523}524525static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[])526{527PROV_DRBG *drbg = (PROV_DRBG *)vctx;528int ret;529530if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))531return 0;532533ret = drbg_hmac_set_ctx_params_locked(vctx, params);534535if (drbg->lock != NULL)536CRYPTO_THREAD_unlock(drbg->lock);537538return ret;539}540541static const OSSL_PARAM *drbg_hmac_settable_ctx_params(ossl_unused void *vctx,542ossl_unused void *p_ctx)543{544static const OSSL_PARAM known_settable_ctx_params[] = {545OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0),546OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0),547OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0),548OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON,549OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)550OSSL_PARAM_END551};552return known_settable_ctx_params;553}554555const OSSL_DISPATCH ossl_drbg_ossl_hmac_functions[] = {556{ OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hmac_new_wrapper },557{ OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hmac_free },558{ OSSL_FUNC_RAND_INSTANTIATE,559(void(*)(void))drbg_hmac_instantiate_wrapper },560{ OSSL_FUNC_RAND_UNINSTANTIATE,561(void(*)(void))drbg_hmac_uninstantiate_wrapper },562{ OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hmac_generate_wrapper },563{ OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hmac_reseed_wrapper },564{ OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking },565{ OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock },566{ OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock },567{ OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS,568(void(*)(void))drbg_hmac_settable_ctx_params },569{ OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hmac_set_ctx_params },570{ OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,571(void(*)(void))drbg_hmac_gettable_ctx_params },572{ OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hmac_get_ctx_params },573{ OSSL_FUNC_RAND_VERIFY_ZEROIZATION,574(void(*)(void))drbg_hmac_verify_zeroization },575{ OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed },576{ OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed },577OSSL_DISPATCH_END578};579580581