]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Place all md4/md5 functions in a struct and swap the pointer where we're building... developer/arr2036
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 13 Aug 2025 02:17:44 +0000 (20:17 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 13 Aug 2025 02:17:44 +0000 (20:17 -0600)
This prevents potential skew during startup

src/lib/util/md4.c
src/lib/util/md4.h
src/lib/util/md5.c
src/lib/util/md5.h

index 8f0f3e17b6b6689d24065998753e49f332e45cc5..774f74e3d49871113aa756137cf339b959d75be2 100644 (file)
@@ -26,6 +26,32 @@ typedef struct {
        fr_md4_ctx_t    *md_ctx;
 } fr_md4_free_list_t;
 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);
+
+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
+};
+fr_md4_funcs_t const *fr_md4_funcs = &md4_local_funcs;
+
 /*
  *     If we have OpenSSL's EVP API available, then build wrapper functions.
  *
@@ -39,8 +65,6 @@ static _Thread_local fr_md4_free_list_t *md4_array;
 #  include <openssl/err.h>
 #  include <openssl/provider.h>
 
-static int have_openssl_md4 = -1;
-
 /** @copydoc fr_md4_ctx_reset
  *
  */
@@ -111,6 +135,15 @@ static void fr_md4_openssl_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_c
 
        if (!fr_cond_assert(len == MD4_DIGEST_LENGTH)) return;
 }
+
+static fr_md4_funcs_t md4_openssl_funcs = {
+       .reset = fr_md4_openssl_ctx_reset,
+       .copy = fr_md4_openssl_ctx_copy,
+       .alloc = fr_md4_openssl_ctx_alloc,
+       .free = fr_md4_openssl_ctx_free,
+       .update = fr_md4_openssl_update,
+       .final = fr_md4_openssl_final
+};
 #endif
 
 /*
@@ -312,33 +345,6 @@ static fr_md4_ctx_t *fr_md4_local_ctx_alloc(void)
 {
        fr_md4_ctx_local_t *ctx_local;
 
-#ifdef HAVE_OPENSSL_EVP_H
-       if (unlikely(have_openssl_md4 == -1)) {
-               /*
-                *      If we're not in FIPS mode, then swap out the
-                *      md4 functions, and call the OpenSSL init
-                *      function.
-                */
-               if (!EVP_default_properties_is_fips_enabled(NULL)) {
-                       have_openssl_md4 = 1;
-
-                       /*
-                        *      Swap out the functions pointers
-                        *      for the OpenSSL versions.
-                        */
-                       fr_md4_ctx_reset = fr_md4_openssl_ctx_reset;
-                       fr_md4_ctx_copy = fr_md4_openssl_ctx_copy;
-                       fr_md4_ctx_alloc = fr_md4_openssl_ctx_alloc;
-                       fr_md4_ctx_free = fr_md4_openssl_ctx_free;
-                       fr_md4_update = fr_md4_openssl_update;
-                       fr_md4_final = fr_md4_openssl_final;
-
-                       return fr_md4_ctx_alloc();
-               }
-
-               have_openssl_md4 = 0;
-       }
-#endif
        ctx_local = talloc(NULL, fr_md4_ctx_local_t);
        if (unlikely(!ctx_local)) return NULL;
        fr_md4_local_ctx_reset(ctx_local);
@@ -346,6 +352,33 @@ 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
  *
  */
index 8ae9010f53065f9ecbd6a0a8a9d5311891538d52..94ed5698a6d67176048b24235829f1bc8f6221ea 100644 (file)
@@ -29,20 +29,38 @@ typedef void fr_md4_ctx_t;
 
 /* md4.c */
 
+typedef                void (*fr_md4_ctx_reset_t)(fr_md4_ctx_t *ctx);
+typedef                void (*fr_md4_ctx_copy_t)(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src);
+typedef                fr_md4_ctx_t *(*fr_md4_ctx_alloc_t)(void);
+typedef                void (*fr_md4_ctx_free_t)(fr_md4_ctx_t **ctx);
+typedef                void (*fr_md4_update_t)(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen);
+typedef                void (*fr_md4_final_t)(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx);
+
+typedef struct {
+       fr_md4_ctx_reset_t      reset;
+       fr_md4_ctx_copy_t       copy;
+       fr_md4_ctx_alloc_t      alloc;
+       fr_md4_ctx_free_t       free;
+       fr_md4_update_t         update;
+       fr_md4_final_t          final;
+} fr_md4_funcs_t;
+
+/** Swap a single pointer, so all functions get swapped as an atomic operation
+ */
+extern fr_md4_funcs_t const *fr_md4_funcs;
+
 /** Reset the ctx to allow reuse
  *
  * @param[in] ctx      To reuse.
  */
