diff --git a/librz/hash/algorithms/openssl_common.h b/librz/hash/algorithms/openssl_common.h index c4c70b413e..a60fd3762e 100644 --- a/librz/hash/algorithms/openssl_common.h +++ b/librz/hash/algorithms/openssl_common.h @@ -9,6 +9,9 @@ #include #include #include +#include + +#include #define rz_openssl_plugin_context_new(pluginname) \ static void *openssl_plugin_##pluginname##_context_new() { \ @@ -35,6 +38,10 @@ static bool openssl_plugin_##pluginname##_init(void *context) { \ rz_return_val_if_fail(context, false); \ if (EVP_DigestInit_ex((EVP_MD_CTX *)context, evpmd(), NULL) != 1) { \ + char emsg[256] = { 0 }; \ + ERR_error_string_n(ERR_get_error(), emsg, sizeof(emsg)); \ + RZ_LOG_ERROR("openssl: %s\n", emsg); \ + ERR_clear_error(); \ return false; \ } \ return true; \ @@ -47,6 +54,10 @@ return true; \ } \ if (EVP_DigestUpdate((EVP_MD_CTX *)context, data, size) != 1) { \ + char emsg[256] = { 0 }; \ + ERR_error_string_n(ERR_get_error(), emsg, sizeof(emsg)); \ + RZ_LOG_ERROR("openssl: %s\n", emsg); \ + ERR_clear_error(); \ return false; \ } \ return true; \ @@ -56,6 +67,10 @@ static bool openssl_plugin_##pluginname##_final(void *context, ut8 *digest) { \ rz_return_val_if_fail((context) && (digest), false); \ if (EVP_DigestFinal_ex((EVP_MD_CTX *)context, digest, NULL) != 1) { \ + char emsg[256] = { 0 }; \ + ERR_error_string_n(ERR_get_error(), emsg, sizeof(emsg)); \ + RZ_LOG_ERROR("openssl: %s\n", emsg); \ + ERR_clear_error(); \ return false; \ } \ return true; \ diff --git a/librz/hash/hash.c b/librz/hash/hash.c index 5eff57df5a..f72d58aefc 100644 --- a/librz/hash/hash.c +++ b/librz/hash/hash.c @@ -24,6 +24,52 @@ typedef struct hash_cfg_config_t { const RzHashPlugin *plugin; } HashCfgConfig; +#if HAVE_LIB_SSL +#include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/** + * From openssl 3.0 some algos got moved to the legacy provider. + * this means that their availability requires to preload a provider + * before calling the initialization of each algorithms. + */ + +#define REQUIRE_OPENSSL_PROVIDER 1 +#include + +typedef struct { + OSSL_PROVIDER *provider; + size_t counter; +} RzHashOpenSSL; + +static RzHashOpenSSL *openssl_lib = NULL; + +static void rz_hash_init_openssl_lib(void) { + if (!openssl_lib) { + openssl_lib = RZ_NEW0(RzHashOpenSSL); + if (!openssl_lib) { + RZ_LOG_ERROR("Cannot allocate RzHashOpenSSL\n"); + return; + } + openssl_lib->provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1); + if (!OSSL_PROVIDER_available(NULL, "legacy")) { + RZ_LOG_WARN("Cannot load openssl legacy provider. Some algorithm might not be available.\n"); + } + } + openssl_lib->counter++; +} + +static void rz_hash_fini_openssl_lib(void) { + if (!openssl_lib || (--openssl_lib->counter) > 0) { + return; + } + OSSL_PROVIDER_unload(openssl_lib->provider); + free(openssl_lib); + openssl_lib = NULL; +} + +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +#endif /* HAVE_LIB_SSL */ + static RzHashPlugin *hash_static_plugins[] = { RZ_HASH_STATIC_PLUGINS }; /** @@ -659,6 +705,9 @@ RZ_API RzHash *rz_hash_new(void) { if (!rh) { return NULL; } +#if REQUIRE_OPENSSL_PROVIDER + rz_hash_init_openssl_lib(); +#endif /* REQUIRE_OPENSSL_PROVIDER */ rh->plugins = rz_list_new(); for (int i = 0; i < RZ_ARRAY_SIZE(hash_static_plugins); i++) { rz_hash_plugin_add(rh, hash_static_plugins[i]); @@ -666,12 +715,15 @@ RZ_API RzHash *rz_hash_new(void) { return rh; } -RZ_API void rz_hash_free(RzHash *rh) { +RZ_API void rz_hash_free(RZ_NULLABLE RzHash *rh) { if (!rh) { return; } rz_list_free(rh->plugins); free(rh); +#if REQUIRE_OPENSSL_PROVIDER + rz_hash_fini_openssl_lib(); +#endif /* REQUIRE_OPENSSL_PROVIDER */ } /** diff --git a/librz/include/rz_hash.h b/librz/include/rz_hash.h index e7881cd860..83f280a7c7 100644 --- a/librz/include/rz_hash.h +++ b/librz/include/rz_hash.h @@ -51,7 +51,7 @@ typedef struct rz_hash_cfg_t { #ifdef RZ_API RZ_API RzHash *rz_hash_new(void); -RZ_API void rz_hash_free(RzHash *rh); +RZ_API void rz_hash_free(RZ_NULLABLE RzHash *rh); RZ_API bool rz_hash_plugin_add(RZ_NONNULL RzHash *rh, RZ_NONNULL RZ_OWN RzHashPlugin *plugin); RZ_API bool rz_hash_plugin_del(RZ_NONNULL RzHash *rh, RZ_NONNULL RzHashPlugin *plugin); RZ_API RZ_BORROW const RzHashPlugin *rz_hash_plugin_by_index(RZ_NONNULL RzHash *rh, size_t index);