* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
#ifdef USE_METALINK
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
# define MD5_CTX gcry_md_hd_t
# define SHA_CTX gcry_md_hd_t
# define SHA256_CTX gcry_md_hd_t
-#elif defined(USE_DARWINSSL)
-/* For darwinssl: CommonCrypto has the functions we need. The library's
- headers are even backward-compatible with OpenSSL's headers as long as
- we define COMMON_DIGEST_FOR_OPENSSL first.
-
- These functions are available on Tiger and later, as well as iOS 5.0
+#elif defined(USE_NSS)
+# include <nss.h>
+# include <pk11pub.h>
+# define MD5_CTX void *
+# define SHA_CTX void *
+# define SHA256_CTX void *
+ static NSSInitContext *nss_context;
+#elif defined(USE_POLARSSL)
+# include <polarssl/md5.h>
+# include <polarssl/sha1.h>
+# include <polarssl/sha256.h>
+# define MD5_CTX md5_context
+# define SHA_CTX sha1_context
+# define SHA256_CTX sha256_context
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+/* For Apple operating systems: CommonCrypto has the functions we need.
+ The library's headers are even backward-compatible with OpenSSL's
+ headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
+
+ These functions are available on Tiger and later, as well as iOS 2.0
and later. If you're building for an older cat, well, sorry. */
# define COMMON_DIGEST_FOR_OPENSSL
# include <CommonCrypto/CommonDigest.h>
#elif defined(_WIN32)
/* For Windows: If no other crypto library is provided, we fallback
to the hash functions provided within the Microsoft Windows CryptoAPI */
-# include <WinCrypt.h>
+# include <wincrypt.h>
/* Custom structure in order to store the required provider and hash handle */
struct win32_crypto_hash {
HCRYPTPROV hCryptProv;
#ifdef USE_GNUTLS_NETTLE
-static void MD5_Init(MD5_CTX *ctx)
+static int MD5_Init(MD5_CTX *ctx)
{
md5_init(ctx);
+ return 1;
}
static void MD5_Update(MD5_CTX *ctx,
md5_digest(ctx, 16, digest);
}
-static void SHA1_Init(SHA_CTX *ctx)
+static int SHA1_Init(SHA_CTX *ctx)
{
sha1_init(ctx);
+ return 1;
}
static void SHA1_Update(SHA_CTX *ctx,
sha1_digest(ctx, 20, digest);
}
-static void SHA256_Init(SHA256_CTX *ctx)
+static int SHA256_Init(SHA256_CTX *ctx)
{
sha256_init(ctx);
+ return 1;
}
static void SHA256_Update(SHA256_CTX *ctx,
#elif defined(USE_GNUTLS)
-static void MD5_Init(MD5_CTX *ctx)
+static int MD5_Init(MD5_CTX *ctx)
{
gcry_md_open(ctx, GCRY_MD_MD5, 0);
+ return 1;
}
static void MD5_Update(MD5_CTX *ctx,
gcry_md_close(*ctx);
}
-static void SHA1_Init(SHA_CTX *ctx)
+static int SHA1_Init(SHA_CTX *ctx)
{
gcry_md_open(ctx, GCRY_MD_SHA1, 0);
+ return 1;
}
static void SHA1_Update(SHA_CTX *ctx,
gcry_md_close(*ctx);
}
-static void SHA256_Init(SHA256_CTX *ctx)
+static int SHA256_Init(SHA256_CTX *ctx)
{
gcry_md_open(ctx, GCRY_MD_SHA256, 0);
+ return 1;
}
static void SHA256_Update(SHA256_CTX *ctx,
gcry_md_close(*ctx);
}
-#elif defined(_WIN32)
+#elif defined(USE_NSS)
+
+static int nss_hash_init(void **pctx, SECOidTag hash_alg)
+{
+ PK11Context *ctx;
+
+ /* we have to initialize NSS if not initialized alraedy */
+ if(!NSS_IsInitialized() && !nss_context) {
+ static NSSInitParameters params;
+ params.length = sizeof params;
+ nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
+ | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
+ }
+
+ ctx = PK11_CreateDigestContext(hash_alg);
+ if(!ctx)
+ return /* failure */ 0;
+
+ if(PK11_DigestBegin(ctx) != SECSuccess) {
+ PK11_DestroyContext(ctx, PR_TRUE);
+ return /* failure */ 0;
+ }
+
+ *pctx = ctx;
+ return /* success */ 1;
+}
+
+static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
+{
+ PK11Context *ctx = *pctx;
+ unsigned int outlen;
+ PK11_DigestFinal(ctx, out, &outlen, len);
+ PK11_DestroyContext(ctx, PR_TRUE);
+}
+
+static int MD5_Init(MD5_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_MD5);
+}
+
+static void MD5_Update(MD5_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 16);
+}
+
+static int SHA1_Init(SHA_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_SHA1);
+}
+
+static void SHA1_Update(SHA_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 20);
+}
+
+static int SHA256_Init(SHA256_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_SHA256);
+}
+
+static void SHA256_Update(SHA256_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 32);
+}
+
+#elif defined(USE_POLARSSL)
+
+static int MD5_Init(MD5_CTX *ctx)
+{
+ md5_starts(ctx);
+ return 1;
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ md5_update(ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ md5_finish(ctx, digest);
+}
+
+static int SHA1_Init(SHA_CTX *ctx)
+{
+ sha1_starts(ctx);
+ return 1;
+}
+
+static void SHA1_Update(SHA_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ sha1_update(ctx, input, inputLen);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
+{
+ sha1_finish(ctx, digest);
+}
+
+static int SHA256_Init(SHA256_CTX *ctx)
+{
+ sha256_starts(ctx, 0); /* 0 = sha256 */
+ return 1;
+}
+
+static void SHA256_Update(SHA256_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ sha256_update(ctx, input, inputLen);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
+{
+ sha256_finish(ctx, digest);
+}
+
+#elif defined(_WIN32) && !defined(USE_SSLEAY)
static void win32_crypto_final(struct win32_crypto_hash *ctx,
unsigned char *digest,
CryptReleaseContext(ctx->hCryptProv, 0);
}
-static void MD5_Init(MD5_CTX *ctx)
+static int MD5_Init(MD5_CTX *ctx)
{
if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
}
+ return 1;
}
static void MD5_Update(MD5_CTX *ctx,
win32_crypto_final(ctx, digest, 16);
}
-static void SHA1_Init(SHA_CTX *ctx)
+static int SHA1_Init(SHA_CTX *ctx)
{
if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
}
+ return 1;
}
static void SHA1_Update(SHA_CTX *ctx,
win32_crypto_final(ctx, digest, 20);
}
-static void SHA256_Init(SHA256_CTX *ctx)
+static int SHA256_Init(SHA256_CTX *ctx)
{
if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
}
+ return 1;
}
static void SHA256_Update(SHA256_CTX *ctx,
ctxt->digest_hash = dparams;
- dparams->digest_init(ctxt->digest_hashctx);
+ if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
+ free(ctxt);
+ return NULL;
+ }
return ctxt;
}
* Checksum didn't match.
* -1:
* Could not open file; or could not read data from file.
+ * -2:
+ * Hash algorithm not available.
*/
static int check_hash(const char *filename,
const metalink_digest_def *digest_def,
fd = open(filename, flags);
if(fd == -1) {
- fprintf(error, "Metalink: validating (%s) FAILED (%s)\n", filename,
- strerror(errno));
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, strerror(errno));
return -1;
}
+
dctx = Curl_digest_init(digest_def->dparams);
+ if(!dctx) {
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, "failed to initialize hash algorithm");
+ close(fd);
+ return -2;
+ }
+
result = malloc(digest_def->dparams->digest_resultlen);
while(1) {
unsigned char buf[4096];
break;
}
else if(len == -1) {
- fprintf(error, "Metalink: validating (%s) FAILED (%s)\n", filename,
- strerror(errno));
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, strerror(errno));
Curl_digest_final(dctx, result);
close(fd);
return -1;
digest_def->dparams->digest_resultlen) == 0;
/* sha*sum style verdict output */
if(check_ok)
- fprintf(error, "Metalink: validating (%s) OK\n", filename);
+ fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
+ digest_def->hash_name);
else
- fprintf(error, "Metalink: validating (%s) FAILED (digest mismatch)\n",
- filename);
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
+ filename, digest_def->hash_name);
free(result);
close(fd);
return check_ok;
}
-int metalink_check_hash(struct Configurable *config,
+int metalink_check_hash(struct GlobalConfig *config,
metalinkfile *mlfile,
const char *filename)
{
fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
if(mlfile->checksum == NULL) {
fprintf(config->errors,
- "Metalink: validating (%s) FAILED (digest missing)\n",
- filename);
+ "Metalink: validating (%s) FAILED (digest missing)\n", filename);
return -2;
}
rv = check_hash(filename, mlfile->checksum->digest_def,
tail = &root;
for(p = fileinfo->resources; *p; ++p) {
metalink_resource *res;
- res = new_metalink_resource((*p)->url);
- tail->next = res;
- tail = res;
+ /* Filter by type if it is non-NULL. In Metalink v3, type
+ includes the type of the resource. In curl, we are only
+ interested in HTTP, HTTPS and FTP. In addition to them,
+ Metalink v3 file may contain bittorrent type URL, which
+ points to the BitTorrent metainfo file. We ignore it here.
+ In Metalink v4, type was deprecated and all
+ fileinfo->resources point to the target file. BitTorrent
+ metainfo file URL may be appeared in fileinfo->metaurls.
+ */
+ if((*p)->type == NULL ||
+ Curl_raw_equal((*p)->type, "http") ||
+ Curl_raw_equal((*p)->type, "https") ||
+ Curl_raw_equal((*p)->type, "ftp") ||
+ Curl_raw_equal((*p)->type, "ftps")) {
+ res = new_metalink_resource((*p)->url);
+ tail->next = res;
+ tail = res;
+ }
}
f->resource = root.next;
}
return f;
}
-int parse_metalink(struct Configurable *config, struct OutStruct *outs,
+int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
const char *metalink_url)
{
metalink_error_t r;
return -1;
}
if(metalink->files == NULL) {
- fprintf(config->errors, "Metalink: parsing (%s) WARNING "
+ fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
"(missing or invalid file name)\n",
metalink_url);
metalink_delete(metalink);
struct getout *url;
/* Skip an entry which has no resource. */
if(!(*files)->resources) {
- fprintf(config->errors, "Metalink: parsing (%s) WARNING "
+ fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
"(missing or invalid resource)\n",
metalink_url, (*files)->name);
continue;
mlfile = new_metalinkfile(*files);
if(!mlfile->checksum) {
warnings = TRUE;
- fprintf(config->errors, "Metalink: parsing (%s) WARNING "
- "(digest missing)\n",
+ fprintf(config->global->errors,
+ "Metalink: parsing (%s) WARNING (digest missing)\n",
metalink_url);
}
/* Set name as url */
void *userdata)
{
struct OutStruct *outs = userdata;
- struct Configurable *config = outs->config;
+ struct OperationConfig *config = outs->config;
int rv;
/*
if(rv == 0)
return sz * nmemb;
else {
- fprintf(config->errors, "Metalink: parsing FAILED\n");
+ fprintf(config->global->errors, "Metalink: parsing FAILED\n");
return failure;
}
}
Curl_safefree(mlfile);
}
-void clean_metalink(struct Configurable *config)
+void clean_metalink(struct OperationConfig *config)
{
while(config->metalinkfile_list) {
metalinkfile *mlfile = config->metalinkfile_list;
config->metalinkfile_last = 0;
}
+void metalink_cleanup(void)
+{
+#ifdef USE_NSS
+ if(nss_context) {
+ NSS_ShutdownContext(nss_context);
+ nss_context = NULL;
+ }
+#endif
+}
+
#endif /* USE_METALINK */