]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Refactor digest computation
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 24 Aug 2022 16:02:46 +0000 (16:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 24 Aug 2022 16:02:46 +0000 (16:02 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/digest.c
src/libpakfire/include/pakfire/archive.h
src/libpakfire/include/pakfire/digest.h
src/libpakfire/transaction.c

index d7c19e0e67769306e037accbade7cb83a048dbdd..192a562383de284e16b6dfe00ecc1b2ce8567abd 100644 (file)
@@ -79,6 +79,10 @@ struct pakfire_archive {
        struct pakfire_scriptlet** scriptlets;
        int scriptlets_loaded;
 
+       // Digests
+       struct pakfire_digests digests;
+       unsigned int digests_computed:1;
+
        // Verify Status
        int verify;
 };
@@ -108,6 +112,27 @@ static const char* pakfire_archive_legacy_filename(
        return filename;
 }
 
+static int pakfire_archive_compute_digests(struct pakfire_archive* archive) {
+       int r;
+
+       // Skip if already done
+       if (archive->digests_computed)
+               return 0;
+
+       // Calculate digest
+       r = pakfire_digests_compute_from_file(archive->pakfire, &archive->digests,
+                       PAKFIRE_ARCHIVE_CHECKSUM, archive->f);
+       if (r) {
+               ERROR(archive->pakfire, "Could not calculate digest of %s: %m\n", archive->path);
+               return r;
+       }
+
+       // Mark as computed
+       archive->digests_computed = 1;
+
+       return 0;
+}
+
 /*
        A helper function to close the archive and reset our data structures
 */
@@ -846,93 +871,33 @@ PAKFIRE_EXPORT ssize_t pakfire_archive_get_size(struct pakfire_archive* archive)
        return buf.st_size;
 }
 
-int pakfire_archive_digest(struct pakfire_archive* archive,
-               enum pakfire_digest_types type, unsigned char* digest, size_t* length) {
-       int r = 1;
-
-       const EVP_MD* md = NULL;
-
-       // Select hash function
-       switch (type) {
-               case PAKFIRE_DIGEST_SHA512:
-                       md = EVP_sha512();
-                       break;
-
-               case PAKFIRE_DIGEST_SHA256:
-                       md = EVP_sha256();
-                       break;
-
-               default:
-                       errno = ENOTSUP;
-                       return 1;
-       }
-
-       // Initialize context
-       EVP_MD_CTX* ctx = EVP_MD_CTX_new();
-       if (!ctx) {
-               ERROR(archive->pakfire, "Could not initialize EVP context: %m\n");
-               goto ERROR;
-       }
-
-       r = EVP_DigestInit_ex(ctx, md, NULL);
-       if (r != 1) {
-               ERROR(archive->pakfire, "EVP_DigestInit_ex failed: %s\n",
-                       ERR_error_string(ERR_get_error(), NULL));
-               r = 1;
-               goto ERROR;
-       }
-
-       char buffer[64 * 1024];
-
-       // Feed archive into the hash functions
-       while (!feof(archive->f)) {
-               size_t bytes_read = fread(buffer, 1, sizeof(buffer), archive->f);
-
-               if (ferror(archive->f)) {
-                       ERROR(archive->pakfire, "Error reading from file: %m\n");
-                       goto ERROR;
-               }
+int pakfire_archive_check_digest(struct pakfire_archive* archive,
+               const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
+       int r;
 
-               r = EVP_DigestUpdate(ctx, buffer, bytes_read);
-               if (r != 1) {
-                       ERROR(archive->pakfire, "EVP_DigestUpdate failed: %s\n",
-                               ERR_error_string(ERR_get_error(), NULL));
-                       r = 1;
-                       goto ERROR;
-               }
-       }
+       // Compute the digest
+       r = pakfire_archive_compute_digests(archive);
+       if (r)
+               return r;
 
-       // Finalise hash function
-       r = EVP_DigestFinal_ex(ctx, digest, (unsigned int*)length);
-       if (r != 1) {
-               ERROR(archive->pakfire, "EVP_DigestFinal_ex failed: %s\n",
-                       ERR_error_string(ERR_get_error(), NULL));
-               r = 1;
-               goto ERROR;
+       // Compare computed with expected digest
+       r = pakfire_digests_compare_one(archive->pakfire, &archive->digests,
+               type, digest, length);
+       if (r) {
+               ERROR(archive->pakfire, "Archive digest does not match");
        }
 
-       // Success
-       r = 0;
-
-ERROR:
-       // Cleanup
-       if (ctx)
-               EVP_MD_CTX_free(ctx);
-
-       rewind(archive->f);
-
        return r;
 }
 
 static int pakfire_archive_make_package_from_json(struct pakfire_archive* archive,
                struct pakfire_repo* repo, struct pakfire_package** package) {
-       unsigned char digest[EVP_MAX_MD_SIZE];
-       size_t digest_length = 0;
+       struct pakfire_digests digests;
        int r;
 
        // Calculate digest
-       // This must be done before we create the package object
-       r = pakfire_archive_digest(archive, PAKFIRE_DIGEST_SHA512, digest, &digest_length);
+       r = pakfire_digests_compute_from_file(archive->pakfire, &digests,
+               PAKFIRE_ARCHIVE_CHECKSUM, archive->f);
        if (r) {
                ERROR(archive->pakfire, "Could not calculate digest of %s: %m\n", archive->path);
                return r;
@@ -959,7 +924,19 @@ static int pakfire_archive_make_package_from_json(struct pakfire_archive* archiv
        pakfire_package_set_path(pkg, archive->path);
 
        // Set digest
-       pakfire_package_set_digest(pkg, PAKFIRE_DIGEST_SHA512, digest);
+       switch (PAKFIRE_ARCHIVE_CHECKSUM) {
+               case PAKFIRE_DIGEST_SHA512:
+                       pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, digests.sha512);
+                       break;
+
+               case PAKFIRE_DIGEST_SHA256:
+                       pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, digests.sha256);
+                       break;
+
+               case PAKFIRE_DIGEST_UNDEFINED:
+                       r = 1;
+                       goto ERROR;
+       }
 
        // Vendor
        const char* vendor = pakfire_archive_metadata_get(archive, "vendor", NULL);
@@ -1095,16 +1072,19 @@ static int pakfire_archive_make_package_from_json(struct pakfire_archive* archiv
        // Success!
        *package = pkg;
        return 0;
+
+ERROR:
+       return r;
 }
 
 static int pakfire_archive_make_legacy_package(struct pakfire_archive* archive,
                struct pakfire_repo* repo, struct pakfire_package** package) {
-       unsigned char digest[EVP_MAX_MD_SIZE];
-       size_t digest_length = 0;
+       struct pakfire_digests digests;
        int r;
 
        // Calculate digest
-       r = pakfire_archive_digest(archive, PAKFIRE_DIGEST_SHA512, digest, &digest_length);
+       r = pakfire_digests_compute_from_file(archive->pakfire, &digests,
+               PAKFIRE_ARCHIVE_CHECKSUM, archive->f);
        if (r) {
                ERROR(archive->pakfire, "Could not calculate digest of %s: %m\n", archive->path);
                return r;
@@ -1282,8 +1262,19 @@ static int pakfire_archive_make_legacy_package(struct pakfire_archive* archive,
                }
        }
 
-       // Set digests
-       pakfire_package_set_digest(pkg, PAKFIRE_DIGEST_SHA512, digest);
+       // Set digest
+       switch (PAKFIRE_ARCHIVE_CHECKSUM) {
+               case PAKFIRE_DIGEST_SHA512:
+                       pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, digests.sha512);
+                       break;
+
+               case PAKFIRE_DIGEST_SHA256:
+                       pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, digests.sha256);
+                       break;
+
+               case PAKFIRE_DIGEST_UNDEFINED:
+                       break;
+       }
 
        *package = pkg;
 
index 2eb12818f9f0fc42f5cc68fb400a88438a4a4969..1d64f891fe95bdd57e3d34b7e8617e25fcea1f82 100644 (file)
@@ -198,3 +198,29 @@ int pakfire_digests_compare(struct pakfire* pakfire, const struct pakfire_digest
        // All digests match
        return 0;
 }
+
+int pakfire_digests_compare_one(struct pakfire* pakfire, struct pakfire_digests* digests1,
+               const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
+       struct pakfire_digests digests2;
+       int r;
+
+       // Check for valid inputs
+       r = pakfire_digests_check_length(pakfire, type, length);
+       if (r)
+               return r;
+
+       switch (type) {
+               case PAKFIRE_DIGEST_SHA512:
+                       memcpy(digests2.sha512, digest, sizeof(digests2.sha512));
+                       break;
+
+               case PAKFIRE_DIGEST_SHA256:
+                       memcpy(digests2.sha256, digest, sizeof(digests2.sha256));
+                       break;
+
+               case PAKFIRE_DIGEST_UNDEFINED:
+                       break;
+       }
+
+       return pakfire_digests_compare(pakfire, digests1, &digests2, type);
+}
index 0c1d3a028cc8f7fb312b8a885078aa800661b43b..44eb04dcef8e274d5cd96d8cd6e5196827014277 100644 (file)
@@ -59,8 +59,8 @@ int pakfire_archive_make_package(struct pakfire_archive* archive,
 
 int pakfire_archive_copy(struct pakfire_archive* archive, const char* path);
 
-int pakfire_archive_digest(struct pakfire_archive* archive,
-       enum pakfire_digest_types type, unsigned char* digest, size_t* length);
+int pakfire_archive_check_digest(struct pakfire_archive* archive,
+       const enum pakfire_digest_types type, const unsigned char* digest, const size_t length);
 
 struct pakfire_scriptlet* pakfire_archive_get_scriptlet(
        struct pakfire_archive* archive, const char* type);
index 1baee3be63de3150c2eee65a6b355bcb9766838d..63fcfa8d898e6d01ea4bb92bb61fac0b71a66787 100644 (file)
@@ -36,6 +36,9 @@ enum pakfire_digest_types {
 
 #include <pakfire/pakfire.h>
 
+// libsolv only supports storing one checksum which has to be of a supported type
+#define PAKFIRE_ARCHIVE_CHECKSUM PAKFIRE_DIGEST_SHA512
+
 // Digests
 struct pakfire_digests {
        // SHA-512
@@ -52,6 +55,8 @@ int pakfire_digests_compute_from_file(struct pakfire* pakfire,
 
 int pakfire_digests_compare(struct pakfire* pakfire, const struct pakfire_digests* digests1,
        const struct pakfire_digests* digests2, const int types);
+int pakfire_digests_compare_one(struct pakfire* pakfire, struct pakfire_digests* digests1,
+       const enum pakfire_digest_types type, const unsigned char* digest, const size_t length);
 
 #endif
 
index f2f1fbce0f1c87ba289eb590df5dced959eb103f..04fd363d95ed742454318373c0e5870d5208bb6c 100644 (file)
@@ -21,9 +21,6 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include <openssl/crypto.h>
-#include <openssl/evp.h>
-
 #include <solv/pool_fileconflicts.h>
 #include <solv/transaction.h>
 
@@ -682,8 +679,6 @@ static int pakfire_transaction_check(struct pakfire_transaction* transaction) {
 
 static int pakfire_transaction_verify(struct pakfire_transaction* transaction,
                struct pakfire_package* pkg, struct pakfire_archive* archive) {
-       int r;
-
        const char* nevra = pakfire_package_get_nevra(pkg);
 
        // Nothing to do if this step does not have an archive
@@ -692,7 +687,7 @@ static int pakfire_transaction_verify(struct pakfire_transaction* transaction,
                return 0;
        }
 
-       enum pakfire_digest_types digest_type = 0;
+       enum pakfire_digest_types digest_type = PAKFIRE_DIGEST_UNDEFINED;
 
        // Fetch digest from package
        const unsigned char* expected_digest = pakfire_package_get_digest(pkg, &digest_type);
@@ -701,24 +696,10 @@ static int pakfire_transaction_verify(struct pakfire_transaction* transaction,
                return 0;
        }
 
-       unsigned char computed_digest[EVP_MAX_MD_SIZE];
-       size_t digest_length = 0;
+       const size_t length = pakfire_digest_length(digest_type);
 
-       // Compute digest of the archive
-       r = pakfire_archive_digest(archive, digest_type, computed_digest, &digest_length);
-       if (r) {
-               ERROR(transaction->pakfire, "Could not compute digest for %s: %m\n", nevra);
-               return r;
-       }
-
-       // Compare digests
-       r = CRYPTO_memcmp(computed_digest, expected_digest, digest_length);
-       if (r) {
-               ERROR(transaction->pakfire, "Digests of %s do not match\n", nevra);
-               return 1;
-       }
-
-       return 0;
+       // Check against the digest of the archive
+       return pakfire_archive_check_digest(archive, digest_type, expected_digest, length);
 }
 
 static int pakfire_transaction_run_script(struct pakfire_transaction* transaction,