From: Michael Tremer Date: Wed, 24 Aug 2022 10:46:41 +0000 (+0000) Subject: digests: Add a compute and comparison function X-Git-Tag: 0.9.28~377 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=293881bcd05336c75f5973536e1b4cf563ac6fca;p=pakfire.git digests: Add a compute and comparison function Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/digest.c b/src/libpakfire/digest.c index e69e9afa9..02cee06e9 100644 --- a/src/libpakfire/digest.c +++ b/src/libpakfire/digest.c @@ -17,3 +17,154 @@ # along with this program. If not, see . # # # #############################################################################*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +static EVP_MD_CTX* __pakfire_digest_setup(struct pakfire* pakfire, const EVP_MD* md) { + EVP_MD_CTX* ctx = NULL; + int r; + + // Setup a new context + ctx = EVP_MD_CTX_new(); + if (!ctx) { + ERROR(pakfire, "Could not initialize OpenSSL context: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + + // Setup digest + r = EVP_DigestInit_ex(ctx, md, NULL); + if (r != 1) { + ERROR(pakfire, "Could not setup digest: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + + return ctx; + +ERROR: + if (ctx) + EVP_MD_CTX_free(ctx); + + return NULL; +} + +int pakfire_digests_compute_from_file(struct pakfire* pakfire, + struct pakfire_digests* digests, const int types, FILE* f) { + EVP_MD_CTX* sha512_ctx = NULL; + EVP_MD_CTX* sha256_ctx = NULL; + char buffer[PAKFIRE_BUFFER_SIZE]; + int r = 1; + + // Initialize context for SHA-512 + if (types & PAKFIRE_DIGEST_SHA512) { + sha512_ctx = __pakfire_digest_setup(pakfire, EVP_sha512()); + if (!sha512_ctx) + goto ERROR; + } + + // Initialize context for SHA-256 + if (types & PAKFIRE_DIGEST_SHA256) { + sha512_ctx = __pakfire_digest_setup(pakfire, EVP_sha256()); + if (!sha512_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-512 + r = EVP_DigestUpdate(sha512_ctx, buffer, bytes_read); + if (r != 1) { + ERROR(pakfire, "EVP_Digest_Update() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + + // SHA-256 + r = EVP_DigestUpdate(sha256_ctx, buffer, bytes_read); + if (r != 1) { + ERROR(pakfire, "EVP_Digest_Update() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + } + + // Finalize SHA-512 + r = EVP_DigestFinal_ex(sha512_ctx, digests->sha512, NULL); + if (r != 1) { + ERROR(pakfire, "EVP_DigestFinal_ex() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + + // Finalize SHA-256 + r = EVP_DigestFinal_ex(sha256_ctx, digests->sha256, NULL); + if (r != 1) { + ERROR(pakfire, "EVP_DigestFinal_ex() failed: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + r = 1; + goto ERROR; + } + +ERROR: + if (sha512_ctx) + EVP_MD_CTX_free(sha512_ctx); + if (sha256_ctx) + EVP_MD_CTX_free(sha256_ctx); + + return r; +} + +int pakfire_digests_compare(struct pakfire* pakfire, 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) { + errno = EINVAL; + return 1; + } + + // Check SHA-512 + if (types & PAKFIRE_DIGEST_SHA512) { + r = CRYPTO_memcmp(digests1->sha512, digests2->sha512, sizeof(digests1->sha512)); + if (r) { + DEBUG(pakfire, "SHA-512 digest does not match\n"); + return 1; + } + } + + // Check SHA-256 + if (types & PAKFIRE_DIGEST_SHA256) { + r = CRYPTO_memcmp(digests1->sha256, digests2->sha256, sizeof(digests1->sha256)); + if (r) { + DEBUG(pakfire, "SHA-256 digest does not match\n"); + return 1; + } + } + + // All digests match + return 0; +} diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index 54e393e26..eafa22c24 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -28,8 +29,6 @@ #include #include -#include -#include #include #include @@ -733,14 +732,11 @@ 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) { - char buffer[PAKFIRE_BUFFER_SIZE]; FILE* f = NULL; int r; - EVP_MD_CTX* sha512_ctx = NULL; - EVP_MD_CTX* sha256_ctx = NULL; - 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)) @@ -753,46 +749,15 @@ static int pakfire_file_verify_payload(struct pakfire_file* file, const struct s } // Check if this file has any digests at all - if (!pakfire_file_has_digest(file->digests.sha512) && - !pakfire_file_has_digest(file->digests.sha256)) { - ERROR(file->pakfire, "%s: No digests available\n", file->path); - return 0; - } - - // Initialize context for SHA-512 - sha512_ctx = EVP_MD_CTX_new(); - if (!sha512_ctx) { - ERROR(file->pakfire, "Could not initialize OpenSSL context: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - - // Setup SHA-512 digest - r = EVP_DigestInit_ex(sha512_ctx, EVP_sha512(), NULL); - if (r != 1) { - ERROR(file->pakfire, "Could not setup SHA-512 digest: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } + if (pakfire_file_has_digest(file->digests.sha512)) + digest_types |= PAKFIRE_DIGEST_SHA512; - // Initialize context for SHA-256 - sha256_ctx = EVP_MD_CTX_new(); - if (!sha256_ctx) { - ERROR(file->pakfire, "Could not initialize OpenSSL context: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } + if (pakfire_file_has_digest(file->digests.sha256)) + digest_types |= PAKFIRE_DIGEST_SHA256; - // Setup SHA-256 digest - r = EVP_DigestInit_ex(sha256_ctx, EVP_sha256(), NULL); - if (r != 1) { - ERROR(file->pakfire, "Could not setup SHA-256 digest: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; + if (!digest_types) { + ERROR(file->pakfire, "%s: No digests available\n", file->path); + return 0; } // Open the file @@ -802,79 +767,20 @@ static int pakfire_file_verify_payload(struct pakfire_file* file, const struct s 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-512 - r = EVP_DigestUpdate(sha512_ctx, buffer, bytes_read); - if (r != 1) { - ERROR(file->pakfire, "EVP_Digest_Update() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - - // SHA-256 - r = EVP_DigestUpdate(sha256_ctx, buffer, bytes_read); - if (r != 1) { - ERROR(file->pakfire, "EVP_Digest_Update() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - } - - // Finalize SHA-512 - r = EVP_DigestFinal_ex(sha512_ctx, computed_digests.sha512, NULL); - if (r != 1) { - ERROR(file->pakfire, "EVP_DigestFinal_ex() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; - goto ERROR; - } - - // Finalize SHA-256 - r = EVP_DigestFinal_ex(sha256_ctx, computed_digests.sha256, NULL); - if (r != 1) { - ERROR(file->pakfire, "EVP_DigestFinal_ex() failed: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - r = 1; + // Compute digests + r = pakfire_digests_compute_from_file(file->pakfire, &computed_digests, digest_types, f); + if (r) goto ERROR; - } - // Check SHA-512 - r = CRYPTO_memcmp(computed_digests.sha512, - file->digests.sha512, sizeof(file->digests.sha512)); + // Compare digests + r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types); if (r) { file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; - DEBUG(file->pakfire, "%s: SHA-512 digest does not match\n", file->path); + DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path); } - // Check SHA-256 - r = CRYPTO_memcmp(computed_digests.sha256, - file->digests.sha256, sizeof(file->digests.sha256)); - if (r) { - file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; - - DEBUG(file->pakfire, "%s: SHA-256 digest does not match\n", file->path); - } - - // Success - r = 0; - ERROR: - if (sha512_ctx) - EVP_MD_CTX_free(sha512_ctx); - if (sha256_ctx) - EVP_MD_CTX_free(sha256_ctx); if (f) fclose(f); diff --git a/src/libpakfire/include/pakfire/digest.h b/src/libpakfire/include/pakfire/digest.h index 5ed91ea7f..df6a3b446 100644 --- a/src/libpakfire/include/pakfire/digest.h +++ b/src/libpakfire/include/pakfire/digest.h @@ -30,8 +30,12 @@ enum pakfire_digest_types { #ifdef PAKFIRE_PRIVATE +#include + #include +#include + // Digests struct pakfire_digests { // SHA-512 @@ -41,6 +45,12 @@ struct pakfire_digests { unsigned char sha256[SHA256_DIGEST_LENGTH]; }; +int pakfire_digests_compute_from_file(struct pakfire* pakfire, + struct pakfire_digests* digests, int flags, FILE* f); + +int pakfire_digests_compare(struct pakfire* pakfire, const struct pakfire_digests* digests1, + const struct pakfire_digests* digests2, const int types); + #endif #endif /* PAKFIRE_DIGEST_H */