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