• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "tool_setup.h"
23 
24 #ifdef USE_METALINK
25 
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 
29 #ifdef HAVE_FCNTL_H
30 #  include <fcntl.h>
31 #endif
32 
33 #undef HAVE_NSS_CONTEXT
34 
35 #ifdef USE_OPENSSL
36 #  include <openssl/md5.h>
37 #  include <openssl/sha.h>
38 #elif defined(USE_GNUTLS_NETTLE)
39 #  include <nettle/md5.h>
40 #  include <nettle/sha.h>
41 #  define MD5_CTX    struct md5_ctx
42 #  define SHA_CTX    struct sha1_ctx
43 #  define SHA256_CTX struct sha256_ctx
44 #elif defined(USE_GNUTLS)
45 #  include <gcrypt.h>
46 #  define MD5_CTX    gcry_md_hd_t
47 #  define SHA_CTX    gcry_md_hd_t
48 #  define SHA256_CTX gcry_md_hd_t
49 #elif defined(USE_NSS)
50 #  include <nss.h>
51 #  include <pk11pub.h>
52 #  define MD5_CTX    void *
53 #  define SHA_CTX    void *
54 #  define SHA256_CTX void *
55 #  define HAVE_NSS_CONTEXT
56    static NSSInitContext *nss_context;
57 #elif defined(USE_POLARSSL)
58 #  include <polarssl/md5.h>
59 #  include <polarssl/sha1.h>
60 #  include <polarssl/sha256.h>
61 #  define MD5_CTX    md5_context
62 #  define SHA_CTX    sha1_context
63 #  define SHA256_CTX sha256_context
64 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
65               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
66       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
67               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
68 /* For Apple operating systems: CommonCrypto has the functions we need.
69    The library's headers are even backward-compatible with OpenSSL's
70    headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
71 
72    These functions are available on Tiger and later, as well as iOS 2.0
73    and later. If you're building for an older cat, well, sorry. */
74 #  define COMMON_DIGEST_FOR_OPENSSL
75 #  include <CommonCrypto/CommonDigest.h>
76 #elif defined(WIN32)
77 /* For Windows: If no other crypto library is provided, we fallback
78    to the hash functions provided within the Microsoft Windows CryptoAPI */
79 #  include <wincrypt.h>
80 /* Custom structure in order to store the required provider and hash handle */
81 struct win32_crypto_hash {
82   HCRYPTPROV hCryptProv;
83   HCRYPTHASH hHash;
84 };
85 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
86 #  ifndef ALG_SID_SHA_256
87 #    define ALG_SID_SHA_256  12
88 #  endif
89 #  ifndef CALG_SHA_256
90 #    define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
91 #  endif
92 #  define MD5_CTX    struct win32_crypto_hash
93 #  define SHA_CTX    struct win32_crypto_hash
94 #  define SHA256_CTX struct win32_crypto_hash
95 #else
96 #  error "Can't compile METALINK support without a crypto library."
97 #endif
98 
99 #define ENABLE_CURLX_PRINTF
100 /* use our own printf() functions */
101 #include "curlx.h"
102 
103 #include "tool_getparam.h"
104 #include "tool_paramhlp.h"
105 #include "tool_cfgable.h"
106 #include "tool_metalink.h"
107 #include "tool_operate.h"
108 #include "tool_msgs.h"
109 
110 #include "memdebug.h" /* keep this as LAST include */
111 
112 /* Copied from tool_getparam.c */
113 #define GetStr(str,val) do { \
114   if(*(str)) { \
115     free(*(str)); \
116     *(str) = NULL; \
117   } \
118   if((val)) \
119     *(str) = strdup((val)); \
120   if(!(val)) \
121     return PARAM_NO_MEM; \
122 } WHILE_FALSE
123 
124 #if defined(USE_OPENSSL)
125 /* Functions are already defined */
126 #elif defined(USE_GNUTLS_NETTLE)
127 
MD5_Init(MD5_CTX * ctx)128 static int MD5_Init(MD5_CTX *ctx)
129 {
130   md5_init(ctx);
131   return 1;
132 }
133 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)134 static void MD5_Update(MD5_CTX *ctx,
135                        const unsigned char *input,
136                        unsigned int inputLen)
137 {
138   md5_update(ctx, inputLen, input);
139 }
140 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)141 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
142 {
143   md5_digest(ctx, 16, digest);
144 }
145 
SHA1_Init(SHA_CTX * ctx)146 static int SHA1_Init(SHA_CTX *ctx)
147 {
148   sha1_init(ctx);
149   return 1;
150 }
151 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)152 static void SHA1_Update(SHA_CTX *ctx,
153                         const unsigned char *input,
154                         unsigned int inputLen)
155 {
156   sha1_update(ctx, inputLen, input);
157 }
158 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)159 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
160 {
161   sha1_digest(ctx, 20, digest);
162 }
163 
SHA256_Init(SHA256_CTX * ctx)164 static int SHA256_Init(SHA256_CTX *ctx)
165 {
166   sha256_init(ctx);
167   return 1;
168 }
169 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)170 static void SHA256_Update(SHA256_CTX *ctx,
171                           const unsigned char *input,
172                           unsigned int inputLen)
173 {
174   sha256_update(ctx, inputLen, input);
175 }
176 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)177 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
178 {
179   sha256_digest(ctx, 32, digest);
180 }
181 
182 #elif defined(USE_GNUTLS)
183 
MD5_Init(MD5_CTX * ctx)184 static int MD5_Init(MD5_CTX *ctx)
185 {
186   gcry_md_open(ctx, GCRY_MD_MD5, 0);
187   return 1;
188 }
189 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)190 static void MD5_Update(MD5_CTX *ctx,
191                        const unsigned char *input,
192                        unsigned int inputLen)
193 {
194   gcry_md_write(*ctx, input, inputLen);
195 }
196 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)197 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
198 {
199   memcpy(digest, gcry_md_read(*ctx, 0), 16);
200   gcry_md_close(*ctx);
201 }
202 
SHA1_Init(SHA_CTX * ctx)203 static int SHA1_Init(SHA_CTX *ctx)
204 {
205   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
206   return 1;
207 }
208 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)209 static void SHA1_Update(SHA_CTX *ctx,
210                         const unsigned char *input,
211                         unsigned int inputLen)
212 {
213   gcry_md_write(*ctx, input, inputLen);
214 }
215 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)216 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
217 {
218   memcpy(digest, gcry_md_read(*ctx, 0), 20);
219   gcry_md_close(*ctx);
220 }
221 
SHA256_Init(SHA256_CTX * ctx)222 static int SHA256_Init(SHA256_CTX *ctx)
223 {
224   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
225   return 1;
226 }
227 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)228 static void SHA256_Update(SHA256_CTX *ctx,
229                           const unsigned char *input,
230                           unsigned int inputLen)
231 {
232   gcry_md_write(*ctx, input, inputLen);
233 }
234 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)235 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
236 {
237   memcpy(digest, gcry_md_read(*ctx, 0), 32);
238   gcry_md_close(*ctx);
239 }
240 
241 #elif defined(USE_NSS)
242 
nss_hash_init(void ** pctx,SECOidTag hash_alg)243 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
244 {
245   PK11Context *ctx;
246 
247   /* we have to initialize NSS if not initialized already */
248   if(!NSS_IsInitialized() && !nss_context) {
249     static NSSInitParameters params;
250     params.length = sizeof(params);
251     nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
252         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
253         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
254   }
255 
256   ctx = PK11_CreateDigestContext(hash_alg);
257   if(!ctx)
258     return /* failure */ 0;
259 
260   if(PK11_DigestBegin(ctx) != SECSuccess) {
261     PK11_DestroyContext(ctx, PR_TRUE);
262     return /* failure */ 0;
263   }
264 
265   *pctx = ctx;
266   return /* success */ 1;
267 }
268 
nss_hash_final(void ** pctx,unsigned char * out,unsigned int len)269 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
270 {
271   PK11Context *ctx = *pctx;
272   unsigned int outlen;
273   PK11_DigestFinal(ctx, out, &outlen, len);
274   PK11_DestroyContext(ctx, PR_TRUE);
275 }
276 
MD5_Init(MD5_CTX * pctx)277 static int MD5_Init(MD5_CTX *pctx)
278 {
279   return nss_hash_init(pctx, SEC_OID_MD5);
280 }
281 
MD5_Update(MD5_CTX * pctx,const unsigned char * input,unsigned int input_len)282 static void MD5_Update(MD5_CTX *pctx,
283                        const unsigned char *input,
284                        unsigned int input_len)
285 {
286   PK11_DigestOp(*pctx, input, input_len);
287 }
288 
MD5_Final(unsigned char digest[16],MD5_CTX * pctx)289 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
290 {
291   nss_hash_final(pctx, digest, 16);
292 }
293 
SHA1_Init(SHA_CTX * pctx)294 static int SHA1_Init(SHA_CTX *pctx)
295 {
296   return nss_hash_init(pctx, SEC_OID_SHA1);
297 }
298 
SHA1_Update(SHA_CTX * pctx,const unsigned char * input,unsigned int input_len)299 static void SHA1_Update(SHA_CTX *pctx,
300                         const unsigned char *input,
301                         unsigned int input_len)
302 {
303   PK11_DigestOp(*pctx, input, input_len);
304 }
305 
SHA1_Final(unsigned char digest[20],SHA_CTX * pctx)306 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
307 {
308   nss_hash_final(pctx, digest, 20);
309 }
310 
SHA256_Init(SHA256_CTX * pctx)311 static int SHA256_Init(SHA256_CTX *pctx)
312 {
313   return nss_hash_init(pctx, SEC_OID_SHA256);
314 }
315 
SHA256_Update(SHA256_CTX * pctx,const unsigned char * input,unsigned int input_len)316 static void SHA256_Update(SHA256_CTX *pctx,
317                           const unsigned char *input,
318                           unsigned int input_len)
319 {
320   PK11_DigestOp(*pctx, input, input_len);
321 }
322 
SHA256_Final(unsigned char digest[32],SHA256_CTX * pctx)323 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
324 {
325   nss_hash_final(pctx, digest, 32);
326 }
327 
328 #elif defined(USE_POLARSSL)
329 
MD5_Init(MD5_CTX * ctx)330 static int MD5_Init(MD5_CTX *ctx)
331 {
332   md5_starts(ctx);
333   return 1;
334 }
335 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)336 static void MD5_Update(MD5_CTX *ctx,
337                        const unsigned char *input,
338                        unsigned int inputLen)
339 {
340   md5_update(ctx, input, inputLen);
341 }
342 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)343 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
344 {
345   md5_finish(ctx, digest);
346 }
347 
SHA1_Init(SHA_CTX * ctx)348 static int SHA1_Init(SHA_CTX *ctx)
349 {
350   sha1_starts(ctx);
351   return 1;
352 }
353 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)354 static void SHA1_Update(SHA_CTX *ctx,
355                         const unsigned char *input,
356                         unsigned int inputLen)
357 {
358   sha1_update(ctx, input, inputLen);
359 }
360 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)361 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
362 {
363   sha1_finish(ctx, digest);
364 }
365 
SHA256_Init(SHA256_CTX * ctx)366 static int SHA256_Init(SHA256_CTX *ctx)
367 {
368   sha256_starts(ctx, 0); /* 0 = sha256 */
369   return 1;
370 }
371 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)372 static void SHA256_Update(SHA256_CTX *ctx,
373                           const unsigned char *input,
374                           unsigned int inputLen)
375 {
376   sha256_update(ctx, input, inputLen);
377 }
378 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)379 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
380 {
381   sha256_finish(ctx, digest);
382 }
383 
384 #elif defined(WIN32)
385 
win32_crypto_final(struct win32_crypto_hash * ctx,unsigned char * digest,unsigned int digestLen)386 static void win32_crypto_final(struct win32_crypto_hash *ctx,
387                                unsigned char *digest,
388                                unsigned int digestLen)
389 {
390   unsigned long length;
391   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
392   if(length == digestLen)
393     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
394   if(ctx->hHash)
395     CryptDestroyHash(ctx->hHash);
396   if(ctx->hCryptProv)
397     CryptReleaseContext(ctx->hCryptProv, 0);
398 }
399 
MD5_Init(MD5_CTX * ctx)400 static int MD5_Init(MD5_CTX *ctx)
401 {
402   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
403                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
404     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
405   }
406   return 1;
407 }
408 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)409 static void MD5_Update(MD5_CTX *ctx,
410                        const unsigned char *input,
411                        unsigned int inputLen)
412 {
413   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
414 }
415 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)416 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
417 {
418   win32_crypto_final(ctx, digest, 16);
419 }
420 
SHA1_Init(SHA_CTX * ctx)421 static int SHA1_Init(SHA_CTX *ctx)
422 {
423   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
424                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
425     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
426   }
427   return 1;
428 }
429 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)430 static void SHA1_Update(SHA_CTX *ctx,
431                         const unsigned char *input,
432                         unsigned int inputLen)
433 {
434   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
435 }
436 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)437 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
438 {
439   win32_crypto_final(ctx, digest, 20);
440 }
441 
SHA256_Init(SHA256_CTX * ctx)442 static int SHA256_Init(SHA256_CTX *ctx)
443 {
444   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
445                          PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
446     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
447   }
448   return 1;
449 }
450 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)451 static void SHA256_Update(SHA256_CTX *ctx,
452                           const unsigned char *input,
453                           unsigned int inputLen)
454 {
455   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
456 }
457 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)458 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
459 {
460   win32_crypto_final(ctx, digest, 32);
461 }
462 
463 #endif /* CRYPTO LIBS */
464 
465 const digest_params MD5_DIGEST_PARAMS[] = {
466   {
467     CURLX_FUNCTION_CAST(Curl_digest_init_func, MD5_Init),
468     CURLX_FUNCTION_CAST(Curl_digest_update_func, MD5_Update),
469     CURLX_FUNCTION_CAST(Curl_digest_final_func, MD5_Final),
470     sizeof(MD5_CTX),
471     16
472   }
473 };
474 
475 const digest_params SHA1_DIGEST_PARAMS[] = {
476   {
477     CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA1_Init),
478     CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA1_Update),
479     CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA1_Final),
480     sizeof(SHA_CTX),
481     20
482   }
483 };
484 
485 const digest_params SHA256_DIGEST_PARAMS[] = {
486   {
487     CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA256_Init),
488     CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA256_Update),
489     CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA256_Final),
490     sizeof(SHA256_CTX),
491     32
492   }
493 };
494 
495 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
496   {"sha-256", SHA256_DIGEST_PARAMS}
497 };
498 
499 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
500   {"sha-1", SHA1_DIGEST_PARAMS}
501 };
502 
503 static const metalink_digest_def MD5_DIGEST_DEF[] = {
504   {"md5", MD5_DIGEST_PARAMS}
505 };
506 
507 /*
508  * The alias of supported hash functions in the order by preference
509  * (basically stronger hash comes first). We included "sha-256" and
510  * "sha256". The former is the name defined in the IANA registry named
511  * "Hash Function Textual Names". The latter is widely (and
512  * historically) used in Metalink version 3.
513  */
514 static const metalink_digest_alias digest_aliases[] = {
515   {"sha-256", SHA256_DIGEST_DEF},
516   {"sha256", SHA256_DIGEST_DEF},
517   {"sha-1", SHA1_DIGEST_DEF},
518   {"sha1", SHA1_DIGEST_DEF},
519   {"md5", MD5_DIGEST_DEF},
520   {NULL, NULL}
521 };
522 
Curl_digest_init(const digest_params * dparams)523 digest_context *Curl_digest_init(const digest_params *dparams)
524 {
525   digest_context *ctxt;
526 
527   /* Create digest context */
528   ctxt = malloc(sizeof(*ctxt));
529 
530   if(!ctxt)
531     return ctxt;
532 
533   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
534 
535   if(!ctxt->digest_hashctx) {
536     free(ctxt);
537     return NULL;
538   }
539 
540   ctxt->digest_hash = dparams;
541 
542   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
543     free(ctxt->digest_hashctx);
544     free(ctxt);
545     return NULL;
546   }
547 
548   return ctxt;
549 }
550 
Curl_digest_update(digest_context * context,const unsigned char * data,unsigned int len)551 int Curl_digest_update(digest_context *context,
552                        const unsigned char *data,
553                        unsigned int len)
554 {
555   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
556 
557   return 0;
558 }
559 
Curl_digest_final(digest_context * context,unsigned char * result)560 int Curl_digest_final(digest_context *context, unsigned char *result)
561 {
562   if(result)
563     (*context->digest_hash->digest_final)(result, context->digest_hashctx);
564 
565   free(context->digest_hashctx);
566   free(context);
567 
568   return 0;
569 }
570 
hex_to_uint(const char * s)571 static unsigned char hex_to_uint(const char *s)
572 {
573   char buf[3];
574   unsigned long val;
575   buf[0] = s[0];
576   buf[1] = s[1];
577   buf[2] = 0;
578   val = strtoul(buf, NULL, 16);
579   return (unsigned char)(val&0xff);
580 }
581 
582 /*
583  * Check checksum of file denoted by filename. The expected hash value
584  * is given in hex_hash which is hex-encoded string.
585  *
586  * This function returns 1 if it succeeds or one of the following
587  * integers:
588  *
589  * 0:
590  *   Checksum didn't match.
591  * -1:
592  *   Could not open file; or could not read data from file.
593  * -2:
594  *   Hash algorithm not available.
595  */
check_hash(const char * filename,const metalink_digest_def * digest_def,const unsigned char * digest,FILE * error)596 static int check_hash(const char *filename,
597                       const metalink_digest_def *digest_def,
598                       const unsigned char *digest, FILE *error)
599 {
600   unsigned char *result;
601   digest_context *dctx;
602   int check_ok, flags, fd;
603 
604   flags = O_RDONLY;
605 #ifdef O_BINARY
606   /* O_BINARY is required in order to avoid binary EOF in text mode */
607   flags |= O_BINARY;
608 #endif
609 
610   fd = open(filename, flags);
611   if(fd == -1) {
612     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
613             digest_def->hash_name, strerror(errno));
614     return -1;
615   }
616 
617   dctx = Curl_digest_init(digest_def->dparams);
618   if(!dctx) {
619     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
620             digest_def->hash_name, "failed to initialize hash algorithm");
621     close(fd);
622     return -2;
623   }
624 
625   result = malloc(digest_def->dparams->digest_resultlen);
626   if(!result) {
627     close(fd);
628     Curl_digest_final(dctx, NULL);
629     return -1;
630   }
631   while(1) {
632     unsigned char buf[4096];
633     ssize_t len = read(fd, buf, sizeof(buf));
634     if(len == 0) {
635       break;
636     }
637     else if(len == -1) {
638       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
639               digest_def->hash_name, strerror(errno));
640       Curl_digest_final(dctx, result);
641       close(fd);
642       return -1;
643     }
644     Curl_digest_update(dctx, buf, (unsigned int)len);
645   }
646   Curl_digest_final(dctx, result);
647   check_ok = memcmp(result, digest,
648                     digest_def->dparams->digest_resultlen) == 0;
649   /* sha*sum style verdict output */
650   if(check_ok)
651     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
652             digest_def->hash_name);
653   else
654     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
655             filename, digest_def->hash_name);
656 
657   free(result);
658   close(fd);
659   return check_ok;
660 }
661 
metalink_check_hash(struct GlobalConfig * config,metalinkfile * mlfile,const char * filename)662 int metalink_check_hash(struct GlobalConfig *config,
663                         metalinkfile *mlfile,
664                         const char *filename)
665 {
666   int rv;
667   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
668   if(mlfile->checksum == NULL) {
669     fprintf(config->errors,
670             "Metalink: validating (%s) FAILED (digest missing)\n", filename);
671     return -2;
672   }
673   rv = check_hash(filename, mlfile->checksum->digest_def,
674                   mlfile->checksum->digest, config->errors);
675   return rv;
676 }
677 
678 static metalink_checksum *
checksum_from_hex_digest(const metalink_digest_def * digest_def,const char * hex_digest)679 checksum_from_hex_digest(const metalink_digest_def *digest_def,
680                          const char *hex_digest)
681 {
682   metalink_checksum *chksum;
683   unsigned char *digest;
684   size_t i;
685   size_t len = strlen(hex_digest);
686   digest = malloc(len/2);
687   if(!digest)
688     return 0;
689 
690   for(i = 0; i < len; i += 2) {
691     digest[i/2] = hex_to_uint(hex_digest + i);
692   }
693   chksum = malloc(sizeof(metalink_checksum));
694   if(chksum) {
695     chksum->digest_def = digest_def;
696     chksum->digest = digest;
697   }
698   else
699     free(digest);
700   return chksum;
701 }
702 
new_metalink_resource(const char * url)703 static metalink_resource *new_metalink_resource(const char *url)
704 {
705   metalink_resource *res;
706   res = malloc(sizeof(metalink_resource));
707   if(res) {
708     res->next = NULL;
709     res->url = strdup(url);
710     if(!res->url) {
711       free(res);
712       return NULL;
713     }
714   }
715   return res;
716 }
717 
718 /* Returns nonzero if hex_digest is properly formatted; that is each
719    letter is in [0-9A-Za-z] and the length of the string equals to the
720    result length of digest * 2. */
check_hex_digest(const char * hex_digest,const metalink_digest_def * digest_def)721 static int check_hex_digest(const char *hex_digest,
722                             const metalink_digest_def *digest_def)
723 {
724   size_t i;
725   for(i = 0; hex_digest[i]; ++i) {
726     char c = hex_digest[i];
727     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
728          ('A' <= c && c <= 'Z'))) {
729       return 0;
730     }
731   }
732   return digest_def->dparams->digest_resultlen * 2 == i;
733 }
734 
new_metalinkfile(metalink_file_t * fileinfo)735 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
736 {
737   metalinkfile *f;
738   f = (metalinkfile*)malloc(sizeof(metalinkfile));
739   if(!f)
740     return NULL;
741 
742   f->next = NULL;
743   f->filename = strdup(fileinfo->name);
744   if(!f->filename) {
745     free(f);
746     return NULL;
747   }
748   f->checksum = NULL;
749   f->resource = NULL;
750   if(fileinfo->checksums) {
751     const metalink_digest_alias *digest_alias;
752     for(digest_alias = digest_aliases; digest_alias->alias_name;
753         ++digest_alias) {
754       metalink_checksum_t **p;
755       for(p = fileinfo->checksums; *p; ++p) {
756         if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
757            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
758           f->checksum =
759             checksum_from_hex_digest(digest_alias->digest_def,
760                                      (*p)->hash);
761           break;
762         }
763       }
764       if(f->checksum) {
765         break;
766       }
767     }
768   }
769   if(fileinfo->resources) {
770     metalink_resource_t **p;
771     metalink_resource root, *tail;
772     root.next = NULL;
773     tail = &root;
774     for(p = fileinfo->resources; *p; ++p) {
775       metalink_resource *res;
776       /* Filter by type if it is non-NULL. In Metalink v3, type
777          includes the type of the resource. In curl, we are only
778          interested in HTTP, HTTPS and FTP. In addition to them,
779          Metalink v3 file may contain bittorrent type URL, which
780          points to the BitTorrent metainfo file. We ignore it here.
781          In Metalink v4, type was deprecated and all
782          fileinfo->resources point to the target file. BitTorrent
783          metainfo file URL may be appeared in fileinfo->metaurls.
784       */
785       if((*p)->type == NULL ||
786          curl_strequal((*p)->type, "http") ||
787          curl_strequal((*p)->type, "https") ||
788          curl_strequal((*p)->type, "ftp") ||
789          curl_strequal((*p)->type, "ftps")) {
790         res = new_metalink_resource((*p)->url);
791         if(res) {
792           tail->next = res;
793           tail = res;
794         }
795         else {
796           tail = root.next;
797 
798           /* clean up the linked list */
799           while(tail) {
800             res = tail->next;
801             free(tail->url);
802             free(tail);
803             tail = res;
804           }
805           free(f->filename);
806           free(f);
807           return NULL;
808         }
809       }
810     }
811     f->resource = root.next;
812   }
813   return f;
814 }
815 
parse_metalink(struct OperationConfig * config,struct OutStruct * outs,const char * metalink_url)816 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
817                    const char *metalink_url)
818 {
819   metalink_error_t r;
820   metalink_t* metalink;
821   metalink_file_t **files;
822   bool warnings = FALSE;
823 
824   /* metlaink_parse_final deletes outs->metalink_parser */
825   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
826   outs->metalink_parser = NULL;
827   if(r != 0) {
828     return -1;
829   }
830   if(metalink->files == NULL) {
831     fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
832             "(missing or invalid file name)\n",
833             metalink_url);
834     metalink_delete(metalink);
835     return -1;
836   }
837   for(files = metalink->files; *files; ++files) {
838     struct getout *url;
839     /* Skip an entry which has no resource. */
840     if(!(*files)->resources) {
841       fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
842               "(missing or invalid resource)\n",
843               metalink_url);
844       continue;
845     }
846     if(config->url_get ||
847        ((config->url_get = config->url_list) != NULL)) {
848       /* there's a node here, if it already is filled-in continue to
849          find an "empty" node */
850       while(config->url_get && (config->url_get->flags & GETOUT_URL))
851         config->url_get = config->url_get->next;
852     }
853 
854     /* now there might or might not be an available node to fill in! */
855 
856     if(config->url_get)
857       /* existing node */
858       url = config->url_get;
859     else
860       /* there was no free node, create one! */
861       url = new_getout(config);
862 
863     if(url) {
864       metalinkfile *mlfile = new_metalinkfile(*files);
865       if(!mlfile)
866         break;
867 
868       if(!mlfile->checksum) {
869         warnings = TRUE;
870         fprintf(config->global->errors,
871                 "Metalink: parsing (%s) WARNING (digest missing)\n",
872                 metalink_url);
873       }
874       /* Set name as url */
875       GetStr(&url->url, mlfile->filename);
876 
877       /* set flag metalink here */
878       url->flags |= GETOUT_URL | GETOUT_METALINK;
879 
880       if(config->metalinkfile_list) {
881         config->metalinkfile_last->next = mlfile;
882         config->metalinkfile_last = mlfile;
883       }
884       else {
885         config->metalinkfile_list = config->metalinkfile_last = mlfile;
886       }
887     }
888   }
889   metalink_delete(metalink);
890   return (warnings) ? -2 : 0;
891 }
892 
metalink_write_cb(void * buffer,size_t sz,size_t nmemb,void * userdata)893 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
894                          void *userdata)
895 {
896   struct per_transfer *per = userdata;
897   struct OutStruct *outs = &per->outs;
898   struct OperationConfig *config = outs->config;
899   int rv;
900 
901   /*
902    * Once that libcurl has called back tool_write_cb() the returned value
903    * is checked against the amount that was intended to be written, if
904    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
905    * point returning a value different from sz*nmemb indicates failure.
906    */
907   const size_t failure = (sz && nmemb) ? 0 : 1;
908 
909   if(!config)
910     return failure;
911 
912   rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb);
913   if(rv == 0)
914     return sz * nmemb;
915   else {
916     fprintf(config->global->errors, "Metalink: parsing FAILED\n");
917     return failure;
918   }
919 }
920 
921 /*
922  * Returns nonzero if content_type includes mediatype.
923  */
check_content_type(const char * content_type,const char * media_type)924 static int check_content_type(const char *content_type, const char *media_type)
925 {
926   const char *ptr = content_type;
927   size_t media_type_len = strlen(media_type);
928   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
929   if(!*ptr) {
930     return 0;
931   }
932   return curl_strnequal(ptr, media_type, media_type_len) &&
933     (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' ||
934      *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';');
935 }
936 
check_metalink_content_type(const char * content_type)937 int check_metalink_content_type(const char *content_type)
938 {
939   return check_content_type(content_type, "application/metalink+xml");
940 }
941 
count_next_metalink_resource(metalinkfile * mlfile)942 int count_next_metalink_resource(metalinkfile *mlfile)
943 {
944   int count = 0;
945   metalink_resource *res;
946   for(res = mlfile->resource; res; res = res->next, ++count);
947   return count;
948 }
949 
delete_metalink_checksum(metalink_checksum * chksum)950 static void delete_metalink_checksum(metalink_checksum *chksum)
951 {
952   if(chksum == NULL) {
953     return;
954   }
955   Curl_safefree(chksum->digest);
956   Curl_safefree(chksum);
957 }
958 
delete_metalink_resource(metalink_resource * res)959 static void delete_metalink_resource(metalink_resource *res)
960 {
961   if(res == NULL) {
962     return;
963   }
964   Curl_safefree(res->url);
965   Curl_safefree(res);
966 }
967 
delete_metalinkfile(metalinkfile * mlfile)968 void delete_metalinkfile(metalinkfile *mlfile)
969 {
970   metalink_resource *res;
971   if(mlfile == NULL) {
972     return;
973   }
974   Curl_safefree(mlfile->filename);
975   delete_metalink_checksum(mlfile->checksum);
976   for(res = mlfile->resource; res;) {
977     metalink_resource *next;
978     next = res->next;
979     delete_metalink_resource(res);
980     res = next;
981   }
982   Curl_safefree(mlfile);
983 }
984 
clean_metalink(struct OperationConfig * config)985 void clean_metalink(struct OperationConfig *config)
986 {
987   if(config) {
988     while(config->metalinkfile_list) {
989       metalinkfile *mlfile = config->metalinkfile_list;
990       config->metalinkfile_list = config->metalinkfile_list->next;
991       delete_metalinkfile(mlfile);
992     }
993     config->metalinkfile_last = 0;
994   }
995 }
996 
metalink_cleanup(void)997 void metalink_cleanup(void)
998 {
999 #ifdef HAVE_NSS_CONTEXT
1000   if(nss_context) {
1001     NSS_ShutdownContext(nss_context);
1002     nss_context = NULL;
1003   }
1004 #endif
1005 }
1006 
1007 #endif /* USE_METALINK */
1008