From: Michael Tremer Date: Wed, 8 Sep 2021 11:54:01 +0000 (+0000) Subject: downloader: Compute message digest of downloaded files X-Git-Tag: 0.9.28~973 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6a7af91dd354ec2183a23204defe0b82176dc8b8;p=pakfire.git downloader: Compute message digest of downloaded files This is the first part of where we want to check if we have downloaded a file that has the expected checksum. Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/downloader.c b/src/libpakfire/downloader.c index 156493920..8befa7073 100644 --- a/src/libpakfire/downloader.c +++ b/src/libpakfire/downloader.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include @@ -63,6 +65,12 @@ struct pakfire_transfer { char tempfile[PATH_MAX]; FILE* f; + // Crypto Stuff + EVP_MD_CTX* evp; + const EVP_MD* md; + unsigned char computed_digest[EVP_MAX_MD_SIZE]; + unsigned int computed_digest_length; + // Mirrors char baseurl[PATH_MAX]; struct pakfire_mirrorlist* mirrors; @@ -130,6 +138,10 @@ static void pakfire_transfer_free(struct pakfire_transfer* transfer) { if (transfer->f) fclose(transfer->f); + // Free OpenSSL EVP context + if (transfer->evp) + EVP_MD_CTX_free(transfer->evp); + if (transfer->mirrors) pakfire_mirrorlist_unref(transfer->mirrors); @@ -300,6 +312,9 @@ static struct pakfire_transfer* pakfire_downloader_create_transfer( // Copy flags transfer->flags = flags; + // Set message digest + transfer->md = EVP_sha512(); + // Allocate handle transfer->handle = curl_easy_init(); if (!transfer->handle) @@ -484,6 +499,16 @@ static int pakfire_transfer_done(struct pakfire_downloader* downloader, DEBUG(downloader->pakfire, "cURL transfer done: %d - %s\n", code, curl_easy_strerror(code)); + // Finish message digest computation + if (transfer->evp) { + r = EVP_DigestFinal_ex(transfer->evp, transfer->computed_digest, &transfer->computed_digest_length); + if (r != 1) { + ERROR(downloader->pakfire, "Could not finish message digest computation: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return 1; + } + } + // Protocol curl_easy_getinfo(h, CURLINFO_PROTOCOL, &protocol); @@ -516,6 +541,15 @@ static int pakfire_transfer_done(struct pakfire_downloader* downloader, if (speed) DEBUG(downloader->pakfire, " Download Speed: %ld bps\n", speed); + // Message Digest + char* hexdigest = __pakfire_hexlify(transfer->computed_digest, transfer->computed_digest_length); + if (hexdigest) { + DEBUG(downloader->pakfire, " Message Digest: %s\n", hexdigest); + free(hexdigest); + } + + // XXX check if digest matches + switch (protocol) { case CURLPROTO_FILE: // Handle any errors @@ -562,10 +596,21 @@ static int pakfire_transfer_done(struct pakfire_downloader* downloader, static size_t pakfire_downloader_write(char* data, size_t size, size_t nmemb, void* userdata) { struct pakfire_transfer* transfer = (struct pakfire_transfer*)userdata; + int r; // Do not write empty blocks - if (!size) - return size; + if (!nmemb) + return nmemb; + + // Update message digest + if (transfer->evp) { + r = EVP_DigestUpdate(transfer->evp, data, nmemb); + if (r != 1) { + //ERROR(downloader->pakfire, "EVP_DigestUpdate failed: %s\n", + // ERR_error_string(ERR_get_error(), NULL)); + return 0; + } + } // Write everything to the allocated file descriptor return fwrite(data, size, nmemb, transfer->f); @@ -573,6 +618,8 @@ static size_t pakfire_downloader_write(char* data, size_t size, size_t nmemb, vo static int pakfire_downloader_prepare_transfer(struct pakfire_downloader* downloader, struct pakfire_transfer* transfer) { + int r; + // Increment tries transfer->tries++; @@ -627,6 +674,29 @@ static int pakfire_downloader_prepare_transfer(struct pakfire_downloader* downlo } } + // Drop any previously used EVP contexts + if (transfer->evp) { + EVP_MD_CTX_free(transfer->evp); + transfer->evp = NULL; + } + + // Create a new EVP context + if (transfer->md) { + transfer->evp = EVP_MD_CTX_new(); + if (!transfer->evp) { + ERROR(downloader->pakfire, "Could not create EVP context: %m\n"); + return 1; + } + + // Initialize the EVP context + r = EVP_DigestInit_ex(transfer->evp, transfer->md, NULL); + if (r != 1) { + ERROR(downloader->pakfire, "Could not initialize EVP context: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return 1; + } + } + // Write all data to the callback function curl_easy_setopt(transfer->handle, CURLOPT_WRITEFUNCTION, pakfire_downloader_write); curl_easy_setopt(transfer->handle, CURLOPT_WRITEDATA, transfer);