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   MD5_u32plus saved_a, saved_b, saved_c, saved_d;
279 
280   ptr = (const unsigned char *)data;
281 
282   a = ctx->a;
283   b = ctx->b;
284   c = ctx->c;
285   d = ctx->d;
286 
287   do {
288     saved_a = a;
289     saved_b = b;
290     saved_c = c;
291     saved_d = d;
292 
293 /* Round 1 */
294     STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
295       STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
296       STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
297       STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
298       STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
299       STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
300       STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
301       STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
302       STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
303       STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
304       STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
305       STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
306       STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
307       STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
308       STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
309       STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
310 
311 /* Round 2 */
312       STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
313       STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
314       STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
315       STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
316       STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
317       STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
318       STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
319       STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
320       STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
321       STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
322       STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
323       STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
324       STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
325       STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
326       STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
327       STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
328 
329 /* Round 3 */
330       STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
331       STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
332       STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
333       STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
334       STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
335       STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
336       STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
337       STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
338       STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
339       STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
340       STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
341       STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
342       STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
343       STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
344       STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
345       STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
346 
347 /* Round 4 */
348       STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
349       STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
350       STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
351       STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
352       STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
353       STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
354       STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
355       STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
356       STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
357       STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
358       STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
359       STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
360       STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
361       STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
362       STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
363       STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
364 
365       a += saved_a;
366     b += saved_b;
367     c += saved_c;
368     d += saved_d;
369 
370     ptr += 64;
371   } while(size -= 64);
372 
373   ctx->a = a;
374   ctx->b = b;
375   ctx->c = c;
376   ctx->d = d;
377 
378   return ptr;
379 }
380 
MD5_Init(MD5_CTX * ctx)381 static void MD5_Init(MD5_CTX *ctx)
382 {
383   ctx->a = 0x67452301;
384   ctx->b = 0xefcdab89;
385   ctx->c = 0x98badcfe;
386   ctx->d = 0x10325476;
387 
388   ctx->lo = 0;
389   ctx->hi = 0;
390 }
391 
MD5_Update(MD5_CTX * ctx,const void * data,unsigned long size)392 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
393 {
394   MD5_u32plus saved_lo;
395   unsigned long used, available;
396 
397   saved_lo = ctx->lo;
398   ctx->lo = (saved_lo + size) & 0x1fffffff;
399   if(ctx->lo < saved_lo)
400     ctx->hi++;
401   ctx->hi += (MD5_u32plus)size >> 29;
402 
403   used = saved_lo & 0x3f;
404 
405   if(used) {
406     available = 64 - used;
407 
408     if(size < available) {
409       memcpy(&ctx->buffer[used], data, size);
410       return;
411     }
412 
413     memcpy(&ctx->buffer[used], data, available);
414     data = (const unsigned char *)data + available;
415     size -= available;
416     body(ctx, ctx->buffer, 64);
417   }
418 
419   if(size >= 64) {
420     data = body(ctx, data, size & ~(unsigned long)0x3f);
421     size &= 0x3f;
422   }
423 
424   memcpy(ctx->buffer, data, size);
425 }
426 
MD5_Final(unsigned char * result,MD5_CTX * ctx)427 static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
428 {
429   unsigned long used, available;
430 
431   used = ctx->lo & 0x3f;
432 
433   ctx->buffer[used++] = 0x80;
434 
435   available = 64 - used;
436 
437   if(available < 8) {
438     memset(&ctx->buffer[used], 0, available);
439     body(ctx, ctx->buffer, 64);
440     used = 0;
441     available = 64;
442   }
443 
444   memset(&ctx->buffer[used], 0, available - 8);
445 
446   ctx->lo <<= 3;
447   ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
448   ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
449   ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
450   ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
451   ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
452   ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
453   ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
454   ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
455 
456   body(ctx, ctx->buffer, 64);
457 
458   result[0] = curlx_ultouc((ctx->a)&0xff);
459   result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
460   result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
461   result[3] = curlx_ultouc(ctx->a >> 24);
462   result[4] = curlx_ultouc((ctx->b)&0xff);
463   result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
464   result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
465   result[7] = curlx_ultouc(ctx->b >> 24);
466   result[8] = curlx_ultouc((ctx->c)&0xff);
467   result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
468   result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
469   result[11] = curlx_ultouc(ctx->c >> 24);
470   result[12] = curlx_ultouc((ctx->d)&0xff);
471   result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
472   result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
473   result[15] = curlx_ultouc(ctx->d >> 24);
474 
475   memset(ctx, 0, sizeof(*ctx));
476 }
477 
478 #endif /* CRYPTO LIBS */
479 
480 const HMAC_params Curl_HMAC_MD5[] = {
481   {
482     /* Hash initialization function. */
483     CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init),
484     /* Hash update function. */
485     CURLX_FUNCTION_CAST(HMAC_hupdate_func, MD5_Update),
486     /* Hash computation end function. */
487     CURLX_FUNCTION_CAST(HMAC_hfinal_func, MD5_Final),
488     /* Size of hash context structure. */
489     sizeof(MD5_CTX),
490     /* Maximum key length. */
491     64,
492     /* Result size. */
493     16
494   }
495 };
496 
497 const MD5_params Curl_DIGEST_MD5[] = {
498   {
499     /* Digest initialization function */
500     CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init),
501     /* Digest update function */
502     CURLX_FUNCTION_CAST(Curl_MD5_update_func, MD5_Update),
503     /* Digest computation end function */
504     CURLX_FUNCTION_CAST(Curl_MD5_final_func, MD5_Final),
505     /* Size of digest context struct */
506     sizeof(MD5_CTX),
507     /* Result size */
508     16
509   }
510 };
511 
512 /*
513  * @unittest: 1601
514  */
Curl_md5it(unsigned char * outbuffer,const unsigned char * input)515 void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
516                 const unsigned char *input)
517 {
518   MD5_CTX ctx;
519   MD5_Init(&ctx);
520   MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
521   MD5_Final(outbuffer, &ctx);
522 }
523 
Curl_MD5_init(const MD5_params * md5params)524 MD5_context *Curl_MD5_init(const MD5_params *md5params)
525 {
526   MD5_context *ctxt;
527 
528   /* Create MD5 context */
529   ctxt = malloc(sizeof(*ctxt));
530 
531   if(!ctxt)
532     return ctxt;
533 
534   ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
535 
536   if(!ctxt->md5_hashctx) {
537     free(ctxt);
538     return NULL;
539   }
540 
541   ctxt->md5_hash = md5params;
542 
543   (*md5params->md5_init_func)(ctxt->md5_hashctx);
544 
545   return ctxt;
546 }
547 
Curl_MD5_update(MD5_context * context,const unsigned char * data,unsigned int len)548 int Curl_MD5_update(MD5_context *context,
549                     const unsigned char *data,
550                     unsigned int len)
551 {
552   (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
553 
554   return 0;
555 }
556 
Curl_MD5_final(MD5_context * context,unsigned char * result)557 int Curl_MD5_final(MD5_context *context, unsigned char *result)
558 {
559   (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
560 
561   free(context->md5_hashctx);
562   free(context);
563 
564   return 0;
565 }
566 
567 #endif /* CURL_DISABLE_CRYPTO_AUTH */
568