From: Alan T. DeKok Date: Wed, 10 Dec 2025 19:21:52 +0000 (-0500) Subject: manually switch to local / openssl versions of MD4 and MD5. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a303bc6f94c4fffed02dc81c8c06193bf07e3612;p=thirdparty%2Ffreeradius-server.git manually switch to local / openssl versions of MD4 and MD5. The fuzzer doesn't call all of the OpenSSL initialization functions, so if it calls any MD5 routines in RADIUS, it crashes. If we try to call fr_openssl_fips_mode(), we need to link to libfreeradius-tls, libfreeradius-server, libfreeradius-unlang, and then call fr_openssl_init(), which does a ton of other things. The solution is to manually swap the functions to their local versions, OR the OpenSSL versions. This is done in fr_openssl_init() and in fr_openssl_free(). And for good measure, in then also in fr_openssl_fips_mode(). The previous code could boot with FIPS disabled, set the MD5 pointers, and then at some later point FIPS would be disabled. The MD5 pointers wouldn't be updated, and bad things could happen. That case deosn't happen now, because the current code only changes the FIPs status once at boot. But it's better to fix the APIs to be more correct. --- diff --git a/src/bin/radclient-ng.c b/src/bin/radclient-ng.c index 9dad5f97ba9..645d89cc913 100644 --- a/src/bin/radclient-ng.c +++ b/src/bin/radclient-ng.c @@ -41,6 +41,8 @@ RCSID("$Id$") #ifdef HAVE_OPENSSL_SSL_H #include +#include +#include #endif #include @@ -233,6 +235,9 @@ static int openssl3_init(void) return -1; } + fr_md5_openssl_init(); + fr_md4_openssl_init(); + return 0; } @@ -247,6 +252,9 @@ static void openssl3_free(void) ERROR("Failed unloading legacy provider"); } openssl_legacy_provider = NULL; + + fr_md5_openssl_free(); + fr_md4_openssl_free(); } #else #define openssl3_init() diff --git a/src/bin/radclient.c b/src/bin/radclient.c index cf9515931e2..33c3f489a11 100644 --- a/src/bin/radclient.c +++ b/src/bin/radclient.c @@ -38,6 +38,8 @@ RCSID("$Id$") #include #ifdef HAVE_OPENSSL_SSL_H #include +#include +#include #endif #include @@ -228,6 +230,9 @@ static int openssl3_init(void) return -1; } + fr_md5_openssl_init(); + fr_md4_openssl_init(); + return 0; } @@ -242,6 +247,9 @@ static void openssl3_free(void) ERROR("Failed unloading legacy provider"); } openssl_legacy_provider = NULL; + + fr_md5_openssl_free(); + fr_md4_openssl_free(); } #else #define openssl3_init() diff --git a/src/lib/tls/base.c b/src/lib/tls/base.c index 8c6520a829f..cb5a425ae41 100644 --- a/src/lib/tls/base.c +++ b/src/lib/tls/base.c @@ -45,6 +45,8 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ #include #include #include +#include +#include static uint32_t openssl_instance_count = 0; @@ -397,6 +399,9 @@ void fr_openssl_free(void) fr_tls_log_free(); fr_tls_bio_free(); + + fr_md5_openssl_free(); + fr_md4_openssl_free(); } static void _openssl_provider_free(void) @@ -538,6 +543,9 @@ int fr_openssl_init(void) fr_tls_bio_init(); + fr_md5_openssl_init(); + fr_md4_openssl_init(); + /* * Use an atexit handler to try and ensure * that OpenSSL gets freed last. @@ -567,6 +575,17 @@ int fr_openssl_fips_mode(bool enabled) return -1; } + /* + * Swap the MD4 / MD5 functions as appropriate. + */ + if (enabled) { + fr_md5_openssl_init(); + fr_md4_openssl_init(); + } else { + fr_md5_openssl_free(); + fr_md4_openssl_free(); + } + return 0; } diff --git a/src/lib/util/md4.c b/src/lib/util/md4.c index 774f74e3d49..041a5475b03 100644 --- a/src/lib/util/md4.c +++ b/src/lib/util/md4.c @@ -29,11 +29,7 @@ static _Thread_local fr_md4_free_list_t *md4_array; static void fr_md4_local_ctx_reset(fr_md4_ctx_t *ctx); static void fr_md4_local_ctx_copy(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src); -#ifdef HAVE_OPENSSL_EVP_H -static fr_md4_ctx_t *fr_md4_local_ctx_init(void); -#else static fr_md4_ctx_t *fr_md4_local_ctx_alloc(void); -#endif static void fr_md4_local_ctx_free(fr_md4_ctx_t **ctx); static void fr_md4_local_update(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen); static void fr_md4_local_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx); @@ -41,11 +37,7 @@ static void fr_md4_local_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx static fr_md4_funcs_t md4_local_funcs = { .reset = fr_md4_local_ctx_reset, .copy = fr_md4_local_ctx_copy, -#ifdef HAVE_OPENSSL_EVP_H - .alloc = fr_md4_local_ctx_init, -#else .alloc = fr_md4_local_ctx_alloc, -#endif .free = fr_md4_local_ctx_free, .update = fr_md4_local_update, .final = fr_md4_local_final @@ -352,32 +344,6 @@ static fr_md4_ctx_t *fr_md4_local_ctx_alloc(void) return ctx_local; } -#ifdef HAVE_OPENSSL_EVP_H -/** Initialize whether or not we use the local allocator, or the OpenSSL one. - * - */ -static fr_md4_ctx_t *fr_md4_local_ctx_init(void) -{ - /* - * If we are in FIPS mode, then use the local allocator. - */ - if (!EVP_default_properties_is_fips_enabled(NULL)) { - /* - * OpenSSL isn't in FIPS mode. Swap out the functions - * pointers for the OpenSSL versions. - * - * We do this by swapping out a pointer to a structure - * containing the functions, as this prevents possible - * skew where some threads see a mixture of functions. - */ - fr_md4_funcs = &md4_openssl_funcs; - } else { - md4_local_funcs.alloc = fr_md4_local_ctx_alloc; /* Don't call this (init) function again */ - } - - return fr_md4_ctx_alloc(); -} -#endif /** @copydoc fr_md4_ctx_free * @@ -496,16 +462,6 @@ static void fr_md4_local_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx memset(ctx_local, 0, sizeof(*ctx_local)); /* in case it's sensitive */ } -/* - * Digest function pointers - */ -fr_md4_ctx_reset_t fr_md4_ctx_reset = fr_md4_local_ctx_reset; -fr_md4_ctx_copy_t fr_md4_ctx_copy = fr_md4_local_ctx_copy; -fr_md4_ctx_alloc_t fr_md4_ctx_alloc = fr_md4_local_ctx_alloc; -fr_md4_ctx_free_t fr_md4_ctx_free = fr_md4_local_ctx_free; -fr_md4_update_t fr_md4_update = fr_md4_local_update; -fr_md4_final_t fr_md4_final = fr_md4_local_final; - /** Calculate the MD4 hash of the contents of a buffer * * @param[out] out Where to write the MD4 digest. Must be a minimum of MD4_DIGEST_LENGTH. @@ -602,3 +558,29 @@ void fr_md4_ctx_free_from_list(fr_md4_ctx_t **ctx) fr_md4_ctx_free(*ctx); *ctx = NULL; } + +#ifdef HAVE_OPENSSL_EVP_H +void fr_md4_openssl_init(void) +{ + /* + * If we are in FIPS mode, then we still use the local + * allocator. + */ + if (!EVP_default_properties_is_fips_enabled(NULL)) return; + + /* + * OpenSSL isn't in FIPS mode. Swap out the functions + * pointers for the OpenSSL versions. + * + * We do this by swapping out a pointer to a structure + * containing the functions, as this prevents possible + * skew where some threads see a mixture of functions. + */ + fr_md4_funcs = &md4_openssl_funcs; +} + +void fr_md4_openssl_free(void) +{ + fr_md4_funcs = &md4_local_funcs; +} +#endif diff --git a/src/lib/util/md4.h b/src/lib/util/md4.h index 94ed5698a6d..00a8a02a264 100644 --- a/src/lib/util/md4.h +++ b/src/lib/util/md4.h @@ -106,6 +106,12 @@ fr_md4_ctx_t *fr_md4_ctx_alloc_from_list(void); * */ void fr_md4_ctx_free_from_list(fr_md4_ctx_t **ctx); + +#ifdef HAVE_OPENSSL_EVP_H +void fr_md4_openssl_init(void); +void fr_md4_openssl_free(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/lib/util/md5.c b/src/lib/util/md5.c index c8885e91239..f0f12cababa 100644 --- a/src/lib/util/md5.c +++ b/src/lib/util/md5.c @@ -29,11 +29,7 @@ static _Thread_local fr_md5_free_list_t *md5_array; static void fr_md5_local_ctx_reset(fr_md5_ctx_t *ctx); static void fr_md5_local_ctx_copy(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src); -#ifdef HAVE_OPENSSL_EVP_H -static fr_md5_ctx_t *fr_md5_local_ctx_init(void); -#else static fr_md5_ctx_t *fr_md5_local_ctx_alloc(void); -#endif static void fr_md5_local_ctx_free(fr_md5_ctx_t **ctx); static void fr_md5_local_update(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen); static void fr_md5_local_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx); @@ -41,11 +37,7 @@ static void fr_md5_local_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx static fr_md5_funcs_t md5_local_funcs = { .reset = fr_md5_local_ctx_reset, .copy = fr_md5_local_ctx_copy, -#ifdef HAVE_OPENSSL_EVP_H - .alloc = fr_md5_local_ctx_init, -#else .alloc = fr_md5_local_ctx_alloc, -#endif .free = fr_md5_local_ctx_free, .update = fr_md5_local_update, .final = fr_md5_local_final @@ -346,33 +338,6 @@ static fr_md5_ctx_t *fr_md5_local_ctx_alloc(void) return ctx_local; } -#ifdef HAVE_OPENSSL_EVP_H -/** Initialize whether or not we use the local allocator, or the OpenSSL one. - * - */ -static fr_md5_ctx_t *fr_md5_local_ctx_init(void) -{ - /* - * If we are in FIPS mode, then use the local allocator. - */ - if (!EVP_default_properties_is_fips_enabled(NULL)) { - /* - * OpenSSL isn't in FIPS mode. Swap out the functions - * pointers for the OpenSSL versions. - * - * We do this by swapping out a pointer to a structure - * containing the functions, as this prevents possible - * skew where some threads see a mixture of functions. - */ - fr_md5_funcs = &md5_openssl_funcs; - } else { - md5_local_funcs.alloc = fr_md5_local_ctx_alloc; /* Don't call this (init) function again */ - } - - return fr_md5_ctx_alloc(); -} -#endif - /** @copydoc fr_md5_ctx_free * */ @@ -560,3 +525,29 @@ void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx) fr_md5_ctx_free(*ctx); *ctx = NULL; } + +#ifdef HAVE_OPENSSL_EVP_H +void fr_md5_openssl_init(void) +{ + /* + * If we are in FIPS mode, then we still use the local + * allocator. + */ + if (!EVP_default_properties_is_fips_enabled(NULL)) return; + + /* + * OpenSSL isn't in FIPS mode. Swap out the functions + * pointers for the OpenSSL versions. + * + * We do this by swapping out a pointer to a structure + * containing the functions, as this prevents possible + * skew where some threads see a mixture of functions. + */ + fr_md5_funcs = &md5_openssl_funcs; +} + +void fr_md5_openssl_free(void) +{ + fr_md5_funcs = &md5_local_funcs; +} +#endif diff --git a/src/lib/util/md5.h b/src/lib/util/md5.h index 9337b7afabf..4a65954b2ed 100644 --- a/src/lib/util/md5.h +++ b/src/lib/util/md5.h @@ -110,6 +110,12 @@ void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx); /* hmac.c */ int fr_hmac_md5(uint8_t digest[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len); + +#ifdef HAVE_OPENSSL_EVP_H +void fr_md5_openssl_init(void); +void fr_md5_openssl_free(void); +#endif + #ifdef __cplusplus } #endif