]> git.ipfire.org Git - pakfire.git/commitdiff
downloader: Compute message digest of downloaded files
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Sep 2021 11:54:01 +0000 (11:54 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Sep 2021 11:54:01 +0000 (11:54 +0000)
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 <michael.tremer@ipfire.org>
src/libpakfire/downloader.c

index 156493920bab5eaa48f76eb672246afd6644159e..8befa70736d264d1935287604db8efe7a02219fc 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <curl/curl.h>
 #include <json.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
 
 #include <pakfire/downloader.h>
 #include <pakfire/i18n.h>
@@ -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);