From ed6fda2f98bdcde56a67e43a6bcf644c549892a2 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Mon, 22 Nov 2010 15:06:09 +1000 Subject: Add functions for verifying database 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 refactoring. Signed-off-by: Allan McRae --- lib/libalpm/alpm.h | 1 + lib/libalpm/db.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/db.h | 6 +++++ lib/libalpm/package.h | 11 +-------- lib/libalpm/signing.c | 66 +++++++++++++++++++++++++++++++-------------------- lib/libalpm/signing.h | 12 +++++++++- 6 files changed, 124 insertions(+), 37 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 276d49cb..b08191d0 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -250,6 +250,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 f61ea918..2c9b25f3 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -365,6 +365,69 @@ 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); + if(bytes == -1) { + _alpm_log(PM_LOG_WARNING, _("Failed reading PGP signature file for %s"), + dbfile); + goto cleanup; + } + 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 == (size_t)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); + } + +cleanup: + 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; @@ -373,6 +436,8 @@ void _alpm_db_free(pmdb_t *db) _alpm_db_free_pkgcache(db); /* cleanup server list */ FREELIST(db->servers); + /* only need to free rawdata */ + FREE(db->pgpsig.rawdata); FREE(db->_path); FREE(db->treename); FREE(db); diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index dfd9f933..204a0be0 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -31,6 +31,9 @@ #include #include +#include "alpm.h" +#include "signing.h" + /* Database entries */ typedef enum _pmdbinfrq_t { INFRQ_BASE = 1, @@ -60,6 +63,8 @@ struct __pmdb_t { pmpkghash_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; @@ -76,6 +81,7 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles); pmdb_t *_alpm_db_register_local(void); pmdb_t *_alpm_db_register_sync(const char *treename); void _alpm_db_unregister(pmdb_t *db); +const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db); /* be_*.c, backend specific calls */ int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index 25ed5cf4..0b5f32d4 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, @@ -87,16 +88,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 { unsigned long name_hash; char *filename; diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 684cacf2..ecb81c9c 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -92,52 +92,51 @@ 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() */ return -1; } - _alpm_log(PM_LOG_DEBUG, "checking package signature for %s\n", pkgpath); + _alpm_log(PM_LOG_DEBUG, "checking signature for %s\n", path); memset(&ctx, 0, sizeof(ctx)); memset(&sigdata, 0, sizeof(sigdata)); - memset(&pkgdata, 0, sizeof(pkgdata)); + memset(&filedata, 0, sizeof(filedata)); err = gpgme_new(&ctx); CHECK_ERR(); /* 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 */ @@ -145,7 +144,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; @@ -168,34 +167,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)); @@ -218,4 +217,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 bd12de42..07773780 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 */ -- cgit v1.2.3-24-g4f1b