]> git.ipfire.org Git - pakfire.git/commitdiff
libpakfire: Verify signatures of all files in the archive
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 25 Nov 2017 14:07:58 +0000 (15:07 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 25 Nov 2017 14:14:11 +0000 (15:14 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/include/pakfire/archive.h

index bdffc084a809229a87adb6cde9270a8b8a6e33a9..d71fb06b01d9d405ad86e342fe854b5a011a9da4 100644 (file)
@@ -31,6 +31,9 @@
 #include <archive.h>
 #include <archive_entry.h>
 
+// libgcrypt
+#include <gcrypt.h>
+
 #include <pakfire/archive.h>
 #include <pakfire/errno.h>
 #include <pakfire/file.h>
@@ -150,6 +153,20 @@ static void pakfire_archive_checksum_free(archive_checksum_t* c) {
        pakfire_free(c);
 }
 
+static archive_checksum_t* pakfire_archive_checksum_find(PakfireArchive archive, const char* filename) {
+       archive_checksum_t** checksums = archive->checksums;
+
+       while (checksums && *checksums) {
+               archive_checksum_t* checksum = *checksums++;
+
+               if (strcmp(checksum->filename, filename) == 0)
+                       return checksum;
+       }
+
+       // Nothing found
+       return NULL;
+}
+
 static archive_signature_t* pakfire_archive_signature_create(const char* sigdata) {
        archive_signature_t* s = pakfire_calloc(1, sizeof(*s));
        if (s) {
@@ -751,25 +768,111 @@ CLEANUP:
        return status;
 }
 
-static pakfire_archive_verify_status_t pakfire_archive_verify_file(PakfireArchive archive, const archive_checksum_t* checksum) {
-       return PAKFIRE_ARCHIVE_VERIFY_OK; // TODO
+static char* digest_to_hexdigest(const unsigned char* digest, unsigned int len) {
+       char* hexdigest = pakfire_calloc(len * 2, sizeof(*hexdigest));
+
+       char* p = hexdigest;
+       for (unsigned int i = 0; i < len; i++) {
+               snprintf(p, 3, "%02x", digest[i]);
+               p += 2;
+       }
+
+       return hexdigest;
+}
+
+static pakfire_archive_verify_status_t pakfire_archive_verify_file(struct archive* a, const archive_checksum_t* checksum) {
+       pakfire_archive_verify_status_t status = PAKFIRE_ARCHIVE_VERIFY_INVALID;
+
+       // Make sure libgcrypt is initialized
+       init_libgcrypt();
+
+       int algo = 0;
+       switch (checksum->algo) {
+               case PAKFIRE_CHECKSUM_SHA512:
+                       algo = GCRY_MD_SHA512;
+                       break;
+
+               case PAKFIRE_CHECKSUM_UNKNOWN:
+                       break;
+       }
+       assert(algo);
+
+       gcry_md_hd_t hd = NULL;
+       gcry_error_t error = gcry_md_open(&hd, algo, 0);
+       if (error != GPG_ERR_NO_ERROR)
+               return PAKFIRE_ARCHIVE_VERIFY_ERROR;
+
+       const void* buff;
+       size_t size;
+       off_t offset;
+
+       for (;;) {
+               int r = archive_read_data_block(a, &buff, &size, &offset);
+               if (r == ARCHIVE_EOF)
+                       break;
+
+               if (r != ARCHIVE_OK) {
+                       pakfire_errno = r;
+                       status = PAKFIRE_ARCHIVE_VERIFY_ERROR;
+                       goto FAIL;
+               }
+
+               // Update hash digest
+               gcry_md_write(hd, buff, size);
+       }
+
+       // Finish computing the hash
+       gcry_md_final(hd);
+
+       // Get the hash digest
+       unsigned int l = gcry_md_get_algo_dlen(algo);
+       unsigned char* digest = gcry_md_read(hd, algo);
+
+       // Convert to hexdigest
+       char* hexdigest = digest_to_hexdigest(digest, l);
+
+       // Compare digests
+       if (strcmp(checksum->checksum, hexdigest) == 0)
+               status = PAKFIRE_ARCHIVE_VERIFY_OK;
+
+       pakfire_free(hexdigest);
+
+FAIL:
+       gcry_md_close(hd);
+
+       return status;
 }
 
 pakfire_archive_verify_status_t pakfire_archive_verify(PakfireArchive archive) {
-       // TODO Verify that checksums file is signed with a valid key
-       pakfire_archive_verify_status_t r = pakfire_archive_verify_checksums(archive);
-       if (r)
-               return r;
+       // Verify that checksums file is signed with a valid key
+       pakfire_archive_verify_status_t status = pakfire_archive_verify_checksums(archive);
+       if (status)
+               return status;
 
-       // TODO Verify checksum of each file
-       archive_checksum_t** checksum = archive->checksums;
-       while (*checksum) {
-               r = pakfire_archive_verify_file(archive, *checksum);
-               if (r)
-                       return r;
+       // Open the archive file
+       struct archive* a;
+       int r = archive_open(archive, &a);
+       if (r) {
+               pakfire_errno = r;
+               return PAKFIRE_ARCHIVE_VERIFY_ERROR;
        }
 
-       return 0;
+       struct archive_entry* entry;
+       while ((r = archive_read_next_header(a, &entry)) == ARCHIVE_OK) {
+               const char* entry_name = archive_entry_pathname(entry);
+
+               // See if we have a checksum for this file
+               const archive_checksum_t* checksum = pakfire_archive_checksum_find(archive, entry_name);
+               if (!checksum)
+                       continue;
+
+               // Compare the checksums
+               status = pakfire_archive_verify_file(a, checksum);
+               if (status)
+                       return status;
+       }
+
+       return PAKFIRE_ARCHIVE_VERIFY_OK;
 }
 
 const char* pakfire_archive_verify_strerror(pakfire_archive_verify_status_t status) {
@@ -777,6 +880,9 @@ const char* pakfire_archive_verify_strerror(pakfire_archive_verify_status_t stat
                case PAKFIRE_ARCHIVE_VERIFY_OK:
                        return _("Verify OK");
 
+               case PAKFIRE_ARCHIVE_VERIFY_ERROR:
+                       return _("Error performing validation");
+
                case PAKFIRE_ARCHIVE_VERIFY_INVALID:
                        return _("Invalid signature");
 
index d102dbd9d50635469a8204ce45174bb4b2ca8bf3..48b10c1dfc1f1f474647045601b79cc54b18b0c8 100644 (file)
@@ -31,6 +31,7 @@ typedef enum pakfire_archive_verify_status {
        PAKFIRE_ARCHIVE_VERIFY_SIG_EXPIRED,
        PAKFIRE_ARCHIVE_VERIFY_KEY_EXPIRED,
        PAKFIRE_ARCHIVE_VERIFY_KEY_UNKNOWN,
+       PAKFIRE_ARCHIVE_VERIFY_ERROR,
 } pakfire_archive_verify_status_t;
 
 PakfireArchive pakfire_archive_create(Pakfire pakfire);