-typedef                void (*fr_md4_ctx_reset_t)(fr_md4_ctx_t *ctx);
-extern         fr_md4_ctx_reset_t      fr_md4_ctx_reset;
+#define fr_md4_ctx_reset(_ctx)                 fr_md4_funcs->reset(_ctx)
 
 /** Copy the contents of a ctx
  *
  * @param[in] dst      Where to copy the context to.
  * @param[in] src      Where to copy the context from.
  */
-typedef                void (*fr_md4_ctx_copy_t)(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src);
-extern         fr_md4_ctx_copy_t       fr_md4_ctx_copy;
+#define fr_md4_ctx_copy(_dst, _src)            fr_md4_funcs->copy(_dst, _src)
 
 /** Allocation function for MD4 digest context
  *
@@ -50,17 +68,14 @@ extern              fr_md4_ctx_copy_t       fr_md4_ctx_copy;
  *     - An MD4 ctx.
  *     - NULL if out of memory.
  */
-typedef                fr_md4_ctx_t *(*fr_md4_ctx_alloc_t)(void);
-extern         fr_md4_ctx_alloc_t      fr_md4_ctx_alloc;
+#define fr_md4_ctx_alloc()                     fr_md4_funcs->alloc()
 
 /** Free function for MD4 digest ctx
  *
  * @param[in] ctx      MD4 ctx to free.  If the shared ctx is passed in
  *                     then the ctx is reset but not freed.
  */
-typedef                void (*fr_md4_ctx_free_t)(fr_md4_ctx_t **ctx);
-extern         fr_md4_ctx_free_t       fr_md4_ctx_free;
-
+#define fr_md4_ctx_free(_ctx)                  fr_md4_funcs->free(_ctx)
 
 /** Ingest plaintext into the digest
  *
@@ -68,16 +83,14 @@ extern              fr_md4_ctx_free_t       fr_md4_ctx_free;
  * @param[in] in       Data to ingest.
  * @param[in] inlen    Length of data to ingest.
  */
-typedef                void (*fr_md4_update_t)(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen);
-extern         fr_md4_update_t         fr_md4_update;
+#define fr_md4_update(_ctx, _in, _inlen)       fr_md4_funcs->update(_ctx, _in, _inlen)
 
 /** Finalise the ctx, producing the digest
  *
  * @param[out] out     The MD4 digest.
  * @param[in] ctx      To finalise.
  */
-typedef                void (*fr_md4_final_t)(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx);
-extern         fr_md4_final_t          fr_md4_final;
+#define fr_md4_final(_out, _ctx)               fr_md4_funcs->final(_out, _ctx)
 
 /** Perform a single digest operation on a single input buffer
  *
index e8a0a56ea3885caada529f01602632a31e7285a7..c8885e9123963185b38c4218a569cc87ac59231e 100644 (file)
@@ -27,6 +27,31 @@ typedef struct {
 } fr_md5_free_list_t;
 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);
+
+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
+};
+fr_md5_funcs_t const *fr_md5_funcs = &md5_local_funcs;
+
 /*
  *     If we have OpenSSL's EVP API available, then build wrapper functions.
  *
@@ -110,6 +135,15 @@ static void fr_md5_openssl_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_c
 
        if (!fr_cond_assert(len == MD5_DIGEST_LENGTH)) return;
 }
+
+static fr_md5_funcs_t md5_openssl_funcs = {
+       .reset = fr_md5_openssl_ctx_reset,
+       .copy = fr_md5_openssl_ctx_copy,
+       .alloc = fr_md5_openssl_ctx_alloc,
+       .free = fr_md5_openssl_ctx_free,
+       .update = fr_md5_openssl_update,
+       .final = fr_md5_openssl_final
+};
 #endif
 
 #  define MD5_BLOCK_LENGTH 64
@@ -321,23 +355,21 @@ 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)) {
-               fr_md5_ctx_alloc = fr_md5_local_ctx_alloc;
-               return fr_md5_local_ctx_alloc();
+       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 */
        }
 
-       /*
-        *      Otherwise OpenSSL isn't in FIPS mode.  Swap out the
-        *      functions pointers for the OpenSSL versions.
-        */
-       fr_md5_ctx_reset = fr_md5_openssl_ctx_reset;
-       fr_md5_ctx_copy = fr_md5_openssl_ctx_copy;
-       fr_md5_ctx_alloc = fr_md5_openssl_ctx_alloc;
-       fr_md5_ctx_free = fr_md5_openssl_ctx_free;
-       fr_md5_update = fr_md5_openssl_update;
-       fr_md5_final = fr_md5_openssl_final;
-
-       return fr_md5_openssl_ctx_alloc();
+       return fr_md5_ctx_alloc();
 }
 #endif
 
@@ -432,20 +464,6 @@ static void fr_md5_local_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx
        memset(ctx_local, 0, sizeof(*ctx_local));       /* in case it's sensitive */
 }
 
