From: Michael Tremer Date: Tue, 23 Aug 2022 15:24:03 +0000 (+0000) Subject: archive: Drop support for checksums X-Git-Tag: 0.9.28~397 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb9bda45914f133a15bc253dbea25cf48e6a2cb6;p=pakfire.git archive: Drop support for checksums Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 4a1d34851..6cf8e944e 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -59,21 +59,6 @@ #include #include -static const char* pakfire_archive_files_without_chksums[] = { - "pakfire-format", - "chksums", - NULL, -}; - -struct pakfire_archive_chksum { - STAILQ_ENTRY(pakfire_archive_chksum) nodes; - - char path[PATH_MAX]; - - unsigned char digest_sha512[64]; - unsigned char digest_sha256[32]; -}; - struct pakfire_archive { struct pakfire* pakfire; int nrefs; @@ -89,9 +74,6 @@ struct pakfire_archive { struct pakfire_filelist* filelist; - // Checksums - STAILQ_HEAD(chksums, pakfire_archive_chksum) chksums; - // Scriptlets struct pakfire_scriptlet** scriptlets; int scriptlets_loaded; @@ -110,7 +92,6 @@ static const char* pakfire_archive_legacy_filename( const char* file; const char* legacy; } filenames[] = { - { "CHKSUMS", "chksums" }, { "DATA", "data.img" }, { "FILELIST", "filelist"}, { "PKGINFO", "info" }, @@ -351,98 +332,11 @@ ERROR: return NULL; } -// Checksum Stuff - -static int pakfire_archive_add_chksum(struct pakfire_archive* archive, const char* path, - const unsigned char* digest_sha512, const unsigned char* digest_sha256) { - int r = 1; - - // Path must be set - if (!path) { - errno = EINVAL; - return 1; - } - - // At least one of the digests must be set - if (!digest_sha512 && !digest_sha256) { - errno = EINVAL; - return 1; - } - - // Allocate a new chksum object - struct pakfire_archive_chksum* chksum = calloc(1, sizeof(*chksum)); - if (!chksum) - return ENOMEM; - - // Store path - r = pakfire_string_set(chksum->path, path); - if (r) - goto ERROR; - - // SHA512 - if (digest_sha512) - memcpy(chksum->digest_sha512, digest_sha512, sizeof(chksum->digest_sha512)); - - // SHA256 - if (digest_sha256) - memcpy(chksum->digest_sha256, digest_sha256, sizeof(chksum->digest_sha256)); - - // Append it - STAILQ_INSERT_TAIL(&archive->chksums, chksum, nodes); - - DEBUG(archive->pakfire, "Added checksum for %s\n", path); - - return 0; - -ERROR: - free(chksum); - - return r; -} - -static struct pakfire_archive_chksum* pakfire_archive_find_chksum( - struct pakfire_archive* archive, const char* path) { - struct pakfire_archive_chksum* chksum = NULL; - - STAILQ_FOREACH(chksum, &archive->chksums, nodes) { - if (strcmp(chksum->path, path) == 0) - return chksum; - } - - // Nothing found - return NULL; -} - -static int __pakfire_archive_chksum_has_digest(const unsigned char* digest, const size_t length) { - for (unsigned int i = 0; i < length; i++) { - if (digest[i]) - return 1; - } - - return 0; -} - -#define pakfire_archive_chksum_has_digest(digest) \ - __pakfire_archive_chksum_has_digest(digest, sizeof(digest)) - -static void pakfire_archive_free_chksums(struct pakfire_archive* archive) { - struct pakfire_archive_chksum* chksum; - - while ((chksum = STAILQ_FIRST(&archive->chksums))) { - STAILQ_REMOVE_HEAD(&archive->chksums, nodes); - - free(chksum); - } -} - static void pakfire_archive_free(struct pakfire_archive* archive) { // Close the file if (archive->f) fclose(archive->f); - // Free all checksums - pakfire_archive_free_chksums(archive); - // Free scriptlets if (archive->scriptlets) { for (struct pakfire_scriptlet** scriptlet = archive->scriptlets; *scriptlet; scriptlet++) @@ -470,10 +364,7 @@ static int pakfire_archive_create(struct pakfire_archive** archive, struct pakfi a->pakfire = pakfire_ref(pakfire); a->nrefs = 1; - STAILQ_INIT(&a->chksums); - *archive = a; - return 0; } @@ -932,413 +823,8 @@ PAKFIRE_EXPORT struct pakfire_filelist* pakfire_archive_get_filelist(struct pakf return pakfire_filelist_ref(archive->filelist); } -static int pakfire_archive_load_checksums_mtree(struct pakfire_archive* archive) { - struct archive* a = NULL; - struct archive_entry* entry = NULL; - int r; - - // Find chksums - r = open_archive_and_find(archive, &a, &entry, "FILELIST"); - if (r) - return r; - - // Allocate a new archive reader - struct archive* mtree = archive_read_new(); - if (!mtree) { - ERROR(archive->pakfire, "Could not allocate mtree reader\n"); - goto ERROR; - } - - // Enable reading the mtree format - r = archive_read_support_format_mtree(mtree); - if (r) { - ERROR(archive->pakfire, "Could not enable mtree format: %s\n", - archive_error_string(mtree)); - goto ERROR; - } - - // Filelists can be Zstandard-compressed - r = archive_read_support_filter_zstd(mtree); - if (r) - goto ERROR; - - // Try opening the mtree - r = archive_read_open2(mtree, a, NULL, pakfire_archive_read_callback, NULL, NULL); - if (r) { - ERROR(archive->pakfire, "Could not open checksum mtree in %s: %s\n", - archive->path, archive_error_string(mtree)); - goto ERROR; - } - - for (;;) { - // Read next entry - r = archive_read_next_header(mtree, &entry); - - // We have reached the end of the list - if (r == ARCHIVE_EOF) - break; - - // An unexpected error has occurred - else if (r) { - ERROR(archive->pakfire, "Could not read mtree entry: %s\n", - archive_error_string(mtree)); - goto ERROR; - } - - // Fetch pathname - const char* path = archive_entry_pathname(entry); - - // Fetch all supported digests - const unsigned char* digest_sha512 = archive_entry_digest( - entry, ARCHIVE_ENTRY_DIGEST_SHA512); - const unsigned char* digest_sha256 = archive_entry_digest( - entry, ARCHIVE_ENTRY_DIGEST_SHA256); - - // Add the checksum to the internal list - r = pakfire_archive_add_chksum(archive, path + 2, digest_sha512, digest_sha256); - if (r) - goto ERROR; - } - - // Success - r = 0; - -ERROR: - if (mtree) - archive_read_free(mtree); - close_archive(archive, a); - - return r; -} - -static int pakfire_archive_load_checksums_legacy_line( - struct pakfire_archive* archive, char* line) { - char path[PATH_MAX] = ""; - char hexdigest[LINE_MAX] = ""; - char* tok = NULL; - - unsigned int i = 0; - int r = 1; - - char* word = strtok_r(line, " ", &tok); - while (word) { - switch (i) { - // path - case 0: - r = pakfire_string_set(path, word); - if (r) - return r; - break; - - // hexdigest - case 1: - r = pakfire_string_set(hexdigest, word); - if (r) - return r; - break; - - default: - ERROR(archive->pakfire, "Invalid line in checksums:\n%s\n", line); - r = 1; - return r; - } - - word = strtok_r(NULL, " ", &tok); - i++; - } - - // Check if we have input for path and hexdigest - if (!*path || !*hexdigest) { - errno = EINVAL; - return r; - } - - unsigned char digest[EVP_MAX_MD_SIZE]; - - // Convert hexdigest to digest - r = pakfire_unhexlify(digest, hexdigest); - if (r) - return r; - - // Add a chksum object - r = pakfire_archive_add_chksum(archive, path, digest, NULL); - if (r) - return r; - - // Success - return 0; -} - -static int pakfire_archive_load_checksums_legacy(struct pakfire_archive* archive) { - char* buffer = NULL; - size_t length = 0; - - // Find chksums - int r = open_archive_and_read(archive, "CHKSUMS", &buffer, &length); - if (r) - return r; - - // Empty file - if (!length) { - ERROR(archive->pakfire, "Checksums file was unexpectedly empty\n"); - return 1; - } - - char line[LINE_MAX]; - char* l = line; - - // Split the input into lines and call pakfire_archive_load_checksums_legacy_line - for (char* p = buffer; (size_t)(p - buffer) < length; p++) { - if (*p == '\n' || p == (buffer + length)) { - // Terminate line - *l = '\0'; - - // Process the line - r = pakfire_archive_load_checksums_legacy_line(archive, line); - if (r) - goto ERROR; - - // Reset line pointer - l = line; - - continue; - } - - // Copy character to line - *l++ = *p; - - // Check if line has enough space - if ((size_t)(l - line) >= sizeof(line)) { - errno = ENOBUFS; - goto ERROR; - } - } - -ERROR: - if (buffer) - free(buffer); - return r; -} - -static int pakfire_archive_load_checksums(struct pakfire_archive* archive) { - // Do nothing if the list has already been loaded - if (!STAILQ_EMPTY(&archive->chksums)) - return 0; - - DEBUG(archive->pakfire, "Loading checksums from archive %p\n", archive); - - if (archive->format >= 6) - return pakfire_archive_load_checksums_mtree(archive); - else - return pakfire_archive_load_checksums_legacy(archive); -} - -struct pakfire_archive_validator { - EVP_MD_CTX* ctx; - const unsigned char* digest; -}; - -static int pakfire_archive_verify_add_validator(struct pakfire_archive_validator*** list, - struct pakfire* pakfire, const EVP_MD* md, const unsigned char* digest) { - // Allocate validator - struct pakfire_archive_validator* v = calloc(1, sizeof(*v)); - if (!v) - return 1; - - int r = 1; - - // Allocate an EVP context - v->ctx = EVP_MD_CTX_new(); - if (!v->ctx) { - ERROR(pakfire, "Could not allocate an EVP context\n"); - goto ERROR; - } - - // Initialise the hash algorithm - r = EVP_DigestInit_ex(v->ctx, md, NULL); - if (r != 1) { - ERROR(pakfire, "Could not initialize hash algorithm: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - - // Store digest - v->digest = digest; - - unsigned int counter = 0; - - // Calculate list size - if (*list) { - for (struct pakfire_archive_validator** l = *list; *l; l++) - counter++; - } - - // Grow list - *list = reallocarray(*list, counter + 2, sizeof(**list)); - if (!*list) { - r = 1; - goto ERROR; - } - - // Append validator - (*list)[counter] = v; - - // Terminate list - (*list)[counter + 1] = NULL; - - // Success - return 0; - -ERROR: - if (v->ctx) - EVP_MD_CTX_free(v->ctx); - free(v); - - return r; -} - -static int pakfire_archive_verify_file(struct pakfire_archive* archive, - struct archive* a, struct archive_entry* entry, void* data) { - const char* path = archive_entry_pathname(entry); - - // Some files do not have checksums - for (const char** file = pakfire_archive_files_without_chksums; *file; file++) { - if (strcmp(*file, path) == 0) - return 0; - } - - // Fetch the checksum - struct pakfire_archive_chksum* chksum = pakfire_archive_find_chksum(archive, path); - if (!chksum) { - ERROR(archive->pakfire, "No checksum found for %s\n", path); - return 1; - } - - struct pakfire_archive_validator** validators = NULL; - int r; - - // SHA512 - if (pakfire_archive_chksum_has_digest(chksum->digest_sha512)) { - r = pakfire_archive_verify_add_validator(&validators, archive->pakfire, - EVP_sha512(), chksum->digest_sha512); - if (r) - return r; - } - - // SHA256 - if (pakfire_archive_chksum_has_digest(chksum->digest_sha256)) { - r = pakfire_archive_verify_add_validator(&validators, archive->pakfire, - EVP_sha256(), chksum->digest_sha256); - if (r) - return r; - } - - // Check if anything was selected (this should not happen) - if (!validators) { - ERROR(archive->pakfire, "No validators selected\n"); - return 1; - } - - DEBUG(archive->pakfire, "Verifying %s\n", path); - - const void* buffer = NULL; - size_t size = 0; - off_t offset = 0; - - // Read the payload of the file and feed it into the validators - for (;;) { - r = archive_read_data_block(a, &buffer, &size, &offset); - if (r == ARCHIVE_EOF) - break; - - // End on any errors - if (r) { - r = 1; - goto ERROR; - } - - // Update all hash digests - for (struct pakfire_archive_validator** v = validators; *v; v++) { - r = EVP_DigestUpdate((*v)->ctx, buffer, size); - if (r != 1) { - ERROR(archive->pakfire, "%s\n", ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - } - } - - unsigned char digest[EVP_MAX_MD_SIZE]; - - // Finalize all digests - for (struct pakfire_archive_validator** v = validators; *v; v++) { - // Reset digest array size - unsigned int length = sizeof(digest); - - // Finish computation - r = EVP_DigestFinal_ex((*v)->ctx, digest, &length); - if (r != 1) { - ERROR(archive->pakfire, "%s\n", ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - - // Compare digests - r = CRYPTO_memcmp(digest, (*v)->digest, length); - - // Handle mismatches - if (r) { - ERROR(archive->pakfire, "Checksum of %s did not match\n", chksum->path); - - char* hexdigest_expected = pakfire_hexlify((*v)->digest); - if (hexdigest_expected) { - ERROR(archive->pakfire, " Expected: %s\n", hexdigest_expected); - free(hexdigest_expected); - } - - char* hexdigest_computed = pakfire_hexlify(digest); - if (hexdigest_computed) { - ERROR(archive->pakfire, " Computed: %s\n", hexdigest_computed); - free(hexdigest_computed); - } - - goto ERROR; - } - } - - DEBUG(archive->pakfire, "All (checked) checksums of %s matched\n", chksum->path); - - // Success - r = 0; - -ERROR: - if (validators) { - for (struct pakfire_archive_validator** v = validators; *v; v++) { - EVP_MD_CTX_free((*v)->ctx); - free(*v); - } - free(validators); - } - - return r; -} - PAKFIRE_EXPORT int pakfire_archive_verify(struct pakfire_archive* archive, int* status) { - int r; - - // Read checksums from archive - r = pakfire_archive_load_checksums(archive); - if (r) - return r; - - // Iterate over all files and verify them if a checksum is present - r = pakfire_archive_walk(archive, pakfire_archive_verify_file, NULL); - if (r) { - ERROR(archive->pakfire, "File verification failed\n"); - return r; - } - + // XXX currently not implemented return 0; }