Coverage Report

Created: 2026-04-12 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/md5.c
Line
Count
Source
1
/** A local MD5 implementation
2
 *
3
 * @note license is LGPL, but largely derived from a public domain source.
4
 *
5
 * @file src/lib/util/md5.c
6
 */
7
RCSID("$Id: b236a4acb6bb1283a1c656c7a3dba5693d379fb3 $")
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 MD5 TO USE OUR MD5 HEADER FILE!
15
 *  If we don't do this, it might pick up the systems broken MD5.
16
 */
17
#include <freeradius-devel/util/md5.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
85.3k
#define ARRAY_SIZE (8)
24
typedef struct {
25
  bool    used;
26
  fr_md5_ctx_t  *md_ctx;
27
} fr_md5_free_list_t;
28
static _Thread_local fr_md5_free_list_t *md5_array;
29
30
static void fr_md5_local_ctx_reset(fr_md5_ctx_t *ctx);
31
static void fr_md5_local_ctx_copy(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src);
32
static fr_md5_ctx_t *fr_md5_local_ctx_alloc(void);
33
static void fr_md5_local_ctx_free(fr_md5_ctx_t **ctx);
34
static void fr_md5_local_update(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen);
35
static void fr_md5_local_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx);
36
37
static fr_md5_funcs_t md5_local_funcs = {
38
  .reset = fr_md5_local_ctx_reset,
39
  .copy = fr_md5_local_ctx_copy,
40
  .alloc = fr_md5_local_ctx_alloc,
41
  .free = fr_md5_local_ctx_free,
42
  .update = fr_md5_local_update,
43
  .final = fr_md5_local_final
44
};
45
fr_md5_funcs_t const *fr_md5_funcs = &md5_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 MD5 functions as OpenSSL could
51
 *  be operating in FIPS mode where MD5 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_md5_ctx_reset
61
 *
62
 */
63
static void fr_md5_openssl_ctx_reset(fr_md5_ctx_t *ctx)
64
0
{
65
0
  EVP_MD_CTX *md_ctx = ctx;
66
67
0
  EVP_MD_CTX_reset(md_ctx);
68
0
  (void)EVP_DigestInit_ex(md_ctx, EVP_md5(), NULL);
69
0
}
70
71
/** @copydoc fr_md5_ctx_copy
72
 *
73
 */
74
static void fr_md5_openssl_ctx_copy(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src)
75
0
{
76
0
  EVP_MD_CTX_copy_ex(dst, src);
77
0
}
78
79
/** @copydoc fr_md5_ctx_alloc
80
 *
81
 */
82
static fr_md5_ctx_t *fr_md5_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_md5(), 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 MD5 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_md5_ctx_free
103
 *
104
 */
105
static void fr_md5_openssl_ctx_free(fr_md5_ctx_t **ctx)
106
0
{
107
0
  if (!*ctx) return;
108
109
0
  EVP_MD_CTX_free(*ctx);
110
0
  *ctx = NULL;
111
0
}
112
113
/** @copydoc fr_md5_update
114
 *
115
 */
116
static void fr_md5_openssl_update(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen)
117
0
{
118
0
  EVP_DigestUpdate(ctx, in, inlen);
119
0
}
120
121
/** @copydoc fr_md5_final
122
 *
123
 */
