1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifndef CURL_DISABLE_CRYPTO_AUTH
26 
27 #include <curl/curl.h>
28 
29 #include "curl_md5.h"
30 #include "curl_hmac.h"
31 #include "warnless.h"
32 
33 #if defined(USE_GNUTLS_NETTLE)
34 
35 #include <nettle/md5.h>
36 #include "curl_memory.h"
37 /* The last #include file should be: */
38 #include "memdebug.h"
39 
40 typedef struct md5_ctx MD5_CTX;
41 
MD5_Init(MD5_CTX * ctx)42 static void MD5_Init(MD5_CTX *ctx)
43 {
44   md5_init(ctx);
45 }
46 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)47 static void MD5_Update(MD5_CTX *ctx,
48                        const unsigned char *input,
49                        unsigned int inputLen)
50 {
51   md5_update(ctx, inputLen, input);
52 }
53 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)54 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
55 {
56   md5_digest(ctx, 16, digest);
57 }
58 
59 #elif defined(USE_GNUTLS)
60 
61 #include <gcrypt.h>
62 #include "curl_memory.h"
63 /* The last #include file should be: */
64 #include "memdebug.h"
65 
66 typedef gcry_md_hd_t MD5_CTX;
67 
MD5_Init(MD5_CTX * ctx)68 static void MD5_Init(MD5_CTX *ctx)
69 {
70   gcry_md_open(ctx, GCRY_MD_MD5, 0);
71 }
72 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)73 static void MD5_Update(MD5_CTX *ctx,
74                        const unsigned char *input,
75                        unsigned int inputLen)
76 {
77   gcry_md_write(*ctx, input, inputLen);
78 }
79 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)80 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
81 {
82   memcpy(digest, gcry_md_read(*ctx, 0), 16);
83   gcry_md_close(*ctx);
84 }
85 
86 #elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
87 /* When OpenSSL is available we use the MD5-function from OpenSSL */
88 #include <openssl/md5.h>
89 #include "curl_memory.h"
90 /* The last #include file should be: */
91 #include "memdebug.h"
92 
93 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
94               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
95       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
96               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
97 
98 /* For Apple operating systems: CommonCrypto has the functions we need.
99    These functions are available on Tiger and later, as well as iOS 2.0
100    and later. If you're building for an older cat, well, sorry.
101 
102    Declaring the functions as static like this seems to be a bit more
103    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
104 #  include <CommonCrypto/CommonDigest.h>
105 #  define MD5_CTX CC_MD5_CTX
106 #include "curl_memory.h"
107 /* The last #include file should be: */
108 #include "memdebug.h"
109 
MD5_Init(MD5_CTX * ctx)110 static void MD5_Init(MD5_CTX *ctx)
111 {
112   CC_MD5_Init(ctx);
113 }
114 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)115 static void MD5_Update(MD5_CTX *ctx,
116                        const unsigned char *input,
117                        unsigned int inputLen)
118 {
119   CC_MD5_Update(ctx, input, inputLen);
120 }
121 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)122 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
123 {
124   CC_MD5_Final(digest, ctx);
125 }
126 
127 #elif defined(WIN32) && !defined(CURL_WINDOWS_APP)
128 
129 #include <wincrypt.h>
130 #include "curl_memory.h"
131 /* The last #include file should be: */
132 #include "memdebug.h"
133 
134 typedef struct {
135   HCRYPTPROV hCryptProv;
136   HCRYPTHASH hHash;
137 } MD5_CTX;
138 
MD5_Init(MD5_CTX * ctx)139 static void MD5_Init(MD5_CTX *ctx)
140 {
141   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
142                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
143     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
144   }
145 }
146 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)147 static void MD5_Update(MD5_CTX *ctx,
148                        const unsigned char *input,
149                        unsigned int inputLen)
150 {
151   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
152 }
153 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)154 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
155 {
156   unsigned long length = 0;
157   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
158   if(length == 16)
159     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
160   if(ctx->hHash)
161     CryptDestroyHash(ctx->hHash);
162   if(ctx->hCryptProv)
163     CryptReleaseContext(ctx->hCryptProv, 0);
164 }
165 
166 #else
167 /* When no other crypto library is available we use this code segment */
168 /*
169  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
170  * MD5 Message-Digest Algorithm (RFC 1321).
171  *
172  * Homepage:
173  https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
174  *
175  * Author:
176  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
177  *
178  * This software was written by Alexander Peslyak in 2001.  No copyright is
179  * claimed, and the software is hereby placed in the public domain.
180  * In case this attempt to disclaim copyright and place the software in the
181  * public domain is deemed null and void, then the software is
182  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
183  * general public under the following terms:
184  *
185  * Redistribution and use in source and binary forms, with or without
186  * modification, are permitted.
187  *
188  * There's ABSOLUTELY NO WARRANTY, express or implied.
189  *
190  * (This is a heavily cut-down "BSD license".)
191  *
192  * This differs from Colin Plumb's older public domain implementation in that
193  * no exactly 32-bit integer data type is required (any 32-bit or wider
194  * unsigned integer data type will do), there's no compile-time endianness
195  * configuration, and the function prototypes match OpenSSL's.  No code from
196  * Colin Plumb's implementation has been reused; this comment merely compares
197  * the properties of the two independent implementations.
198  *
199  * The primary goals of this implementation are portability and ease of use.
200  * It is meant to be fast, but not as fast as possible.  Some known
201  * optimizations are not included to reduce source code size and avoid
202  * compile-time configuration.
203  */
204 
205 #include <string.h>
206 
207 /* The last #include files should be: */
208 #include "curl_memory.h"
209 #include "memdebug.h"
210 
211 /* Any 32-bit or wider unsigned integer data type will do */
212 typedef unsigned int MD5_u32plus;
213 
214 typedef struct {
215   MD5_u32plus lo, hi;
216   MD5_u32plus a, b, c, d;
217   unsigned char buffer[64];
218   MD5_u32plus block[16];
219 } MD5_CTX;
220 
221 static void MD5_Init(MD5_CTX *ctx);
222 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
223 static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
224 
225 /*
226  * The basic MD5 functions.
227  *
228  * F and G are optimized compared to their RFC 1321 definitions for
229  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
230  * implementation.
231  */
232 #define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
233 #define G(x, y, z)                      ((y) ^ ((z) & ((x) ^ (y))))
234 #define H(x, y, z)                      (((x) ^ (y)) ^ (z))
235 #define H2(x, y, z)                     ((x) ^ ((y) ^ (z)))
236 #define I(x, y, z)                      ((y) ^ ((x) | ~(z)))
237 
238 /*
239  * The MD5 transformation for all four rounds.
240  */
241 #define STEP(f, a, b, c, d, x, t, s) \
242         (a) += f((b), (c), (d)) + (x) + (t); \
243         (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
244         (a) += (b);
245 
246 /*
247  * SET reads 4 input bytes in little-endian byte order and stores them
248  * in a properly aligned word in host byte order.
249  *
250  * The check for little-endian architectures that tolerate unaligned
251  * memory accesses is just an optimization.  Nothing will break if it
252  * doesn't work.
253  */
254 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
255 #define SET(n) \
256         (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
257 #define GET(n) \
258         SET(n)
259 #else
260 #define SET(n) \
261         (ctx->block[(n)] = \
262         (MD5_u32plus)ptr[(n) * 4] | \
263         ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
264         ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
265         ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
266 #define GET(n) \
267         (ctx->block[(n)])
268 #endif
269 
270 /*
271  * This processes one or more 64-byte data blocks, but does NOT update
272  * the bit counters.  There are no alignment requirements.
273  */
body(MD5_CTX * ctx,const void * data,unsigned long size)274 static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
275 {
276   const unsigned char *ptr;
277   MD5_u32plus a, b, c, d;
278 
279   ptr = (const unsigned char *)data;
280 
281   a = ctx->a;
282   b = ctx->b;
283   c = ctx->c;
284   d = ctx->d;
285 
286   do {
287     MD5_u32plus saved_a, saved_b, saved_c, saved_d;
288 
289     saved_a = a;
290     saved_b = b;
291     saved_c = c;
292     saved_d = d;
293 
294 /* Round 1 */
295     STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
296     STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
297     STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
298     STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
299     STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
300     STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
301     STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
302     STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
303     STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
304     STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
305     STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
306     STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
307     STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
308     STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
309     STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
310     STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
311 
312 /* Round 2 */
313     STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
314     STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
315     STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
316     STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
317     STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
318     STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
319     STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
320     STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
321     STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
322     STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
323     STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
324     STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
325     STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
326     STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
327     STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
328     STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
329 
330 /* Round 3 */
331     STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
332     STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
333     STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
334     STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
335     STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
336     STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
337     STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
338     STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
339     STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
340     STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
341     STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
342     STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
343     STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
344     STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
345     STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
346     STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
347 
348 /* Round 4 */
349     STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
350     STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
351     STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
352     STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
353     STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
354     STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
355     STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
356     STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
357     STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
358     STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
359     STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
360     STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
361     STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
362     STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
363     STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
364     STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
365 
366     a += saved_a;
367     b += saved_b;
368     c += saved_c;
369     d += saved_d;
370 
371     ptr += 64;
372   } while(size -= 64);
373 
374   ctx->a = a;
375   ctx->b = b;
376   ctx->c = c;
377   ctx->d = d;
378 
379   return ptr;
380 }
381 
MD5_Init(MD5_CTX * ctx)382 static void MD5_Init(MD5_CTX *ctx)
383 {
384   ctx->a = 0x67452301;
385   ctx->b = 0xefcdab89;
386   ctx->c = 0x98badcfe;
387   ctx->d = 0x10325476;
388 
389   ctx->lo = 0;
390   ctx->hi = 0;
391 }
392 
MD5_Update(MD5_CTX * ctx,const void * data,unsigned long size)393 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
394 {
395   MD5_u32plus saved_lo;
396   unsigned long used;
397 
398   saved_lo = ctx->lo;
399   ctx->lo = (saved_lo + size) & 0x1fffffff;
400   if(ctx->lo < saved_lo)
401     ctx->hi++;
402   ctx->hi += (MD5_u32plus)size >> 29;
403 
404   used = saved_lo & 0x3f;
405 
406   if(used) {
407     unsigned long available = 64 - used;
408 
409     if(size < available) {
410       memcpy(&ctx->buffer[used], data, size);
411       return;
412     }
413 
414     memcpy(&ctx->buffer[used], data, available);
415     data = (const unsigned char *)data + available;
416     size -= available;
417     body(ctx, ctx->buffer, 64);
418   }
419 
420   if(size >= 64) {
421     data = body(ctx, data, size & ~(unsigned long)0x3f);
422     size &= 0x3f;
423   }
424 
425   memcpy(ctx->buffer, data, size);
426 }
427 
MD5_Final(unsigned char * result,MD5_CTX * ctx)428 static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
429 {
430   unsigned long used, available;
431 
432   used = ctx->lo & 0x3f;
433 
434   ctx->buffer[used++] = 0x80;
435 
436   available = 64 - used;
437 
438   if(available < 8) {
439     memset(&ctx->buffer[used], 0, available);
440     body(ctx, ctx->buffer, 64);
441     used = 0;
442     available = 64;
443   }
444 
445   memset(&ctx->buffer[used], 0, available - 8);
446 
447   ctx->lo <<= 3;
448   ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
449   ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
450   ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
451   ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
452   ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
453   ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
454   ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
455   ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
456 
457   body(ctx, ctx->buffer, 64);
458 
459   result[0] = curlx_ultouc((ctx->a)&0xff);
460   result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
461   result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
462   result[3] = curlx_ultouc(ctx->a >> 24);
463   result[4] = curlx_ultouc((ctx->b)&0xff);
464   result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
465   result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
466   result[7] = curlx_ultouc(ctx->b >> 24);
467   result[8] = curlx_ultouc((ctx->c)&0xff);
468   result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
469   result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
470   result[11] = curlx_ultouc(ctx->c >> 24);
471   result[12] = curlx_ultouc((ctx->d)&0xff);
472   result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
473   result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
474   result[15] = curlx_ultouc(ctx->d >> 24);
475 
476   memset(ctx, 0, sizeof(*ctx));
477 }
478 
479 #endif /* CRYPTO LIBS */
480 
481 const HMAC_params Curl_HMAC_MD5[] = {
482   {
483     /* Hash initialization function. */
484     CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init),
485     /* Hash update function. */
486     CURLX_FUNCTION_CAST(HMAC_hupdate_func, MD5_Update),
487     /* Hash computation end function. */
488     CURLX_FUNCTION_CAST(HMAC_hfinal_func, MD5_Final),
489     /* Size of hash context structure. */
490     sizeof(MD5_CTX),
491     /* Maximum key length. */
492     64,
493     /* Result size. */
494     16
495   }
496 };
497 
498 const MD5_params Curl_DIGEST_MD5[] = {
499   {
500     /* Digest initialization function */
501     CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init),
502     /* Digest update function */
503     CURLX_FUNCTION_CAST(Curl_MD5_update_func, MD5_Update),
504     /* Digest computation end function */
505     CURLX_FUNCTION_CAST(Curl_MD5_final_func, MD5_Final),
506     /* Size of digest context struct */
507     sizeof(MD5_CTX),
508     /* Result size */
509     16
510   }
511 };
512 
513 /*
514  * @unittest: 1601
515  */
Curl_md5it(unsigned char * outbuffer,const unsigned char * input)516 void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
517                 const unsigned char *input)
518 {
519   MD5_CTX ctx;
520   MD5_Init(&ctx);
521   MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
522   MD5_Final(outbuffer, &ctx);
523 }
524 
Curl_MD5_init(const MD5_params * md5params)525 MD5_context *Curl_MD5_init(const MD5_params *md5params)
526 {
527   MD5_context *ctxt;
528 
529   /* Create MD5 context */
530   ctxt = malloc(sizeof(*ctxt));
531 
532   if(!ctxt)
533     return ctxt;
534 
535   ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
536 
537   if(!ctxt->md5_hashctx) {
538     free(ctxt);
539     return NULL;
540   }
541 
542   ctxt->md5_hash = md5params;
543 
544   (*md5params->md5_init_func)(ctxt->md5_hashctx);
545 
546   return ctxt;
547 }
548 
Curl_MD5_update(MD5_context * context,const unsigned char * data,unsigned int len)549 CURLcode Curl_MD5_update(MD5_context *context,
550                          const unsigned char *data,
551                          unsigned int len)
552 {
553   (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
554 
555   return CURLE_OK;
556 }
557 
Curl_MD5_final(MD5_context * context,unsigned char * result)558 CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result)
559 {
560   (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
561 
562   free(context->md5_hashctx);
563   free(context);
564 
565   return CURLE_OK;
566 }
567 
568 #endif /* CURL_DISABLE_CRYPTO_AUTH */
569