[pacman-dev] [PATCH 1/2] Add functions for verifying db signature
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@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
participants (1)
-
Allan McRae