[pacman-dev] [PATCH 1/2] Add functions for verifying db signature

Allan McRae allan at archlinux.org
Mon Nov 22 12:30:35 CET 2010


Add a pmpgpsig_t struct to the database entry struct and functions for
the lazy loading of database signatures.  Add a function for checking
database signatures, reusing (and generalizing) the code currently used
for checking package signatures.

TODO: The code for reading in signature files from the filesystem is
duplicated for local packages and database and needs refactored.

Signed-off-by: Allan McRae <allan at archlinux.org>
---
 lib/libalpm/alpm.h    |    1 +
 lib/libalpm/db.c      |   56 +++++++++++++++++++++++++++++++++++++++++++++
 lib/libalpm/db.h      |    7 +++++-
 lib/libalpm/package.h |   11 +--------
 lib/libalpm/signing.c |   61 ++++++++++++++++++++++++++++++------------------
 lib/libalpm/signing.h |   12 +++++++++-
 6 files changed, 113 insertions(+), 35 deletions(-)

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 9dd222d..74598ef 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -253,6 +253,7 @@ alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg);
  */
 
 int alpm_pkg_check_pgp_signature(pmpkg_t *pkg);
+int alpm_db_check_pgp_signature(pmdb_t *db);
 
 /* GPG signature verification option */
 typedef enum _pgp_verify_t {
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 9fd918a..a7718d5 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -409,6 +409,62 @@ pmdb_t *_alpm_db_new(const char *treename, int is_local)
 	return(db);
 }
 
