Coverage Report

Created: 2026-01-17 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/md4.c
Line
Count
Source
1
/** A local MD4 implementation
2
 *
3
 * @note license is LGPL, but largely derived from a public domain source.
4
 *
5
 * @file src/lib/util/md4.c
6
 */
7
RCSID("$Id: 041a5475b03843098de143e61cca8af5b7bab0e0 $")
8
9
#include <freeradius-devel/util/debug.h>
10
#include <freeradius-devel/util/strerror.h>
11
#include <freeradius-devel/util/atexit.h>
12
13
/*
14
 *  FORCE MD4 TO USE OUR MD4 HEADER FILE!
15
 *  If we don't do this, it might pick up the systems broken MD4.
16
 */
17
#include <freeradius-devel/util/md4.h>
18
19
/** The thread local free list
20
 *
21
 * Any entries remaining in the list will be freed when the thread is joined
22
 */
23
0
#define ARRAY_SIZE (8)
24
typedef struct {
25
  bool    used;
26
  fr_md4_ctx_t  *md_ctx;
27
} fr_md4_free_list_t;
28
static _Thread_local fr_md4_free_list_t *md4_array;
29
30
static void fr_md4_local_ctx_reset(fr_md4_ctx_t *ctx);
31
static void fr_md4_local_ctx_copy(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src);
32
static fr_md4_ctx_t *fr_md4_local_ctx_alloc(void);
33
static void fr_md4_local_ctx_free(fr_md4_ctx_t **ctx);
34
static void fr_md4_local_update(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen);
35
static void fr_md4_local_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx);
36
37
static fr_md4_funcs_t md4_local_funcs = {
38
  .reset = fr_md4_local_ctx_reset,
39
  .copy = fr_md4_local_ctx_copy,
40
  .alloc = fr_md4_local_ctx_alloc,
41
  .free = fr_md4_local_ctx_free,
42
  .update = fr_md4_local_update,
43
  .final = fr_md4_local_final
44
};
45
fr_md4_funcs_t const *fr_md4_funcs = &md4_local_funcs;
46
47
/*
48
 *  If we have OpenSSL's EVP API available, then build wrapper functions.
49
 *
50
 *  We always need to build the local MD4 functions as OpenSSL could
51
 *  be operating in FIPS mode where MD4 digest functions are unavailable.
52
 */
53
#ifdef HAVE_OPENSSL_EVP_H
54
#  include <freeradius-devel/tls/openssl_user_macros.h>
55
#  include <openssl/evp.h>
56
#  include <openssl/crypto.h>
57
#  include <openssl/err.h>
58
#  include <openssl/provider.h>
59
60
/** @copydoc fr_md4_ctx_reset
61
 *
62
 */
63
static void fr_md4_openssl_ctx_reset(fr_md4_ctx_t *ctx)
64
0
{
65
0
  EVP_MD_CTX *md_ctx = ctx;
66
67
0
  EVP_MD_CTX_reset(md_ctx);
68
0
  EVP_DigestInit_ex(md_ctx, EVP_md4(), NULL);
69
0
}
70
71
/** @copydoc fr_md4_ctx_copy
72
 *
73
 */
74
static void fr_md4_openssl_ctx_copy(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src)
75
0
{
76
0
  EVP_MD_CTX_copy_ex(dst, src);
77
0
}
78
79
/** @copydoc fr_md4_ctx_alloc
80
 *
81
 */
82
static fr_md4_ctx_t *fr_md4_openssl_ctx_alloc(void)
83
0
{
84
0
  EVP_MD_CTX *md_ctx;
85
86
0
  md_ctx = EVP_MD_CTX_new();
87
0
  if (unlikely(!md_ctx)) return NULL;
88
89
0
  if (EVP_DigestInit_ex(md_ctx, EVP_md4(), NULL) != 1) {
90
0
    char buffer[256];
91
92
0
    ERR_error_string_n(ERR_get_error(), buffer, sizeof(buffer));
93
0
    fr_strerror_printf("Failed initialising md4 ctx: %s", buffer);
94
0
    EVP_MD_CTX_free(md_ctx);
95
96
0
    return NULL;
97
0
  }
98
99
0
  return md_ctx;
100
0
}
101
102
/** @copydoc fr_md4_ctx_free
103
 *
104
 */
