From: Michael Tremer Date: Wed, 7 Jul 2021 22:06:32 +0000 (+0000) Subject: archive: Refactor scaffolding for signature check X-Git-Tag: 0.9.28~1080 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6bf26d8f2b6edd7b273e080d2caa180abe867745;p=pakfire.git archive: Refactor scaffolding for signature check Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index bb1901092..076f94269 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -85,6 +85,8 @@ struct _PakfireArchive { struct pakfire_scriptlet** scriptlets; size_t nscriptlets; + // Verify Status + int verify; }; struct _PakfireArchiveSignature { @@ -1405,9 +1407,144 @@ ERROR: return status; } +/* + This function is called to examine whether we have a signature and if so verify it +*/ +static int pakfire_archive_verify_signature(PakfireArchive archive, struct archive* a, + struct archive_entry* e, void* data) { + const char* entry_name = archive_entry_pathname(e); + + // This is not a signature + if (!pakfire_string_startswith(entry_name, "signatures/")) + return 0; + + // Fetch GPGME context + gpgme_ctx_t gpgctx = pakfire_get_gpgctx(archive->pakfire); + if (!gpgctx) + return 1; + + gpgme_data_t* checksums = (gpgme_data_t*)data; + + char* buffer = NULL; + size_t size = 0; + + // Load the signature into memory + int r = pakfire_archive_copy_data_to_buffer(archive->pakfire, a, e, &buffer, &size); + if (r) + return 1; + + gpgme_data_t signature; + gpgme_error_t error; + + // Make signature readable for GPGME + error = gpgme_data_new_from_mem(&signature, buffer, size, 0); + if (error != GPG_ERR_NO_ERROR) { + r = 1; + goto ERROR; + } + + printf("GOT HERE\n"); + + // Perform verification + error = gpgme_op_verify(gpgctx, signature, *checksums, NULL); + if (error != GPG_ERR_NO_ERROR) + goto ERROR; + + // Run the operation + gpgme_verify_result_t result = gpgme_op_verify_result(gpgctx); + + // Check if any signatures have been returned + if (!result || !result->signatures) + goto ERROR; + + // XXX This is some old code and does not entirely do what is desired, yet + int status = 0; + + // Walk through all signatures + for (gpgme_signature_t sig = result->signatures; sig; sig = sig->next) { + switch (gpg_err_code(sig->status)) { + // All good + case GPG_ERR_NO_ERROR: + status = PAKFIRE_ARCHIVE_VERIFY_OK; + break; + + // Key has expired (still good) + case GPG_ERR_KEY_EXPIRED: + status = PAKFIRE_ARCHIVE_VERIFY_KEY_EXPIRED; + break; + + // Signature has expired (bad) + case GPG_ERR_SIG_EXPIRED: + status = PAKFIRE_ARCHIVE_VERIFY_SIG_EXPIRED; + break; + + // We don't have the key + case GPG_ERR_NO_PUBKEY: + status = PAKFIRE_ARCHIVE_VERIFY_KEY_UNKNOWN; + break; + + // Bad signature (or any other errors) + case GPG_ERR_BAD_SIGNATURE: + default: + status = PAKFIRE_ARCHIVE_VERIFY_INVALID; + break; + } + } + +ERROR: + // Free signature + gpgme_data_release(signature); + if (buffer) + free(buffer); + + return r; +} + +/* + This function walks through the archive looking for signatures and verifies them +*/ +static int pakfire_archive_verify_signatures(PakfireArchive archive) { + char* buffer = NULL; + size_t size = 0; + + // Find checksums + int r = open_archive_and_read(archive, "chksums", &buffer, &size); + if (r) { + ERROR(archive->pakfire, "Could not open chksums file: %m\n"); + return r; + } + + gpgme_data_t checksums; + + // Convert checksums readable for GPGME + gpgme_error_t error = gpgme_data_new_from_mem(&checksums, buffer, size, 0); + if (error != GPG_ERR_NO_ERROR) { + r = 1; + goto ERROR; + } + + // Verify all signatures + r = pakfire_archive_walk(archive, pakfire_archive_verify_signature, &checksums); + +ERROR: + gpgme_data_release(checksums); + if (buffer) + free(buffer); + + return r; +} + PAKFIRE_EXPORT pakfire_archive_verify_status_t pakfire_archive_verify(PakfireArchive archive) { DEBUG(archive->pakfire, "Verifying archive %p\n", archive); + // Return previous result if this has already been called + if (archive->verify != PAKFIRE_ARCHIVE_VERIFY_UNKNOWN) + return archive->verify; + + int r = pakfire_archive_verify_signatures(archive); + if (r) + return r; + return PAKFIRE_ARCHIVE_VERIFY_OK; // XXX DEBUG // Verify that checksums file is signed with a valid key @@ -1417,7 +1554,7 @@ PAKFIRE_EXPORT pakfire_archive_verify_status_t pakfire_archive_verify(PakfireArc // Open the archive file struct archive* a; - int r = open_archive(archive, &a); + r = open_archive(archive, &a); if (r) return PAKFIRE_ARCHIVE_VERIFY_ERROR; diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index a57fbf6e2..452cc2f2e 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -29,7 +29,8 @@ #include typedef enum pakfire_archive_verify_status { - PAKFIRE_ARCHIVE_VERIFY_OK = 0, + PAKFIRE_ARCHIVE_VERIFY_UNKNOWN = 0, + PAKFIRE_ARCHIVE_VERIFY_OK, PAKFIRE_ARCHIVE_VERIFY_NO_SIGNATURES, PAKFIRE_ARCHIVE_VERIFY_INVALID, PAKFIRE_ARCHIVE_VERIFY_SIG_EXPIRED,