124
static void fr_md5_openssl_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx)
125
{
126
  unsigned int len;
127
128
  EVP_DigestFinal(ctx, out, &len);
129
130
  if (!fr_cond_assert(len == MD5_DIGEST_LENGTH)) return;
131
}
132
133
static fr_md5_funcs_t md5_openssl_funcs = {
134
  .reset = fr_md5_openssl_ctx_reset,
135
  .copy = fr_md5_openssl_ctx_copy,
136
  .alloc = fr_md5_openssl_ctx_alloc,
137
  .free = fr_md5_openssl_ctx_free,
138
  .update = fr_md5_openssl_update,
139
  .final = fr_md5_openssl_final
140
};
141
#endif
142
143
971k
#  define MD5_BLOCK_LENGTH 64
144
typedef struct {
145
  uint32_t state[4];      //!< State.
146
  uint32_t count[2];      //!< Number of bits, mod 2^64.
147
  uint8_t buffer[MD5_BLOCK_LENGTH]; //!< Input buffer.
148
} fr_md5_ctx_local_t;
149
150
/*
151
 * This code implements the MD5 message-digest algorithm.
152
 * The algorithm is due to Ron Rivest.  This code was
153
 * written by Colin Plumb in 1993, no copyright is claimed.
154
 * This code is in the public domain; do with it what you wish.
155
 *
156
 * Equivalent code is available from RSA Data Security, Inc.
157
 * This code has been tested against that, and is equivalent,
158
 * except that you don't need to include two pages of legalese
159
 * with every copy.
160
 *
161
 * To compute the message digest of a chunk of bytes, declare an
162
 * MD5Context structure, pass it to fr_md5_init, call fr_md5_update as
163
 * needed on buffers full of bytes, and then call fr_md5_final, which
164
 * will fill a supplied 16-byte array with the digest.
165
 */
166
36.9k
#define PUT_64BIT_LE(cp, value) do {\
167
36.9k
  (cp)[7] = (value)[1] >> 24;\
168
36.9k
  (cp)[6] = (value)[1] >> 16;\
169
36.9k
  (cp)[5] = (value)[1] >> 8;\
170
36.9k
  (cp)[4] = (value)[1];\
171
36.9k
  (cp)[3] = (value)[0] >> 24;\
172
36.9k
  (cp)[2] = (value)[0] >> 16;\
173
36.9k
  (cp)[1] = (value)[0] >> 8;\
174
36.9k
  (cp)[0] = (value)[0];\
175
36.9k
} while (0)
176
177
147k
#define PUT_32BIT_LE(cp, value) do {\
178
147k
  (cp)[3] = (value) >> 24;\
179
147k
  (cp)[2] = (value) >> 16;\
180
147k
  (cp)[1] = (value) >> 8;\
181
147k
  (cp)[0] = (value);\
182
147k
} while (0)
183
184
static const uint8_t PADDING[MD5_BLOCK_LENGTH] = {
185
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
188
};
189
190
191
/* The four core functions - MD5_F1 is optimized somewhat */
192
1.18M
#define MD5_F1(x, y, z) (z ^ (x & (y ^ z)))
193
590k
#define MD5_F2(x, y, z) MD5_F1(z, x, y)
194
590k
#define MD5_F3(x, y, z) (x ^ y ^ z)
195
590k
#define MD5_F4(x, y, z) (y ^ (x | ~z))
196
197
/* This is the central step in the MD5 algorithm. */
198
2.36M
#define MD5STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s),  w += x)
199
200
/** The core of the MD5 algorithm
201
 *
202
 * This alters an existing MD5 hash to reflect the addition of 16
203
 * longwords of new data.  fr_md5_update blocks the data and converts bytes
204
 * into longwords for this routine.
205
 *
206
 * @param[in] state 16 bytes of data to feed into the hashing function.
207
 * @param[in,out] block MD5 digest block to update.
208
 */
