[pacman-dev] [PATCH 3/5] Verify the signatures of databases and packages

Denis A. Altoé Falqueto denisfalqueto at gmail.com
Mon Jul 26 16:26:03 EDT 2010


The signatures of databases will be verified when the database
is being updated. The option VerifySig in the database section
of pacman.conf will dictate how to deal with the signature.
If there is a need to verify (VerifySig is Always or Optional),
the signature will be downloaded and verifyed.

When signing packages, the signature will come from the database
repository where it belongs. So, if a package will be installed from
core, the signature will be read from the desc file, field %PGPSIG%.

Signed-off-by: Denis A. Altoé Falqueto <denisfalqueto at gmail.com>
---
 lib/libalpm/be_files.c |   84 +++++++++++++++++++++++++++++++++++++++++++++--
 lib/libalpm/sync.c     |    2 +-
 2 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
index 97c5c4b..505560f 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_files.c
@@ -49,6 +49,9 @@
 #include "delta.h"
 #include "deps.h"
 #include "dload.h"
+#include "signing.h"
+
+#define DBSIGEXT ".sig"
 
 
 static int checkdbdir(pmdb_t *db)
@@ -241,6 +244,55 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
 	sprintf(syncpath, "%s%s", dbpath, "sync/");
 
 	ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
+	/* Check the signature of the database, if it is marked as signed */
+	if(db->pgp_verify != PM_PGP_VERIFY_NEVER) {
+		char *dbsigfile = NULL;
+
+		/* Assemble the signature file name */
+		len = strlen(dbfile) + strlen(DBSIGEXT) + 1;
+		MALLOC(dbsigfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+		sprintf(dbsigfile, "%s" DBSIGEXT, dbfile);
+
+		/* Try to download the signature file */
+		ret = _alpm_download_single_file(dbsigfile, db->servers, syncpath, force);
+		if (ret == -1 && db->pgp_verify == PM_PGP_VERIFY_ALWAYS) {
+			_alpm_log(PM_LOG_DEBUG, "failed to download signature for db: %s\n", alpm_strerrorlast());
+			free(dbfile);
+			free(dbsigfile);
+			RET_ERR(PM_ERR_SIG_MISSINGDIR, -1);
+		}
+		else if (ret != -1) {
+			char *fulldbfile = NULL, *fulldbsigfile = NULL;
+
+			/* Assemble the full db and signature file names */
+			MALLOC(fulldbfile, strlen(syncpath) + strlen(dbfile) + 2, RET_ERR(PM_ERR_MEMORY, -1));
+			MALLOC(fulldbsigfile, strlen(syncpath) + strlen(dbsigfile) + 2, RET_ERR(PM_ERR_MEMORY, -1));
+			sprintf(fulldbfile, "%s/%s", syncpath, dbfile);
+			sprintf(fulldbsigfile, "%s/%s", syncpath, dbsigfile);
+
+			/* Check the signature */
+			_alpm_log(PM_LOG_DEBUG, "fulldbfile = %s\n", fulldbfile);
+			_alpm_log(PM_LOG_DEBUG, "fulldbsigfile = %s\n", fulldbsigfile);
+			int ret = _alpm_gpgme_checksig_file(fulldbfile, fulldbsigfile);
+			_alpm_log(PM_LOG_DEBUG, "return from _alpm_gpgme_checksig_file = %d\n", ret);
+
+			FREE(fulldbfile);
+			FREE(fulldbsigfile);
+
+			/* VerifSig = Always -> we will only accept 0 as a correct value
+			 *            (missing or invalid signatures are errors)
+			 * VerifSig = Optional -> we will accept 0 or -1 as correct values
+			 *            (missing signature is ok, but if it present, it must be valid) */
+			if((db->pgp_verify == PM_PGP_VERIFY_ALWAYS && ret != 0) ||
+					(db->pgp_verify == PM_PGP_VERIFY_OPTIONAL && ret == 1)) {
+				_alpm_log(PM_LOG_ERROR, "the signature doesn't match the repository database.\n");
+				free(dbfile);
+				free(dbsigfile);
+				RET_ERR(PM_ERR_SIG_INVALID, -1);
+			}
+		}
+		FREE(dbsigfile);
+	}
 	free(dbfile);
 	free(syncpath);
 
@@ -614,11 +666,35 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
 				STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
 			} else if(strcmp(line, "%PGPSIG%") == 0) {
 				/* PGPSIG tag only appears in sync repositories,
-				 * not the local one. */
-				if(fgets(line, 512, fp) == NULL) {
-					goto error;
+				 * not the local one. The size must not be fixed,
+				 * because the key used will affect the final size */
+				alpm_list_t *pgpsiglines = NULL;
+				int len = 0;
+
+				/* Create a list of strings to store each line of the signature */
+				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					pgpsiglines = alpm_list_add(pgpsiglines, linedup);
+					len += strlen(linedup);
+				}
+
+				/* Allocate a buffer to hold the full signature */
+				MALLOC(info->pgpsig.encdata, (size_t)(len + 1), goto error);
+				info->pgpsig.encdata[0] = '\0';
+
+				/* Assemble the signature from the list of strings */
+				while (pgpsiglines != NULL) {
+					alpm_list_t *pgpsig_line = pgpsiglines;
+					pgpsiglines = pgpsiglines->next;
+
+					strcat(info->pgpsig.encdata, (char *)pgpsig_line->data);
+
+					/* Free the current node, as it is not needed anymore */
+					free(pgpsig_line->data);
+					free(pgpsig_line);
 				}
-				STRDUP(info->pgpsig.encdata, _alpm_strtrim(line), goto error);
+				pgpsiglines = NULL;
 			} else if(strcmp(line, "%REPLACES%") == 0) {
 				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
 					char *linedup;
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 77afe24..38aa508 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -942,7 +942,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
 		pmdb_t *sdb = alpm_pkg_get_db(spkg);
 
 		if(sdb->pgp_verify != PM_PGP_VERIFY_NEVER) {
-			int ret = _alpm_gpgme_checksig(filepath, pgpsig);
+			int ret = _alpm_gpgme_checksig_memory(filepath, pgpsig);
 			if((sdb->pgp_verify == PM_PGP_VERIFY_ALWAYS && ret != 0) ||
 					(sdb->pgp_verify == PM_PGP_VERIFY_OPTIONAL && ret == 1)) {
 				errors++;
-- 
1.7.1.1



More information about the pacman-dev mailing list