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"
34 # include <openssl/md5.h>
35 # include <openssl/sha.h>
40 #elif defined(USE_GNUTLS_NETTLE)
41 # include <nettle/md5.h>
42 # include <nettle/sha.h>
43 # define MD5_CTX struct md5_ctx
44 # define SHA_CTX struct sha1_ctx
45 # define SHA256_CTX struct sha256_ctx
46 #elif defined(USE_GNUTLS)
48 # define MD5_CTX gcry_md_hd_t
49 # define SHA_CTX gcry_md_hd_t
50 # define SHA256_CTX gcry_md_hd_t
51 #elif defined(USE_NSS)
54 # define MD5_CTX void *
55 # define SHA_CTX void *
56 # define SHA256_CTX void *
57 static NSSInitContext *nss_context;
58 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
59 (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
60 (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
61 (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
62 /* For Apple operating systems: CommonCrypto has the functions we need.
63 The library's headers are even backward-compatible with OpenSSL's
64 headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
66 These functions are available on Tiger and later, as well as iOS 2.0
67 and later. If you're building for an older cat, well, sorry. */
68 # define COMMON_DIGEST_FOR_OPENSSL
69 # include <CommonCrypto/CommonDigest.h>
71 /* For Windows: If no other crypto library is provided, we fallback
72 to the hash functions provided within the Microsoft Windows CryptoAPI */
73 # include <wincrypt.h>
74 /* Custom structure in order to store the required provider and hash handle */
75 struct win32_crypto_hash {
76 HCRYPTPROV hCryptProv;
79 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
80 # ifndef ALG_SID_SHA_256
81 # define ALG_SID_SHA_256 12
84 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
86 # define MD5_CTX struct win32_crypto_hash
87 # define SHA_CTX struct win32_crypto_hash
88 # define SHA256_CTX struct win32_crypto_hash
90 # error "Can't compile METALINK support without a crypto library."
95 #define ENABLE_CURLX_PRINTF
96 /* use our own printf() functions */
99 #include "tool_getparam.h"
100 #include "tool_paramhlp.h"
101 #include "tool_cfgable.h"
102 #include "tool_metalink.h"
103 #include "tool_msgs.h"
105 #include "memdebug.h" /* keep this as LAST include */
107 /* Copied from tool_getparam.c */
108 #define GetStr(str,val) do { \
114 *(str) = strdup((val)); \
116 return PARAM_NO_MEM; \
119 #ifdef USE_GNUTLS_NETTLE
121 static int MD5_Init(MD5_CTX *ctx)
127 static void MD5_Update(MD5_CTX *ctx,
128 const unsigned char *input,
129 unsigned int inputLen)
131 md5_update(ctx, inputLen, input);
134 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
136 md5_digest(ctx, 16, digest);
139 static int SHA1_Init(SHA_CTX *ctx)
145 static void SHA1_Update(SHA_CTX *ctx,
146 const unsigned char *input,
147 unsigned int inputLen)
149 sha1_update(ctx, inputLen, input);
152 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
154 sha1_digest(ctx, 20, digest);
157 static int SHA256_Init(SHA256_CTX *ctx)
163 static void SHA256_Update(SHA256_CTX *ctx,
164 const unsigned char *input,
165 unsigned int inputLen)
167 sha256_update(ctx, inputLen, input);
170 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
172 sha256_digest(ctx, 32, digest);
175 #elif defined(USE_GNUTLS)
177 static int MD5_Init(MD5_CTX *ctx)
179 gcry_md_open(ctx, GCRY_MD_MD5, 0);
183 static void MD5_Update(MD5_CTX *ctx,
184 const unsigned char *input,
185 unsigned int inputLen)
187 gcry_md_write(*ctx, input, inputLen);
190 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
192 memcpy(digest, gcry_md_read(*ctx, 0), 16);
196 static int SHA1_Init(SHA_CTX *ctx)
198 gcry_md_open(ctx, GCRY_MD_SHA1, 0);
202 static void SHA1_Update(SHA_CTX *ctx,
203 const unsigned char *input,
204 unsigned int inputLen)
206 gcry_md_write(*ctx, input, inputLen);
209 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
211 memcpy(digest, gcry_md_read(*ctx, 0), 20);
215 static int SHA256_Init(SHA256_CTX *ctx)
217 gcry_md_open(ctx, GCRY_MD_SHA256, 0);
221 static void SHA256_Update(SHA256_CTX *ctx,
222 const unsigned char *input,
223 unsigned int inputLen)
225 gcry_md_write(*ctx, input, inputLen);
228 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
230 memcpy(digest, gcry_md_read(*ctx, 0), 32);
234 #elif defined(USE_NSS)
236 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
240 /* we have to initialize NSS if not initialized alraedy */
241 if(!NSS_IsInitialized() && !nss_context) {
242 static NSSInitParameters params;
243 params.length = sizeof params;
244 nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY
245 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
246 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
249 ctx = PK11_CreateDigestContext(hash_alg);
251 return /* failure */ 0;
253 if(PK11_DigestBegin(ctx) != SECSuccess) {
254 PK11_DestroyContext(ctx, PR_TRUE);
255 return /* failure */ 0;
259 return /* success */ 1;
262 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
264 PK11Context *ctx = *pctx;
266 PK11_DigestFinal(ctx, out, &outlen, len);
267 PK11_DestroyContext(ctx, PR_TRUE);
270 static int MD5_Init(MD5_CTX *pctx)
272 return nss_hash_init(pctx, SEC_OID_MD5);
275 static void MD5_Update(MD5_CTX *pctx,
276 const unsigned char *input,
277 unsigned int input_len)
279 PK11_DigestOp(*pctx, input, input_len);
282 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
284 nss_hash_final(pctx, digest, 16);
287 static int SHA1_Init(SHA_CTX *pctx)
289 return nss_hash_init(pctx, SEC_OID_SHA1);
292 static void SHA1_Update(SHA_CTX *pctx,
293 const unsigned char *input,
294 unsigned int input_len)
296 PK11_DigestOp(*pctx, input, input_len);
299 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
301 nss_hash_final(pctx, digest, 20);
304 static int SHA256_Init(SHA256_CTX *pctx)
306 return nss_hash_init(pctx, SEC_OID_SHA256);
309 static void SHA256_Update(SHA256_CTX *pctx,
310 const unsigned char *input,
311 unsigned int input_len)
313 PK11_DigestOp(*pctx, input, input_len);
316 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
318 nss_hash_final(pctx, digest, 32);
321 #elif defined(_WIN32) && !defined(USE_SSLEAY)
323 static void win32_crypto_final(struct win32_crypto_hash *ctx,
324 unsigned char *digest,
325 unsigned int digestLen)
327 unsigned long length;
328 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
329 if(length == digestLen)
330 CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
332 CryptDestroyHash(ctx->hHash);
334 CryptReleaseContext(ctx->hCryptProv, 0);
337 static int MD5_Init(MD5_CTX *ctx)
339 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
340 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
341 CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
346 static void MD5_Update(MD5_CTX *ctx,
347 const unsigned char *input,
348 unsigned int inputLen)
350 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
353 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
355 win32_crypto_final(ctx, digest, 16);
358 static int SHA1_Init(SHA_CTX *ctx)
360 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
361 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
362 CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
367 static void SHA1_Update(SHA_CTX *ctx,
368 const unsigned char *input,
369 unsigned int inputLen)
371 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
374 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
376 win32_crypto_final(ctx, digest, 20);
379 static int SHA256_Init(SHA256_CTX *ctx)
381 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
382 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
383 CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
388 static void SHA256_Update(SHA256_CTX *ctx,
389 const unsigned char *input,
390 unsigned int inputLen)
392 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
395 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
397 win32_crypto_final(ctx, digest, 32);
400 #endif /* CRYPTO LIBS */
402 const digest_params MD5_DIGEST_PARAMS[] = {
404 (Curl_digest_init_func) MD5_Init,
405 (Curl_digest_update_func) MD5_Update,
406 (Curl_digest_final_func) MD5_Final,
412 const digest_params SHA1_DIGEST_PARAMS[] = {
414 (Curl_digest_init_func) SHA1_Init,
415 (Curl_digest_update_func) SHA1_Update,
416 (Curl_digest_final_func) SHA1_Final,
422 const digest_params SHA256_DIGEST_PARAMS[] = {
424 (Curl_digest_init_func) SHA256_Init,
425 (Curl_digest_update_func) SHA256_Update,
426 (Curl_digest_final_func) SHA256_Final,
432 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
433 {"sha-256", SHA256_DIGEST_PARAMS}
436 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
437 {"sha-1", SHA1_DIGEST_PARAMS}
440 static const metalink_digest_def MD5_DIGEST_DEF[] = {
441 {"md5", MD5_DIGEST_PARAMS}
445 * The alias of supported hash functions in the order by preference
446 * (basically stronger hash comes first). We included "sha-256" and
447 * "sha256". The former is the name defined in the IANA registry named
448 * "Hash Function Textual Names". The latter is widely (and
449 * historically) used in Metalink version 3.
451 static const metalink_digest_alias digest_aliases[] = {
452 {"sha-256", SHA256_DIGEST_DEF},
453 {"sha256", SHA256_DIGEST_DEF},
454 {"sha-1", SHA1_DIGEST_DEF},
455 {"sha1", SHA1_DIGEST_DEF},
456 {"md5", MD5_DIGEST_DEF},
460 digest_context *Curl_digest_init(const digest_params *dparams)
462 digest_context *ctxt;
464 /* Create digest context */
465 ctxt = malloc(sizeof *ctxt);
470 ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
472 if(!ctxt->digest_hashctx) {
477 ctxt->digest_hash = dparams;
479 if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
487 int Curl_digest_update(digest_context *context,
488 const unsigned char *data,
491 (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
496 int Curl_digest_final(digest_context *context, unsigned char *result)
498 (*context->digest_hash->digest_final)(result, context->digest_hashctx);
500 free(context->digest_hashctx);
506 static unsigned char hex_to_uint(const char *s)
510 for(i = 0; i < 2; ++i) {
511 v[i] = Curl_raw_toupper(s[i]);
512 if('0' <= v[i] && v[i] <= '9') {
515 else if('A' <= v[i] && v[i] <= 'Z') {
519 return (unsigned char)((v[0] << 4) | v[1]);
523 * Check checksum of file denoted by filename. The expected hash value
524 * is given in hex_hash which is hex-encoded string.
526 * This function returns 1 if it succeeds or one of the following
530 * Checksum didn't match.
532 * Could not open file; or could not read data from file.
534 * Hash algorithm not available.
536 static int check_hash(const char *filename,
537 const metalink_digest_def *digest_def,
538 const unsigned char *digest, FILE *error)
540 unsigned char *result;
541 digest_context *dctx;
542 int check_ok, flags, fd;
546 /* O_BINARY is required in order to avoid binary EOF in text mode */
550 fd = open(filename, flags);
552 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
553 digest_def->hash_name, strerror(errno));
557 dctx = Curl_digest_init(digest_def->dparams);
559 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
560 digest_def->hash_name, "failed to initialize hash algorithm");
565 result = malloc(digest_def->dparams->digest_resultlen);
567 unsigned char buf[4096];
568 ssize_t len = read(fd, buf, sizeof(buf));
573 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
574 digest_def->hash_name, strerror(errno));
575 Curl_digest_final(dctx, result);
579 Curl_digest_update(dctx, buf, (unsigned int)len);
581 Curl_digest_final(dctx, result);
582 check_ok = memcmp(result, digest,
583 digest_def->dparams->digest_resultlen) == 0;
584 /* sha*sum style verdict output */
586 fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
587 digest_def->hash_name);
589 fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
590 filename, digest_def->hash_name);
597 int metalink_check_hash(struct Configurable *config,
598 metalinkfile *mlfile,
599 const char *filename)
602 fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
603 if(mlfile->checksum == NULL) {
604 fprintf(config->errors,
605 "Metalink: validating (%s) FAILED (digest missing)\n",
609 rv = check_hash(filename, mlfile->checksum->digest_def,
610 mlfile->checksum->digest, config->errors);
614 static metalink_checksum *new_metalink_checksum_from_hex_digest
615 (const metalink_digest_def *digest_def, const char *hex_digest)
617 metalink_checksum *chksum;
618 unsigned char *digest;
620 size_t len = strlen(hex_digest);
621 digest = malloc(len/2);
622 for(i = 0; i < len; i += 2) {
623 digest[i/2] = hex_to_uint(hex_digest+i);
625 chksum = malloc(sizeof(metalink_checksum));
626 chksum->digest_def = digest_def;
627 chksum->digest = digest;
631 static metalink_resource *new_metalink_resource(const char *url)
633 metalink_resource *res;
634 res = malloc(sizeof(metalink_resource));
636 res->url = strdup(url);
640 /* Returns nonzero if hex_digest is properly formatted; that is each
641 letter is in [0-9A-Za-z] and the length of the string equals to the
642 result length of digest * 2. */
643 static int check_hex_digest(const char *hex_digest,
644 const metalink_digest_def *digest_def)
647 for(i = 0; hex_digest[i]; ++i) {
648 char c = hex_digest[i];
649 if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
650 ('A' <= c && c <= 'Z'))) {
654 return digest_def->dparams->digest_resultlen * 2 == i;
657 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
660 f = (metalinkfile*)malloc(sizeof(metalinkfile));
662 f->filename = strdup(fileinfo->name);
665 if(fileinfo->checksums) {
666 const metalink_digest_alias *digest_alias;
667 for(digest_alias = digest_aliases; digest_alias->alias_name;
669 metalink_checksum_t **p;
670 for(p = fileinfo->checksums; *p; ++p) {
671 if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
672 check_hex_digest((*p)->hash, digest_alias->digest_def)) {
674 new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
684 if(fileinfo->resources) {
685 metalink_resource_t **p;
686 metalink_resource root, *tail;
689 for(p = fileinfo->resources; *p; ++p) {
690 metalink_resource *res;
691 /* Filter by type if it is non-NULL. In Metalink v3, type
692 includes the type of the resource. In curl, we are only
693 interested in HTTP, HTTPS and FTP. In addition to them,
694 Metalink v3 file may contain bittorrent type URL, which
695 points to the BitTorrent metainfo file. We ignore it here.
696 In Metalink v4, type was deprecated and all
697 fileinfo->resources point to the target file. BitTorrent
698 metainfo file URL may be appeared in fileinfo->metaurls.
700 if((*p)->type == NULL ||
701 Curl_raw_equal((*p)->type, "http") ||
702 Curl_raw_equal((*p)->type, "https") ||
703 Curl_raw_equal((*p)->type, "ftp") ||
704 Curl_raw_equal((*p)->type, "ftps")) {
705 res = new_metalink_resource((*p)->url);
710 f->resource = root.next;
715 int parse_metalink(struct Configurable *config, struct OutStruct *outs,
716 const char *metalink_url)
719 metalink_t* metalink;
720 metalink_file_t **files;
721 bool warnings = FALSE;
723 /* metlaink_parse_final deletes outs->metalink_parser */
724 r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
725 outs->metalink_parser = NULL;
729 if(metalink->files == NULL) {
730 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
731 "(missing or invalid file name)\n",
733 metalink_delete(metalink);
736 for(files = metalink->files; *files; ++files) {
738 /* Skip an entry which has no resource. */
739 if(!(*files)->resources) {
740 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
741 "(missing or invalid resource)\n",
742 metalink_url, (*files)->name);
745 if(config->url_get ||
746 ((config->url_get = config->url_list) != NULL)) {
747 /* there's a node here, if it already is filled-in continue to
748 find an "empty" node */
749 while(config->url_get && (config->url_get->flags & GETOUT_URL))
750 config->url_get = config->url_get->next;
753 /* now there might or might not be an available node to fill in! */
757 url = config->url_get;
759 /* there was no free node, create one! */
760 url = new_getout(config);
763 metalinkfile *mlfile;
764 mlfile = new_metalinkfile(*files);
765 if(!mlfile->checksum) {
767 fprintf(config->errors, "Metalink: parsing (%s) WARNING "
768 "(digest missing)\n",
771 /* Set name as url */
772 GetStr(&url->url, mlfile->filename);
774 /* set flag metalink here */
775 url->flags |= GETOUT_URL | GETOUT_METALINK;
777 if(config->metalinkfile_list) {
778 config->metalinkfile_last->next = mlfile;
779 config->metalinkfile_last = mlfile;
782 config->metalinkfile_list = config->metalinkfile_last = mlfile;
786 metalink_delete(metalink);
787 return (warnings) ? -2 : 0;
790 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
793 struct OutStruct *outs = userdata;
794 struct Configurable *config = outs->config;
798 * Once that libcurl has called back tool_write_cb() the returned value
799 * is checked against the amount that was intended to be written, if
800 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
801 * point returning a value different from sz*nmemb indicates failure.
803 const size_t failure = (sz * nmemb) ? 0 : 1;
808 rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
812 fprintf(config->errors, "Metalink: parsing FAILED\n");
818 * Returns nonzero if content_type includes mediatype.
820 static int check_content_type(const char *content_type, const char *media_type)
822 const char *ptr = content_type;
823 size_t media_type_len = strlen(media_type);
824 for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
828 return Curl_raw_nequal(ptr, media_type, media_type_len) &&
829 (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
830 *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
833 int check_metalink_content_type(const char *content_type)
835 return check_content_type(content_type, "application/metalink+xml");
838 int count_next_metalink_resource(metalinkfile *mlfile)
841 metalink_resource *res;
842 for(res = mlfile->resource; res; res = res->next, ++count);
846 static void delete_metalink_checksum(metalink_checksum *chksum)
851 Curl_safefree(chksum->digest);
852 Curl_safefree(chksum);
855 static void delete_metalink_resource(metalink_resource *res)
860 Curl_safefree(res->url);
864 static void delete_metalinkfile(metalinkfile *mlfile)
866 metalink_resource *res;
870 Curl_safefree(mlfile->filename);
871 delete_metalink_checksum(mlfile->checksum);
872 for(res = mlfile->resource; res;) {
873 metalink_resource *next;
875 delete_metalink_resource(res);
878 Curl_safefree(mlfile);
881 void clean_metalink(struct Configurable *config)
883 while(config->metalinkfile_list) {
884 metalinkfile *mlfile = config->metalinkfile_list;
885 config->metalinkfile_list = config->metalinkfile_list->next;
886 delete_metalinkfile(mlfile);
888 config->metalinkfile_last = 0;
891 void metalink_cleanup(void)
895 NSS_ShutdownContext(nss_context);
901 #endif /* USE_METALINK */