1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
22 #include "tool_setup.h"
38 # include <openssl/md5.h>
39 # include <openssl/sha.h>
44 #elif defined(USE_GNUTLS_NETTLE)
45 # include <nettle/md5.h>
46 # include <nettle/sha.h>
47 # define MD5_CTX struct md5_ctx
48 # define SHA_CTX struct sha1_ctx
49 # define SHA256_CTX struct sha256_ctx
50 #elif defined(USE_GNUTLS)
52 # define MD5_CTX gcry_md_hd_t
53 # define SHA_CTX gcry_md_hd_t
54 # define SHA256_CTX gcry_md_hd_t
55 #elif defined(USE_DARWINSSL)
56 /* For darwinssl: CommonCrypto has the functions we need. The library's
57 headers are even backward-compatible with OpenSSL's headers as long as
58 we define COMMON_DIGEST_FOR_OPENSSL first.
60 These functions are available on Tiger and later, as well as iOS 5.0
61 and later. If you're building for an older cat, well, sorry. */
62 # define COMMON_DIGEST_FOR_OPENSSL
63 # include <CommonCrypto/CommonDigest.h>
65 /* For Windows: If no other crypto library is provided, we fallback
66 to the hash functions provided within the Microsoft Windows CryptoAPI */
67 # include <wincrypt.h>
68 /* Custom structure in order to store the required provider and hash handle */
69 struct win32_crypto_hash {
70 HCRYPTPROV hCryptProv;
73 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
74 # ifndef ALG_SID_SHA_256
75 # define ALG_SID_SHA_256 12
78 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
80 # define MD5_CTX struct win32_crypto_hash
81 # define SHA_CTX struct win32_crypto_hash
82 # define SHA256_CTX struct win32_crypto_hash
84 # error "Can't compile METALINK support without a crypto library."
89 #define ENABLE_CURLX_PRINTF
90 /* use our own printf() functions */
93 #include "tool_getparam.h"
94 #include "tool_paramhlp.h"
95 #include "tool_cfgable.h"
96 #include "tool_metalink.h"
97 #include "tool_msgs.h"
99 #include "memdebug.h" /* keep this as LAST include */
101 /* Copied from tool_getparam.c */
102 #define GetStr(str,val) do { \
108 *(str) = strdup((val)); \
110 return PARAM_NO_MEM; \
113 #ifdef USE_GNUTLS_NETTLE
115 static void MD5_Init(MD5_CTX *ctx)
120 static void MD5_Update(MD5_CTX *ctx,
121 const unsigned char *input,
122 unsigned int inputLen)
124 md5_update(ctx, inputLen, input);
127 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
129 md5_digest(ctx, 16, digest);
132 static void SHA1_Init(SHA_CTX *ctx)
137 static void SHA1_Update(SHA_CTX *ctx,
138 const unsigned char *input,
139 unsigned int inputLen)
141 sha1_update(ctx, inputLen, input);
144 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
146 sha1_digest(ctx, 20, digest);
149 static void SHA256_Init(SHA256_CTX *ctx)
154 static void SHA256_Update(SHA256_CTX *ctx,
155 const unsigned char *input,
156 unsigned int inputLen)
158 sha256_update(ctx, inputLen, input);
161 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
163 sha256_digest(ctx, 32, digest);
166 #elif defined(USE_GNUTLS)
168 static void MD5_Init(MD5_CTX *ctx)
170 gcry_md_open(ctx, GCRY_MD_MD5, 0);
173 static void MD5_Update(MD5_CTX *ctx,
174 const unsigned char *input,
175 unsigned int inputLen)
177 gcry_md_write(*ctx, input, inputLen);
180 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
182 memcpy(digest, gcry_md_read(*ctx, 0), 16);
186 static void SHA1_Init(SHA_CTX *ctx)
188 gcry_md_open(ctx, GCRY_MD_SHA1, 0);
191 static void SHA1_Update(SHA_CTX *ctx,
192 const unsigned char *input,
193 unsigned int inputLen)
195 gcry_md_write(*ctx, input, inputLen);
198 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
200 memcpy(digest, gcry_md_read(*ctx, 0), 20);
204 static void SHA256_Init(SHA256_CTX *ctx)
206 gcry_md_open(ctx, GCRY_MD_SHA256, 0);
209 static void SHA256_Update(SHA256_CTX *ctx,
210 const unsigned char *input,
211 unsigned int inputLen)
213 gcry_md_write(*ctx, input, inputLen);
216 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
218 memcpy(digest, gcry_md_read(*ctx, 0), 32);
222 #elif defined(_WIN32) && !defined(USE_SSLEAY)
224 static void win32_crypto_final(struct win32_crypto_hash *ctx,
225 unsigned char *digest,
226 unsigned int digestLen)
228 unsigned long length;
229 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
230 if(length == digestLen)
231 CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
233 CryptDestroyHash(ctx->hHash);
235 CryptReleaseContext(ctx->hCryptProv, 0);
238 static void MD5_Init(MD5_CTX *ctx)
240 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
241 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
242 CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
246 static void MD5_Update(MD5_CTX *ctx,
247 const unsigned char *input,
248 unsigned int inputLen)
250 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
253 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
255 win32_crypto_final(ctx, digest, 16);
258 static void SHA1_Init(SHA_CTX *ctx)
260 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
261 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
262 CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
266 static void SHA1_Update(SHA_CTX *ctx,
267 const unsigned char *input,
268 unsigned int inputLen)
270 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
273 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
275 win32_crypto_final(ctx, digest, 20);
278 static void SHA256_Init(SHA256_CTX *ctx)
280 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
281 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
282 CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
286 static void SHA256_Update(SHA256_CTX *ctx,
287 const unsigned char *input,
288 unsigned int inputLen)
290 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
293 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
295 win32_crypto_final(ctx, digest, 32);
298 #endif /* CRYPTO LIBS */
300 const digest_params MD5_DIGEST_PARAMS[] = {
302 (Curl_digest_init_func) MD5_Init,
303 (Curl_digest_update_func) MD5_Update,
304 (Curl_digest_final_func) MD5_Final,
310 const digest_params SHA1_DIGEST_PARAMS[] = {
312 (Curl_digest_init_func) SHA1_Init,
313 (Curl_digest_update_func) SHA1_Update,
314 (Curl_digest_final_func) SHA1_Final,
320 const digest_params SHA256_DIGEST_PARAMS[] = {
322 (Curl_digest_init_func) SHA256_Init,
323 (Curl_digest_update_func) SHA256_Update,
324 (Curl_digest_final_func) SHA256_Final,
330 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
331 {"sha-256", SHA256_DIGEST_PARAMS}
334 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
335 {"sha-1", SHA1_DIGEST_PARAMS}
338 static const metalink_digest_def MD5_DIGEST_DEF[] = {
339 {"md5", MD5_DIGEST_PARAMS}
343 * The alias of supported hash functions in the order by preference
344 * (basically stronger hash comes first). We included "sha-256" and
345 * "sha256". The former is the name defined in the IANA registry named
346 * "Hash Function Textual Names". The latter is widely (and
347 * historically) used in Metalink version 3.
349 static const metalink_digest_alias digest_aliases[] = {
350 {"sha-256", SHA256_DIGEST_DEF},
351 {"sha256", SHA256_DIGEST_DEF},
352 {"sha-1", SHA1_DIGEST_DEF},
353 {"sha1", SHA1_DIGEST_DEF},
354 {"md5", MD5_DIGEST_DEF},
358 digest_context *Curl_digest_init(const digest_params *dparams)
360 digest_context *ctxt;
362 /* Create digest context */
363 ctxt = malloc(sizeof *ctxt);
368 ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
370 if(!ctxt->digest_hashctx) {
375 ctxt->digest_hash = dparams;
377 dparams->digest_init(ctxt->digest_hashctx);
382 int Curl_digest_update(digest_context *context,
383 const unsigned char *data,
386 (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
391 int Curl_digest_final(digest_context *context, unsigned char *result)
393 (*context->digest_hash->digest_final)(result, context->digest_hashctx);
395 free(context->digest_hashctx);
401 static unsigned char hex_to_uint(const char *s)
405 for(i = 0; i < 2; ++i) {
406 v[i] = Curl_raw_toupper(s[i]);
407 if('0' <= v[i] && v[i] <= '9') {
410 else if('A' <= v[i] && v[i] <= 'Z') {
414 return (unsigned char)((v[0] << 4) | v[1]);
418 * Check checksum of file denoted by filename. The expected hash value
419 * is given in hex_hash which is hex-encoded string.
421 * This function returns 1 if it succeeds or one of the following
425 * Checksum didn't match.
427 * Could not open file; or could not read data from file.
429 static int check_hash(const char *filename,
430 const metalink_digest_def *digest_def,
431 const unsigned char *digest, FILE *error)
433 unsigned char *result;
434 digest_context *dctx;
435 int check_ok, flags, fd;
439 /* O_BINARY is required in order to avoid binary EOF in text mode */
443 fd = open(filename, flags);
445 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
446 digest_def->hash_name, strerror(errno));
449 dctx = Curl_digest_init(digest_def->dparams);
450 result = malloc(digest_def->dparams->digest_resultlen);
452 unsigned char buf[4096];
453 ssize_t len = read(fd, buf, sizeof(buf));
458 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
459 digest_def->hash_name, strerror(errno));
460 Curl_digest_final(dctx, result);
464 Curl_digest_update(dctx, buf, (unsigned int)len);
466 Curl_digest_final(dctx, result);
467 check_ok = memcmp(result, digest,
468 digest_def->dparams->digest_resultlen) == 0;
469 /* sha*sum style verdict output */
471 fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
472 digest_def->hash_name);
474 fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
475 filename, digest_def->hash_name);
482 int metalink_check_hash(struct Configurable *config,
483 metalinkfile *mlfile,
484 const char *filename)
487 fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
488 if(mlfile->checksum == NULL) {
489 fprintf(config->errors,
490 "Metalink: validating (%s) FAILED (digest missing)\n",
494 rv = check_hash(filename, mlfile->checksum->digest_def,
495 mlfile->checksum->digest, config->errors);
499 static metalink_checksum *new_metalink_checksum_from_hex_digest
500 (const metalink_digest_def *digest_def, const char *hex_digest)
502 metalink_checksum *chksum;
503 unsigned char *digest;
505 size_t len = strlen(hex_digest);
506 digest = malloc(len/2);
507 for(i = 0; i < len; i += 2) {
508 digest[i/2] = hex_to_uint(hex_digest+i);
510 chksum = malloc(sizeof(metalink_checksum));
511 chksum->digest_def = digest_def;
512 chksum->digest = digest;
516 static metalink_resource *new_metalink_resource(const char *url)
518 metalink_resource *res;
519 res = malloc(sizeof(metalink_resource));
521 res->url = strdup(url);
525 /* Returns nonzero if hex_digest is properly formatted; that is each
526 letter is in [0-9A-Za-z] and the length of the string equals to the
527 result length of digest * 2. */
528 static int check_hex_digest(const char *hex_digest,
529 const metalink_digest_def *digest_def)
532 for(i = 0; hex_digest[i]; ++i) {
533 char c = hex_digest[i];
534 if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
535 ('A' <= c && c <= 'Z'))) {
539 return digest_def->dparams->digest_resultlen * 2 == i;
542 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
545 f = (metalinkfile*)malloc(sizeof(metalinkfile));
547 f->filename = strdup(fileinfo->name);
550 if(fileinfo->checksums) {
551 const metalink_digest_alias *digest_alias;
552 for(digest_alias = digest_aliases; digest_alias->alias_name;
554 metalink_checksum_t **p;
555 for(p = fileinfo->checksums; *p; ++p) {
556 if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
557 check_hex_digest((*p)->hash, digest_alias->digest_def)) {
559 new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
569 if(fileinfo->resources) {
570 metalink_resource_t **p;
571 metalink_resource root, *tail;
574 for(p = fileinfo->resources; *p; ++p) {
575 metalink_resource *res;
576 /* Filter by type if it is non-NULL. In Metalink v3, type
577 includes the type of the resource. In curl, we are only
578 interested in HTTP, HTTPS and FTP. In addition to them,
579 Metalink v3 file may contain bittorrent type URL, which
580 points to the BitTorrent metainfo file. We ignore it here.
581 In Metalink v4, type was deprecated and all
582 fileinfo->resources point to the target file. BitTorrent
583 metainfo file URL may be appeared in fileinfo->metaurls.
585 if((*p)->type == NULL ||
586 Curl_raw_equal((*p)->type, "http") ||
587 Curl_raw_equal((*p)->type, "https") ||
588 Curl_raw_equal((*p)->type, "ftp") ||
589 Curl_raw_equal((*p)->type, "ftps")) {
590 res = new_metalink_resource((*p)->url);
595 f->resource = root.next;
600 int parse_metalink(struct Configurable *config, struct OutStruct *outs,
601 const char *metalink_url)
604 metalink_t* metalink;
605 metalink_file_t **files;
606 bool warnings = FALSE;
608 /* metlaink_parse_final deletes outs->metalink_parser */
609 r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
610 outs->metalink_parser = NULL;
614 if(metalink->files == NULL) {
615 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
616 "(missing or invalid file name)\n",
618 metalink_delete(metalink);
621 for(files = metalink->files; *files; ++files) {
623 /* Skip an entry which has no resource. */
624 if(!(*files)->resources) {
625 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
626 "(missing or invalid resource)\n",
627 metalink_url, (*files)->name);
630 if(config->url_get ||
631 ((config->url_get = config->url_list) != NULL)) {
632 /* there's a node here, if it already is filled-in continue to
633 find an "empty" node */
634 while(config->url_get && (config->url_get->flags & GETOUT_URL))
635 config->url_get = config->url_get->next;
638 /* now there might or might not be an available node to fill in! */
642 url = config->url_get;
644 /* there was no free node, create one! */
645 url = new_getout(config);
648 metalinkfile *mlfile;
649 mlfile = new_metalinkfile(*files);
650 if(!mlfile->checksum) {
652 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
653 "(digest missing)\n",
656 /* Set name as url */
657 GetStr(&url->url, mlfile->filename);
659 /* set flag metalink here */
660 url->flags |= GETOUT_URL | GETOUT_METALINK;
662 if(config->metalinkfile_list) {
663 config->metalinkfile_last->next = mlfile;
664 config->metalinkfile_last = mlfile;
667 config->metalinkfile_list = config->metalinkfile_last = mlfile;
671 metalink_delete(metalink);
672 return (warnings) ? -2 : 0;
675 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
678 struct OutStruct *outs = userdata;
679 struct Configurable *config = outs->config;
683 * Once that libcurl has called back tool_write_cb() the returned value
684 * is checked against the amount that was intended to be written, if
685 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
686 * point returning a value different from sz*nmemb indicates failure.
688 const size_t failure = (sz * nmemb) ? 0 : 1;
693 rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
697 fprintf(config->errors, "Metalink: parsing FAILED\n");
703 * Returns nonzero if content_type includes mediatype.
705 static int check_content_type(const char *content_type, const char *media_type)
707 const char *ptr = content_type;
708 size_t media_type_len = strlen(media_type);
709 for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
713 return Curl_raw_nequal(ptr, media_type, media_type_len) &&
714 (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
715 *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
718 int check_metalink_content_type(const char *content_type)
720 return check_content_type(content_type, "application/metalink+xml");
723 int count_next_metalink_resource(metalinkfile *mlfile)
726 metalink_resource *res;
727 for(res = mlfile->resource; res; res = res->next, ++count);
731 static void delete_metalink_checksum(metalink_checksum *chksum)
736 Curl_safefree(chksum->digest);
737 Curl_safefree(chksum);
740 static void delete_metalink_resource(metalink_resource *res)
745 Curl_safefree(res->url);
749 static void delete_metalinkfile(metalinkfile *mlfile)
751 metalink_resource *res;
755 Curl_safefree(mlfile->filename);
756 delete_metalink_checksum(mlfile->checksum);
757 for(res = mlfile->resource; res;) {
758 metalink_resource *next;
760 delete_metalink_resource(res);
763 Curl_safefree(mlfile);
766 void clean_metalink(struct Configurable *config)
768 while(config->metalinkfile_list) {
769 metalinkfile *mlfile = config->metalinkfile_list;
770 config->metalinkfile_list = config->metalinkfile_list->next;
771 delete_metalinkfile(mlfile);
773 config->metalinkfile_last = 0;
776 #endif /* USE_METALINK */