From: Michael Tremer Date: Wed, 24 Aug 2022 16:02:46 +0000 (+0000) Subject: archive: Refactor digest computation X-Git-Tag: 0.9.28~375 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cddcedd30569a9b49a4156183ffdd6ee52e883bd;p=pakfire.git archive: Refactor digest computation Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index d7c19e0e6..192a56238 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -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; diff --git a/src/libpakfire/digest.c b/src/libpakfire/digest.c index 2eb12818f..1d64f891f 100644 --- a/src/libpakfire/digest.c +++ b/src/libpakfire/digest.c @@ -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); +} diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index 0c1d3a028..44eb04dce 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -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); diff --git a/src/libpakfire/include/pakfire/digest.h b/src/libpakfire/include/pakfire/digest.h index 1baee3be6..63fcfa8d8 100644 --- a/src/libpakfire/include/pakfire/digest.h +++ b/src/libpakfire/include/pakfire/digest.h @@ -36,6 +36,9 @@ enum pakfire_digest_types { #include +// 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 diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index f2f1fbce0..04fd363d9 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -21,9 +21,6 @@ #include #include -#include -#include - #include #include @@ -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,