]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
manually switch to local / openssl versions of MD4 and MD5.
authorAlan T. DeKok <aland@freeradius.org>
Wed, 10 Dec 2025 19:21:52 +0000 (14:21 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 10 Dec 2025 19:28:00 +0000 (14:28 -0500)
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.

src/bin/radclient-ng.c
src/bin/radclient.c
src/lib/tls/base.c
src/lib/util/md4.c
src/lib/util/md4.h
src/lib/util/md5.c
src/lib/util/md5.h

index 9dad5f97ba907772b738cda24b6ab0594414b0a7..645d89cc913d0766ff148247ad456de07c4b54f3 100644 (file)
@@ -41,6 +41,8 @@ RCSID("$Id$")
 
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
+#include <freeradius-devel/util/md4.h>
+#include <freeradius-devel/util/md5.h>
 #endif
 #include <ctype.h>
 
@@ -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()
index cf9515931e26aa5b6a4770e9bdcb8926756c8812..33c3f489a11a82de7dfe8af27cc1c189bc56f373 100644 (file)
@@ -38,6 +38,8 @@ RCSID("$Id$")
 #include <freeradius-devel/util/chap.h>
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
+#include <freeradius-devel/util/md5.h>
+#include <freeradius-devel/util/md4.h>
 #endif
 #include <ctype.h>
 
@@ -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()
index 8c6520a829fb34b11e445f9681fb65310346fa02..cb5a425ae41344988a98bdce9f18a7c78003c9ac 100644 (file)
@@ -45,6 +45,8 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/math.h>
 #include <freeradius-devel/util/syserror.h>
+#include <freeradius-devel/util/md5.h>
+#include <freeradius-devel/util/md4.h>
 
 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;
 }
 
index 774f74e3d49871113aa756137cf339b959d75be2..041a5475b03843098de143e61cca8af5b7bab0e0 100644 (file)
@@ -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
index 94ed5698a6d67176048b24235829f1bc8f6221ea..00a8a02a264f4aee68674048bf1a4bb840d13d01 100644 (file)
@@ -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
index c8885e9123963185b38c4218a569cc87ac59231e..f0f12cababa84b8d644abad5470737f90710a899 100644 (file)
@@ -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
index 9337b7afabfe542007d5b7ad40ae21cb8dbc7342..4a65954b2ed914a82bfbc5e3b58a5a710159fa4c 100644 (file)
@@ -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