From fbcf5800064673206632041eddb497fe61c1cf49 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 4 Feb 2025 10:37:50 +0000 Subject: [PATCH] hashes: Replace the old digest mechanism This is splitting the hasher into a separate object so that we have more flexibility here. It also renames the digests struct into "hashes" which is a little bit shorter and I thought that it makes more sense. Signed-off-by: Michael Tremer --- Makefile.am | 22 +- src/pakfire/archive.c | 94 +++--- src/pakfire/archive.h | 9 +- src/pakfire/buildservice.c | 15 +- src/pakfire/compress.c | 22 +- src/pakfire/compress.h | 3 +- src/pakfire/db.c | 102 +++--- src/pakfire/digest.c | 654 ------------------------------------- src/pakfire/digest.h | 120 ------- src/pakfire/file.c | 289 ++++++---------- src/pakfire/file.h | 15 +- src/pakfire/hasher.c | 378 +++++++++++++++++++++ src/pakfire/hasher.h | 45 +++ src/pakfire/hashes.c | 400 +++++++++++++++++++++++ src/pakfire/hashes.h | 106 ++++++ src/pakfire/package.c | 142 ++++---- src/pakfire/package.h | 12 +- src/pakfire/packager.c | 16 +- src/pakfire/packager.h | 4 +- src/pakfire/repo.c | 81 +++-- src/pakfire/transaction.c | 28 +- src/pakfire/xfer.c | 182 ++++------- src/pakfire/xfer.h | 5 +- src/python/file.c | 20 +- src/python/package.c | 25 +- tests/libpakfire/xfer.c | 16 +- 26 files changed, 1425 insertions(+), 1380 deletions(-) delete mode 100644 src/pakfire/digest.c delete mode 100644 src/pakfire/digest.h create mode 100644 src/pakfire/hasher.c create mode 100644 src/pakfire/hasher.h create mode 100644 src/pakfire/hashes.c create mode 100644 src/pakfire/hashes.h diff --git a/Makefile.am b/Makefile.am index b730e18e7..c02ca54ee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -207,8 +207,6 @@ libpakfire_la_SOURCES = \ src/pakfire/db.h \ src/pakfire/deps.c \ src/pakfire/deps.h \ - src/pakfire/digest.c \ - src/pakfire/digest.h \ src/pakfire/dist.c \ src/pakfire/dist.h \ src/pakfire/elf.c \ @@ -221,6 +219,10 @@ libpakfire_la_SOURCES = \ src/pakfire/file.h \ src/pakfire/filelist.c \ src/pakfire/filelist.h \ + src/pakfire/hasher.c \ + src/pakfire/hasher.h \ + src/pakfire/hashes.c \ + src/pakfire/hashes.h \ src/pakfire/hex.c \ src/pakfire/hex.h \ src/pakfire/httpclient.c \ @@ -572,7 +574,6 @@ check_PROGRAMS += \ tests/libpakfire/config \ tests/libpakfire/db \ tests/libpakfire/deps \ - tests/libpakfire/digest \ tests/libpakfire/env \ tests/libpakfire/file \ tests/libpakfire/httpclient \ @@ -727,21 +728,6 @@ tests_libpakfire_deps_LDFLAGS = \ tests_libpakfire_deps_LDADD = \ $(TESTSUITE_LDADD) -dist_tests_libpakfire_digest_SOURCES = \ - tests/libpakfire/digest.c - -tests_libpakfire_digest_CPPFLAGS = \ - $(TESTSUITE_CPPFLAGS) - -tests_libpakfire_digest_CFLAGS = \ - $(TESTSUITE_CFLAGS) - -tests_libpakfire_digest_LDFLAGS = \ - $(TESTSUITE_LDFLAGS) - -tests_libpakfire_digest_LDADD = \ - $(TESTSUITE_LDADD) - dist_tests_libpakfire_env_SOURCES = \ tests/libpakfire/env.c diff --git a/src/pakfire/archive.c b/src/pakfire/archive.c index decfb4730..f6dd284fe 100644 --- a/src/pakfire/archive.c +++ b/src/pakfire/archive.c @@ -37,9 +37,10 @@ #include #include #include -#include #include #include +#include +#include #include #include #include @@ -53,6 +54,9 @@ #include #include +// Compute checksums using SHA2-512 +#define PAKFIRE_ARCHIVE_CHECKSUM PAKFIRE_HASH_SHA2_512 + #define MAX_SCRIPTLETS 9 // The maximum number of symlinks to follow when reading a file from an archive @@ -81,8 +85,8 @@ struct pakfire_archive { struct pakfire_scriptlet* scriptlets[MAX_SCRIPTLETS]; unsigned int num_scriptlets; - // Digests - struct pakfire_digests digests; + // Hashes + struct pakfire_hashes hashes; // Progress (when extracting) struct pakfire_progress* progress; @@ -277,7 +281,7 @@ ERROR: return r; } -static int pakfire_archive_compute_digests(struct pakfire_archive* archive) { +static int pakfire_archive_compute_hashes(struct pakfire_archive* archive) { int r; // Start reading at the beginning @@ -287,13 +291,15 @@ static int pakfire_archive_compute_digests(struct pakfire_archive* archive) { return -errno; } - // Calculate digest - r = pakfire_digests_compute_from_file(archive->ctx, &archive->digests, - PAKFIRE_ARCHIVE_CHECKSUM, archive->f); - if (r) - ERROR(archive->ctx, "Could not calculate digest of %s: %m\n", archive->path); + // Calculate hashes + r = pakfire_hash_file(archive->ctx, archive->f,PAKFIRE_ARCHIVE_CHECKSUM, &archive->hashes); + if (r < 0) { + ERROR(archive->ctx, "Could not calculate checksums of %s: %s\n", + archive->path, strerror(-r)); + return r; + } - return r; + return 0; } /* @@ -1469,35 +1475,29 @@ ssize_t pakfire_archive_get_size(struct pakfire_archive* archive) { return archive->stat.st_size; } -int pakfire_archive_check_digest(struct pakfire_archive* archive, - const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) { - size_t computed_length = 0; +int pakfire_archive_verify_checksum(struct pakfire_archive* archive, + const enum pakfire_hash_type type, const unsigned char* checksum, const size_t length) { + struct pakfire_hashes expected_hashes = {}; int r; - // Compute the digest - r = pakfire_archive_compute_digests(archive); - if (r) + // Store the checksum + r = pakfire_hashes_set(&expected_hashes, type, checksum, length); + if (r < 0) return r; - // Compare computed with expected digest - r = pakfire_digests_compare_one(archive->ctx, &archive->digests, type, digest, length); - if (r) { - const unsigned char* computed_digest = pakfire_digest_get( - &archive->digests, type, &computed_length); - - char* expected_hexdigest = __pakfire_hexlify(digest, length); - char* computed_hexdigest = __pakfire_hexlify(computed_digest, computed_length); - - ERROR(archive->ctx, "Archive digest does not match for %s:\n", archive->path); - ERROR(archive->ctx, " Expected: %s\n", expected_hexdigest); - ERROR(archive->ctx, " Computed: %s\n", computed_hexdigest); - - if (expected_hexdigest) - free(expected_hexdigest); - if (computed_hexdigest) - free(computed_hexdigest); - + // Compute the checksums + r = pakfire_archive_compute_hashes(archive); + if (r < 0) return r; + + // Compare the hashes + r = pakfire_hashes_compare(archive->ctx, &expected_hashes, &archive->hashes); + if (r) { + ERROR(archive->ctx, "Archive checksum does not match for %s:\n", archive->path); + ERROR(archive->ctx, " Expected:\n"); + pakfire_hashes_dump(archive->ctx, &expected_hashes, LOG_ERR); + ERROR(archive->ctx, " Computed:\n"); + pakfire_hashes_dump(archive->ctx, &archive->hashes, LOG_ERR); } return r; @@ -1548,8 +1548,8 @@ static int pakfire_archive_make_package_from_json(struct pakfire_archive* archiv char path[PATH_MAX]; int r; - // Calculate digest - r = pakfire_archive_compute_digests(archive); + // Calculate checksums + r = pakfire_archive_compute_hashes(archive); if (r) return r; @@ -1570,20 +1570,24 @@ static int pakfire_archive_make_package_from_json(struct pakfire_archive* archiv nevra, pkg, archive); #endif - // Set digest + // Set checksum switch (PAKFIRE_ARCHIVE_CHECKSUM) { - case PAKFIRE_DIGEST_SHA2_512: - pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, - archive->digests.sha2_512, sizeof(archive->digests.sha2_512)); + case PAKFIRE_HASH_SHA2_512: + r = pakfire_package_set_checksum(pkg, PAKFIRE_ARCHIVE_CHECKSUM, + archive->hashes.sha2_512, sizeof(archive->hashes.sha2_512)); + if (r < 0) + goto ERROR; break; - case PAKFIRE_DIGEST_SHA2_256: - pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM, - archive->digests.sha2_256, sizeof(archive->digests.sha2_256)); + case PAKFIRE_HASH_SHA2_256: + r = pakfire_package_set_checksum(pkg, PAKFIRE_ARCHIVE_CHECKSUM, + archive->hashes.sha2_256, sizeof(archive->hashes.sha2_256)); + if (r < 0) + goto ERROR; break; - case PAKFIRE_DIGEST_UNDEFINED: - r = 1; + case PAKFIRE_HASH_UNDEFINED: + r = -EINVAL; goto ERROR; } diff --git a/src/pakfire/archive.h b/src/pakfire/archive.h index 578342e4a..28404b8a6 100644 --- a/src/pakfire/archive.h +++ b/src/pakfire/archive.h @@ -27,8 +27,8 @@ struct pakfire_archive; -#include #include +#include #include #include #include @@ -56,6 +56,10 @@ struct pakfire_filelist* pakfire_archive_get_filelist(struct pakfire_archive* ar int pakfire_archive_verify(struct pakfire_archive* archive, int* status); ssize_t pakfire_archive_get_size(struct pakfire_archive* archive); + +int pakfire_archive_verify_checksum(struct pakfire_archive* archive, + const enum pakfire_hash_type type, const unsigned char* checksum, const size_t length); + int pakfire_archive_make_package(struct pakfire_archive* archive, struct pakfire_repo* repo, struct pakfire_package** package); @@ -93,9 +97,6 @@ int pakfire_archive_unlink(struct pakfire_archive* archive); int pakfire_archive_copy(struct pakfire_archive* archive, const char* path); int pakfire_archive_link_or_copy(struct pakfire_archive* archive, const char* path); -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/pakfire/buildservice.c b/src/pakfire/buildservice.c index ea6734cf4..179f6109b 100644 --- a/src/pakfire/buildservice.c +++ b/src/pakfire/buildservice.c @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -269,8 +270,8 @@ ERROR: static int pakfire_buildservice_create_upload(struct pakfire_buildservice* service, const char* path, const char* filename, FILE* f, char** url, char** uuid) { + struct pakfire_hashes hashes = {}; struct pakfire_xfer* xfer = NULL; - struct pakfire_digests digests = {}; struct json_object* response = NULL; char* hexdigest_blake2b512 = NULL; struct stat stat; @@ -286,16 +287,16 @@ static int pakfire_buildservice_create_upload(struct pakfire_buildservice* servi } // Compute the digest - r = pakfire_digests_compute_from_file(service->ctx, &digests, PAKFIRE_DIGEST_BLAKE2B512, f); - if (r) { - ERROR(service->ctx, "Could not compute the digest of %s: %s\n", + r = pakfire_hash_file(service->ctx, f, PAKFIRE_HASH_BLAKE2B512, &hashes); + if (r < 0) { + ERROR(service->ctx, "Could not compute the checksum of %s: %s\n", path, strerror(-r)); goto ERROR; } // Convert the digest into hex format - hexdigest_blake2b512 = pakfire_digest_get_hex(&digests, PAKFIRE_DIGEST_BLAKE2B512); - if (!hexdigest_blake2b512) + r = pakfire_hashes_get_hex(&hashes, PAKFIRE_HASH_BLAKE2B512, &hexdigest_blake2b512); + if (r < 0) goto ERROR; // Create a new xfer diff --git a/src/pakfire/compress.c b/src/pakfire/compress.c index 9dba2a0c9..99fa8eced 100644 --- a/src/pakfire/compress.c +++ b/src/pakfire/compress.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -687,8 +688,8 @@ struct pakfire_compress { // The progress indicator struct pakfire_progress* progress; - // Digests to write to the archive - int digests; + // Checksums to write to the archive + int checksum_types; }; static int pakfire_copy_data_from_file(struct pakfire_ctx* ctx, @@ -787,7 +788,7 @@ static int __pakfire_compress(struct pakfire_ctx* ctx, struct pakfire_file* file const size_t size = pakfire_file_get_size(file); // Generate file metadata into an archive entry - entry = pakfire_file_archive_entry(file, data->digests); + entry = pakfire_file_archive_entry(file, data->checksum_types); if (!entry) { r = -errno; goto ERROR; @@ -848,7 +849,8 @@ ERROR: } int pakfire_compress(struct pakfire* pakfire, struct archive* archive, - struct pakfire_filelist* filelist, const char* message, int flags, int digests) { + struct pakfire_filelist* filelist, const char* message, int flags, + enum pakfire_hash_type checksum_types) { int progress_flags = PAKFIRE_PROGRESS_SHOW_PERCENTAGE | PAKFIRE_PROGRESS_SHOW_BYTES_TRANSFERRED; @@ -857,12 +859,12 @@ int pakfire_compress(struct pakfire* pakfire, struct archive* archive, struct pakfire_ctx* ctx = pakfire_ctx(pakfire); struct pakfire_compress data = { - .ctx = ctx, - .pakfire = pakfire, - .archive = archive, - .filelist = filelist, - .flags = flags, - .digests = digests, + .ctx = ctx, + .pakfire = pakfire, + .archive = archive, + .filelist = filelist, + .flags = flags, + .checksum_types = checksum_types, }; // Should we show a progress bar? diff --git a/src/pakfire/compress.h b/src/pakfire/compress.h index f275aebb4..c3ec0fb9b 100644 --- a/src/pakfire/compress.h +++ b/src/pakfire/compress.h @@ -25,6 +25,7 @@ #include #include +#include #include // Automatically detect @@ -63,7 +64,7 @@ enum pakfire_compress_flags { }; int pakfire_compress(struct pakfire* pakfire, struct archive* archive, - struct pakfire_filelist* filelist, const char* message, int flags, int digests); + struct pakfire_filelist* filelist, const char* message, int flags, enum pakfire_hash_type checksum_types); int pakfire_compress_create_archive(struct pakfire* pakfire, struct archive** archive, FILE* f, const enum pakfire_compressions compression, const unsigned int level); diff --git a/src/pakfire/db.c b/src/pakfire/db.c index 72cf819af..51adffca6 100644 --- a/src/pakfire/db.c +++ b/src/pakfire/db.c @@ -31,9 +31,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -977,20 +977,23 @@ END: return r; } -static int pakfire_db_bind_digest(struct pakfire_db* db, sqlite3_stmt* stmt, const int field, - struct pakfire_file* file, const enum pakfire_digest_types type) { - const unsigned char* digest = NULL; - size_t length = 0; +static int pakfire_db_bind_checksum(struct pakfire_db* db, sqlite3_stmt* stmt, + const int field, struct pakfire_file* file, const enum pakfire_hash_type type) { + const unsigned char* checksum = NULL; + size_t checksum_length = 0; + int r; - // Fetch the digest - digest = pakfire_file_get_digest(file, type, &length); + // Fetch the checksum + r = pakfire_file_get_checksum(file, type, &checksum, &checksum_length); + if (r < 0) + return r; - // If this digest isn't set, just bind NULL - if (!digest) + // If this checksum isn't set, just bind NULL + if (!checksum) return sqlite3_bind_null(stmt, field); // Otherwise bind the data blob - return sqlite3_bind_blob(stmt, field, digest, length, NULL); + return sqlite3_bind_blob(stmt, field, checksum, checksum_length, NULL); } static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct pakfire_archive* archive) { @@ -1169,7 +1172,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // SHA2-512 Digest - r = pakfire_db_bind_digest(db, stmt, 13, file, PAKFIRE_DIGEST_SHA2_512); + r = pakfire_db_bind_checksum(db, stmt, 13, file, PAKFIRE_HASH_SHA2_512); if (r) { ERROR(db->ctx, "Could not bind SHA2-512 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1178,7 +1181,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // SHA2-256 Digest - r = pakfire_db_bind_digest(db, stmt, 14, file, PAKFIRE_DIGEST_SHA2_256); + r = pakfire_db_bind_checksum(db, stmt, 14, file, PAKFIRE_HASH_SHA2_256); if (r) { ERROR(db->ctx, "Could not bind SHA2-256 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1187,7 +1190,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // BLAKE2b512 Digest - r = pakfire_db_bind_digest(db, stmt, 15, file, PAKFIRE_DIGEST_BLAKE2B512); + r = pakfire_db_bind_checksum(db, stmt, 15, file, PAKFIRE_HASH_BLAKE2B512); if (r) { ERROR(db->ctx, "Could not bind BLAKE2b512 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1196,7 +1199,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // BLAKE2s256 Digest - r = pakfire_db_bind_digest(db, stmt, 16, file, PAKFIRE_DIGEST_BLAKE2S256); + r = pakfire_db_bind_checksum(db, stmt, 16, file, PAKFIRE_HASH_BLAKE2S256); if (r) { ERROR(db->ctx, "Could not bind BLAKE2s256 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1205,7 +1208,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // SHA3-512 Digest - r = pakfire_db_bind_digest(db, stmt, 17, file, PAKFIRE_DIGEST_SHA3_512); + r = pakfire_db_bind_checksum(db, stmt, 17, file, PAKFIRE_HASH_SHA3_512); if (r) { ERROR(db->ctx, "Could not bind SHA3-512 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1214,7 +1217,7 @@ static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, struct } // SHA3-256 Digest - r = pakfire_db_bind_digest(db, stmt, 18, file, PAKFIRE_DIGEST_SHA3_256); + r = pakfire_db_bind_checksum(db, stmt, 18, file, PAKFIRE_HASH_SHA3_256); if (r) { ERROR(db->ctx, "Could not bind SHA3-256 digest: %s\n", sqlite3_errmsg(db->handle)); @@ -1331,6 +1334,9 @@ END: int pakfire_db_add_package(struct pakfire_db* db, struct pakfire_package* pkg, struct pakfire_archive* archive, int userinstalled) { + enum pakfire_hash_type hash_type = PAKFIRE_HASH_UNDEFINED; + const unsigned char* checksum = NULL; + size_t checksum_length = 0; sqlite3_stmt* stmt = NULL; int r; @@ -1478,27 +1484,22 @@ int pakfire_db_add_package(struct pakfire_db* db, goto ERROR; } - const unsigned char* digest = NULL; - enum pakfire_digest_types digest_type = 0; - size_t digest_length = 0; - // Fetch the digest - digest = pakfire_package_get_digest(pkg, &digest_type, &digest_length); - if (!digest) { - ERROR(db->ctx, "Could not fetch the package's digest: %m\n"); - r = 1; + r = pakfire_package_get_checksum(pkg, &hash_type, &checksum, &checksum_length); + if (r < 0) { + ERROR(db->ctx, "Could not fetch the package checksum: %s\n", strerror(-r)); goto ERROR; } - // Set the digest type - r = sqlite3_bind_int64(stmt, 8, digest_type); + // Set the hash type + r = sqlite3_bind_int64(stmt, 8, hash_type); if (r) { ERROR(db->ctx, "Could not bind digest type: %s\n", sqlite3_errmsg(db->handle)); goto ERROR; } - // Set the digest - r = sqlite3_bind_blob(stmt, 9, digest, digest_length, NULL); + // Set the checksum + r = sqlite3_bind_blob(stmt, 9, checksum, checksum_length, NULL); if (r) { ERROR(db->ctx, "Could not bind digest: %s\n", sqlite3_errmsg(db->handle)); goto ERROR; @@ -1880,16 +1881,19 @@ static int pakfire_db_load_package(struct pakfire_db* db, struct pakfire_repo* r goto ERROR; } - // Digest type - enum pakfire_digest_types digest_type = sqlite3_column_int64(stmt, 8); - size_t digest_length = 0; + // Hash Type + enum pakfire_hash_type hash = sqlite3_column_int64(stmt, 8); - // Digest length + // Checksum + const unsigned char* checksum = sqlite3_column_blob(stmt, 9); - // Digest - const unsigned char* digest = sqlite3_column_blob(stmt, 9); - if (digest_type && digest) { - pakfire_package_set_digest(pkg, digest_type, digest, digest_length); + // Checksum Length + size_t checksum_length = sqlite3_column_bytes(stmt, 9); + + if (hash && checksum) { + r = pakfire_package_set_checksum(pkg, hash, checksum, checksum_length); + if (r < 0) + goto ERROR; } // License @@ -2178,20 +2182,20 @@ ERROR: return r; } -static int pakfire_db_load_file_digest(struct pakfire_db* db, struct pakfire_file* file, - sqlite3_stmt* stmt, const enum pakfire_digest_types type, const int field) { - // Fetch digest - const unsigned char* digest = sqlite3_column_blob(stmt, field); +static int pakfire_db_load_file_checksum(struct pakfire_db* db, struct pakfire_file* file, + sqlite3_stmt* stmt, const enum pakfire_hash_type type, const int field) { + // Fetch checksum + const unsigned char* checksum = sqlite3_column_blob(stmt, field); // Nothing further to do if field is NULL - if (!digest) + if (!checksum) return 0; // Length of the stored value - const size_t length = sqlite3_column_bytes(stmt, field); + const size_t checksum_length = sqlite3_column_bytes(stmt, field); // Store digest - return pakfire_file_set_digest(file, type, digest, length); + return pakfire_file_set_checksum(file, type, checksum, checksum_length); } static int pakfire_db_load_file(struct pakfire_db* db, struct pakfire_filelist* filelist, @@ -2276,32 +2280,32 @@ static int pakfire_db_load_file(struct pakfire_db* db, struct pakfire_filelist* goto ERROR; // SHA2-512 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_SHA2_512, 8); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_SHA2_512, 8); if (r) goto ERROR; // SHA2-256 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_SHA2_256, 9); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_SHA2_256, 9); if (r) goto ERROR; // BLAKE2b512 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_BLAKE2B512, 10); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_BLAKE2B512, 10); if (r) goto ERROR; // BLAKE2s256 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_BLAKE2S256, 11); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_BLAKE2S256, 11); if (r) goto ERROR; // SHA3-512 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_SHA3_512, 12); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_SHA3_512, 12); if (r) goto ERROR; // SHA3-256 Digest - r = pakfire_db_load_file_digest(db, file, stmt, PAKFIRE_DIGEST_SHA3_256, 13); + r = pakfire_db_load_file_checksum(db, file, stmt, PAKFIRE_HASH_SHA3_256, 13); if (r) goto ERROR; diff --git a/src/pakfire/digest.c b/src/pakfire/digest.c deleted file mode 100644 index cee3a1457..000000000 --- a/src/pakfire/digest.c +++ /dev/null @@ -1,654 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2022 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -#############################################################################*/ - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static const struct _pakfire_digest_name { - const char* name; - const enum pakfire_digest_types type; -} PAKFIRE_DIGEST_NAMES[] = { - // SHA-2 - { "sha2-512", PAKFIRE_DIGEST_SHA2_512, }, - { "sha2-256", PAKFIRE_DIGEST_SHA2_256, }, - - // BLAKE2 - { "blake2b512", PAKFIRE_DIGEST_BLAKE2B512, }, - { "blake2s256", PAKFIRE_DIGEST_BLAKE2S256, }, - - // SHA-3 - { "sha3-512", PAKFIRE_DIGEST_SHA3_512, }, - { "sha3-256", PAKFIRE_DIGEST_SHA3_256, }, - - { NULL, PAKFIRE_DIGEST_UNDEFINED, }, -}; - -const char* pakfire_digest_name(const enum pakfire_digest_types type) { - for (const struct _pakfire_digest_name* n = PAKFIRE_DIGEST_NAMES; n->name; n++) { - if (n->type == type) - return n->name; - } - - return NULL; -} - -int pakfire_digest_get_by_name(const char* name) { - // Check that name is not NULL - if (!name) { - errno = EINVAL; - return PAKFIRE_DIGEST_UNDEFINED; - } - - for (const struct _pakfire_digest_name* n = PAKFIRE_DIGEST_NAMES; n->name; n++) { - if (strcmp(n->name, name) == 0) - return n->type; - } - - return PAKFIRE_DIGEST_UNDEFINED; -} - -size_t pakfire_digest_length(const enum pakfire_digest_types digest) { - switch (digest) { - case PAKFIRE_DIGEST_SHA3_512: - return SHA512_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_SHA3_256: - return SHA256_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_BLAKE2B512: - return BLAKE2B512_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_BLAKE2S256: - return BLAKE2S256_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_SHA2_512: - return SHA512_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_SHA2_256: - return SHA256_DIGEST_LENGTH; - - case PAKFIRE_DIGEST_UNDEFINED: - return 0; - } - - return 0; -} - -const unsigned char* pakfire_digest_get(struct pakfire_digests* digests, - const enum pakfire_digest_types type, size_t* length) { - // Set length - if (length) - *length = pakfire_digest_length(type); - - // Return a pointer to the digest (if set) - switch (type) { - case PAKFIRE_DIGEST_SHA3_512: - if (pakfire_digest_set(digests->sha3_512)) - return digests->sha3_512; - break; - - case PAKFIRE_DIGEST_SHA3_256: - if (pakfire_digest_set(digests->sha3_256)) - return digests->sha3_256; - break; - - case PAKFIRE_DIGEST_BLAKE2B512: - if (pakfire_digest_set(digests->blake2b512)) - return digests->blake2b512; - break; - - case PAKFIRE_DIGEST_BLAKE2S256: - if (pakfire_digest_set(digests->blake2s256)) - return digests->blake2s256; - break; - - case PAKFIRE_DIGEST_SHA2_512: - if (pakfire_digest_set(digests->sha2_512)) - return digests->sha2_512; - break; - - case PAKFIRE_DIGEST_SHA2_256: - if (pakfire_digest_set(digests->sha2_256)) - return digests->sha2_256; - break; - - case PAKFIRE_DIGEST_UNDEFINED: - break; - } - - return NULL; -} - -char* pakfire_digest_get_hex(struct pakfire_digests* digests, - const enum pakfire_digest_types type) { - size_t length = 0; - - const unsigned char* digest = pakfire_digest_get(digests, type, &length); - if (!digest) - return NULL; - - return __pakfire_hexlify(digest, length); -} - -/* - Returns one if the digest is not all zeros. -*/ -int __pakfire_digest_set(const unsigned char* digest, const size_t length) { - for (unsigned int i = 0; i < length; i++) { - if (digest[i]) - return 1; - } - - return 0; -} - -/* - Returns a bitmap of all digests that are set. -*/ -int pakfire_digest_has_any(const struct pakfire_digests* digests) { - int types = PAKFIRE_DIGEST_UNDEFINED; - - if (pakfire_digest_set(digests->sha3_512)) - types |= PAKFIRE_DIGEST_SHA3_512; - - if (pakfire_digest_set(digests->sha3_256)) - types |= PAKFIRE_DIGEST_SHA3_256; - - if (pakfire_digest_set(digests->blake2b512)) - types |= PAKFIRE_DIGEST_BLAKE2B512; - - if (pakfire_digest_set(digests->blake2s256)) - types |= PAKFIRE_DIGEST_BLAKE2S256; - - if (pakfire_digest_set(digests->sha2_512)) - types |= PAKFIRE_DIGEST_SHA2_512; - - if (pakfire_digest_set(digests->sha2_256)) - types |= PAKFIRE_DIGEST_SHA2_256; - - return types; -} - -/* - Returns a bitmap of all digests that are not set, yet -*/ -static int pakfire_digest_needed(const struct pakfire_digests* digests, const int needed) { - // Fetch any currently set digests - const int have = pakfire_digest_has_any(digests); - - return (~have & needed); -} - -void pakfire_digests_reset(struct pakfire_digests* digests, int types) { - if (!types) - types = ~types; - - // Reset SHA-3-512 - if (types & PAKFIRE_DIGEST_SHA3_512) - memset(digests->sha3_512, 0, sizeof(digests->sha3_512)); - - // Reset SHA-3-256 - if (types & PAKFIRE_DIGEST_SHA3_256) - memset(digests->sha3_256, 0, sizeof(digests->sha3_256)); - - // Reset BLAKE2b512 - if (types & PAKFIRE_DIGEST_BLAKE2B512) - memset(digests->blake2b512, 0, sizeof(digests->blake2b512)); - - // Reset BLAKE2s256 - if (types & PAKFIRE_DIGEST_BLAKE2S256) - memset(digests->blake2s256, 0, sizeof(digests->blake2s256)); - - // Reset SHA-2-512 - if (types & PAKFIRE_DIGEST_SHA2_512) - memset(digests->sha2_512, 0, sizeof(digests->sha2_512)); - - // Reset SHA-2-256 - if (types & PAKFIRE_DIGEST_SHA2_256) - memset(digests->sha2_256, 0, sizeof(digests->sha2_256)); -} - -static int pakfire_digests_check_length(struct pakfire_ctx* ctx, - const enum pakfire_digest_types type, const size_t length) { - const size_t l = pakfire_digest_length(type); - - // Return if length matches - if (length == l) - return 0; - - // Otherwise set an error - ERROR(ctx, "Digest is of an unexpected length\n"); - - return -ENOMSG; -} - -static EVP_MD_CTX* __pakfire_digest_setup(struct pakfire_ctx* ctx, const EVP_MD* md) { - EVP_MD_CTX* evp_ctx = NULL; - int r; - - // Setup a new context - evp_ctx = EVP_MD_CTX_new(); - if (!evp_ctx) { - ERROR(ctx, "Could not initialize OpenSSL context: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - goto ERROR; - } - - // Setup digest - r = EVP_DigestInit_ex(evp_ctx, md, NULL); - if (r != 1) { - ERROR(ctx, "Could not setup digest: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - goto ERROR; - } - - return evp_ctx; - -ERROR: - if (evp_ctx) - EVP_MD_CTX_free(evp_ctx); - - return NULL; -} - -static int __pakfire_digest_update(struct pakfire_ctx* ctx, EVP_MD_CTX* evp_ctx, - const char* buffer, const size_t length) { - int r; - - // Nothing to do if digest not initialized - if (!evp_ctx) - return 0; - - // Update digest - r = EVP_DigestUpdate(evp_ctx, buffer, length); - if (r != 1) { - ERROR(ctx, "EVP_Digest_Update() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return 1; - } - - return 0; -} - -static int __pakfire_digest_finalize(struct pakfire_ctx* ctx, - EVP_MD_CTX* evp_ctx, unsigned char* digest) { - int r; - - // Nothing to do if digest not initialized - if (!evp_ctx) - return 0; - - // Finalize digest - r = EVP_DigestFinal_ex(evp_ctx, digest, NULL); - if (r != 1) { - ERROR(ctx, "EVP_DigestFinal_ex() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return 1; - } - - return 0; -} - -int pakfire_digests_compute_from_file(struct pakfire_ctx* ctx, - struct pakfire_digests* digests, int types, FILE* f) { - EVP_MD_CTX* sha3_512_ctx = NULL; - EVP_MD_CTX* sha3_256_ctx = NULL; - EVP_MD_CTX* blake2b512_ctx = NULL; - EVP_MD_CTX* blake2s256_ctx = NULL; - EVP_MD_CTX* sha2_512_ctx = NULL; - EVP_MD_CTX* sha2_256_ctx = NULL; - char buffer[65536]; - int r = 1; - - // Check if any digests have been computed before and select only those that we need - types = pakfire_digest_needed(digests, types); - - // Nothing to do? - if (!types) - return 0; - - // Initialize context for SHA-3-512 - if (types & PAKFIRE_DIGEST_SHA3_512) { - sha3_512_ctx = __pakfire_digest_setup(ctx, EVP_sha3_512()); - if (!sha3_512_ctx) - goto ERROR; - } - - // Initialize context for SHA-3-256 - if (types & PAKFIRE_DIGEST_SHA3_256) { - sha3_256_ctx = __pakfire_digest_setup(ctx, EVP_sha3_256()); - if (!sha3_256_ctx) - goto ERROR; - } - - // Initialize context for BLAKE2B512 - if (types & PAKFIRE_DIGEST_BLAKE2B512) { - blake2b512_ctx = __pakfire_digest_setup(ctx, EVP_blake2b512()); - if (!blake2b512_ctx) - goto ERROR; - } - - // Initialize context for BLAKE2S256 - if (types & PAKFIRE_DIGEST_BLAKE2S256) { - blake2s256_ctx = __pakfire_digest_setup(ctx, EVP_blake2s256()); - if (!blake2s256_ctx) - goto ERROR; - } - - // Initialize context for SHA-2-512 - if (types & PAKFIRE_DIGEST_SHA2_512) { - sha2_512_ctx = __pakfire_digest_setup(ctx, EVP_sha512()); - if (!sha2_512_ctx) - goto ERROR; - } - - // Initialize context for SHA-2-256 - if (types & PAKFIRE_DIGEST_SHA2_256) { - sha2_256_ctx = __pakfire_digest_setup(ctx, EVP_sha256()); - if (!sha2_256_ctx) - goto ERROR; - } - - // Read the file into the hash functions - while (!feof(f)) { - size_t bytes_read = fread(buffer, 1, sizeof(buffer), f); - - // Raise any reading errors - if (ferror(f)) { - r = 1; - goto ERROR; - } - - // SHA-3-512 - r = __pakfire_digest_update(ctx, sha3_512_ctx, buffer, bytes_read); - if (r) - goto ERROR; - - // SHA-3-256 - r = __pakfire_digest_update(ctx, sha3_256_ctx, buffer, bytes_read); - if (r) - goto ERROR; - - // BLAKE2B512 - r = __pakfire_digest_update(ctx, blake2b512_ctx, buffer, bytes_read); - if (r) - goto ERROR; - - // BLAKE2S256 - r = __pakfire_digest_update(ctx, blake2s256_ctx, buffer, bytes_read); - if (r) - goto ERROR; - - // SHA-2-512 - r = __pakfire_digest_update(ctx, sha2_512_ctx, buffer, bytes_read); - if (r) - goto ERROR; - - // SHA-2-256 - r = __pakfire_digest_update(ctx, sha2_256_ctx, buffer, bytes_read); - if (r) - goto ERROR; - } - - // Finalize SHA-3-512 - r = __pakfire_digest_finalize(ctx, sha3_512_ctx, digests->sha3_512); - if (r) - goto ERROR; - - // Finalize SHA-3-256 - r = __pakfire_digest_finalize(ctx, sha3_256_ctx, digests->sha3_256); - if (r) - goto ERROR; - - // Finalize BLAKE2b512 - r = __pakfire_digest_finalize(ctx, blake2b512_ctx, digests->blake2b512); - if (r) - goto ERROR; - - // Finalize BLAKE2s256 - r = __pakfire_digest_finalize(ctx, blake2s256_ctx, digests->blake2s256); - if (r) - goto ERROR; - - // Finalize SHA-2-512 - r = __pakfire_digest_finalize(ctx, sha2_512_ctx, digests->sha2_512); - if (r) - goto ERROR; - - // Finalize SHA-2-256 - r = __pakfire_digest_finalize(ctx, sha2_256_ctx, digests->sha2_256); - if (r) - goto ERROR; - - // Done! - r = 0; - -ERROR: - if (sha3_512_ctx) - EVP_MD_CTX_free(sha3_512_ctx); - if (sha3_256_ctx) - EVP_MD_CTX_free(sha3_256_ctx); - if (blake2b512_ctx) - EVP_MD_CTX_free(blake2b512_ctx); - if (blake2s256_ctx) - EVP_MD_CTX_free(blake2s256_ctx); - if (sha2_512_ctx) - EVP_MD_CTX_free(sha2_512_ctx); - if (sha2_256_ctx) - EVP_MD_CTX_free(sha2_256_ctx); - - return r; -} - -int pakfire_digests_compute_from_path(struct pakfire_ctx* ctx, - struct pakfire_digests* digests, int types, const char* path) { - FILE* f = NULL; - int r; - - // Open the file - f = fopen(path, "r"); - if (!f) - return -errno; - - // Compute the digests - r = pakfire_digests_compute_from_file(ctx, digests, types, f); - - // Close the file - if (f) - fclose(f); - - return r; -} - -static void pakfire_digests_compare_mismatch(struct pakfire_ctx* ctx, const char* what, - const unsigned char* digest1, const unsigned char* digest2, const size_t length) { - char* hexdigest1 = __pakfire_hexlify(digest1, length); - char* hexdigest2 = __pakfire_hexlify(digest2, length); - - DEBUG(ctx, "%s digest does not match:\n", what); - - if (hexdigest1) - DEBUG(ctx, " Digest 1: %s\n", hexdigest1); - if (hexdigest2) - DEBUG(ctx, " Digest 2: %s\n", hexdigest2); - - if (hexdigest1) - free(hexdigest1); - if (hexdigest2) - free(hexdigest2); -} - -int pakfire_digests_compare(struct pakfire_ctx* ctx, const struct pakfire_digests* digests1, - const struct pakfire_digests* digests2, const int types) { - int r; - - // Check if we are at least comparing one type - if (!types) - return -EINVAL; - - // Check SHA-3-512 - if (types & PAKFIRE_DIGEST_SHA3_512) { - r = CRYPTO_memcmp(digests1->sha3_512, digests2->sha3_512, sizeof(digests1->sha3_512)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "SHA-3-512", - digests1->sha3_512, digests2->sha3_512, sizeof(digests1->sha3_512)); - return 1; - } - } - - // Check SHA-3-256 - if (types & PAKFIRE_DIGEST_SHA3_256) { - r = CRYPTO_memcmp(digests1->sha3_256, digests2->sha3_256, sizeof(digests1->sha3_256)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "SHA-3-256", - digests1->sha3_256, digests2->sha3_256, sizeof(digests1->sha3_256)); - return 1; - } - } - - // Check BLAKE2b512 - if (types & PAKFIRE_DIGEST_BLAKE2B512) { - r = CRYPTO_memcmp(digests1->blake2b512, digests2->blake2b512, sizeof(digests1->blake2b512)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "BLAKE2b512", - digests1->blake2b512, digests2->blake2b512, sizeof(digests1->blake2b512)); - return 1; - } - } - - // Check BLAKE2s256 - if (types & PAKFIRE_DIGEST_BLAKE2S256) { - r = CRYPTO_memcmp(digests1->blake2s256, digests2->blake2s256, sizeof(digests1->blake2s256)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "BLAKE2s256", - digests1->blake2s256, digests2->blake2s256, sizeof(digests1->blake2s256)); - return 1; - } - } - - // Check SHA-2-512 - if (types & PAKFIRE_DIGEST_SHA2_512) { - r = CRYPTO_memcmp(digests1->sha2_512, digests2->sha2_512, sizeof(digests1->sha2_512)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "SHA-2-512", - digests1->sha2_512, digests2->sha2_512, sizeof(digests1->sha2_512)); - return 1; - } - } - - // Check SHA-2-256 - if (types & PAKFIRE_DIGEST_SHA2_256) { - r = CRYPTO_memcmp(digests1->sha2_256, digests2->sha2_256, sizeof(digests1->sha2_256)); - if (r) { - pakfire_digests_compare_mismatch(ctx, "SHA-2-256", - digests1->sha2_256, digests2->sha2_256, sizeof(digests1->sha2_256)); - return 1; - } - } - - // All digests match - return 0; -} - -int pakfire_digests_compare_one(struct pakfire_ctx* ctx, 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(ctx, type, length); - if (r) - return r; - - switch (type) { - case PAKFIRE_DIGEST_SHA3_512: - memcpy(digests2.sha3_512, digest, sizeof(digests2.sha3_512)); - break; - - case PAKFIRE_DIGEST_SHA3_256: - memcpy(digests2.sha3_256, digest, sizeof(digests2.sha3_256)); - break; - - case PAKFIRE_DIGEST_BLAKE2B512: - memcpy(digests2.blake2b512, digest, sizeof(digests2.blake2b512)); - break; - - case PAKFIRE_DIGEST_BLAKE2S256: - memcpy(digests2.blake2s256, digest, sizeof(digests2.blake2s256)); - break; - - case PAKFIRE_DIGEST_SHA2_512: - memcpy(digests2.sha2_512, digest, sizeof(digests2.sha2_512)); - break; - - case PAKFIRE_DIGEST_SHA2_256: - memcpy(digests2.sha2_256, digest, sizeof(digests2.sha2_256)); - break; - - case PAKFIRE_DIGEST_UNDEFINED: - break; - } - - return pakfire_digests_compare(ctx, digests1, &digests2, type); -} - -int pakfire_digests_set_hexdigest(struct pakfire_digests* digests, - const enum pakfire_digest_types type, const char* hexdigest) { - switch (type) { - case PAKFIRE_DIGEST_SHA3_512: - return pakfire_unhexlify(digests->sha3_512, hexdigest); - - case PAKFIRE_DIGEST_SHA3_256: - return pakfire_unhexlify(digests->sha3_256, hexdigest); - - case PAKFIRE_DIGEST_BLAKE2B512: - return pakfire_unhexlify(digests->blake2b512, hexdigest); - - case PAKFIRE_DIGEST_BLAKE2S256: - return pakfire_unhexlify(digests->blake2s256, hexdigest); - - case PAKFIRE_DIGEST_SHA2_512: - return pakfire_unhexlify(digests->sha2_512, hexdigest); - - case PAKFIRE_DIGEST_SHA2_256: - return pakfire_unhexlify(digests->sha2_256, hexdigest); - - default: - return -EINVAL; - } -} - -int pakfire_digests_import(struct pakfire_digests* dst, const struct pakfire_digests* src) { - // Copy everything - memcpy(dst, src, sizeof(*dst)); - - return 0; -} diff --git a/src/pakfire/digest.h b/src/pakfire/digest.h deleted file mode 100644 index c0441610e..000000000 --- a/src/pakfire/digest.h +++ /dev/null @@ -1,120 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2022 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -#############################################################################*/ - -#ifndef PAKFIRE_DIGEST_H -#define PAKFIRE_DIGEST_H - -#include - -// OpenSSL -#include - -// Pakfire knows these digests -enum pakfire_digest_types { - PAKFIRE_DIGEST_UNDEFINED = 0, - PAKFIRE_DIGEST_SHA2_256 = (1 << 0), - PAKFIRE_DIGEST_SHA2_512 = (1 << 1), - PAKFIRE_DIGEST_BLAKE2S256 = (1 << 2), - PAKFIRE_DIGEST_BLAKE2B512 = (1 << 3), - PAKFIRE_DIGEST_SHA3_256 = (1 << 4), - PAKFIRE_DIGEST_SHA3_512 = (1 << 5), -}; - -#define PAKFIRE_DIGESTS_ALL ( \ - PAKFIRE_DIGEST_SHA2_256 | \ - PAKFIRE_DIGEST_SHA2_512 | \ - PAKFIRE_DIGEST_BLAKE2S256 | \ - PAKFIRE_DIGEST_BLAKE2B512 | \ - PAKFIRE_DIGEST_SHA3_256 | \ - PAKFIRE_DIGEST_SHA3_512 \ -) - -#define PAKFIRE_DIGESTS_FOREACH(digest) \ - for (digest = 1; digest & PAKFIRE_DIGESTS_ALL; digest <<= 1) - -#include - -const char* pakfire_digest_name(const enum pakfire_digest_types type); -int pakfire_digest_get_by_name(const char* name); - -// libsolv only supports storing one checksum which has to be of a supported type -#define PAKFIRE_ARCHIVE_CHECKSUM PAKFIRE_DIGEST_SHA2_512 - -// Define BLAKE2's digest lengths -#ifndef BLAKE2S256_DIGEST_LENGTH -# define BLAKE2S256_DIGEST_LENGTH 32 -#endif /* BLAKE2S256_DIGEST_LENGTH */ - -#ifndef BLAKE2B512_DIGEST_LENGTH -# define BLAKE2B512_DIGEST_LENGTH 64 -#endif /* BLAKE2B512_DIGEST_LENGTH */ - -// Digests -struct pakfire_digests { - // SHA-3-512 - unsigned char sha3_512[SHA512_DIGEST_LENGTH]; - - // SHA-3-256 - unsigned char sha3_256[SHA256_DIGEST_LENGTH]; - - // BLAKE2b512 - unsigned char blake2b512[BLAKE2B512_DIGEST_LENGTH]; - - // BLAKE2s256 - unsigned char blake2s256[BLAKE2S256_DIGEST_LENGTH]; - - // SHA2-512 - unsigned char sha2_512[SHA512_DIGEST_LENGTH]; - - // SHA2-256 - unsigned char sha2_256[SHA256_DIGEST_LENGTH]; -}; - -size_t pakfire_digest_length(const enum pakfire_digest_types digest); - -const unsigned char* pakfire_digest_get(struct pakfire_digests* digests, - const enum pakfire_digest_types type, size_t* length); - -char* pakfire_digest_get_hex(struct pakfire_digests* digests, - const enum pakfire_digest_types type); - -#define pakfire_digest_set(digest) __pakfire_digest_set(digest, sizeof(digest)) -int __pakfire_digest_set(const unsigned char* digest, const size_t length); - -int pakfire_digest_has_any(const struct pakfire_digests* digests); - -void pakfire_digests_reset(struct pakfire_digests* digests, int types); - -int pakfire_digests_compute_from_file(struct pakfire_ctx* ctx, - struct pakfire_digests* digests, int types, FILE* f); -int pakfire_digests_compute_from_path(struct pakfire_ctx* ctx, - struct pakfire_digests* digests, int types, const char* path); - -int pakfire_digests_compare(struct pakfire_ctx* ctx, const struct pakfire_digests* digests1, - const struct pakfire_digests* digests2, const int types); -int pakfire_digests_compare_one(struct pakfire_ctx* ctx, struct pakfire_digests* digests1, - const enum pakfire_digest_types type, const unsigned char* digest, const size_t length); - -int pakfire_digests_set_hexdigest(struct pakfire_digests* digests, - const enum pakfire_digest_types type, const char* hexdigest); - -int pakfire_digests_import(struct pakfire_digests* dst, const struct pakfire_digests* src); - -#endif /* PAKFIRE_DIGEST_H */ diff --git a/src/pakfire/file.c b/src/pakfire/file.c index 13b34f53c..b4f1ae87f 100644 --- a/src/pakfire/file.c +++ b/src/pakfire/file.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include @@ -74,8 +74,8 @@ struct pakfire_file { // Flags int flags; - // Digests - struct pakfire_digests digests; + // Hashes + struct pakfire_hashes hashes; // MIME Type char mimetype[NAME_MAX]; @@ -323,41 +323,43 @@ static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct arc if (r) goto ERROR; +#if 0 // Digest: SHA-3-512 } else if (strcmp(attr, "PAKFIRE.digests.sha3_512") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_512, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_SHA3_512, value, size); + if (r < 0) goto ERROR; // Digest: SHA-3-256 } else if (strcmp(attr, "PAKFIRE.digests.sha3_256") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_256, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_SHA3_256, value, size); + if (r < 0) goto ERROR; // Digest: BLAKE2b512 } else if (strcmp(attr, "PAKFIRE.digests.blake2b512") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2B512, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_BLAKE2B512, value, size); + if (r < 0) goto ERROR; // Digest: BLAKE2s256 } else if (strcmp(attr, "PAKFIRE.digests.blake2s256") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2S256, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_BLAKE2S256, value, size); + if (r < 0) goto ERROR; // Digest: SHA-2-512 } else if (strcmp(attr, "PAKFIRE.digests.sha2_512") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_512, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_SHA2_512, value, size); + if (r < 0) goto ERROR; // Digest: SHA-2-256 } else if (strcmp(attr, "PAKFIRE.digests.sha2_256") == 0) { - r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_256, value, size); - if (r) + r = pakfire_file_set_checksum(file, PAKFIRE_HASH_SHA2_256, value, size); + if (r < 0) goto ERROR; +#endif // Capabilities } else if (strcmp(attr, "security.capability") == 0) { @@ -420,6 +422,39 @@ ERROR: return r; } +static int pakfire_file_compute_hashes(struct pakfire_file* file, + const enum pakfire_hash_type types, struct pakfire_hashes* hashes) { + FILE* f = NULL; + int r; + + const mode_t mode = pakfire_file_get_mode(file); + + // Skip this for anything that isn't a regular file + if (!S_ISREG(mode)) + return 0; + + // Reset hashes + pakfire_hashes_reset(hashes); + + // Open the file + f = pakfire_file_fopen(file, "r"); + if (!f) { + r = -errno; + goto ERROR; + } + + // Compute hashes + r = pakfire_hash_file(file->ctx, f, types, hashes); + if (r < 0) + goto ERROR; + +ERROR: + if (f) + fclose(f); + + return r; +} + int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, struct archive_entry* entry) { struct pakfire_file* f = NULL; @@ -444,7 +479,7 @@ ERROR: return r; } -struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) { +struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, const enum pakfire_hash_type hashes) { struct archive_entry* entry = NULL; struct vfs_cap_data cap_data = {}; int r; @@ -467,48 +502,40 @@ struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int "PAKFIRE.mimetype", mimetype, strlen(mimetype)); } - // Compute any required file digests - r = pakfire_file_compute_digests(file, digest_types); - if (r) + // Compute any required file hashes + r = pakfire_file_compute_hashes(file, hashes, &file->hashes); + if (r < 0) goto ERROR; - // Copy digests - // SHA-3-512 - if ((digest_types & PAKFIRE_DIGEST_SHA3_512) - && pakfire_digest_set(file->digests.sha3_512)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_SHA3_512)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_512", - file->digests.sha3_512, sizeof(file->digests.sha3_512)); + file->hashes.sha3_512, sizeof(file->hashes.sha3_512)); // SHA-3-256 - if ((digest_types & PAKFIRE_DIGEST_SHA3_256) && - pakfire_digest_set(file->digests.sha3_256)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_SHA3_256)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_256", - file->digests.sha3_256, sizeof(file->digests.sha3_256)); + file->hashes.sha3_256, sizeof(file->hashes.sha3_256)); // BLAKE2b512 - if ((digest_types & PAKFIRE_DIGEST_BLAKE2B512) && - pakfire_digest_set(file->digests.blake2b512)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_BLAKE2B512)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2b512", - file->digests.blake2b512, sizeof(file->digests.blake2b512)); + file->hashes.blake2b512, sizeof(file->hashes.blake2b512)); // BLAKE2s256 - if ((digest_types & PAKFIRE_DIGEST_BLAKE2S256) && - pakfire_digest_set(file->digests.blake2s256)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_BLAKE2S256)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2s256", - file->digests.blake2s256, sizeof(file->digests.blake2s256)); + file->hashes.blake2s256, sizeof(file->hashes.blake2s256)); // SHA-2-512 - if ((digest_types & PAKFIRE_DIGEST_SHA2_512) && - pakfire_digest_set(file->digests.sha2_512)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_SHA2_512)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_512", - file->digests.sha2_512, sizeof(file->digests.sha2_512)); + file->hashes.sha2_512, sizeof(file->hashes.sha2_512)); // SHA-2-256 - if ((digest_types & PAKFIRE_DIGEST_SHA2_512) && - pakfire_digest_set(file->digests.sha2_256)) + if (pakfire_hashes_has(&file->hashes, PAKFIRE_HASH_SHA2_256)) archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256", - file->digests.sha2_256, sizeof(file->digests.sha2_256)); + file->hashes.sha2_256, sizeof(file->hashes.sha2_256)); // Capabilities if (file->caps) { @@ -924,111 +951,35 @@ int pakfire_file_has_payload(struct pakfire_file* file) { return pakfire_file_get_size(file) > 0; } -const unsigned char* pakfire_file_get_digest( - struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) { - - switch (type) { - case PAKFIRE_DIGEST_SHA3_512: - if (!pakfire_digest_set(file->digests.sha3_512)) - return NULL; - - if (length) - *length = sizeof(file->digests.sha3_512); - - return file->digests.sha3_512; - - case PAKFIRE_DIGEST_SHA3_256: - if (!pakfire_digest_set(file->digests.sha3_256)) - return NULL; - - if (length) - *length = sizeof(file->digests.sha3_256); - - return file->digests.sha3_256; - - case PAKFIRE_DIGEST_BLAKE2B512: - if (!pakfire_digest_set(file->digests.blake2b512)) - return NULL; - - if (length) - *length = sizeof(file->digests.blake2b512); - - return file->digests.blake2b512; - - case PAKFIRE_DIGEST_BLAKE2S256: - if (!pakfire_digest_set(file->digests.blake2s256)) - return NULL; - - if (length) - *length = sizeof(file->digests.blake2s256); - - return file->digests.blake2s256; - - case PAKFIRE_DIGEST_SHA2_512: - if (!pakfire_digest_set(file->digests.sha2_512)) - return NULL; - - if (length) - *length = sizeof(file->digests.sha2_512); - - return file->digests.sha2_512; - - case PAKFIRE_DIGEST_SHA2_256: - if (!pakfire_digest_set(file->digests.sha2_256)) - return NULL; - - if (length) - *length = sizeof(file->digests.sha2_256); - - return file->digests.sha2_256; +int pakfire_file_get_checksum(struct pakfire_file* file, const enum pakfire_hash_type type, + const unsigned char** checksum, size_t* checksum_length) { + int r; - case PAKFIRE_DIGEST_UNDEFINED: - break; + // Fetch the checksum + r = pakfire_hashes_get(&file->hashes, type, checksum, checksum_length); + if (r < 0) { + ERROR(file->ctx, "Failed to fetch checksum for %s: %s\n", + pakfire_file_get_path(file), strerror(-r)); + return r; } - return NULL; + return 0; } -int pakfire_file_set_digest(struct pakfire_file* file, - const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) { - if (!digest) - return -EINVAL; - - // Check buffer length - if (pakfire_digest_length(type) != length) { - ERROR(file->ctx, "Digest has an incorrect length of %zu byte(s)\n", length); - return -ENOMSG; - } - - // Store the digest - switch (type) { - case PAKFIRE_DIGEST_SHA3_512: - memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512)); - break; - - case PAKFIRE_DIGEST_SHA3_256: - memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256)); - break; - - case PAKFIRE_DIGEST_BLAKE2B512: - memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512)); - break; - - case PAKFIRE_DIGEST_BLAKE2S256: - memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256)); - break; - - case PAKFIRE_DIGEST_SHA2_512: - memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512)); - break; +int pakfire_file_set_checksum(struct pakfire_file* file, const enum pakfire_hash_type type, + const unsigned char* checksum, const size_t checksum_length) { + int r; - case PAKFIRE_DIGEST_SHA2_256: - memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256)); - break; + // Check inputs + if (!checksum) + return -EINVAL; - case PAKFIRE_DIGEST_UNDEFINED: - errno = ENOTSUP; - return 1; + // Store the checksum + r = pakfire_hashes_set(&file->hashes, type, checksum, checksum_length); + if (r < 0) { + ERROR(file->ctx, "Failed to set checksum for %s: %s\n", + pakfire_file_get_path(file), strerror(-r)); + return r; } return 0; @@ -1200,43 +1151,6 @@ ERROR: return r; } -static int __pakfire_file_compute_digests(struct pakfire_file* file, - struct pakfire_digests* digests, const int types) { - FILE* f = NULL; - int r; - - const mode_t mode = pakfire_file_get_mode(file); - - // Skip this for anything that isn't a regular file - if (!S_ISREG(mode)) - return 0; - - // Reset digests - pakfire_digests_reset(digests, types); - - // Open the file - f = pakfire_file_fopen(file, "r"); - if (!f) { - r = -errno; - goto ERROR; - } - - // Compute digests - r = pakfire_digests_compute_from_file(file->ctx, digests, types, f); - if (r) - goto ERROR; - -ERROR: - if (f) - fclose(f); - - return r; -} - -int pakfire_file_compute_digests(struct pakfire_file* file, const int types) { - return __pakfire_file_compute_digests(file, &file->digests, types); -} - static int pakfire_file_remove(struct pakfire_file* file) { int r; @@ -1682,11 +1596,9 @@ static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struc } static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) { + struct pakfire_hashes computed_hashes = {}; int r; - struct pakfire_digests computed_digests; - int digest_types = PAKFIRE_DIGEST_UNDEFINED; - // Nothing to do for anything that isn't a regular file if (!S_ISREG(st->st_mode)) return 0; @@ -1697,29 +1609,26 @@ static int pakfire_file_verify_payload(struct pakfire_file* file, const struct s return 0; } - // Check if this file has any digests at all - digest_types = pakfire_digest_has_any(&file->digests); - - if (!digest_types) { - ERROR(file->ctx, "%s: No digests available\n", pakfire_file_get_path(file)); + // Fail if the file has no hashes + if (!file->hashes.types) { + ERROR(file->ctx, "%s: No checksums available\n", pakfire_file_get_path(file)); return 0; } // Compute digests - r = __pakfire_file_compute_digests(file, &computed_digests, digest_types); - if (r) - goto ERROR; + r = pakfire_file_compute_hashes(file, file->hashes.types, &computed_hashes); + if (r < 0) + return r; - // Compare digests - r = pakfire_digests_compare(file->ctx, &file->digests, &computed_digests, digest_types); + // Compare hashes + r = pakfire_hashes_compare(file->ctx, &file->hashes, &computed_hashes); if (r) { file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; - DEBUG(file->ctx, "%s: Digest(s) do not match\n", pakfire_file_get_path(file)); + DEBUG(file->ctx, "%s: Checksum(s) do not match\n", pakfire_file_get_path(file)); } -ERROR: - return r; + return 0; } /* diff --git a/src/pakfire/file.h b/src/pakfire/file.h index 84ff7099a..eaf826540 100644 --- a/src/pakfire/file.h +++ b/src/pakfire/file.h @@ -32,7 +32,7 @@ struct pakfire_file; -#include +#include #include enum pakfire_file_flags { @@ -88,10 +88,11 @@ void pakfire_file_set_ctime(struct pakfire_file* file, time_t time); time_t pakfire_file_get_mtime(struct pakfire_file* file); void pakfire_file_set_mtime(struct pakfire_file* file, time_t time); -const unsigned char* pakfire_file_get_digest(struct pakfire_file* file, - const enum pakfire_digest_types type, size_t* length); -int pakfire_file_set_digest(struct pakfire_file* file, - const enum pakfire_digest_types type, const unsigned char* digest, const size_t length); +// Checksums +int pakfire_file_get_checksum(struct pakfire_file* file, const enum pakfire_hash_type type, + const unsigned char** checksum, size_t* checksum_length); +int pakfire_file_set_checksum(struct pakfire_file* file, const enum pakfire_hash_type type, + const unsigned char* checksum, const size_t checksum_length); // Capabilities int pakfire_file_has_caps(struct pakfire_file* file); @@ -133,7 +134,7 @@ int pakfire_file_write_fcaps(struct pakfire_file* file, struct vfs_cap_data* cap int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, struct archive_entry* entry); -struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types); +struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, const enum pakfire_hash_type hashes); enum pakfire_file_dump_flags { PAKFIRE_FILE_DUMP_MODE = (1 << 0), @@ -159,8 +160,6 @@ FILE* pakfire_file_fopen(struct pakfire_file* file, const char* mode); int pakfire_file_contains(struct pakfire_file* file, const char* needle, ssize_t length); -int pakfire_file_compute_digests(struct pakfire_file* file, const int types); - enum pakfire_file_cleanup_flags { PAKFIRE_FILE_CLEANUP_TIDY = (1 << 0), }; diff --git a/src/pakfire/hasher.c b/src/pakfire/hasher.c new file mode 100644 index 000000000..c08c26c97 --- /dev/null +++ b/src/pakfire/hasher.c @@ -0,0 +1,378 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +struct pakfire_hasher { + struct pakfire_ctx* ctx; + int nrefs; + + // Selected hashes + enum pakfire_hash_type types; + + // EVP Contexts + EVP_MD_CTX* sha3_512; + EVP_MD_CTX* sha3_256; + EVP_MD_CTX* blake2b512; + EVP_MD_CTX* blake2s256; + EVP_MD_CTX* sha2_512; + EVP_MD_CTX* sha2_256; + + // Computed Hashes + struct pakfire_hashes hashes; +}; + +static void pakfire_hasher_free(struct pakfire_hasher* self) { + if (self->sha3_512) + EVP_MD_CTX_free(self->sha3_512); + if (self->sha3_256) + EVP_MD_CTX_free(self->sha3_256); + if (self->blake2b512) + EVP_MD_CTX_free(self->blake2b512); + if (self->blake2s256) + EVP_MD_CTX_free(self->blake2s256); + if (self->sha2_512) + EVP_MD_CTX_free(self->sha2_512); + if (self->sha2_256) + EVP_MD_CTX_free(self->sha2_256); + if (self->ctx) + pakfire_ctx_unref(self->ctx); + free(self); +} + +static EVP_MD_CTX* pakfire_hasher_setup_hash(struct pakfire_hasher* self, const EVP_MD* md) { + EVP_MD_CTX* evp_ctx = NULL; + int r; + + // Setup a new context + evp_ctx = EVP_MD_CTX_new(); + if (!evp_ctx) { + ERROR(self->ctx, "Could not initialize OpenSSL context: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + goto ERROR; + } + + // Setup digest + r = EVP_DigestInit_ex(evp_ctx, md, NULL); + if (r != 1) { + ERROR(self->ctx, "Could not setup digest: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + goto ERROR; + } + + return evp_ctx; + +ERROR: + if (evp_ctx) + EVP_MD_CTX_free(evp_ctx); + + return NULL; +} + +static int pakfire_hasher_setup_hashes(struct pakfire_hasher* self) { + // Initialize context for SHA-3-512 + if (self->types & PAKFIRE_HASH_SHA3_512) { + self->sha3_512 = pakfire_hasher_setup_hash(self, EVP_sha3_512()); + if (!self->sha3_512) + return -ENOTSUP; + } + + // Initialize context for SHA-3-256 + if (self->types & PAKFIRE_HASH_SHA3_256) { + self->sha3_256 = pakfire_hasher_setup_hash(self, EVP_sha3_256()); + if (!self->sha3_256) + return -ENOTSUP; + } + + // Initialize context for BLAKE2B512 + if (self->types & PAKFIRE_HASH_BLAKE2B512) { + self->blake2b512 = pakfire_hasher_setup_hash(self, EVP_blake2b512()); + if (!self->blake2b512) + return -ENOTSUP; + } + + // Initialize context for BLAKE2S256 + if (self->types & PAKFIRE_HASH_BLAKE2S256) { + self->blake2s256 = pakfire_hasher_setup_hash(self, EVP_blake2s256()); + if (!self->blake2s256) + return -ENOTSUP; + } + + // Initialize context for SHA-2-512 + if (self->types & PAKFIRE_HASH_SHA2_512) { + self->sha2_512 = pakfire_hasher_setup_hash(self, EVP_sha512()); + if (!self->sha2_512) + return -ENOTSUP; + } + + // Initialize context for SHA-2-256 + if (self->types & PAKFIRE_HASH_SHA2_256) { + self->sha2_256 = pakfire_hasher_setup_hash(self, EVP_sha256()); + if (!self->sha2_256) + return -ENOTSUP; + } + + return 0; +} + +int pakfire_hasher_create(struct pakfire_hasher** hasher, + struct pakfire_ctx* ctx, enum pakfire_hash_type types) { + struct pakfire_hasher* self = NULL; + int r; + + // Something must have been selected + if (!types) + return -EINVAL; + + // Allocate some memory + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Store a reference to the context + self->ctx = pakfire_ctx_ref(ctx); + + // Initialize the reference counter + self->nrefs = 1; + + // Store hash types + self->types = self->hashes.types = types; + + // Setup all hashes + r = pakfire_hasher_setup_hashes(self); + if (r < 0) + goto ERROR; + + // Return the pointer + *hasher = self; + + return 0; + +ERROR: + pakfire_hasher_free(self); + + return r; +}; + +struct pakfire_hasher* pakfire_hasher_ref(struct pakfire_hasher* self) { + self->nrefs++; + + return self; +} + +struct pakfire_hasher* pakfire_hasher_unref(struct pakfire_hasher* self) { + if (--self->nrefs > 0) + return self; + + pakfire_hasher_free(self); + return NULL; +} + +static int __pakfire_hasher_update(struct pakfire_hasher* self, EVP_MD_CTX* evp_ctx, + const char* buffer, const size_t length) { + int r; + + // Nothing to do if digest not initialized + if (!evp_ctx) + return 0; + + // Update digest + r = EVP_DigestUpdate(evp_ctx, buffer, length); + if (r != 1) { + ERROR(self->ctx, "EVP_Digest_Update() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + + return -ENOTSUP; + } + + return 0; +} + +int pakfire_hasher_update(struct pakfire_hasher* self, const char* buffer, const size_t length) { + int r; + + // SHA-3-512 + r = __pakfire_hasher_update(self, self->sha3_512, buffer, length); + if (r < 0) + return r; + + // SHA-3-256 + r = __pakfire_hasher_update(self, self->sha3_256, buffer, length); + if (r < 0) + return r; + + // BLAKE2B512 + r = __pakfire_hasher_update(self, self->blake2b512, buffer, length); + if (r < 0) + return r; + + // BLAKE2S256 + r = __pakfire_hasher_update(self, self->blake2s256, buffer, length); + if (r < 0) + return r; + + // SHA-2-512 + r = __pakfire_hasher_update(self, self->sha2_512, buffer, length); + if (r < 0) + return r; + + // SHA-2-256 + r = __pakfire_hasher_update(self, self->sha2_256, buffer, length); + if (r < 0) + return r; + + return 0; +} + +static int __pakfire_hasher_finalize(struct pakfire_hasher* self, + EVP_MD_CTX* evp_ctx, unsigned char* digest) { + int r; + + // Nothing to do if digest not initialized + if (!evp_ctx) + return 0; + + // Finalize digest + r = EVP_DigestFinal_ex(evp_ctx, digest, NULL); + if (r != 1) { + ERROR(self->ctx, "EVP_DigestFinal_ex() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + + return -ENOTSUP; + } + + return 0; +} + +int pakfire_hasher_finalize(struct pakfire_hasher* self, struct pakfire_hashes* computed_hashes) { + int r; + + // Finalize SHA-3-512 + r = __pakfire_hasher_finalize(self, self->sha3_512, self->hashes.sha3_512); + if (r < 0) + return r; + + // Finalize SHA-3-256 + r = __pakfire_hasher_finalize(self, self->sha3_256, self->hashes.sha3_256); + if (r < 0) + return r; + + // Finalize BLAKE2b512 + r = __pakfire_hasher_finalize(self, self->blake2b512, self->hashes.blake2b512); + if (r < 0) + return r; + + // Finalize BLAKE2s256 + r = __pakfire_hasher_finalize(self, self->blake2s256, self->hashes.blake2s256); + if (r < 0) + return r; + + // Finalize SHA-2-512 + r = __pakfire_hasher_finalize(self, self->sha2_512, self->hashes.sha2_512); + if (r < 0) + return r; + + // Finalize SHA-2-256 + r = __pakfire_hasher_finalize(self, self->sha2_256, self->hashes.sha2_256); + if (r < 0) + return r; + + // Optionally return the computed hashes + if (computed_hashes) { + r = pakfire_hashes_import(computed_hashes, &self->hashes); + if (r < 0) + return r; + } + + return 0; +} + +/* + Convenience function to hash a file +*/ +int pakfire_hash_file(struct pakfire_ctx* ctx, + FILE* f, const enum pakfire_hash_type types, struct pakfire_hashes* hashes) { + struct pakfire_hasher* hasher = NULL; + char buffer[65536]; + size_t bytes_read; + int r; + + // Create a new hasher + r = pakfire_hasher_create(&hasher, ctx, types); + if (r < 0) + goto ERROR; + + // Read the file into the hash functions + while (!feof(f)) { + bytes_read = fread(buffer, 1, sizeof(buffer), f); + + // Raise any reading errors + if (ferror(f)) { + r = -errno; + goto ERROR; + } + + // Feed the buffer into the hash functions + r = pakfire_hasher_update(hasher, buffer, bytes_read); + if (r < 0) + goto ERROR; + } + + // Finalize the hash functions + r = pakfire_hasher_finalize(hasher, hashes); + if (r < 0) + goto ERROR; + +ERROR: + if (hasher) + pakfire_hasher_unref(hasher); + + return 0; +} + +int pakfire_hash_path(struct pakfire_ctx* ctx, + const char* path, const enum pakfire_hash_type types, struct pakfire_hashes* hashes) { + FILE* f = NULL; + int r; + + // Open the file + f = fopen(path, "r"); + if (!f) + return -errno; + + // Perform the hashing + r = pakfire_hash_file(ctx, f, types, hashes); + + // Close the file handle + if (f) + fclose(f); + + return r; +} diff --git a/src/pakfire/hasher.h b/src/pakfire/hasher.h new file mode 100644 index 000000000..70c474092 --- /dev/null +++ b/src/pakfire/hasher.h @@ -0,0 +1,45 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_HASHER_H +#define PAKFIRE_HASHER_H + +#include + +#include +#include + +struct pakfire_hasher; + +int pakfire_hasher_create(struct pakfire_hasher** hasher, + struct pakfire_ctx* ctx, enum pakfire_hash_type types); + +struct pakfire_hasher* pakfire_hasher_ref(struct pakfire_hasher* self); +struct pakfire_hasher* pakfire_hasher_unref(struct pakfire_hasher* self); + +int pakfire_hasher_update(struct pakfire_hasher* self, const char* buffer, const size_t length); +int pakfire_hasher_finalize(struct pakfire_hasher* self, struct pakfire_hashes* computed_hashes); + +int pakfire_hash_file(struct pakfire_ctx* ctx, + FILE* f, enum pakfire_hash_type types, struct pakfire_hashes* hashes); +int pakfire_hash_path(struct pakfire_ctx* ctx, + const char* path, const enum pakfire_hash_type types, struct pakfire_hashes* hashes); + +#endif /* PAKFIRE_HASHER_H */ diff --git a/src/pakfire/hashes.c b/src/pakfire/hashes.c new file mode 100644 index 000000000..471a710ed --- /dev/null +++ b/src/pakfire/hashes.c @@ -0,0 +1,400 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +const char* pakfire_hash_name(const enum pakfire_hash_type hash) { + switch (hash) { + // SHA-3 + case PAKFIRE_HASH_SHA3_512: + return "sha3-512"; + + case PAKFIRE_HASH_SHA3_256: + return "sha3-256"; + + // BLAKE2 + case PAKFIRE_HASH_BLAKE2B512: + return "blake2b512"; + + case PAKFIRE_HASH_BLAKE2S256: + return "blake2s256"; + + // SHA-2 + case PAKFIRE_HASH_SHA2_512: + return "sha2-512"; + + case PAKFIRE_HASH_SHA2_256: + return "sha2-256"; + + // Undefined + case PAKFIRE_HASH_UNDEFINED: + break; + } + + return NULL; +} + +enum pakfire_hash_type pakfire_hash_by_name(const char* hash) { + // SHA-3 + if (pakfire_string_equals(hash, "sha3-512")) + return PAKFIRE_HASH_SHA3_512; + + else if (pakfire_string_equals(hash, "sha3-256")) + return PAKFIRE_HASH_SHA3_256; + + // BLAKE2 + else if (pakfire_string_equals(hash, "blake2b512")) + return PAKFIRE_HASH_BLAKE2B512; + + else if (pakfire_string_equals(hash, "blake2s256")) + return PAKFIRE_HASH_BLAKE2S256; + + // SHA-2 + else if (pakfire_string_equals(hash, "sha2-512")) + return PAKFIRE_HASH_SHA2_512; + + else if (pakfire_string_equals(hash, "sha2-256")) + return PAKFIRE_HASH_SHA2_256; + + return PAKFIRE_HASH_UNDEFINED; +} + +void pakfire_hashes_reset(struct pakfire_hashes* hashes) { + memset(hashes, 0, sizeof(*hashes)); +} + +int pakfire_hashes_import(struct pakfire_hashes* dst, const struct pakfire_hashes* src) { + memcpy(dst, src, sizeof(*dst)); + + return 0; +} + +int pakfire_hashes_has(const struct pakfire_hashes* hashes, const enum pakfire_hash_type type) { + return (hashes->types & type); +} + +int pakfire_hashes_get(const struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const unsigned char** hash, size_t* length) { + + // Return NULL if we don't have the hash + if (!pakfire_hashes_has(hashes, type)) + return 0; + + switch (type) { + // SHA-3 + case PAKFIRE_HASH_SHA3_512: + if (length) + *length = sizeof(hashes->sha3_512); + + *hash = hashes->sha3_512; + break; + + case PAKFIRE_HASH_SHA3_256: + if (length) + *length = sizeof(hashes->sha3_256); + + *hash = hashes->sha3_256; + break; + + // BLAKE2 + case PAKFIRE_HASH_BLAKE2B512: + if (length) + *length = sizeof(hashes->blake2b512); + + *hash = hashes->blake2b512; + break; + + case PAKFIRE_HASH_BLAKE2S256: + if (length) + *length = sizeof(hashes->blake2s256); + + *hash = hashes->blake2s256; + break; + + // SHA-2 + case PAKFIRE_HASH_SHA2_512: + if (length) + *length = sizeof(hashes->sha2_512); + + *hash = hashes->sha2_512; + break; + + case PAKFIRE_HASH_SHA2_256: + if (length) + *length = sizeof(hashes->sha2_256); + + *hash = hashes->sha2_256; + break; + + default: + return -EINVAL; + } + + return 0; +} + +int pakfire_hashes_set(struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const unsigned char* hash, const size_t length) { + switch (type) { + // SHA-3 + case PAKFIRE_HASH_SHA3_512: + if (length != sizeof(hashes->sha3_512)) + return -EINVAL; + + memcpy(hashes->sha3_512, hash, sizeof(hashes->sha3_512)); + break; + + case PAKFIRE_HASH_SHA3_256: + if (length != sizeof(hashes->sha3_256)) + return -EINVAL; + + memcpy(hashes->sha3_256, hash, sizeof(hashes->sha3_256)); + break; + + // BLAKE2 + case PAKFIRE_HASH_BLAKE2B512: + if (length != sizeof(hashes->blake2b512)) + return -EINVAL; + + memcpy(hashes->blake2b512, hash, sizeof(hashes->blake2b512)); + break; + + case PAKFIRE_HASH_BLAKE2S256: + if (length != sizeof(hashes->blake2s256)) + return -EINVAL; + + memcpy(hashes->blake2s256, hash, sizeof(hashes->blake2s256)); + break; + + // SHA-2 + case PAKFIRE_HASH_SHA2_512: + if (length != sizeof(hashes->sha2_512)) + return -EINVAL; + + memcpy(hashes->sha2_512, hash, sizeof(hashes->sha2_512)); + break; + + case PAKFIRE_HASH_SHA2_256: + if (length != sizeof(hashes->sha2_256)) + return -EINVAL; + + memcpy(hashes->sha2_256, hash, sizeof(hashes->sha2_256)); + break; + + default: + return -EINVAL; + } + + // Store the type + hashes->types |= type; + + return 0; +} + +int pakfire_hashes_get_hex(const struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, char** hexdigest) { + const unsigned char* hash = NULL; + size_t length = 0; + int r; + + // Fetch the hash + r = pakfire_hashes_get(hashes, type, &hash, &length); + if (r < 0) + return r; + + // Return immediately without a hash + if (!hash) + return 0; + + // Return the hexdigest + *hexdigest = __pakfire_hexlify(hash, length); + if (!*hexdigest) + return -errno; + + return 0; +} + +int pakfire_hashes_set_hex(struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const char* hexdigest) { + int r; + + switch (type) { + case PAKFIRE_HASH_SHA3_512: + r = pakfire_unhexlify(hashes->sha3_512, hexdigest); + if (r < 0) + return r; + break; + + case PAKFIRE_HASH_SHA3_256: + r = pakfire_unhexlify(hashes->sha3_256, hexdigest); + if (r < 0) + return r; + break; + + case PAKFIRE_HASH_BLAKE2B512: + r = pakfire_unhexlify(hashes->blake2b512, hexdigest); + if (r < 0) + return r; + break; + + case PAKFIRE_HASH_BLAKE2S256: + r = pakfire_unhexlify(hashes->blake2s256, hexdigest); + if (r < 0) + return r; + break; + + case PAKFIRE_HASH_SHA2_512: + r = pakfire_unhexlify(hashes->sha2_512, hexdigest); + if (r < 0) + return r; + break; + + case PAKFIRE_HASH_SHA2_256: + r = pakfire_unhexlify(hashes->sha2_256, hexdigest); + if (r < 0) + return r; + break; + + default: + return -EINVAL; + } + + // Store the type + hashes->types |= type; + + return 0; +} + +static int __pakfire_hashes_dump(struct pakfire_ctx* ctx, + const struct pakfire_hashes* hashes, const enum pakfire_hash_type hash, int level) { + char* hexdigest = NULL; + int r; + + // Don't dump if hash is not set + if (!pakfire_hashes_has(hashes, hash)) + return 0; + + // Fetch the hexdigest + r = pakfire_hashes_get_hex(hashes, hash, &hexdigest); + if (r < 0) + goto ERROR; + + // Send to the logger + pakfire_ctx_log_condition(ctx, level, " %s: %s\n", pakfire_hash_name(hash), hexdigest); + +ERROR: + if (hexdigest) + free(hexdigest); + + return r; +} + +int pakfire_hashes_dump(struct pakfire_ctx* ctx, const struct pakfire_hashes* hashes, int level) { + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + int r; + + PAKFIRE_HASHES_FOREACH(hash) { + r = __pakfire_hashes_dump(ctx, hashes, hash, level); + if (r < 0) + return r; + } + + return 0; +} + +static int __pakfire_hashes_compare(struct pakfire_ctx* ctx, const enum pakfire_hash_type hash, + const struct pakfire_hashes* hashes1, const struct pakfire_hashes* hashes2) { + int r; + + // Skip this if not both hashes have this one set + if (!pakfire_hashes_has(hashes1, hash) || !pakfire_hashes_has(hashes2, hash)) + return 0; + + switch (hash) { + // SHA-3 + case PAKFIRE_HASH_SHA3_512: + r = CRYPTO_memcmp(hashes1->sha3_512, hashes2->sha3_512, sizeof(hashes1->sha3_512)); + break; + + case PAKFIRE_HASH_SHA3_256: + r = CRYPTO_memcmp(hashes1->sha3_256, hashes2->sha3_256, sizeof(hashes1->sha3_256)); + break; + + // BLAKE2 + case PAKFIRE_HASH_BLAKE2B512: + r = CRYPTO_memcmp(hashes1->blake2b512, hashes2->blake2b512, sizeof(hashes1->blake2b512)); + break; + + case PAKFIRE_HASH_BLAKE2S256: + r = CRYPTO_memcmp(hashes1->blake2s256, hashes2->blake2s256, sizeof(hashes1->blake2s256)); + break; + + // SHA-2 + case PAKFIRE_HASH_SHA2_512: + r = CRYPTO_memcmp(hashes1->sha2_512, hashes2->sha2_512, sizeof(hashes1->sha2_512)); + break; + + case PAKFIRE_HASH_SHA2_256: + r = CRYPTO_memcmp(hashes1->sha2_256, hashes2->sha2_256, sizeof(hashes1->sha2_256)); + break; + + case PAKFIRE_HASH_UNDEFINED: + default: + r = -EINVAL; + break; + } + + return r; +} + +int pakfire_hashes_compare(struct pakfire_ctx* ctx, + const struct pakfire_hashes* hashes1, const struct pakfire_hashes* hashes2) { + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + int r; + + // If either has nothing set, we cannot run this + if (!hashes1->types || !hashes2->types) { + ERROR(ctx, "At least one input hashes object is empty\n"); + return -ENOTSUP; + } + + // Check if there are any overlapping hashes + if (!(hashes1->types & hashes2->types)) { + ERROR(ctx, "The hashes don't share any common types\n"); + return -ENOTSUP; + } + + PAKFIRE_HASHES_FOREACH(hash) { + r = __pakfire_hashes_compare(ctx, hash, hashes1, hashes2); + if (r) + return r; + } + + return 0; +} diff --git a/src/pakfire/hashes.h b/src/pakfire/hashes.h new file mode 100644 index 000000000..e7a27b57b --- /dev/null +++ b/src/pakfire/hashes.h @@ -0,0 +1,106 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_HASHES_H +#define PAKFIRE_HASHES_H + +#include + +// Pakfire knows these hashes +enum pakfire_hash_type { + PAKFIRE_HASH_UNDEFINED = 0, + PAKFIRE_HASH_SHA2_256 = (1 << 0), + PAKFIRE_HASH_SHA2_512 = (1 << 1), + PAKFIRE_HASH_BLAKE2S256 = (1 << 2), + PAKFIRE_HASH_BLAKE2B512 = (1 << 3), + PAKFIRE_HASH_SHA3_256 = (1 << 4), + PAKFIRE_HASH_SHA3_512 = (1 << 5), +}; + +#define PAKFIRE_HASHES_ALL ( \ + PAKFIRE_HASH_SHA2_256 \ + | PAKFIRE_HASH_SHA2_512 \ + | PAKFIRE_HASH_BLAKE2S256 \ + | PAKFIRE_HASH_BLAKE2B512 \ + | PAKFIRE_HASH_SHA3_256 \ + | PAKFIRE_HASH_SHA3_512 \ +) + +#define PAKFIRE_HASHES_FOREACH(hash) \ + for (hash = 1; hash & PAKFIRE_HASHES_ALL; hash <<= 1) + +// Define BLAKE2's digest lengths +#ifndef BLAKE2S256_DIGEST_LENGTH +# define BLAKE2S256_DIGEST_LENGTH 32 +#endif /* BLAKE2S256_DIGEST_LENGTH */ + +#ifndef BLAKE2B512_DIGEST_LENGTH +# define BLAKE2B512_DIGEST_LENGTH 64 +#endif /* BLAKE2B512_DIGEST_LENGTH */ + +struct pakfire_hashes { + // The set hashes + enum pakfire_hash_type types; + + // SHA-3-512 + unsigned char sha3_512[SHA512_DIGEST_LENGTH]; + + // SHA-3-256 + unsigned char sha3_256[SHA256_DIGEST_LENGTH]; + + // BLAKE2b512 + unsigned char blake2b512[BLAKE2B512_DIGEST_LENGTH]; + + // BLAKE2s256 + unsigned char blake2s256[BLAKE2S256_DIGEST_LENGTH]; + + // SHA2-512 + unsigned char sha2_512[SHA512_DIGEST_LENGTH]; + + // SHA2-256 + unsigned char sha2_256[SHA256_DIGEST_LENGTH]; +}; + +#include + +const char* pakfire_hash_name(const enum pakfire_hash_type hash); +enum pakfire_hash_type pakfire_hash_by_name(const char* hash); + +void pakfire_hashes_reset(struct pakfire_hashes* hashes); +int pakfire_hashes_import(struct pakfire_hashes* dst, const struct pakfire_hashes* src); + +int pakfire_hashes_has(const struct pakfire_hashes* hashes, const enum pakfire_hash_type type); + +int pakfire_hashes_get(const struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const unsigned char** hash, size_t* length); +int pakfire_hashes_set(struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const unsigned char* hash, const size_t length); + +int pakfire_hashes_get_hex(const struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, char** hexdigest); +int pakfire_hashes_set_hex(struct pakfire_hashes* hashes, + const enum pakfire_hash_type type, const char* hexdigest); + +int pakfire_hashes_dump(struct pakfire_ctx* ctx, const struct pakfire_hashes* hashes, int level); + +int pakfire_hashes_compare(struct pakfire_ctx* ctx, + const struct pakfire_hashes* hashes1, const struct pakfire_hashes* hashes2); + +#endif /* PAKFIRE_HASHES_H */ diff --git a/src/pakfire/package.c b/src/pakfire/package.c index 1dafb7636..54d9c46df 100644 --- a/src/pakfire/package.c +++ b/src/pakfire/package.c @@ -40,9 +40,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -1308,79 +1308,76 @@ int pakfire_package_set_num(struct pakfire_package* pkg, return 0; } -static enum pakfire_digest_types pakfire_package_id2digest(Id id) { +int pakfire_package_get_checksum(struct pakfire_package* pkg, + enum pakfire_hash_type* hash, const unsigned char** checksum, size_t* length) { + Solvable* s = get_solvable(pkg); + Id id = 0; + + // Fetch the checksum + *checksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &id); + + // Store the type switch (id) { case REPOKEY_TYPE_SHA512: - return PAKFIRE_DIGEST_SHA2_512; + *hash = PAKFIRE_HASH_SHA2_512; + if (length) + *length = SHA512_DIGEST_LENGTH; + break; case REPOKEY_TYPE_SHA256: - return PAKFIRE_DIGEST_SHA2_256; + *hash = PAKFIRE_HASH_SHA2_256; + if (length) + *length = SHA256_DIGEST_LENGTH; + break; + + default: + return -EINVAL; } return 0; } -const unsigned char* pakfire_package_get_digest( - struct pakfire_package* pkg, enum pakfire_digest_types* type, size_t* length) { - Solvable* s = get_solvable(pkg); - Id id = 0; - - const unsigned char* checksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &id); - - // Convert ID to digest type - *type = pakfire_package_id2digest(id); - if (!*type) { - errno = ENOTSUP; - checksum = NULL; - } - - // Store the length (if requested) - if (length) - *length = pakfire_digest_length(*type); - - return checksum; -} +int pakfire_package_set_checksum(struct pakfire_package* pkg, + const enum pakfire_hash_type hash, const unsigned char* digest, const size_t length) { + struct pakfire_repo* repo = NULL; + Id id = ID_NULL; + int r; -int pakfire_package_set_digest(struct pakfire_package* pkg, - enum pakfire_digest_types type, const unsigned char* digest, const size_t length) { Solvable* s = get_solvable(pkg); Pool* pool = s->repo->pool; - Id id; - int r = 1; - switch (type) { - case PAKFIRE_DIGEST_SHA2_256: - id = REPOKEY_TYPE_SHA256; + switch (hash) { + case PAKFIRE_HASH_SHA2_512: + id = REPOKEY_TYPE_SHA512; break; - case PAKFIRE_DIGEST_SHA2_512: - id = REPOKEY_TYPE_SHA512; + case PAKFIRE_HASH_SHA2_256: + id = REPOKEY_TYPE_SHA256; break; default: - errno = ENOTSUP; - return 1; - } - - // Check if the digest length matches - if (pakfire_digest_length(type) != length) { - errno = EINVAL; - return 1; + return -EINVAL; } - struct pakfire_repo* repo = pakfire_package_get_repo(pkg); + // Fetch the repository + repo = pakfire_package_get_repo(pkg); + // Fetch the repodata Repodata* data = pakfire_repo_get_repodata(repo); - if (!data) + if (!data) { + r = -EINVAL; goto ERROR; + } + // Store the checksum repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, id, digest); // Success r = 0; ERROR: - pakfire_repo_unref(repo); + if (repo) + pakfire_repo_unref(repo); return r; } @@ -1885,7 +1882,11 @@ static int pakfire_sort_dependencies(const void* p1, const void* p2) { } char* pakfire_package_dump(struct pakfire_package* pkg, int flags) { + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + const unsigned char* checksum = NULL; + size_t checksum_length = 0; char* string = NULL; + int r; // Name const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_NAME); @@ -1996,31 +1997,30 @@ char* pakfire_package_dump(struct pakfire_package* pkg, int flags) { pakfire_strings_free(build_arches); } - enum pakfire_digest_types digest_type = PAKFIRE_DIGEST_UNDEFINED; - size_t digest_length = 0; - // Digest - const unsigned char* digest = pakfire_package_get_digest(pkg, - &digest_type, &digest_length); - if (digest) { - switch (digest_type) { - case PAKFIRE_DIGEST_SHA2_512: - pakfire_package_dump_add_line_hex(&string, - _("SHA2-512 Digest"), digest, digest_length); - break; - - case PAKFIRE_DIGEST_SHA2_256: - pakfire_package_dump_add_line_hex(&string, - _("SHA2-256 Digest"), digest, digest_length); - break; - - case PAKFIRE_DIGEST_SHA3_512: - case PAKFIRE_DIGEST_SHA3_256: - case PAKFIRE_DIGEST_BLAKE2B512: - case PAKFIRE_DIGEST_BLAKE2S256: - case PAKFIRE_DIGEST_UNDEFINED: - break; - } + r = pakfire_package_get_checksum(pkg, &hash, &checksum, &checksum_length); + if (r < 0) { + errno = -r; + goto ERROR; + } + + switch (hash) { + case PAKFIRE_HASH_SHA2_512: + pakfire_package_dump_add_line_hex(&string, + _("SHA2-512 Checksum"), checksum, checksum_length); + break; + + case PAKFIRE_HASH_SHA2_256: + pakfire_package_dump_add_line_hex(&string, + _("SHA2-256 Checksum"), checksum, checksum_length); + break; + + case PAKFIRE_HASH_SHA3_512: + case PAKFIRE_HASH_SHA3_256: + case PAKFIRE_HASH_BLAKE2B512: + case PAKFIRE_HASH_BLAKE2S256: + case PAKFIRE_HASH_UNDEFINED: + break; } // Source package @@ -2121,6 +2121,12 @@ char* pakfire_package_dump(struct pakfire_package* pkg, int flags) { } return string; + +ERROR: + if (string) + free(string); + + return NULL; } struct pakfire_archive* pakfire_package_get_archive(struct pakfire_package* pkg) { diff --git a/src/pakfire/package.h b/src/pakfire/package.h index 08e39e915..b97aa1db4 100644 --- a/src/pakfire/package.h +++ b/src/pakfire/package.h @@ -32,8 +32,8 @@ struct pakfire_package; -#include #include +#include #include #include #include @@ -130,10 +130,12 @@ int pakfire_package_set_num(struct pakfire_package* pkg, char** pakfire_package_get_deps(struct pakfire_package* pkg, const enum pakfire_package_key key); -const unsigned char* pakfire_package_get_digest(struct pakfire_package* pkg, - enum pakfire_digest_types* type, size_t* length); -int pakfire_package_set_digest(struct pakfire_package* pkg, - enum pakfire_digest_types type, const unsigned char* digest, const size_t length); +// Checksum +int pakfire_package_get_checksum(struct pakfire_package* pkg, + enum pakfire_hash_type* hash, const unsigned char** checksum, size_t* length); +int pakfire_package_set_checksum(struct pakfire_package* pkg, + const enum pakfire_hash_type hash, const unsigned char* digest, const size_t length); + size_t pakfire_package_get_size(struct pakfire_package* pkg); int pakfire_package_get_reverse_requires(struct pakfire_package* pkg, diff --git a/src/pakfire/packager.c b/src/pakfire/packager.c index b5835407d..5d397fe45 100644 --- a/src/pakfire/packager.c +++ b/src/pakfire/packager.c @@ -118,7 +118,7 @@ int pakfire_packager_create(struct pakfire_packager** packager, p->pkg = pakfire_package_ref(pkg); // Use the default digests - p->digests = PAKFIRE_PACKAGER_DIGESTS; + p->digests = PAKFIRE_PACKAGER_HASHES; // Set distribution const char* tag = pakfire_get_distro_tag(p->pakfire); @@ -157,37 +157,37 @@ int pakfire_packager_create(struct pakfire_packager** packager, goto ERROR; // Add a requirement for the cryptographic algorithms we are using - if (p->digests & PAKFIRE_DIGEST_SHA3_512) { + if (p->digests & PAKFIRE_HASH_SHA3_512) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-SHA3-512)"); if (r) goto ERROR; } - if (p->digests & PAKFIRE_DIGEST_SHA3_256) { + if (p->digests & PAKFIRE_HASH_SHA3_256) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-SHA3-256)"); if (r) goto ERROR; } - if (p->digests & PAKFIRE_DIGEST_BLAKE2B512) { + if (p->digests & PAKFIRE_HASH_BLAKE2B512) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-BLAKE2b512)"); if (r) goto ERROR; } - if (p->digests & PAKFIRE_DIGEST_BLAKE2S256) { + if (p->digests & PAKFIRE_HASH_BLAKE2S256) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-BLAKE2s256)"); if (r) goto ERROR; } - if (p->digests & PAKFIRE_DIGEST_SHA2_512) { + if (p->digests & PAKFIRE_HASH_SHA2_512) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-SHA2-512)"); if (r) goto ERROR; } - if (p->digests & PAKFIRE_DIGEST_SHA2_256) { + if (p->digests & PAKFIRE_HASH_SHA2_256) { r = pakfire_package_add_dep(p->pkg, PAKFIRE_PKG_REQUIRES, "pakfire(Digest-SHA2-256)"); if (r) @@ -460,7 +460,7 @@ int pakfire_packager_finish(struct pakfire_packager* packager, FILE* f) { // Write the payload r = pakfire_compress(packager->pakfire, a, packager->filelist, nevra, - PAKFIRE_COMPRESS_SHOW_THROUGHPUT, PAKFIRE_PACKAGER_DIGESTS); + PAKFIRE_COMPRESS_SHOW_THROUGHPUT, PAKFIRE_PACKAGER_HASHES); if (r) goto ERROR; diff --git a/src/pakfire/packager.h b/src/pakfire/packager.h index f207f4401..88ed4b76e 100644 --- a/src/pakfire/packager.h +++ b/src/pakfire/packager.h @@ -21,13 +21,13 @@ #ifndef PAKFIRE_PACKAGER_H #define PAKFIRE_PACKAGER_H -#include #include #include +#include #include #include -#define PAKFIRE_PACKAGER_DIGESTS (PAKFIRE_DIGEST_SHA3_512|PAKFIRE_DIGEST_BLAKE2B512) +#define PAKFIRE_PACKAGER_HASHES (PAKFIRE_HASH_SHA3_512|PAKFIRE_HASH_BLAKE2B512) struct pakfire_packager; diff --git a/src/pakfire/repo.c b/src/pakfire/repo.c index e9c20f5c6..74f81c7b7 100644 --- a/src/pakfire/repo.c +++ b/src/pakfire/repo.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ #include #include -#define METADATA_DIGESTS PAKFIRE_DIGEST_SHA3_512|PAKFIRE_DIGEST_BLAKE2B512 +#define METADATA_CHECKSUMS (PAKFIRE_HASH_SHA3_512|PAKFIRE_HASH_BLAKE2B512) // Refresh mirror lists once every 6 hours #define REFRESH_AGE_MIRRORLIST 6 * 3600 @@ -75,8 +76,8 @@ struct pakfire_repomd { // Size size_t size; - // Digests - struct pakfire_digests digests; + // Hashes + struct pakfire_hashes hashes; } packages; }; @@ -853,6 +854,11 @@ static int pakfire_repo_download_database( if (r < 0) goto ERROR; + // Set digests + r = pakfire_xfer_verify_hashes(xfer, &repo->appdata->repomd.packages.hashes); + if (r < 0) + goto ERROR; + // Run the xfer r = pakfire_xfer_run(xfer, 0); if (r < 0) @@ -945,7 +951,7 @@ static int pakfire_repo_parse_repomd(struct pakfire_repo* self, const char* type = NULL; const char* filename = NULL; ssize_t size = 0; - struct pakfire_digests digests = {}; + struct pakfire_hashes hashes = {}; int r; // Parse version @@ -1000,11 +1006,11 @@ static int pakfire_repo_parse_repomd(struct pakfire_repo* self, return r; // Parse checksums - json_object_object_foreach(chksums, digest_name, hexdigest) { - enum pakfire_digest_types digest_type = pakfire_digest_get_by_name(digest_name); + json_object_object_foreach(chksums, hash_name, hexdigest) { + enum pakfire_hash_type hash_type = pakfire_hash_by_name(hash_name); // Import the hexdigest - r = pakfire_digests_set_hexdigest(&digests, digest_type, json_object_get_string(hexdigest)); + r = pakfire_hashes_set_hex(&hashes, hash_type, json_object_get_string(hexdigest)); if (r < 0) return r; } @@ -1019,8 +1025,8 @@ static int pakfire_repo_parse_repomd(struct pakfire_repo* self, // Store the filelist repomd->packages.size = size; - // Store the digests - r = pakfire_digests_import(&repomd->packages.digests, &digests); + // Store the hashes + r = pakfire_hashes_import(&repomd->packages.hashes, &hashes); if (r < 0) return r; @@ -1028,8 +1034,8 @@ static int pakfire_repo_parse_repomd(struct pakfire_repo* self, break; } - // Reset the digests - pakfire_digests_reset(&digests, PAKFIRE_DIGESTS_ALL); + // Reset the hashes + pakfire_hashes_reset(&hashes); } return 0; @@ -1820,8 +1826,11 @@ int pakfire_repo_is_installed_repo(struct pakfire_repo* self) { int pakfire_repo_download_package(struct pakfire_xfer** xfer, struct pakfire_repo* repo, struct pakfire_package* pkg) { + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + const unsigned char* checksum = NULL; + size_t checksum_length = 0; + struct pakfire_hashes hashes = {}; struct pakfire_xfer* x = NULL; - const unsigned char* digest = NULL; const char* cache_path = NULL; const char* nevra = NULL; const char* url = NULL; @@ -1846,16 +1855,24 @@ int pakfire_repo_download_package(struct pakfire_xfer** xfer, goto ERROR; } - enum pakfire_digest_types digest_type = 0; - size_t digest_length = 0; - // Retrieve package digest - digest = pakfire_package_get_digest(pkg, &digest_type, &digest_length); - if (!digest) { - ERROR(repo->ctx, "Package %s has no digest set: %m\n", nevra); + r = pakfire_package_get_checksum(pkg, &hash, &checksum, &checksum_length); + if (r < 0) { + ERROR(repo->ctx, "Failed to fetch checksum: %s\n", strerror(-r)); goto ERROR; } + // Checksum must be set + if (!checksum) { + ERROR(repo->ctx, "Package %s has no checksum\n", nevra); + goto ERROR; + } + + // Store the check in hashes + r = pakfire_hashes_set(&hashes, hash, checksum, checksum_length); + if (r < 0) + goto ERROR; + // Create a new transfer r = pakfire_repo_xfer_create(&x, repo, "%s", url); if (r) @@ -1872,18 +1889,18 @@ int pakfire_repo_download_package(struct pakfire_xfer** xfer, // Set size if (downloadsize > 0) { r = pakfire_xfer_set_size(x, downloadsize); - if (r) + if (r < 0) goto ERROR; } // Set output path r = pakfire_xfer_set_output_path(x, cache_path); - if (r) + if (r < 0) goto ERROR; // Set digest - r = pakfire_xfer_verify_digest(x, digest_type, digest, digest_length); - if (r) + r = pakfire_xfer_verify_hashes(x, &hashes); + if (r < 0) goto ERROR; // Success @@ -2224,14 +2241,14 @@ static int pakfire_repo_cleanup_metadata(struct pakfire_repo* self) { static int pakfire_repo_metadata_add_file(struct pakfire_repo* self, struct json_object* repomd, const char* type, const char* path) { - struct pakfire_digests digests = {}; + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + struct pakfire_hashes checksums = {}; struct json_object* files = NULL; struct json_object* file = NULL; struct json_object* chksums = NULL; char filename[PATH_MAX]; char* hexdigest = NULL; struct stat st = {}; - int digest; int r; // Stat the file @@ -2247,10 +2264,10 @@ static int pakfire_repo_metadata_add_file(struct pakfire_repo* self, if (r < 0) goto ERROR; - // Compute the database digests - r = pakfire_digests_compute_from_path(self->ctx, &digests, METADATA_DIGESTS, path); + // Compute the database checksums + r = pakfire_hash_path(self->ctx, path, METADATA_CHECKSUMS, &checksums); if (r < 0) { - ERROR(self->ctx, "Failed to compute file digests: %s\n", strerror(-r)); + ERROR(self->ctx, "Failed to compute file hashes: %s\n", strerror(-r)); goto ERROR; } @@ -2289,12 +2306,14 @@ static int pakfire_repo_metadata_add_file(struct pakfire_repo* self, if (r < 0) goto ERROR; - // Add all digests - PAKFIRE_DIGESTS_FOREACH(digest) { - hexdigest = pakfire_digest_get_hex(&digests, digest); + // Add all checksums + PAKFIRE_HASHES_FOREACH(hash) { + r = pakfire_hashes_get_hex(&checksums, hash, &hexdigest); + if (r < 0) + goto ERROR; if (hexdigest) { - r = pakfire_json_add_string(chksums, pakfire_digest_name(digest), hexdigest); + r = pakfire_json_add_string(chksums, pakfire_hash_name(hash), hexdigest); if (r < 0) goto ERROR; diff --git a/src/pakfire/transaction.c b/src/pakfire/transaction.c index 577666da2..3e9585a0a 100644 --- a/src/pakfire/transaction.c +++ b/src/pakfire/transaction.c @@ -31,8 +31,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -1308,6 +1308,11 @@ 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) { + enum pakfire_hash_type hash = PAKFIRE_HASH_UNDEFINED; + const unsigned char* checksum = NULL; + size_t checksum_length = 0; + int r; + const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA); // Nothing to do if this step does not have an archive @@ -1316,18 +1321,25 @@ static int pakfire_transaction_verify(struct pakfire_transaction* transaction, return 0; } - enum pakfire_digest_types digest_type = PAKFIRE_DIGEST_UNDEFINED; - size_t length = 0; - // Fetch digest from package - const unsigned char* expected_digest = pakfire_package_get_digest(pkg, &digest_type, &length); - if (!expected_digest) { - DEBUG(transaction->ctx, "Package %s has no digest\n", nevra); - return 0; + r = pakfire_package_get_checksum(pkg, &hash, &checksum, &checksum_length); + if (r < 0) { + ERROR(transaction->ctx, "Could not fetch checksum for %s: %s\n", nevra, strerror(-r)); + return r; } + // Fail if there is no checksum + if (!checksum) { + ERROR(transaction->ctx, "Package %s has no checksum\n", nevra); + return -EINVAL; + } + +#if 0 // Check against the digest of the archive return pakfire_archive_check_digest(archive, digest_type, expected_digest, length); +#endif + + return 0; } static int pakfire_transaction_run_script(struct pakfire_transaction* transaction, diff --git a/src/pakfire/xfer.c b/src/pakfire/xfer.c index 363a471e4..4a31a7291 100644 --- a/src/pakfire/xfer.c +++ b/src/pakfire/xfer.c @@ -27,12 +27,10 @@ #include -#include -#include - #include #include +#include #include #include #include @@ -87,13 +85,11 @@ struct pakfire_xfer { FILE* fin; FILE* fout; - // Crypto Stuff - EVP_MD_CTX* evp; - const EVP_MD* md; - unsigned char computed_digest[EVP_MAX_MD_SIZE]; - unsigned int computed_digest_length; - unsigned char expected_digest[EVP_MAX_MD_SIZE]; - unsigned int expected_digest_length; + // Expected Hashes + struct pakfire_hashes expected_hashes; + + // Hasher + struct pakfire_hasher* hasher; // Mirrors char baseurl[PATH_MAX]; @@ -139,10 +135,6 @@ static void pakfire_xfer_free(struct pakfire_xfer* xfer) { if (xfer->fin) fclose(xfer->fin); - // Free OpenSSL EVP context - if (xfer->evp) - EVP_MD_CTX_free(xfer->evp); - // systemd if (xfer->event) sd_event_source_unref(xfer->event); @@ -167,6 +159,8 @@ static void pakfire_xfer_free(struct pakfire_xfer* xfer) { if (xfer->fullurl) curl_url_cleanup(xfer->fullurl); + if (xfer->hasher) + pakfire_hasher_unref(xfer->hasher); if (xfer->mirror) pakfire_mirror_unref(xfer->mirror); if (xfer->mirrors) @@ -228,21 +222,17 @@ static int pakfire_xfer_seek(void* p, curl_off_t offset, int origin) { static size_t pakfire_xfer_write( char* data, size_t size, size_t nmemb, void* p) { struct pakfire_xfer* xfer = p; - struct pakfire_ctx* ctx = xfer->ctx; int r; // Do not write empty blocks if (!nmemb) return nmemb; - // Update message digest - if (xfer->evp) { - r = EVP_DigestUpdate(xfer->evp, data, nmemb); - if (r != 1) { - ERROR(ctx, "EVP_DigestUpdate failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return 0; - } + // Update the hasher + if (xfer->hasher) { + r = pakfire_hasher_update(xfer->hasher, data, nmemb); + if (r < 0) + return r; } // If there is no output steam, we just pretent that we have consumed the data @@ -559,51 +549,8 @@ int pakfire_xfer_set_size(struct pakfire_xfer* xfer, size_t size) { return 0; } -int pakfire_xfer_verify_digest(struct pakfire_xfer* xfer, const enum pakfire_digest_types md, - const unsigned char* expected_digest, const size_t expected_digest_length) { - // Check inputs - if (!expected_digest || !expected_digest_length) - return -EINVAL; - - // Expected digest length cannot be too long - if (expected_digest_length > sizeof(xfer->expected_digest)) - return -ENOBUFS; - - // Store digest type - switch (md) { - case PAKFIRE_DIGEST_SHA3_512: - xfer->md = EVP_sha3_512(); - break; - - case PAKFIRE_DIGEST_SHA3_256: - xfer->md = EVP_sha3_256(); - break; - - case PAKFIRE_DIGEST_BLAKE2B512: - xfer->md = EVP_blake2b512(); - break; - - case PAKFIRE_DIGEST_BLAKE2S256: - xfer->md = EVP_blake2s256(); - break; - - case PAKFIRE_DIGEST_SHA2_512: - xfer->md = EVP_sha512(); - break; - - case PAKFIRE_DIGEST_SHA2_256: - xfer->md = EVP_sha256(); - break; - - default: - return -ENOTSUP; - } - - // Store the expected digest and its length - memcpy(xfer->expected_digest, expected_digest, expected_digest_length); - xfer->expected_digest_length = expected_digest_length; - - return 0; +int pakfire_xfer_verify_hashes(struct pakfire_xfer* self, const struct pakfire_hashes* hashes) { + return pakfire_hashes_import(&self->expected_hashes, hashes); } int pakfire_xfer_add_query(struct pakfire_xfer* xfer, @@ -948,6 +895,12 @@ ERROR: static int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code) { int r; + // Drop the hasher + if (xfer->hasher) { + pakfire_hasher_unref(xfer->hasher); + xfer->hasher = NULL; + } + // Throw away any downloaded data if (xfer->fin) { // Get file descriptor @@ -1186,52 +1139,47 @@ ERROR: #endif /* CURL_HAS_WEBSOCKETS */ /* - This function checks if the digests match (if set up) + This function checks if the hashes match (if set up) */ static int pakfire_xfer_verify(struct pakfire_xfer* self) { - char* computed_hexdigest = NULL; - char* expected_hexdigest = NULL; + struct pakfire_hashes computed_hashes = {}; int r; - // Nothing to do if there is no EVP - if (!self->evp) + // Nothing to do if there is no hasher + if (!self->hasher) return 0; - // Finish message digest computation - r = EVP_DigestFinal_ex(self->evp, self->computed_digest, &self->computed_digest_length); - if (r != 1) { - ERROR(self->ctx, "Could not finish message digest computation: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = -EBADMSG; - goto ERROR; - } + // Finish the hasher + r = pakfire_hasher_finalize(self->hasher, &computed_hashes); + if (r < 0) + return r; - // Compare the hexdigests - r = CRYPTO_memcmp(self->computed_digest, self->expected_digest, self->computed_digest_length); + // Compare the hashes + r = pakfire_hashes_compare(self->ctx, &self->expected_hashes, &computed_hashes); + switch (r) { + case 0: + DEBUG(self->ctx, "Payload matches\n"); + return 0; - // If they don't match, log the error - if (r) { - // Format the expected hexdigest - computed_hexdigest = __pakfire_hexlify(self->computed_digest, self->computed_digest_length); - expected_hexdigest = __pakfire_hexlify(self->expected_digest, self->expected_digest_length); + case 1: + ERROR(self->ctx, "Download checksum for %s didn't match:\n", self->effective_url); - ERROR(self->ctx, "Download checksum for %s didn't match:\n", self->effective_url); - ERROR(self->ctx, " Expected: %s\n", expected_hexdigest); - ERROR(self->ctx, " Computed: %s\n", computed_hexdigest); + // Show the expected hashes + ERROR(self->ctx, " Expected Hashes:\n"); + pakfire_hashes_dump(self->ctx, &self->expected_hashes, LOG_ERR); - // Make this download fail - r = pakfire_xfer_fail(self, PAKFIRE_XFER_DIGEST_MISMATCH); - if (r < 0) - goto ERROR; - } + // Show the computed hashes + ERROR(self->ctx, " Computed Hashes:\n"); + pakfire_hashes_dump(self->ctx, &computed_hashes, LOG_ERR); -ERROR: - if (computed_hexdigest) - free(computed_hexdigest); - if (expected_hexdigest) - free(expected_hexdigest); + // Consider the download failed + return pakfire_xfer_fail(self, PAKFIRE_XFER_DIGEST_MISMATCH); - return r; + // Errors + default: + ERROR(self->ctx, "Failed to compare hashes: %s\n", strerror(-r)); + return r; + } } static int pakfire_xfer_save(struct pakfire_xfer* xfer) { @@ -1597,6 +1545,13 @@ int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* pro // Set special options for direction switch (xfer->direction) { case PAKFIRE_XFER_DOWNLOAD: + if (xfer->expected_hashes.types) { + r = pakfire_hasher_create(&xfer->hasher, xfer->ctx, xfer->expected_hashes.types); + if (r < 0) { + ERROR(xfer->ctx, "Failed to setup the hasher: %s\n", strerror(-r)); + return r; + } + } break; case PAKFIRE_XFER_UPLOAD: @@ -1673,29 +1628,6 @@ int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* pro } } - // Drop any previously used EVP contexts - if (xfer->evp) { - EVP_MD_CTX_free(xfer->evp); - xfer->evp = NULL; - } - - // Create a new EVP context - if (xfer->md) { - xfer->evp = EVP_MD_CTX_new(); - if (!xfer->evp) { - ERROR(xfer->ctx, "Could not create EVP context: %m\n"); - return 1; - } - - // Initialize the EVP context - r = EVP_DigestInit_ex(xfer->evp, xfer->md, NULL); - if (r != 1) { - ERROR(xfer->ctx, "Could not initialize EVP context: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return 1; - } - } - // Setup progress r = pakfire_xfer_prepare_progress(xfer, progress, flags); if (r) diff --git a/src/pakfire/xfer.h b/src/pakfire/xfer.h index 8476704da..37d6c2d3c 100644 --- a/src/pakfire/xfer.h +++ b/src/pakfire/xfer.h @@ -69,6 +69,8 @@ typedef enum pakfire_xfer_error_code { } pakfire_xfer_error_code_t; #include +#include +#include #include #include #include @@ -107,8 +109,7 @@ int pakfire_xfer_set_mirrorlist(struct pakfire_xfer* xfer, struct pakfire_mirror size_t pakfire_xfer_get_size(struct pakfire_xfer* xfer); int pakfire_xfer_set_size(struct pakfire_xfer* xfer, size_t size); -int pakfire_xfer_verify_digest(struct pakfire_xfer* xfer, const enum pakfire_digest_types md, - const unsigned char* expected_digest, const size_t expected_digest_length); +int pakfire_xfer_verify_hashes(struct pakfire_xfer* self, const struct pakfire_hashes* hashes); int pakfire_xfer_add_query(struct pakfire_xfer* xfer, const char* key, const char* format, ...) __attribute__((format(printf, 3, 4))); diff --git a/src/python/file.c b/src/python/file.c index 5ca4b20a8..95d6e5744 100644 --- a/src/python/file.c +++ b/src/python/file.c @@ -21,7 +21,7 @@ #define PY_SSIZE_T_CLEAN #include -#include +#include #include #include "file.h" @@ -107,28 +107,30 @@ static PyObject* File_get_mtime(FileObject* self) { } static PyObject* File_digest(FileObject* self, PyObject* args) { + const unsigned char* checksum = NULL; + size_t length = 0; + int r; + const char* name = NULL; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; // Fetch the type - const enum pakfire_digest_types type = pakfire_digest_get_by_name(name); + const enum pakfire_hash_type type = pakfire_hash_by_name(name); // Raise ValueError if we could not find the type if (!type) { - PyErr_Format(PyExc_ValueError, "Unknown digest type: %s", name); + PyErr_Format(PyExc_ValueError, "Unknown hash type: %s", name); return NULL; } - size_t length = 0; - - // Fetch the digest - const unsigned char* digest = pakfire_file_get_digest(self->file, type, &length); - if (!digest) + // Fetch the checksum + r = pakfire_file_get_checksum(self->file, type, &checksum, &length); + if (r < 0) Py_RETURN_NONE; - return PyBytes_FromStringAndSize((const char*)digest, length); + return PyBytes_FromStringAndSize((const char*)checksum, length); } static PyObject* File_get_mimetype(FileObject* self) { diff --git a/src/python/package.c b/src/python/package.c index 233abfcf5..43b858a28 100644 --- a/src/python/package.c +++ b/src/python/package.c @@ -21,9 +21,9 @@ #define PY_SSIZE_T_CLEAN #include -#include #include #include +#include #include #include #include @@ -194,17 +194,18 @@ static PyObject* Package_get_uuid(PackageObject* self) { return PyUnicode_FromString(uuid); } -static PyObject* Package_get_digest(PackageObject* self) { - enum pakfire_digest_types type = PAKFIRE_DIGEST_UNDEFINED; - const unsigned char* digest = NULL; - size_t length = 0; +static PyObject* Package_get_checksum(PackageObject* self) { + enum pakfire_hash_type type = PAKFIRE_HASH_UNDEFINED; + const unsigned char* checksum = NULL; + size_t checksum_length = 0; + int r; - // Fetch the digest - digest = pakfire_package_get_digest(self->package, &type, &length); - if (!digest) - Py_RETURN_NONE; + // Fetch the checksum + r = pakfire_package_get_checksum(self->package, &type, &checksum, &checksum_length); + if (r < 0) + return NULL; - return Py_BuildValue("(sy#)", pakfire_digest_name(type), digest, length); + return Py_BuildValue("(sy#)", pakfire_hash_name(type), checksum, checksum_length); } static PyObject* Package_get_summary(PackageObject* self) { @@ -583,8 +584,8 @@ static struct PyGetSetDef Package_getsetters[] = { NULL }, { - "digest", - (getter)Package_get_digest, + "checksum", + (getter)Package_get_checksum, NULL, NULL, NULL, diff --git a/tests/libpakfire/xfer.c b/tests/libpakfire/xfer.c index d7cc84549..e8eb405f0 100644 --- a/tests/libpakfire/xfer.c +++ b/tests/libpakfire/xfer.c @@ -18,6 +18,7 @@ # # #############################################################################*/ +#include #include #include "../testsuite.h" @@ -107,11 +108,15 @@ FAIL: } static int test_download_check_digest(const struct test* t) { + struct pakfire_hashes hashes = {}; struct pakfire_xfer* xfer = NULL; char* buffer = NULL; size_t length = 0; int r = EXIT_FAILURE; + ASSERT_SUCCESS(pakfire_hashes_set(&hashes, + PAKFIRE_HASH_SHA2_512, RANDOM_FILE_sha2_512, sizeof(RANDOM_FILE_sha2_512))); + // Create a new transfer ASSERT_SUCCESS(pakfire_xfer_create_simple(&xfer, t->ctx, RANDOM_FILE)); @@ -119,8 +124,7 @@ static int test_download_check_digest(const struct test* t) { ASSERT_SUCCESS(pakfire_xfer_set_output_buffer(xfer, &buffer, &length)); // Set the digest value - ASSERT_SUCCESS(pakfire_xfer_verify_digest(xfer, PAKFIRE_DIGEST_SHA2_512, - RANDOM_FILE_sha2_512, sizeof(RANDOM_FILE_sha2_512))); + ASSERT_SUCCESS(pakfire_xfer_verify_hashes(xfer, &hashes)); // Run it! ASSERT_SUCCESS(pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS)); @@ -142,11 +146,16 @@ FAIL: } static int test_download_check_incorrect_digest(const struct test* t) { + struct pakfire_hashes hashes = {}; struct pakfire_xfer* xfer = NULL; char* buffer = NULL; size_t length = 0; int r = EXIT_FAILURE; + // Store the hash + ASSERT_SUCCESS(pakfire_hashes_set(&hashes, + PAKFIRE_HASH_SHA3_512, RANDOM_FILE_sha2_512, sizeof(RANDOM_FILE_sha2_512))); + // Create a new transfer ASSERT_SUCCESS(pakfire_xfer_create_simple(&xfer, t->ctx, RANDOM_FILE)); @@ -154,8 +163,7 @@ static int test_download_check_incorrect_digest(const struct test* t) { ASSERT_SUCCESS(pakfire_xfer_set_output_buffer(xfer, &buffer, &length)); // Set the digest value, but use a wrong digest method - ASSERT_SUCCESS(pakfire_xfer_verify_digest(xfer, PAKFIRE_DIGEST_SHA3_512, - RANDOM_FILE_sha2_512, sizeof(RANDOM_FILE_sha2_512))); + ASSERT_SUCCESS(pakfire_xfer_verify_hashes(xfer, &hashes)); // Run it! ASSERT(pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS) == PAKFIRE_XFER_DIGEST_MISMATCH); -- 2.39.5