[pacman-dev] [PATCH 5/6] Verify the signatures of databases and packages
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@gmail.com> --- lib/libalpm/be_files.c | 90 ++++++++++++++++++++++++++++++++++++++++++++---- lib/libalpm/sync.c | 2 +- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c index 1235165..ae545e8 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_files.c @@ -49,7 +49,9 @@ #include "delta.h" #include "deps.h" #include "dload.h" +#include "signing.h" +#define DBSIGEXT ".sig" static int checkdbdir(pmdb_t *db) { @@ -208,7 +210,7 @@ static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist) */ int SYMEXPORT alpm_db_update(int force, pmdb_t *db) { - char *dbfile, *dbfilepath; + char *dbfile = NULL, *dbfilepath = NULL; const char *dbpath, *syncdbpath; alpm_list_t *newdirlist = NULL, *olddirlist = NULL; alpm_list_t *onlynew = NULL, *onlyold = NULL; @@ -238,18 +240,68 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db) dbpath = alpm_option_get_dbpath(); ret = _alpm_download_single_file(dbfile, db->servers, dbpath, force); - free(dbfile); - if(ret == 1) { /* files match, do nothing */ pm_errno = 0; + free(dbfile); return(1); } else if(ret == -1) { /* pm_errno was set by the download code */ _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); + free(dbfile); return(-1); } + /* 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, dbpath, 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); + return (-1); + } + else if (ret != -1) { + char *fulldbfile = NULL, *fulldbsigfile = NULL; + + /* Assemble the full db and signature file names */ + MALLOC(fulldbfile, strlen(dbpath) + strlen(dbfile) + 2, RET_ERR(PM_ERR_MEMORY, -1)); + MALLOC(fulldbsigfile, strlen(dbpath) + strlen(dbsigfile) + 2, RET_ERR(PM_ERR_MEMORY, -1)); + sprintf(fulldbfile, "%s/%s", dbpath, dbfile); + sprintf(fulldbsigfile, "%s/%s", dbpath, dbsigfile); + + /* Check the signature */ + int ret = _alpm_gpg_checksig_file(fulldbfile, fulldbsigfile); + _alpm_log(PM_LOG_DEBUG, "return from _alpm_gpg_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_DB_SIG, -1); + } + } + FREE(dbsigfile); + } + /* We don't need the db file name anymore */ + FREE(dbfile); + syncdbpath = _alpm_db_path(db); /* form the path to the db location */ @@ -610,11 +662,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 *pgpsig_lines = 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); + pgpsig_lines = alpm_list_add(pgpsig_lines, 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 (pgpsig_lines != NULL) { + alpm_list_t *pgpsig_line = pgpsig_lines; + pgpsig_lines = pgpsig_lines->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); + pgpsig_lines = 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 3994d5d..aa1fffe 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -938,7 +938,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_gpg_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
participants (1)
-
Denis A. Altoé Falqueto