-/*
- *     Digest function pointers
- */
-fr_md5_ctx_reset_t fr_md5_ctx_reset = fr_md5_local_ctx_reset;
-fr_md5_ctx_copy_t fr_md5_ctx_copy = fr_md5_local_ctx_copy;
-#ifdef HAVE_OPENSSL_EVP_H
-fr_md5_ctx_alloc_t fr_md5_ctx_alloc = fr_md5_local_ctx_init; /* check what we should do */
-#else
-fr_md5_ctx_alloc_t fr_md5_ctx_alloc = fr_md5_local_ctx_alloc;
-#endif
-fr_md5_ctx_free_t fr_md5_ctx_free = fr_md5_local_ctx_free;
-fr_md5_update_t fr_md5_update = fr_md5_local_update;
-fr_md5_final_t fr_md5_final = fr_md5_local_final;
-
 /** Calculate the MD5 hash of the contents of a buffer
  *
  * @param[out] out Where to write the MD5 digest. Must be a minimum of MD5_DIGEST_LENGTH.
index de408dca67b56eaf79804a9efe2080ebd36d163e..9337b7afabfe542007d5b7ad40ae21cb8dbc7342 100644 (file)
@@ -29,20 +29,38 @@ typedef void fr_md5_ctx_t;
 
 /* md5.c */
 
+typedef                void (*fr_md5_ctx_reset_t)(fr_md5_ctx_t *ctx);
+typedef                void (*fr_md5_ctx_copy_t)(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src);
+typedef                fr_md5_ctx_t *(*fr_md5_ctx_alloc_t)(void);
+typedef                void (*fr_md5_ctx_free_t)(fr_md5_ctx_t **ctx);
+typedef                void (*fr_md5_update_t)(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen);
+typedef                void (*fr_md5_final_t)(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx);
+
+typedef struct {
+       fr_md5_ctx_reset_t      reset;
+       fr_md5_ctx_copy_t       copy;
+       fr_md5_ctx_alloc_t      alloc;
+       fr_md5_ctx_free_t       free;
+       fr_md5_update_t         update;
+       fr_md5_final_t          final;
+} fr_md5_funcs_t;
+
+/** Swap a single pointer, so all functions get swapped as an atomic operation
+ */
+extern fr_md5_funcs_t const *fr_md5_funcs;
+
 /** Reset the ctx to allow reuse
  *
  * @param[in] ctx      To reuse.
  */
-typedef                void (*fr_md5_ctx_reset_t)(fr_md5_ctx_t *ctx);
-extern         fr_md5_ctx_reset_t      fr_md5_ctx_reset;
+#define fr_md5_ctx_reset(_ctx)                 fr_md5_funcs->reset(_ctx)
 
 /** Copy the contents of a ctx
  *
  * @param[in] dst      Where to copy the context to.
  * @param[in] src      Where to copy the context from.
  */
-typedef                void (*fr_md5_ctx_copy_t)(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src);
-extern         fr_md5_ctx_copy_t       fr_md5_ctx_copy;
+#define fr_md5_ctx_copy(_dst, _src)            fr_md5_funcs->copy(_dst, _src)
 
 /** Allocation function for MD5 digest context
  *
@@ -50,16 +68,14 @@ extern              fr_md5_ctx_copy_t       fr_md5_ctx_copy;
  *     - An MD5 ctx.
  *     - NULL if out of memory.
  */
-typedef                fr_md5_ctx_t *(*fr_md5_ctx_alloc_t)(void);
-extern         fr_md5_ctx_alloc_t      fr_md5_ctx_alloc;
+#define fr_md5_ctx_alloc()                     fr_md5_funcs->alloc()
 
 /** Free function for MD5 digest ctx
  *
  * @param[in] ctx      MD5 ctx to free.  If the shared ctx is passed in
  *                     then the ctx is reset but not freed.
  */
-typedef                void (*fr_md5_ctx_free_t)(fr_md5_ctx_t **ctx);
-extern         fr_md5_ctx_free_t       fr_md5_ctx_free;
+#define fr_md5_ctx_free(_ctx)                  fr_md5_funcs->free(_ctx)
 
 /** Ingest plaintext into the digest
  *
@@ -67,16 +83,14 @@ extern              fr_md5_ctx_free_t       fr_md5_ctx_free;
  * @param[in] in       Data to ingest.
  * @param[in] inlen    Length of data to ingest.
  */
-typedef                void (*fr_md5_update_t)(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen);
-extern         fr_md5_update_t         fr_md5_update;
+#define fr_md5_update(_ctx, _in, _inlen)       fr_md5_funcs->update(_ctx, _in, _inlen)
 
 /** Finalise the ctx, producing the digest
  *
  * @param[out] out     The MD5 digest.
  * @param[in] ctx      To finalise.
  */
-typedef                void (*fr_md5_final_t)(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx);
-extern         fr_md5_final_t          fr_md5_final;
+#define fr_md5_final(_out, _ctx)               fr_md5_funcs->final(_out, _ctx)
 
 /** Perform a single digest operation on a single input buffer
  *