/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 | } |