105
static void fr_md4_openssl_ctx_free(fr_md4_ctx_t **ctx)
106
0
{
107
0
  EVP_MD_CTX_free(*ctx);
108
0
  *ctx = NULL;
109
0
}
110
111
/** @copydoc fr_md4_update
112
 *
113
 */
114
static void fr_md4_openssl_update(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen)
115
0
{
116
0
  EVP_DigestUpdate(ctx, in, inlen);
117
0
}
118
119
/** @copydoc fr_md4_final
120
 *
121
 */
122
static void fr_md4_openssl_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx)
123
{
124
  unsigned int len;
125
126
  EVP_DigestFinal(ctx, out, &len);
127
128
  if (!fr_cond_assert(len == MD4_DIGEST_LENGTH)) return;
129
}
130
131
static fr_md4_funcs_t md4_openssl_funcs = {
132
  .reset = fr_md4_openssl_ctx_reset,
133
  .copy = fr_md4_openssl_ctx_copy,
134
  .alloc = fr_md4_openssl_ctx_alloc,
135
  .free = fr_md4_openssl_ctx_free,
136
  .update = fr_md4_openssl_update,
137
  .final = fr_md4_openssl_final
138
};
139
#endif
140
141
/*
142
 * This code implements the MD4 message-digest algorithm.
143
 * The algorithm is due to Ron Rivest.  This code was
144
 * written by Colin Plumb in 1993, no copyright is claimed.
145
 * This code is in the public domain; do with it what you wish.
146
 * Todd C. Miller modified the md4 code to do MD4 based on RFC 1186.
147
 *
148
 * Equivalent code is available from RSA Data Security, Inc.
149
 * This code has been tested against that, and is equivalent,
150
 * except that you don't need to include two pages of legalese
151
 * with every copy.
152
 *
153
 * To compute the message digest of a chunk of bytes, declare an
154
 * MD4Context structure, pass it to fr_md4_init, call fr_md4_update as
155
 * needed on buffers full of bytes, and then call fr_md4_final, which
156
 * will fill a supplied 16-byte array with the digest.
157
 */
158
#ifndef WORDS_BIGENDIAN
159
#  define htole32_4(buf)    /* Nothing */
160
#  define htole32_14(buf)   /* Nothing */
161
#  define htole32_16(buf)   /* Nothing */
162
#else
163
/* Sometimes defined by endian.h */
164
#  ifndef htole32
165
#    define htole32(x)\
166
  (((((uint32_t)x) & 0xff000000) >> 24) |\
167
  ((((uint32_t)x) & 0x00ff0000) >> 8) |\
168
  ((((uint32_t)x) & 0x0000ff00) << 8) |\
169
  ((((uint32_t)x) & 0x000000ff) << 24))
170
#  endif
171
#  define htole32_4(buf) do {\
172
  (buf)[0] = htole32((buf)[0]);\
173
  (buf)[1] = htole32((buf)[1]);\
174
  (buf)[2] = htole32((buf)[2]);\
175
  (buf)[3] = htole32((buf)[3]);\
176
} while (0)
177
178
#  define htole32_14(buf) do {\
179
  (buf)[0] = htole32((buf)[0]);\
180
  (buf)[1] = htole32((buf)[1]);\
181
  (buf)[2] = htole32((buf)[2]);\
182
  (buf)[3] = htole32((buf)[3]);\
183
  (buf)[4] = htole32((buf)[4]);\
184
  (buf)[5] = htole32((buf)[5]);\
185
  (buf)[6] = htole32((buf)[6]);\
186
  (buf)[7] = htole32((buf)[7]);\
187
  (buf)[8] = htole32((buf)[8]);\
188
  (buf)[9] = htole32((buf)[9]);\
189
  (buf)[10] = htole32((buf)[10]);\
190
  (buf)[11] = htole32((buf)[11]);\
191
  (buf)[12] = htole32((buf)[12]);\
192
  (buf)[13] = htole32((buf)[13]);\
193
} while (0)
194
195
#  define htole32_16(buf) do {\
196
  (buf)[0] = htole32((buf)[0]);\
197
  (buf)[1] = htole32((buf)[1]);\
198
  (buf)[2] = htole32((buf)[2]);\
199
  (buf)[3] = htole32((buf)[3]);\
200
  (buf)[4] = htole32((buf)[4]);\
