md5.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifndef CURL_DISABLE_CRYPTO_AUTH
00026 
00027 #include <curl/curl.h>
00028 
00029 #include "curl_md5.h"
00030 #include "curl_hmac.h"
00031 #include "warnless.h"
00032 
00033 #if defined(USE_GNUTLS_NETTLE)
00034 
00035 #include <nettle/md5.h>
00036 #include "curl_memory.h"
00037 /* The last #include file should be: */
00038 #include "memdebug.h"
00039 
00040 typedef struct md5_ctx MD5_CTX;
00041 
00042 static void MD5_Init(MD5_CTX * ctx)
00043 {
00044   md5_init(ctx);
00045 }
00046 
00047 static void MD5_Update(MD5_CTX * ctx,
00048                        const unsigned char *input,
00049                        unsigned int inputLen)
00050 {
00051   md5_update(ctx, inputLen, input);
00052 }
00053 
00054 static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
00055 {
00056   md5_digest(ctx, 16, digest);
00057 }
00058 
00059 #elif defined(USE_GNUTLS)
00060 
00061 #include <gcrypt.h>
00062 #include "curl_memory.h"
00063 /* The last #include file should be: */
00064 #include "memdebug.h"
00065 
00066 typedef gcry_md_hd_t MD5_CTX;
00067 
00068 static void MD5_Init(MD5_CTX * ctx)
00069 {
00070   gcry_md_open(ctx, GCRY_MD_MD5, 0);
00071 }
00072 
00073 static void MD5_Update(MD5_CTX * ctx,
00074                        const unsigned char *input,
00075                        unsigned int inputLen)
00076 {
00077   gcry_md_write(*ctx, input, inputLen);
00078 }
00079 
00080 static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
00081 {
00082   memcpy(digest, gcry_md_read(*ctx, 0), 16);
00083   gcry_md_close(*ctx);
00084 }
00085 
00086 #elif defined(USE_OPENSSL)
00087 /* When OpenSSL is available we use the MD5-function from OpenSSL */
00088 #include <openssl/md5.h>
00089 #include "curl_memory.h"
00090 /* The last #include file should be: */
00091 #include "memdebug.h"
00092 
00093 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
00094               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
00095       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
00096               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
00097 
00098 /* For Apple operating systems: CommonCrypto has the functions we need.
00099    These functions are available on Tiger and later, as well as iOS 2.0
00100    and later. If you're building for an older cat, well, sorry.
00101 
00102    Declaring the functions as static like this seems to be a bit more
00103    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
00104 #  include <CommonCrypto/CommonDigest.h>
00105 #  define MD5_CTX CC_MD5_CTX
00106 #include "curl_memory.h"
00107 /* The last #include file should be: */
00108 #include "memdebug.h"
00109 
00110 static void MD5_Init(MD5_CTX *ctx)
00111 {
00112   CC_MD5_Init(ctx);
00113 }
00114 
00115 static void MD5_Update(MD5_CTX *ctx,
00116                        const unsigned char *input,
00117                        unsigned int inputLen)
00118 {
00119   CC_MD5_Update(ctx, input, inputLen);
00120 }
00121 
00122 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00123 {
00124   CC_MD5_Final(digest, ctx);
00125 }
00126 
00127 #elif defined(_WIN32) && !defined(CURL_WINDOWS_APP)
00128 
00129 #include <wincrypt.h>
00130 #include "curl_memory.h"
00131 /* The last #include file should be: */
00132 #include "memdebug.h"
00133 
00134 typedef struct {
00135   HCRYPTPROV hCryptProv;
00136   HCRYPTHASH hHash;
00137 } MD5_CTX;
00138 
00139 static void MD5_Init(MD5_CTX *ctx)
00140 {
00141   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00142                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
00143     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
00144   }
00145 }
00146 
00147 static void MD5_Update(MD5_CTX *ctx,
00148                        const unsigned char *input,
00149                        unsigned int inputLen)
00150 {
00151   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00152 }
00153 
00154 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00155 {
00156   unsigned long length = 0;
00157   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
00158   if(length == 16)
00159     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
00160   if(ctx->hHash)
00161     CryptDestroyHash(ctx->hHash);
00162   if(ctx->hCryptProv)
00163     CryptReleaseContext(ctx->hCryptProv, 0);
00164 }
00165 
00166 #elif defined(USE_AXTLS)
00167 #include <axTLS/config.h>
00168 #include <axTLS/os_int.h>
00169 #include <axTLS/crypto.h>
00170 #include "curl_memory.h"
00171 /* The last #include file should be: */
00172 #include "memdebug.h"
00173 #else
00174 /* When no other crypto library is available we use this code segment */
00175 /*
00176  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
00177  * MD5 Message-Digest Algorithm (RFC 1321).
00178  *
00179  * Homepage:
00180  http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
00181  *
00182  * Author:
00183  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
00184  *
00185  * This software was written by Alexander Peslyak in 2001.  No copyright is
00186  * claimed, and the software is hereby placed in the public domain.
00187  * In case this attempt to disclaim copyright and place the software in the
00188  * public domain is deemed null and void, then the software is
00189  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
00190  * general public under the following terms:
00191  *
00192  * Redistribution and use in source and binary forms, with or without
00193  * modification, are permitted.
00194  *
00195  * There's ABSOLUTELY NO WARRANTY, express or implied.
00196  *
00197  * (This is a heavily cut-down "BSD license".)
00198  *
00199  * This differs from Colin Plumb's older public domain implementation in that
00200  * no exactly 32-bit integer data type is required (any 32-bit or wider
00201  * unsigned integer data type will do), there's no compile-time endianness
00202  * configuration, and the function prototypes match OpenSSL's.  No code from
00203  * Colin Plumb's implementation has been reused; this comment merely compares
00204  * the properties of the two independent implementations.
00205  *
00206  * The primary goals of this implementation are portability and ease of use.
00207  * It is meant to be fast, but not as fast as possible.  Some known
00208  * optimizations are not included to reduce source code size and avoid
00209  * compile-time configuration.
00210  */
00211 
00212 #include <string.h>
00213 
00214 /* The last #include files should be: */
00215 #include "curl_memory.h"
00216 #include "memdebug.h"
00217 
00218 /* Any 32-bit or wider unsigned integer data type will do */
00219 typedef unsigned int MD5_u32plus;
00220 
00221 typedef struct {
00222   MD5_u32plus lo, hi;
00223   MD5_u32plus a, b, c, d;
00224   unsigned char buffer[64];
00225   MD5_u32plus block[16];
00226 } MD5_CTX;
00227 
00228 static void MD5_Init(MD5_CTX *ctx);
00229 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
00230 static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
00231 
00232 /*
00233  * The basic MD5 functions.
00234  *
00235  * F and G are optimized compared to their RFC 1321 definitions for
00236  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
00237  * implementation.
00238  */
00239 #define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
00240 #define G(x, y, z)                      ((y) ^ ((z) & ((x) ^ (y))))
00241 #define H(x, y, z)                      (((x) ^ (y)) ^ (z))
00242 #define H2(x, y, z)                     ((x) ^ ((y) ^ (z)))
00243 #define I(x, y, z)                      ((y) ^ ((x) | ~(z)))
00244 
00245 /*
00246  * The MD5 transformation for all four rounds.
00247  */
00248 #define STEP(f, a, b, c, d, x, t, s) \
00249         (a) += f((b), (c), (d)) + (x) + (t); \
00250         (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
00251         (a) += (b);
00252 
00253 /*
00254  * SET reads 4 input bytes in little-endian byte order and stores them
00255  * in a properly aligned word in host byte order.
00256  *
00257  * The check for little-endian architectures that tolerate unaligned
00258  * memory accesses is just an optimization.  Nothing will break if it
00259  * doesn't work.
00260  */
00261 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
00262 #define SET(n) \
00263         (*(MD5_u32plus *)&ptr[(n) * 4])
00264 #define GET(n) \
00265         SET(n)
00266 #else
00267 #define SET(n) \
00268         (ctx->block[(n)] = \
00269         (MD5_u32plus)ptr[(n) * 4] | \
00270         ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
00271         ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
00272         ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
00273 #define GET(n) \
00274         (ctx->block[(n)])
00275 #endif
00276 
00277 /*
00278  * This processes one or more 64-byte data blocks, but does NOT update
00279  * the bit counters.  There are no alignment requirements.
00280  */
00281 static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
00282 {
00283   const unsigned char *ptr;
00284   MD5_u32plus a, b, c, d;
00285   MD5_u32plus saved_a, saved_b, saved_c, saved_d;
00286 
00287   ptr = (const unsigned char *)data;
00288 
00289   a = ctx->a;
00290   b = ctx->b;
00291   c = ctx->c;
00292   d = ctx->d;
00293 
00294   do {
00295     saved_a = a;
00296     saved_b = b;
00297     saved_c = c;
00298     saved_d = d;
00299 
00300 /* Round 1 */
00301     STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
00302       STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
00303       STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
00304       STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
00305       STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
00306       STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
00307       STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
00308       STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
00309       STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
00310       STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
00311       STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
00312       STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
00313       STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
00314       STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
00315       STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
00316       STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
00317 
00318 /* Round 2 */
00319       STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
00320       STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
00321       STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
00322       STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
00323       STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
00324       STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
00325       STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
00326       STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
00327       STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
00328       STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
00329       STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
00330       STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
00331       STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
00332       STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
00333       STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
00334       STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
00335 
00336 /* Round 3 */
00337       STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
00338       STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
00339       STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
00340       STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
00341       STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
00342       STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
00343       STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
00344       STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
00345       STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
00346       STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
00347       STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
00348       STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
00349       STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
00350       STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
00351       STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
00352       STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
00353 
00354 /* Round 4 */
00355       STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
00356       STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
00357       STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
00358       STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
00359       STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
00360       STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
00361       STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
00362       STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
00363       STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
00364       STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
00365       STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
00366       STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
00367       STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
00368       STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
00369       STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
00370       STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
00371 
00372       a += saved_a;
00373     b += saved_b;
00374     c += saved_c;
00375     d += saved_d;
00376 
00377     ptr += 64;
00378   } while(size -= 64);
00379 
00380   ctx->a = a;
00381   ctx->b = b;
00382   ctx->c = c;
00383   ctx->d = d;
00384 
00385   return ptr;
00386 }
00387 
00388 static void MD5_Init(MD5_CTX *ctx)
00389 {
00390   ctx->a = 0x67452301;
00391   ctx->b = 0xefcdab89;
00392   ctx->c = 0x98badcfe;
00393   ctx->d = 0x10325476;
00394 
00395   ctx->lo = 0;
00396   ctx->hi = 0;
00397 }
00398 
00399 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
00400 {
00401   MD5_u32plus saved_lo;
00402   unsigned long used, available;
00403 
00404   saved_lo = ctx->lo;
00405   ctx->lo = (saved_lo + size) & 0x1fffffff;
00406   if(ctx->lo < saved_lo)
00407     ctx->hi++;
00408   ctx->hi += (MD5_u32plus)size >> 29;
00409 
00410   used = saved_lo & 0x3f;
00411 
00412   if(used) {
00413     available = 64 - used;
00414 
00415     if(size < available) {
00416       memcpy(&ctx->buffer[used], data, size);
00417       return;
00418     }
00419 
00420     memcpy(&ctx->buffer[used], data, available);
00421     data = (const unsigned char *)data + available;
00422     size -= available;
00423     body(ctx, ctx->buffer, 64);
00424   }
00425 
00426   if(size >= 64) {
00427     data = body(ctx, data, size & ~(unsigned long)0x3f);
00428     size &= 0x3f;
00429   }
00430 
00431   memcpy(ctx->buffer, data, size);
00432 }
00433 
00434 static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
00435 {
00436   unsigned long used, available;
00437 
00438   used = ctx->lo & 0x3f;
00439 
00440   ctx->buffer[used++] = 0x80;
00441 
00442   available = 64 - used;
00443 
00444   if(available < 8) {
00445     memset(&ctx->buffer[used], 0, available);
00446     body(ctx, ctx->buffer, 64);
00447     used = 0;
00448     available = 64;
00449   }
00450 
00451   memset(&ctx->buffer[used], 0, available - 8);
00452 
00453   ctx->lo <<= 3;
00454   ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
00455   ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
00456   ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
00457   ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
00458   ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
00459   ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
00460   ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
00461   ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
00462 
00463   body(ctx, ctx->buffer, 64);
00464 
00465   result[0] = curlx_ultouc((ctx->a)&0xff);
00466   result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
00467   result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
00468   result[3] = curlx_ultouc(ctx->a >> 24);
00469   result[4] = curlx_ultouc((ctx->b)&0xff);
00470   result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
00471   result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
00472   result[7] = curlx_ultouc(ctx->b >> 24);
00473   result[8] = curlx_ultouc((ctx->c)&0xff);
00474   result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
00475   result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
00476   result[11] = curlx_ultouc(ctx->c >> 24);
00477   result[12] = curlx_ultouc((ctx->d)&0xff);
00478   result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
00479   result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
00480   result[15] = curlx_ultouc(ctx->d >> 24);
00481 
00482   memset(ctx, 0, sizeof(*ctx));
00483 }
00484 
00485 #endif /* CRYPTO LIBS */
00486 
00487 const HMAC_params Curl_HMAC_MD5[] = {
00488   {
00489     (HMAC_hinit_func) MD5_Init,           /* Hash initialization function. */
00490     (HMAC_hupdate_func) MD5_Update,       /* Hash update function. */
00491     (HMAC_hfinal_func) MD5_Final,         /* Hash computation end function. */
00492     sizeof(MD5_CTX),                      /* Size of hash context structure. */
00493     64,                                   /* Maximum key length. */
00494     16                                    /* Result size. */
00495   }
00496 };
00497 
00498 const MD5_params Curl_DIGEST_MD5[] = {
00499   {
00500     (Curl_MD5_init_func) MD5_Init,      /* Digest initialization function */
00501     (Curl_MD5_update_func) MD5_Update,  /* Digest update function */
00502     (Curl_MD5_final_func) MD5_Final,    /* Digest computation end function */
00503     sizeof(MD5_CTX),                    /* Size of digest context struct */
00504     16                                  /* Result size */
00505   }
00506 };
00507 
00508 /*
00509  * @unittest: 1601
00510  */
00511 void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
00512                 const unsigned char *input)
00513 {
00514   MD5_CTX ctx;
00515   MD5_Init(&ctx);
00516   MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
00517   MD5_Final(outbuffer, &ctx);
00518 }
00519 
00520 MD5_context *Curl_MD5_init(const MD5_params *md5params)
00521 {
00522   MD5_context *ctxt;
00523 
00524   /* Create MD5 context */
00525   ctxt = malloc(sizeof *ctxt);
00526 
00527   if(!ctxt)
00528     return ctxt;
00529 
00530   ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
00531 
00532   if(!ctxt->md5_hashctx) {
00533     free(ctxt);
00534     return NULL;
00535   }
00536 
00537   ctxt->md5_hash = md5params;
00538 
00539   (*md5params->md5_init_func)(ctxt->md5_hashctx);
00540 
00541   return ctxt;
00542 }
00543 
00544 int Curl_MD5_update(MD5_context *context,
00545                     const unsigned char *data,
00546                     unsigned int len)
00547 {
00548   (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
00549 
00550   return 0;
00551 }
00552 
00553 int Curl_MD5_final(MD5_context *context, unsigned char *result)
00554 {
00555   (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
00556 
00557   free(context->md5_hashctx);
00558   free(context);
00559 
00560   return 0;
00561 }
00562 
00563 #endif /* CURL_DISABLE_CRYPTO_AUTH */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05