]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
archive: Refactor scaffolding for signature check
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Jul 2021 22:06:32 +0000 (22:06 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Jul 2021 22:06:32 +0000 (22:06 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/include/pakfire/archive.h

index bb19010929eb8b7f9e7adbe33d2550182a8beaad..076f94269703d1abfaefd8af54538024e72df74a 100644 (file)
@@ -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;
 
index a57fbf6e263bfecb171f126aed6248be948c9130..452cc2f2e7f82572584497a06afababef124f971 100644 (file)
@@ -29,7 +29,8 @@
 #include <pakfire/types.h>
 
 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,