+
+static void *drbg_hmac_new_wrapper(void *provctx, void *parent,
+ const OSSL_DISPATCH *parent_dispatch)
+{
+ return prov_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_hmac_new,
+ &drbg_hmac_instantiate, &drbg_hmac_uninstantiate,
+ &drbg_hmac_reseed, &drbg_hmac_generate);
+}
+
+static void drbg_hmac_free(void *vdrbg)
+{
+ PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ PROV_DRBG_HMAC *hmac;
+
+ if (drbg != NULL && (hmac = (PROV_DRBG_HMAC *)drbg->data) != NULL) {
+ EVP_MAC_CTX_free(hmac->ctx);
+ ossl_prov_digest_reset(&hmac->digest);
+ OPENSSL_secure_clear_free(hmac, sizeof(*hmac));
+ }
+ prov_rand_drbg_free(drbg);
+}
+
+static int drbg_hmac_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
+{
+ PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+
+ return drbg_get_ctx_params(drbg, params);
+}
+
+static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *p_ctx)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON,
+ OSSL_PARAM_END
+ };
+ return known_gettable_ctx_params;
+}
+
+static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_DRBG *ctx = (PROV_DRBG *)vctx;
+ PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)ctx->data;
+ OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+ const EVP_MD *md;
+
+ if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx))
+ return 0;
+
+ /*
+ * Confirm digest is allowed. We allow all digests that are not XOF
+ * (such as SHAKE). In FIPS mode, the fetch will fail for non-approved
+ * digests.
+ */
+ md = ossl_prov_digest_md(&hmac->digest);
+ if (md != NULL && (EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
+ return 0;
+ }
+
+ if (!ossl_prov_macctx_load_from_params(&hmac->ctx, params,
+ NULL, NULL, NULL, libctx))
+ return 0;
+
+ if (hmac->ctx != NULL) {
+ /* These are taken from SP 800-90 10.1 Table 2 */
+ hmac->blocklen = EVP_MD_size(md);
+ /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */
+ ctx->strength = 64 * (int)(hmac->blocklen >> 3);
+ if (ctx->strength > 256)
+ ctx->strength = 256;
+ ctx->seedlen = hmac->blocklen;
+ ctx->min_entropylen = ctx->strength / 8;
+ ctx->min_noncelen = ctx->min_entropylen / 2;
+ }
+
+ return drbg_set_ctx_params(ctx, params);
+}
+
+static const OSSL_PARAM *drbg_hmac_settable_ctx_params(ossl_unused void *p_ctx)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0),
+ OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON,
+ OSSL_PARAM_END
+ };
+ return known_settable_ctx_params;
+}
+
+const OSSL_DISPATCH drbg_hmac_functions[] = {
+ { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hmac_new_wrapper },
+ { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hmac_free },
+ { OSSL_FUNC_RAND_INSTANTIATE,
+ (void(*)(void))drbg_hmac_instantiate_wrapper },
+ { OSSL_FUNC_RAND_UNINSTANTIATE,
+ (void(*)(void))drbg_hmac_uninstantiate_wrapper },
+ { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hmac_generate_wrapper },
+ { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hmac_reseed_wrapper },
+ { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking },
+ { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock },
+ { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock },
+ { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS,
+ (void(*)(void))drbg_hmac_settable_ctx_params },
+ { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hmac_set_ctx_params },
+ { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
+ (void(*)(void))drbg_hmac_gettable_ctx_params },
+ { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hmac_get_ctx_params },
+ { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
+ (void(*)(void))drbg_hmac_verify_zeroization },
+ { 0, NULL }
+};