209
static void fr_md5_local_transform(uint32_t state[static 4], uint8_t const block[static MD5_BLOCK_LENGTH])
210
36.9k
{
211
36.9k
  uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
212
213
627k
  for (a = 0; a < (MD5_BLOCK_LENGTH / 4); a++) {
214
590k
    size_t idx = a * 4;
215
216
590k
    in[a] = (uint32_t)(
217
590k
        (uint32_t)(block[idx + 0]) |
218
590k
        (uint32_t)(block[idx + 1]) <<  8 |
219
590k
        (uint32_t)(block[idx + 2]) << 16 |
220
590k
        (uint32_t)(block[idx + 3]) << 24);
221
590k
  }
222
223
36.9k
  a = state[0];
224
36.9k
  b = state[1];
225
36.9k
  c = state[2];
226
36.9k
  d = state[3];
227
228
36.9k
  MD5STEP(MD5_F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
229
36.9k
  MD5STEP(MD5_F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
230
36.9k
  MD5STEP(MD5_F1, c, d, a, b, in[ 2] + 0x242070db, 17);
231
36.9k
  MD5STEP(MD5_F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
232
36.9k
  MD5STEP(MD5_F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
233
36.9k
  MD5STEP(MD5_F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
234
36.9k
  MD5STEP(MD5_F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
235
36.9k
  MD5STEP(MD5_F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
236
36.9k
  MD5STEP(MD5_F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
237
36.9k
  MD5STEP(MD5_F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
238
36.9k
  MD5STEP(MD5_F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
239
36.9k
  MD5STEP(MD5_F1, b, c, d, a, in[11] + 0x895cd7be, 22);
240
36.9k
  MD5STEP(MD5_F1, a, b, c, d, in[12] + 0x6b901122,  7);
241
36.9k
  MD5STEP(MD5_F1, d, a, b, c, in[13] + 0xfd987193, 12);
242
36.9k
  MD5STEP(MD5_F1, c, d, a, b, in[14] + 0xa679438e, 17);
243
36.9k
  MD5STEP(MD5_F1, b, c, d, a, in[15] + 0x49b40821, 22);
244
245
36.9k
  MD5STEP(MD5_F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
246
36.9k
  MD5STEP(MD5_F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
247
36.9k
  MD5STEP(MD5_F2, c, d, a, b, in[11] + 0x265e5a51, 14);
248
36.9k
  MD5STEP(MD5_F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
249
36.9k
  MD5STEP(MD5_F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
250
36.9k
  MD5STEP(MD5_F2, d, a, b, c, in[10] + 0x02441453,  9);
251
36.9k
  MD5STEP(MD5_F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
252
36.9k
  MD5STEP(MD5_F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
253
36.9k
  MD5STEP(MD5_F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
254
36.9k
  MD5STEP(MD5_F2, d, a, b, c, in[14] + 0xc33707d6,  9);
255
36.9k
  MD5STEP(MD5_F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
256
36.9k
  MD5STEP(MD5_F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
257
36.9k
  MD5STEP(MD5_F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
258
36.9k
  MD5STEP(MD5_F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
259
36.9k
  MD5STEP(MD5_F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
260
36.9k
  MD5STEP(MD5_F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
261
262
36.9k
  MD5STEP(MD5_F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
263
36.9k
  MD5STEP(MD5_F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
264
36.9k
  MD5STEP(MD5_F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
265
36.9k
  MD5STEP(MD5_F3, b, c, d, a, in[14] + 0xfde5380c, 23);
266
36.9k
  MD5STEP(MD5_F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
267
36.9k
  MD5STEP(MD5_F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
268
36.9k
  MD5STEP(MD5_F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
269
36.9k
  MD5STEP(MD5_F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
270
36.9k
  MD5STEP(MD5_F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
271
36.9k
  MD5STEP(MD5_F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
272
36.9k
  MD5STEP(MD5_F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
273
36.9k
  MD5STEP(MD5_F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
274
36.9k
  MD5STEP(MD5_F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
275
36.9k
  MD5STEP(MD5_F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
276
36.9k
  MD5STEP(MD5_F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
277
36.9k
  MD5STEP(MD5_F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
278
279
36.9k
  MD5STEP(MD5_F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
280
36.9k
  MD5STEP(MD5_F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
281
36.9k
  MD5STEP(MD5_F4, c, d, a, b, in[14] + 0xab9423a7, 15);
282
36.9k
  MD5STEP(MD5_F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
283
36.9k
  MD5STEP(MD5_F4, a, b, c, d, in[12] + 0x655b59c3,  6);
284
36.9k
  MD5STEP(MD5_F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
285
36.9k
  MD5STEP(MD5_F4, c, d, a, b, in[10] + 0xffeff47d, 15);
286
36.9k
  MD5STEP(MD5_F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
287
36.9k
  MD5STEP(MD5_F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
288
36.9k
  MD5STEP(MD5_F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
289
36.9k
  MD5STEP(MD5_F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
290
36.9k
  MD5STEP(MD5_F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
291
36.9k
  MD5STEP(MD5_F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
292
36.9k
  MD5STEP(MD5_F4, d, a, b, c, in[11] + 0xbd3af235, 10);
293
36.9k
  MD5STEP(MD5_F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
294
36.9k
  MD5STEP(MD5_F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
295
296
36.9k
  state[0] += a;
297
36.9k
  state[1] += b;
298
36.9k
  state[2] += c;
299
36.9k
  state[3] += d;
300
36.9k
}
301
302
/** @copydoc fr_md5_ctx_reset
303
 *
304
 */
305
static void fr_md5_local_ctx_reset(fr_md5_ctx_t *ctx)
306
38.4k
{
307
38.4k
  fr_md5_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md5_ctx_local_t);
308
309
38.4k
  ctx_local->count[0] = 0;
310
38.4k
  ctx_local->count[1] = 0;
311
38.4k
  ctx_local->state[0] = 0x67452301;
312
38.4k
  ctx_local->state[1] = 0xefcdab89;
313
38.4k
  ctx_local->state[2] = 0x98badcfe;
314
38.4k
  ctx_local->state[3] = 0x10325476;
315
38.4k
  memset(ctx_local->buffer, 0, sizeof(ctx_local->buffer));
316
38.4k
}
317
318
/** @copydoc fr_md5_ctx_copy
319
 *
320
 */
321
static void fr_md5_local_ctx_copy(fr_md5_ctx_t *dst, fr_md5_ctx_t const *src)
322
11.1k
{
323
11.1k
  fr_md5_ctx_local_t const *ctx_local_src = talloc_get_type_abort_const(src, fr_md5_ctx_local_t);
324
11.1k
  fr_md5_ctx_local_t *ctx_local_dst = talloc_get_type_abort(dst, fr_md5_ctx_local_t);
325
326
11.1k
  memcpy(ctx_local_dst, ctx_local_src, sizeof(*ctx_local_dst));
327
11.1k
}
328
329
/** @copydoc fr_md5_ctx_alloc
330
 *
331
 */
332
static fr_md5_ctx_t *fr_md5_local_ctx_alloc(void)
333
16
{
334
16
  fr_md5_ctx_local_t *ctx_local;
335
336
16
  ctx_local = talloc(NULL, fr_md5_ctx_local_t);
337
16
  if (unlikely(!ctx_local)) return NULL;
338
16
  fr_md5_local_ctx_reset(ctx_local);
339
340
16
  return ctx_local;
341
16
}
342
343
/** @copydoc fr_md5_ctx_free
344
 *
345
 */
346
static void fr_md5_local_ctx_free(fr_md5_ctx_t **ctx)
347
16
{
348
16
  talloc_free(*ctx);
349
16
  *ctx = NULL;
350
16
}
351
352
static const uint8_t *zero = (uint8_t[]){ 0x00 };
353
354
/** @copydoc fr_md5_update
355
 *
356
 */
357
static void fr_md5_local_update(fr_md5_ctx_t *ctx, uint8_t const *in, size_t inlen)
358
116k
{
359
116k
  fr_md5_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md5_ctx_local_t);
360
361
116k
  size_t have, need;
362
363
  /*
364
   *  Needed so we can calculate the zero
365
   *  length md5 hash correctly.
366
   *  ubsan doesn't like arithmetic on
367
   *  NULL pointers.
368
   */
369
116k
  if (!in) {
370
0
    in = zero;
371
0
    inlen = 0;
372
0
  }
373
374
  /* Check how many bytes we already have and how many more we need. */
375
116k
  have = (size_t)((ctx_local->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
376
116k
  need = MD5_BLOCK_LENGTH - have;
377
378
  /* Update bitcount */
379
/*  ctx_local->count += (uint64_t)inlen << 3;*/
380
116k
  if ((ctx_local->count[0] += ((uint32_t)inlen << 3)) < (uint32_t)inlen) {
381
  /* Overflowed ctx_local->count[0] */
382
0
    ctx_local->count[1]++;
383
0
  }
384
116k
  ctx_local->count[1] += ((uint32_t)inlen >> 29);
385
386
116k
  if (inlen >= need) {
387
36.9k
    if (have != 0) {
388
36.9k
      memcpy(ctx_local->buffer + have, in, need);
389
36.9k
      fr_md5_local_transform(ctx_local->state, ctx_local->buffer);
390
36.9k
      in += need;
391
36.9k
      inlen -= need;
392
36.9k
      have = 0;
393
36.9k
    }
394
395
    /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
396
36.9k
    while (inlen >= MD5_BLOCK_LENGTH) {
397
0
      fr_md5_local_transform(ctx_local->state, in);
398
0
      in += MD5_BLOCK_LENGTH;
399
0
      inlen -= MD5_BLOCK_LENGTH;
400
0
    }
401
36.9k
  }
402
403
  /* Handle any remaining bytes of data. */
404
116k
  memcpy(ctx_local->buffer + have, in, inlen);
405
116k
}
406
407
/** @copydoc fr_md5_final
408
 *
409
 */
410
static void fr_md5_local_final(uint8_t out[static MD5_DIGEST_LENGTH], fr_md5_ctx_t *ctx)
411
36.9k
{
412
36.9k
  fr_md5_ctx_local_t  *ctx_local = talloc_get_type_abort(ctx, fr_md5_ctx_local_t);
413
36.9k
  uint8_t     count[8];
414
36.9k
  size_t      padlen;
415
36.9k
  int     i;
416
417
  /* Convert count to 8 bytes in little endian order. */
418
36.9k
  PUT_64BIT_LE(count, ctx_local->count);
419
420
  /* Pad out to 56 mod 64. */
421
36.9k
  padlen = MD5_BLOCK_LENGTH -
422
36.9k
      ((ctx_local->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
423
36.9k
  if (padlen < 1 + 8)
424
0
    padlen += MD5_BLOCK_LENGTH;
425
36.9k
  fr_md5_update(ctx_local, PADDING, padlen - 8); /* padlen - 8 <= 64 */
426
36.9k
  fr_md5_update(ctx_local, count, 8);
427
428
184k
  for (i = 0; i < 4; i++)
429
147k
    PUT_32BIT_LE(out + i * 4, ctx_local->state[i]);
430
431
36.9k
  memset(ctx_local, 0, sizeof(*ctx_local)); /* in case it's sensitive */
432
36.9k
}
433
434
/** Calculate the MD5 hash of the contents of a buffer
435
 *
436
 * @param[out] out Where to write the MD5 digest. Must be a minimum of MD5_DIGEST_LENGTH.
437
 * @param[in] in Data to hash.
438
 * @param[in] inlen Length of the data.
439
 */
440
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
441
29.7k
{
442
29.7k
  fr_md5_ctx_t *ctx;
443
444
29.7k
  ctx = fr_md5_ctx_alloc_from_list();
445
29.7k
  fr_md5_update(ctx, in, inlen);
446
29.7k
  fr_md5_final(out, ctx);
447
29.7k
  fr_md5_ctx_free_from_list(&ctx);
448
29.7k
}
449
450
static int _md5_ctx_free_on_exit(void *arg)
451
2
{
452
2
  int i;
453
2
  fr_md5_free_list_t *free_list = arg;
454
455
18
  for (i = 0; i < ARRAY_SIZE; i++) {
456
16
    if (free_list[i].used) continue;
457
458
16
    fr_md5_ctx_free(&free_list[i].md_ctx);
459
16
  }
460
461
2
  if (talloc_free(free_list) < 0) return -1;
462
463
2
  md5_array = NULL;
464
2
  return 0;
465
2
}
466
467
/** @copydoc fr_md5_ctx_alloc
468
 *
469
 */
470
fr_md5_ctx_t *fr_md5_ctx_alloc_from_list(void)
471
38.4k
{
472
38.4k
  int     i;
473
38.4k
  fr_md5_ctx_t    *md_ctx;
474
38.4k
  fr_md5_free_list_t  *free_list;
475
476
38.4k
  if (unlikely(!md5_array)) {
477
2
    free_list = talloc_zero_array(NULL, fr_md5_free_list_t, ARRAY_SIZE);
478
2
    if (unlikely(!free_list)) {
479
0
    oom:
480
0
      fr_strerror_const("Out of Memory");
481
0
      return NULL;
482
0
    }
483
484
2
    fr_atexit_thread_local(md5_array, _md5_ctx_free_on_exit, free_list);
485
486
    /*
487
     *  Initialize all MD5 contexts
488
     */
489
18
    for (i = 0; i < ARRAY_SIZE; i++) {
490
16
      md_ctx = fr_md5_ctx_alloc();
491
16
      if (unlikely(md_ctx == NULL)) goto oom;
492
493
16
      free_list[i].md_ctx = md_ctx;
494
16
    }
495
38.4k
  } else {
496
38.4k
    free_list = md5_array;
497
38.4k
  }
498
499
42.6k
  for (i = 0; i < ARRAY_SIZE; i++) {
500
42.6k
    if (free_list[i].used) continue;
501
502
38.4k
    free_list[i].used = true;
503
38.4k
    return free_list[i].md_ctx;
504
42.6k
  }
505
506
  /*
507
   *  No more free contexts, just allocate a new one.
508
   */
509
0
  return fr_md5_ctx_alloc();
510
38.4k
}
511
512
/** @copydoc fr_md5_ctx_free
513
 *
514
 */
515
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
516
38.4k
{
517
38.4k
  int i;
518
38.4k
  fr_md5_free_list_t *free_list = md5_array;
519
520
38.4k
  if (free_list) {
521
42.6k
    for (i = 0; i < ARRAY_SIZE; i++) {
522
42.6k
      if (free_list[i].md_ctx == *ctx) {
523
38.4k
        free_list[i].used = false;
524
38.4k
        fr_md5_ctx_reset(*ctx);
525
38.4k
        *ctx = NULL;
526
38.4k
        return;
527
38.4k
      }
528
42.6k
    }
529
38.4k
  }
530
531
0
  fr_md5_ctx_free(*ctx);
532
0
  *ctx = NULL;
533
0
}
534
535
#ifdef HAVE_OPENSSL_EVP_H
536
static void md5_free_list_reinit(fr_md5_funcs_t *funcs)
537
0
{
538
0
  int i;
539
0
  fr_md5_ctx_t     *md_ctx;
540
0
  fr_md5_free_list_t *free_list = md5_array;
541
542
0
  if (!free_list) {
543
0
    fr_md5_funcs = funcs;
544
0
    return;
545
0
  }
546
547
0
  for (i = 0; i < ARRAY_SIZE; i++) {
548
0
    fr_assert(!free_list[i].used);
549
550
0
    fr_md5_ctx_free(&free_list[i].md_ctx);
551
0
  }
552
553
0
  fr_md5_funcs = funcs;
554
555
0
  for (i = 0; i < ARRAY_SIZE; i++) {
556
0
    md_ctx = fr_md5_ctx_alloc();
557
0
    fr_assert(md_ctx != NULL);
558
559
0
    free_list[i].md_ctx = md_ctx;
560
0
  }
561
0
}
562
563
void fr_md5_openssl_init(void)
564
0
{
565
0
  fr_assert(fr_md5_funcs == &md5_local_funcs);
566
567
  /*
568
   *  If we are in FIPS mode, then we still use the local
569
   *  allocator.
570
   */
571
0
  if (EVP_default_properties_is_fips_enabled(NULL)) return;
572
573
  /*
574
   *  OpenSSL isn't in FIPS mode.  Swap out the functions
575
   *  pointers for the OpenSSL versions.
576
   *
577
   *  We do this by swapping out a pointer to a structure
578
   *  containing the functions, as this prevents possible
579
   *  skew where some threads see a mixture of functions.
580
   */
581
0
  md5_free_list_reinit(&md5_openssl_funcs);
582
0
}
583
584
void fr_md5_openssl_free(void)
585
0
{
586
0
  if (fr_md5_funcs == &md5_local_funcs) return; /* not initialized, or FIPS. */
587
588
0
  md5_free_list_reinit(&md5_local_funcs);
589
0
}
590
#endif