201
  (buf)[5] = htole32((buf)[5]);\
202
  (buf)[6] = htole32((buf)[6]);\
203
  (buf)[7] = htole32((buf)[7]);\
204
  (buf)[8] = htole32((buf)[8]);\
205
  (buf)[9] = htole32((buf)[9]);\
206
  (buf)[10] = htole32((buf)[10]);\
207
  (buf)[11] = htole32((buf)[11]);\
208
  (buf)[12] = htole32((buf)[12]);\
209
  (buf)[13] = htole32((buf)[13]);\
210
  (buf)[14] = htole32((buf)[14]);\
211
  (buf)[15] = htole32((buf)[15]);\
212
} while (0)
213
#endif
214
215
0
#define MD4_BLOCK_LENGTH 64
216
217
/* The three core functions - F1 is optimized somewhat */
218
0
#define MD4_F1(x, y, z) (z ^ (x & (y ^ z)))
219
0
#define MD4_F2(x, y, z) ((x & y) | (x & z) | (y & z))
220
0
#define MD4_F3(x, y, z) (x ^ y ^ z)
221
222
/* This is the central step in the MD4 algorithm. */
223
0
#define MD4STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s))
224
225
/** The core of the MD4 algorithm
226
 *
227
 * This alters an existing MD4 hash to reflect the addition of 16
228
 * longwords of new data.  fr_md4_update blocks the data and converts bytes
229
 * into longwords for this routine.
230
 *
231
 * @param[in] state 16 bytes of data to feed into the hashing function.
232
 * @param[in,out] block MD4 digest block to update.
233
 */
