Coverage Report

Created: 2024-08-28 06:17

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