#include <archive.h>
#include <archive_entry.h>
-// libgcrypt
-#include <gcrypt.h>
+// openssl
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
#include <pakfire/archive.h>
#include <pakfire/errno.h>
typedef struct archive_checksum {
Pakfire pakfire;
char* filename;
- char* checksum;
archive_checksum_algo_t algo;
+ unsigned char digest[EVP_MAX_MD_SIZE];
} archive_checksum_t;
struct _PakfireArchive {
return NULL;
}
-static archive_checksum_t* pakfire_archive_checksum_create(Pakfire pakfire, const char* filename, const char* checksum, archive_checksum_algo_t algo) {
- archive_checksum_t* c = pakfire_calloc(1, sizeof(*c));
- if (c) {
- c->pakfire = pakfire_ref(pakfire);
- c->filename = pakfire_strdup(filename);
- c->checksum = pakfire_strdup(checksum);
- c->algo = algo;
+static int read_hexdigest(unsigned char* dst, size_t l, const char* src) {
+ const char* p = src;
- DEBUG(c->pakfire, "Allocated archive checksum for %s (%s:%s)\n",
- c->filename, checksum_algo_string(c->algo), c->checksum);
+ for (unsigned int i = 0; i < l && *p; i++) {
+ int r = sscanf(p, "%02X", (unsigned int*)&dst[i]);
+ if (r != 1)
+ return 1;
+
+ p += 2;
}
- return c;
+ return 0;
}
static void pakfire_archive_checksum_free(archive_checksum_t* c) {
pakfire_unref(c->pakfire);
pakfire_free(c->filename);
- pakfire_free(c->checksum);
pakfire_free(c);
}
+static archive_checksum_t* pakfire_archive_checksum_create(Pakfire pakfire, const char* filename, archive_checksum_algo_t algo, const char* s) {
+ archive_checksum_t* c = pakfire_calloc(1, sizeof(*c));
+ if (c) {
+ c->pakfire = pakfire_ref(pakfire);
+ c->filename = pakfire_strdup(filename);
+ c->algo = algo;
+
+ int r = read_hexdigest(c->digest, sizeof(c->digest), s);
+ if (r) {
+ pakfire_archive_checksum_free(c);
+ return NULL;
+ }
+
+ DEBUG(c->pakfire, "Allocated archive checksum for %s (%s)\n",
+ c->filename, checksum_algo_string(c->algo));
+ }
+
+ return c;
+}
+
static archive_checksum_t* pakfire_archive_checksum_find(PakfireArchive archive, const char* filename) {
archive_checksum_t** checksums = archive->checksums;
// Add new checksum object
if (filename && checksum) {
- *checksums++ = pakfire_archive_checksum_create(archive->pakfire, filename, checksum, algo);
+ *checksums++ = pakfire_archive_checksum_create(archive->pakfire, filename, algo, checksum);
}
// Eat up any space before next thing starts
return status;
}
-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(Pakfire pakfire, struct archive* a, const archive_checksum_t* checksum) {
- pakfire_archive_verify_status_t status = PAKFIRE_ARCHIVE_VERIFY_INVALID;
+ pakfire_archive_verify_status_t status = PAKFIRE_ARCHIVE_VERIFY_ERROR;
+
+ int r;
+ const EVP_MD* md;
- // Make sure libgcrypt is initialized
- init_libgcrypt();
+ // Initialise context
+ EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
- int algo = 0;
+ // Select algorithm
switch (checksum->algo) {
case PAKFIRE_CHECKSUM_SHA512:
- algo = GCRY_MD_SHA512;
+ md = EVP_sha512();
break;
- case PAKFIRE_CHECKSUM_UNKNOWN:
- break;
+ default:
+ ERROR(pakfire, "Unknown algorithm chosen\n");
+ goto ERROR;
}
- 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;
+ // Initialise the hash algorithm
+ r = EVP_DigestInit_ex(mdctx, md, NULL);
+ if (r != 1) {
+ ERROR(pakfire, "Could not initialize hash algorithm: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto ERROR;
+ }
- const void* buff;
+ const void* buffer;
size_t size;
off_t offset;
for (;;) {
- int r = archive_read_data_block(a, &buff, &size, &offset);
+ int r = archive_read_data_block(a, &buffer, &size, &offset);
if (r == ARCHIVE_EOF)
break;
if (r != ARCHIVE_OK) {
pakfire_errno = r;
status = PAKFIRE_ARCHIVE_VERIFY_ERROR;
- goto FAIL;
+ goto ERROR;
}
// Update hash digest
- gcry_md_write(hd, buff, size);
+ r = EVP_DigestUpdate(mdctx, buffer, size);
+ if (r != 1) {
+ ERROR(pakfire, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ goto ERROR;
+ }
}
- // 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);
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_length = sizeof(digest);
- // Convert to hexdigest
- char* hexdigest = digest_to_hexdigest(digest, l);
+ r = EVP_DigestFinal_ex(mdctx, digest, &digest_length);
+ if (r != 1) {
+ ERROR(pakfire, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ goto ERROR;
+ }
// Compare digests
- if (strcmp(checksum->checksum, hexdigest) == 0) {
+ if (CRYPTO_memcmp(digest, checksum->digest, EVP_MD_CTX_size(mdctx)) == 0) {
DEBUG(pakfire, "Checksum of %s is OK\n", checksum->filename);
status = PAKFIRE_ARCHIVE_VERIFY_OK;
} else {
DEBUG(pakfire, "Checksum of %s did not match\n", checksum->filename);
- DEBUG(pakfire, "Expected %s:%s, got %s\n",
- checksum_algo_string(checksum->algo), checksum->checksum, hexdigest);
+ status = PAKFIRE_ARCHIVE_VERIFY_INVALID;
}
- pakfire_free(hexdigest);
-
-FAIL:
- gcry_md_close(hd);
+ERROR:
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
return status;
}
// See if we have a checksum for this file
const archive_checksum_t* checksum = pakfire_archive_checksum_find(archive, entry_name);
- if (!checksum)
+ if (!checksum) {
+ DEBUG(archive->pakfire, "Could not find checksum for %s\n", entry_name);
continue;
+ }
// Compare the checksums
status = pakfire_archive_verify_file(archive->pakfire, a, checksum);