234
static void fr_md4_local_transform(uint32_t state[static 4], uint8_t const block[static MD4_BLOCK_LENGTH])
235
0
{
236
0
  uint32_t a, b, c, d;
237
0
  uint32_t const *in = (uint32_t const *)block;
238
239
0
  a = state[0];
240
0
  b = state[1];
241
0
  c = state[2];
242
0
  d = state[3];
243
244
0
  MD4STEP(MD4_F1, a, b, c, d, in[ 0],  3);
245
0
  MD4STEP(MD4_F1, d, a, b, c, in[ 1],  7);
246
0
  MD4STEP(MD4_F1, c, d, a, b, in[ 2], 11);
247
0
  MD4STEP(MD4_F1, b, c, d, a, in[ 3], 19);
248
0
  MD4STEP(MD4_F1, a, b, c, d, in[ 4],  3);
249
0
  MD4STEP(MD4_F1, d, a, b, c, in[ 5],  7);
250
0
  MD4STEP(MD4_F1, c, d, a, b, in[ 6], 11);
251
0
  MD4STEP(MD4_F1, b, c, d, a, in[ 7], 19);
252
0
  MD4STEP(MD4_F1, a, b, c, d, in[ 8],  3);
253
0
  MD4STEP(MD4_F1, d, a, b, c, in[ 9],  7);
254
0
  MD4STEP(MD4_F1, c, d, a, b, in[10], 11);
255
0
  MD4STEP(MD4_F1, b, c, d, a, in[11], 19);
256
0
  MD4STEP(MD4_F1, a, b, c, d, in[12],  3);
257
0
  MD4STEP(MD4_F1, d, a, b, c, in[13],  7);
258
0
  MD4STEP(MD4_F1, c, d, a, b, in[14], 11);
259
0
  MD4STEP(MD4_F1, b, c, d, a, in[15], 19);
260
261
0
  MD4STEP(MD4_F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
262
0
  MD4STEP(MD4_F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
263
0
  MD4STEP(MD4_F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
264
0
  MD4STEP(MD4_F2, b, c, d, a, in[12] + 0x5a827999, 13);
265
0
  MD4STEP(MD4_F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
266
0
  MD4STEP(MD4_F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
267
0
  MD4STEP(MD4_F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
268
0
  MD4STEP(MD4_F2, b, c, d, a, in[13] + 0x5a827999, 13);
269
0
  MD4STEP(MD4_F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
270
0
  MD4STEP(MD4_F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
271
0
  MD4STEP(MD4_F2, c, d, a, b, in[10] + 0x5a827999,  9);
272
0
  MD4STEP(MD4_F2, b, c, d, a, in[14] + 0x5a827999, 13);
273
0
  MD4STEP(MD4_F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
274
0
  MD4STEP(MD4_F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
275
0
  MD4STEP(MD4_F2, c, d, a, b, in[11] + 0x5a827999,  9);
276
0
  MD4STEP(MD4_F2, b, c, d, a, in[15] + 0x5a827999, 13);
277
278
0
  MD4STEP(MD4_F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
279
0
  MD4STEP(MD4_F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
280
0
  MD4STEP(MD4_F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
281
0
  MD4STEP(MD4_F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
282
0
  MD4STEP(MD4_F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
283
0
  MD4STEP(MD4_F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
284
0
  MD4STEP(MD4_F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
285
0
  MD4STEP(MD4_F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
286
0
  MD4STEP(MD4_F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
287
0
  MD4STEP(MD4_F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
288
0
  MD4STEP(MD4_F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
289
0
  MD4STEP(MD4_F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
290
0
  MD4STEP(MD4_F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
291
0
  MD4STEP(MD4_F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
292
0
  MD4STEP(MD4_F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
293
0
  MD4STEP(MD4_F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
294
295
0
  state[0] += a;
296
0
  state[1] += b;
297
0
  state[2] += c;
298
0
  state[3] += d;
299
0
}
300
301
typedef struct {
302
  uint32_t state[4];      //!< State.
303
  uint32_t count[2];      //!< Number of bits, mod 2^64.
304
  uint8_t buffer[MD4_BLOCK_LENGTH]; //!< Input buffer.
305
} fr_md4_ctx_local_t;
306
307
/** @copydoc fr_md4_ctx_reset
308
 *
309
 */
310
static void fr_md4_local_ctx_reset(fr_md4_ctx_t *ctx)
311
0
{
312
0
  fr_md4_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md4_ctx_local_t);
313
314
0
  ctx_local->count[0] = 0;
315
0
  ctx_local->count[1] = 0;
316
0
  ctx_local->state[0] = 0x67452301;
317
0
  ctx_local->state[1] = 0xefcdab89;
318
0
  ctx_local->state[2] = 0x98badcfe;
319
0
  ctx_local->state[3] = 0x10325476;
320
0
}
321
322
/** @copydoc fr_md4_ctx_copy
323
 *
324
 */
325
static void fr_md4_local_ctx_copy(fr_md4_ctx_t *dst, fr_md4_ctx_t const *src)
326
0
{
327
0
  fr_md4_ctx_local_t const *ctx_local_src = talloc_get_type_abort_const(src, fr_md4_ctx_local_t);
328
0
  fr_md4_ctx_local_t *ctx_local_dst = talloc_get_type_abort(dst, fr_md4_ctx_local_t);
329
330
0
  memcpy(ctx_local_dst, ctx_local_src, sizeof(*ctx_local_dst));
331
0
}
332
333
/** @copydoc fr_md4_ctx_alloc
334
 *
335
 */
336
static fr_md4_ctx_t *fr_md4_local_ctx_alloc(void)
337
0
{
338
0
  fr_md4_ctx_local_t *ctx_local;
339
340
0
  ctx_local = talloc(NULL, fr_md4_ctx_local_t);
341
0
  if (unlikely(!ctx_local)) return NULL;
342
0
  fr_md4_local_ctx_reset(ctx_local);
343
344
0
  return ctx_local;
345
0
}
346
347
348
/** @copydoc fr_md4_ctx_free
349
 *
350
 */
351
static void fr_md4_local_ctx_free(fr_md4_ctx_t **ctx)
352
0
{
353
0
  talloc_free(*ctx);
354
0
  *ctx = NULL;
355
0
}
356
357
static const uint8_t *zero = (uint8_t[]){ 0x00 };
358
359
/** @copydoc fr_md4_update
360
 *
361
 */
362
static void fr_md4_local_update(fr_md4_ctx_t *ctx, uint8_t const *in, size_t inlen)
363
0
{
364
0
  uint32_t    count;
365
0
  fr_md4_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md4_ctx_local_t);
366
367
  /*
368
   *  Needed so we can calculate the zero
369
   *  length md4 hash correctly.
370
   *  ubsan doesn't like arithmetic on
371
   *  NULL pointers.
372
   */
373
0
  if (!in) {
374
0
    in = zero;
375
0
    inlen = 0;
376
0
  }
377
378
  /* Bytes already stored in ctx_local->buffer */
379
0
  count = (uint32_t)((ctx_local->count[0] >> 3) & 0x3f);
380
381
  /* Update bitcount */
382
/*  ctx_local->count += (uint64_t)inlen << 3;*/
383
0
  if ((ctx_local->count[0] += ((uint32_t)inlen << 3)) < (uint32_t)inlen) {
384
    /* Overflowed ctx_local->count[0] */
385
0
    ctx_local->count[1]++;
386
0
  }
387
0
  ctx_local->count[1] += ((uint32_t)inlen >> 29);
388
389
  /* Handle any leading odd-sized chunks */
390
0
  if (count) {
391
0
    unsigned char *p = (unsigned char *)ctx_local->buffer + count;
392
393
0
    count = MD4_BLOCK_LENGTH - count;
394
0
    if (inlen < count) {
395
0
      memcpy(p, in, inlen);
396
0
      return;
397
0
    }
398
0
    memcpy(p, in, count);
399
0
    htole32_16((uint32_t *)ctx_local->buffer);
400
0
    fr_md4_local_transform(ctx_local->state, ctx_local->buffer);
401
0
    in += count;
402
0
    inlen -= count;
403
0
  }
404
405
  /* Process data in MD4_BLOCK_LENGTH-byte chunks */
406
0
  while (inlen >= MD4_BLOCK_LENGTH) {
407
0
    memcpy(ctx_local->buffer, in, MD4_BLOCK_LENGTH);
408
0
    htole32_16((uint32_t *)ctx_local->buffer);
409
0
    fr_md4_local_transform(ctx_local->state, ctx_local->buffer);
410
0
    in += MD4_BLOCK_LENGTH;
411
0
    inlen -= MD4_BLOCK_LENGTH;
412
0
  }
413
414
  /* Handle any remaining bytes of data. */
415
0
  memcpy(ctx_local->buffer, in, inlen);
416
0
}
417
418
/** @copydoc fr_md4_final
419
 *
420
 */
421
static void fr_md4_local_final(uint8_t out[static MD4_DIGEST_LENGTH], fr_md4_ctx_t *ctx)
422
0
{
423
0
  uint32_t    count;
424
0
  unsigned char   *p;
425
0
  fr_md4_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md4_ctx_local_t);
426
427
  /* number of bytes mod 64 */
428
0
  count = (uint32_t)(ctx_local->count[0] >> 3) & 0x3f;
429
430
  /*
431
   * Set the first char of padding to 0x80.
432
   * This is safe since there is always at least one byte free.
433
   */
434
0
  p = ctx_local->buffer + count;
435
0
  *p++ = 0x80;
436
437
  /* Bytes of padding needed to make 64 bytes */
438
0
  count = 64 - 1 - count;
439
440
  /* Pad out to 56 mod 64 */
441
0
  if (count < 8) {
442
    /* Two lots of padding:  Pad the first block to 64 bytes */
443
0
    memset(p, 0, count);
444
0
    htole32_16((uint32_t *)ctx_local->buffer);
445
0
    fr_md4_local_transform(ctx_local->state, ctx_local->buffer);
446
447
    /* Now fill the next block with 56 bytes */
448
0
    memset(ctx_local->buffer, 0, 56);
449
0
  } else {
450
    /* Pad block to 56 bytes */
451
0
    memset(p, 0, count - 8);
452
0
  }
453
0
  htole32_14((uint32_t *)ctx_local->buffer);
454
455
  /* Append bit count and transform */
456
0
  ((uint32_t *)ctx_local->buffer)[14] = ctx_local->count[0];
457
0
  ((uint32_t *)ctx_local->buffer)[15] = ctx_local->count[1];
458
459
0
  fr_md4_local_transform(ctx_local->state, ctx_local->buffer);
460
0
  htole32_4(ctx_local->state);
461
0
  memcpy(out, ctx_local->state, MD4_DIGEST_LENGTH);
462
0
  memset(ctx_local, 0, sizeof(*ctx_local)); /* in case it's sensitive */
463
0
}
464
465
/** Calculate the MD4 hash of the contents of a buffer
466
 *
467
 * @param[out] out Where to write the MD4 digest. Must be a minimum of MD4_DIGEST_LENGTH.
468
 * @param[in] in Data to hash.
469
 * @param[in] inlen Length of the data.
470
 */
471
void fr_md4_calc(uint8_t out[static MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
472
0
{
473
0
  fr_md4_ctx_t *ctx;
474
475
0
  ctx = fr_md4_ctx_alloc_from_list();
476
0
  fr_md4_update(ctx, in, inlen);
477
0
  fr_md4_final(out, ctx);
478
0
  fr_md4_ctx_free_from_list(&ctx);
479
0
}
480
481
static int _md4_ctx_free_on_exit(void *arg)
482
0
{
483
0
  int i;
484
0
  fr_md4_free_list_t *free_list = arg;
485
486
0
  for (i = 0; i < ARRAY_SIZE; i++) {
487
0
    if (free_list[i].used) continue;
488
489
0
    fr_md4_ctx_free(&free_list[i].md_ctx);
490
0
  }
491
0
  return talloc_free(free_list);
492
0
}
493
494
/** @copydoc fr_md4_ctx_alloc
495
 *
496
 */
497
fr_md4_ctx_t *fr_md4_ctx_alloc_from_list(void)
498
0
{
499
0
  int     i;
500
0
  fr_md4_ctx_t    *md_ctx;
501
0
  fr_md4_free_list_t  *free_list;
502
503
0
  if (unlikely(!md4_array)) {
504
0
    free_list = talloc_zero_array(NULL, fr_md4_free_list_t, ARRAY_SIZE);
505
0
    if (unlikely(!free_list)) {
506
0
    oom:
507
0
      fr_strerror_const("Out of Memory");
508
0
      return NULL;
509
0
    }
510
511
0
    fr_atexit_thread_local(md4_array, _md4_ctx_free_on_exit, free_list);
512
513
    /*
514
     *  Initialize all md4 contexts
515
     */
516
0
    for (i = 0; i < ARRAY_SIZE; i++) {
517
0
      md_ctx = fr_md4_ctx_alloc();
518
0
      if (unlikely(md_ctx == NULL)) goto oom;
519
520
0
      free_list[i].md_ctx = md_ctx;
521
0
    }
522
0
  } else {
523
0
    free_list = md4_array;
524
0
  }
525
526
0
  for (i = 0; i < ARRAY_SIZE; i++) {
527
0
    if (free_list[i].used) continue;
528
529
0
    free_list[i].used = true;
530
0
    return free_list[i].md_ctx;
531
0
  }
532
533
  /*
534
   *  No more free contexts, just allocate a new one.
535
   */
536
0
  return fr_md4_ctx_alloc();
537
0
}
538
539
/** @copydoc fr_md4_ctx_free
540
 *
541
 */
542
void fr_md4_ctx_free_from_list(fr_md4_ctx_t **ctx)
543
0
{
544
0
  int i;
545
0
  fr_md4_free_list_t *free_list = md4_array;
546
547
0
  if (free_list) {
548
0
    for (i = 0; i < ARRAY_SIZE; i++) {
549
0
      if (free_list[i].md_ctx == *ctx) {
550
0
        free_list[i].used = false;
551
0
        fr_md4_ctx_reset(*ctx);
552
0
        *ctx = NULL;
553
0
        return;
554
0
      }
555
0
    }
556
0
  }
557
558
0
  fr_md4_ctx_free(*ctx);
559
0
  *ctx = NULL;
560
0
}
561
562
#ifdef HAVE_OPENSSL_EVP_H
563
void fr_md4_openssl_init(void)
564
0
{
565
  /*
566
   *  If we are in FIPS mode, then we still use the local
567
   *  allocator.
568
   */
569
0
  if (!EVP_default_properties_is_fips_enabled(NULL)) return;
570
571
  /*
572
   *  OpenSSL isn't in FIPS mode.  Swap out the functions
573
   *  pointers for the OpenSSL versions.
574
   *
575
   *  We do this by swapping out a pointer to a structure
576
   *  containing the functions, as this prevents possible
577
   *  skew where some threads see a mixture of functions.
578
   */
579
0
  fr_md4_funcs = &md4_openssl_funcs;
580
0
}
581
582
void fr_md4_openssl_free(void)
583
0
{
584
0
  fr_md4_funcs = &md4_local_funcs;
585
0
}
586
#endif