+static int load_pgpsig(pmdb_t *db) {
+	size_t len;
+	const char *dbfile;
+	char *sigfile;
+
+	dbfile = _alpm_db_path(db);
+	len = strlen(dbfile) + 5;
+	MALLOC(sigfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+	sprintf(sigfile, "%s.sig", dbfile);
+
+	if(access(sigfile, R_OK) == 0) {
+		FILE *f;
+		long bytes;
+		size_t bytes_read;
+		f = fopen(sigfile, "rb");
+		fseek(f, 0L, SEEK_END);
+		bytes = ftell(f);
+		fseek(f, 0L, SEEK_SET);
+		CALLOC(db->pgpsig.rawdata, bytes, sizeof(char),
+				goto error);
+		bytes_read = fread(db->pgpsig.rawdata, sizeof(char), bytes, f);
+		if(bytes_read == bytes) {
+			db->pgpsig.rawlen = bytes;
+			_alpm_log(PM_LOG_DEBUG,
+					"loaded database .sig file, location %s\n", sigfile);
+		} else {
+			_alpm_log(PM_LOG_WARNING, _("Failed reading PGP signature file for %s"),
+						dbfile);
+		}
+		fclose(f);
+	} else {
+		_alpm_log(PM_LOG_DEBUG, "no database signature file found\n");
+	}
+
+	return(0);
+
+error:
+	FREE(db->pgpsig.rawdata);
+	db->pgpsig.rawlen = 0;
+	return(1);
+}
+
+const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(db != NULL, return(NULL));
+
+	if(db->pgpsig.rawdata == NULL) {
+		load_pgpsig(db);
+	}
+
+	return &(db->pgpsig);
+}
+
 void _alpm_db_free(pmdb_t *db)
 {
 	ALPM_LOG_FUNC;
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index ab896b9..1372b0d 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -22,7 +22,6 @@
 #ifndef _ALPM_DB_H
 #define _ALPM_DB_H
 
-#include "alpm.h"
 #include <limits.h>
 #include <time.h>
 
@@ -30,6 +29,9 @@
 #include <archive.h>
 #include <archive_entry.h>
 
+#include "alpm.h"
+#include "signing.h"
+
 /* Database entries */
 typedef enum _pmdbinfrq_t {
 	INFRQ_BASE = 1,
@@ -58,6 +60,8 @@ struct __pmdb_t {
 	alpm_list_t *pkgcache;
 	alpm_list_t *grpcache;
 	alpm_list_t *servers;
+	/* do not access directly, use _alpm_db_pgpsig(db) for lazy access */
+	pmpgpsig_t pgpsig;
 	pgp_verify_t pgp_verify;
 
 	struct db_operations *ops;
@@ -73,6 +77,7 @@ pmdb_t *_alpm_db_register_local(void);
 pmdb_t *_alpm_db_register_sync(const char *treename);
 void _alpm_db_unregister(pmdb_t *db);
 pmdb_t *_alpm_db_new(const char *treename, int is_local);
+const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db);
 
 /* be_*.c, backend specific calls */
 int _alpm_local_db_populate(pmdb_t *db);
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index be5ce32..7c11e38 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -29,6 +29,7 @@
 
 #include "alpm.h"
 #include "db.h"
+#include "signing.h"
 
 typedef enum _pmpkgfrom_t {
 	PKG_FROM_FILE = 1,
@@ -90,16 +91,6 @@ struct pkg_operations {
  */
 extern struct pkg_operations default_pkg_ops;
 
-struct __pmpgpsig_t {
-	/* we will either store the encoded data or the raw data-
-	 * this way we can decode on an as-needed basis since most
-	 * operations won't require the overhead of base64 decodes
-	 * on all packages in a sync repository. */
-	char *encdata;
-	size_t rawlen;
-	unsigned char *rawdata;
-};
-
 struct __pmpkg_t {
 	char *filename;
 	char *name;
diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c
index 2b15528..826c34b 100644
--- a/lib/libalpm/signing.c
+++ b/lib/libalpm/signing.c
@@ -92,28 +92,28 @@ error:
 }
 
 /**
- * Check the PGP package signature for the given package file.
- * @param pkgpath the full path to a package file
+ * Check the PGP package signature for the given file.
+ * @param path the full path to a file
  * @param sig PGP signature data in raw form (already decoded)
  * @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
  */
-int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
+int _alpm_gpgme_checksig(const char *path, const pmpgpsig_t *sig)
 {
 	int ret = 0;
 	gpgme_error_t err;
 	gpgme_ctx_t ctx;
-	gpgme_data_t pkgdata, sigdata;
+	gpgme_data_t filedata, sigdata;
 	gpgme_verify_result_t result;
 	gpgme_signature_t gpgsig;
-	FILE *pkgfile = NULL, *sigfile = NULL;
+	FILE *file = NULL, *sigfile = NULL;
 
 	ALPM_LOG_FUNC;
 
 	if(!sig || !sig->rawdata) {
 		 RET_ERR(PM_ERR_SIG_UNKNOWN, -1);
 	}
-	if(!pkgpath || access(pkgpath, R_OK) != 0) {
-		RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
+	if(!path || access(path, R_OK) != 0) {
+		RET_ERR(PM_ERR_NOT_A_FILE, -1);
 	}
 	if(gpgme_init()) {
 		/* pm_errno was set in gpgme_init() */
@@ -124,13 +124,13 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
 
 	/* create our necessary data objects to verify the signature */
 	/* first the package itself */
-	pkgfile = fopen(pkgpath, "rb");
-	if(pkgfile == NULL) {
-		pm_errno = PM_ERR_PKG_OPEN;
+	file = fopen(path, "rb");
+	if(file == NULL) {
+		pm_errno = PM_ERR_NOT_A_FILE;
 		ret = -1;
 		goto error;
 	}
-	err = gpgme_data_new_from_stream(&pkgdata, pkgfile);
+	err = gpgme_data_new_from_stream(&filedata, file);
 	CHECK_ERR();
 
 	/* next create data object for the signature */
@@ -138,7 +138,7 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
 	CHECK_ERR();
 
 	/* here's where the magic happens */
-	err = gpgme_op_verify(ctx, sigdata, pkgdata, NULL);
+	err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
 	CHECK_ERR();
 	result = gpgme_op_verify_result(ctx);
 		gpgsig = result->signatures;
@@ -161,34 +161,34 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
 
 	if(gpgsig->summary & GPGME_SIGSUM_VALID) {
 		/* good signature, continue */
-		_alpm_log(PM_LOG_DEBUG, _("Package %s has a valid signature.\n"),
-				pkgpath);
+		_alpm_log(PM_LOG_DEBUG, _("File %s has a valid signature.\n"),
+				path);
 	} else if(gpgsig->summary & GPGME_SIGSUM_GREEN) {
 		/* 'green' signature, not sure what to do here */
-		_alpm_log(PM_LOG_WARNING, _("Package %s has a green signature.\n"),
-				pkgpath);
+		_alpm_log(PM_LOG_WARNING, _("File %s has a green signature.\n"),
+				path);
 	} else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) {
 		pm_errno = PM_ERR_SIG_UNKNOWN;
-		_alpm_log(PM_LOG_WARNING, _("Package %s has a signature from an unknown key.\n"),
-				pkgpath);
+		_alpm_log(PM_LOG_WARNING, _("File %s has a signature from an unknown key.\n"),
+				path);
 		ret = -1;
 	} else {
 		/* we'll capture everything else here */
 		pm_errno = PM_ERR_SIG_INVALID;
-		_alpm_log(PM_LOG_ERROR, _("Package %s has an invalid signature.\n"),
-				pkgpath);
+		_alpm_log(PM_LOG_ERROR, _("File %s has an invalid signature.\n"),
+				path);
 		ret = 1;
 	}
 
 error:
 	gpgme_data_release(sigdata);
-	gpgme_data_release(pkgdata);
+	gpgme_data_release(filedata);
 	gpgme_release(ctx);
 	if(sigfile) {
 		fclose(sigfile);
 	}
-	if(pkgfile) {
-		fclose(pkgfile);
+	if(file) {
+		fclose(file);
 	}
 	if(err != GPG_ERR_NO_ERROR) {
 		_alpm_log(PM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(err));
@@ -211,4 +211,19 @@ int SYMEXPORT alpm_pkg_check_pgp_signature(pmpkg_t *pkg)
 			alpm_pkg_get_pgpsig(pkg)));
 }
 
+/**
+ * Check the PGP package signature for the given database.
+ * @param db the database to check
+ * @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
+ */
+int SYMEXPORT alpm_db_check_pgp_signature(pmdb_t *db)
+{
+	ALPM_LOG_FUNC;
+	ASSERT(db != NULL, return(0));
+
+	return(_alpm_gpgme_checksig(_alpm_db_path(db),
+			_alpm_db_pgpsig(db)));
+}
+
+
 /* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/signing.h b/lib/libalpm/signing.h
index c004697..8fbb25d 100644
--- a/lib/libalpm/signing.h
+++ b/lib/libalpm/signing.h
@@ -21,7 +21,17 @@
 
 #include "alpm.h"
 
-int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig);
+struct __pmpgpsig_t {
+	/* we will either store the encoded data or the raw data-
+	 * this way we can decode on an as-needed basis since most
+	 * operations won't require the overhead of base64 decodes
+	 * on all packages in a sync repository. */
+	char *encdata;
+	size_t rawlen;
+	unsigned char *rawdata;
+};
+
+int _alpm_gpgme_checksig(const char *path, const pmpgpsig_t *sig);
 
 #endif /* _ALPM_SIGNING_H */
 
-- 
1.7.3.2



More information about the pacman-dev mailing list