mirror of
https://github.com/moparisthebest/pacman
synced 2025-03-01 01:41:52 -05:00
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 <allan@archlinux.org>
This commit is contained in:
parent
ef26c44524
commit
ed6fda2f98
@ -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_pkg_check_pgp_signature(pmpkg_t *pkg);
|
||||||
|
int alpm_db_check_pgp_signature(pmdb_t *db);
|
||||||
|
|
||||||
/* GPG signature verification option */
|
/* GPG signature verification option */
|
||||||
typedef enum _pgp_verify_t {
|
typedef enum _pgp_verify_t {
|
||||||
|
@ -365,6 +365,69 @@ pmdb_t *_alpm_db_new(const char *treename, int is_local)
|
|||||||
return db;
|
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)
|
void _alpm_db_free(pmdb_t *db)
|
||||||
{
|
{
|
||||||
ALPM_LOG_FUNC;
|
ALPM_LOG_FUNC;
|
||||||
@ -373,6 +436,8 @@ void _alpm_db_free(pmdb_t *db)
|
|||||||
_alpm_db_free_pkgcache(db);
|
_alpm_db_free_pkgcache(db);
|
||||||
/* cleanup server list */
|
/* cleanup server list */
|
||||||
FREELIST(db->servers);
|
FREELIST(db->servers);
|
||||||
|
/* only need to free rawdata */
|
||||||
|
FREE(db->pgpsig.rawdata);
|
||||||
FREE(db->_path);
|
FREE(db->_path);
|
||||||
FREE(db->treename);
|
FREE(db->treename);
|
||||||
FREE(db);
|
FREE(db);
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
#include <archive.h>
|
#include <archive.h>
|
||||||
#include <archive_entry.h>
|
#include <archive_entry.h>
|
||||||
|
|
||||||
|
#include "alpm.h"
|
||||||
|
#include "signing.h"
|
||||||
|
|
||||||
/* Database entries */
|
/* Database entries */
|
||||||
typedef enum _pmdbinfrq_t {
|
typedef enum _pmdbinfrq_t {
|
||||||
INFRQ_BASE = 1,
|
INFRQ_BASE = 1,
|
||||||
@ -60,6 +63,8 @@ struct __pmdb_t {
|
|||||||
pmpkghash_t *pkgcache;
|
pmpkghash_t *pkgcache;
|
||||||
alpm_list_t *grpcache;
|
alpm_list_t *grpcache;
|
||||||
alpm_list_t *servers;
|
alpm_list_t *servers;
|
||||||
|
/* do not access directly, use _alpm_db_pgpsig(db) for lazy access */
|
||||||
|
pmpgpsig_t pgpsig;
|
||||||
pgp_verify_t pgp_verify;
|
pgp_verify_t pgp_verify;
|
||||||
|
|
||||||
struct db_operations *ops;
|
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_local(void);
|
||||||
pmdb_t *_alpm_db_register_sync(const char *treename);
|
pmdb_t *_alpm_db_register_sync(const char *treename);
|
||||||
void _alpm_db_unregister(pmdb_t *db);
|
void _alpm_db_unregister(pmdb_t *db);
|
||||||
|
const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db);
|
||||||
|
|
||||||
/* be_*.c, backend specific calls */
|
/* be_*.c, backend specific calls */
|
||||||
int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
|
int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "alpm.h"
|
#include "alpm.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
#include "signing.h"
|
||||||
|
|
||||||
typedef enum _pmpkgfrom_t {
|
typedef enum _pmpkgfrom_t {
|
||||||
PKG_FROM_FILE = 1,
|
PKG_FROM_FILE = 1,
|
||||||
@ -87,16 +88,6 @@ struct pkg_operations {
|
|||||||
*/
|
*/
|
||||||
extern struct pkg_operations default_pkg_ops;
|
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 {
|
struct __pmpkg_t {
|
||||||
unsigned long name_hash;
|
unsigned long name_hash;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -92,52 +92,51 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the PGP package signature for the given package file.
|
* Check the PGP package signature for the given file.
|
||||||
* @param pkgpath the full path to a package file
|
* @param path the full path to a file
|
||||||
* @param sig PGP signature data in raw form (already decoded)
|
* @param sig PGP signature data in raw form (already decoded)
|
||||||
* @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
|
* @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;
|
int ret = 0;
|
||||||
gpgme_error_t err;
|
gpgme_error_t err;
|
||||||
gpgme_ctx_t ctx;
|
gpgme_ctx_t ctx;
|
||||||
gpgme_data_t pkgdata, sigdata;
|
gpgme_data_t filedata, sigdata;
|
||||||
gpgme_verify_result_t result;
|
gpgme_verify_result_t result;
|
||||||
gpgme_signature_t gpgsig;
|
gpgme_signature_t gpgsig;
|
||||||
FILE *pkgfile = NULL, *sigfile = NULL;
|
FILE *file = NULL, *sigfile = NULL;
|
||||||
|
|
||||||
ALPM_LOG_FUNC;
|
ALPM_LOG_FUNC;
|
||||||
|
|
||||||
if(!sig || !sig->rawdata) {
|
if(!sig || !sig->rawdata) {
|
||||||
RET_ERR(PM_ERR_SIG_UNKNOWN, -1);
|
RET_ERR(PM_ERR_SIG_UNKNOWN, -1);
|
||||||
}
|
}
|
||||||
if(!pkgpath || access(pkgpath, R_OK) != 0) {
|
if(!path || access(path, R_OK) != 0) {
|
||||||
RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
|
RET_ERR(PM_ERR_NOT_A_FILE, -1);
|
||||||
}
|
}
|
||||||
if(gpgme_init()) {
|
if(gpgme_init()) {
|
||||||
/* pm_errno was set in gpgme_init() */
|
/* pm_errno was set in gpgme_init() */
|
||||||
return -1;
|
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(&ctx, 0, sizeof(ctx));
|
||||||
memset(&sigdata, 0, sizeof(sigdata));
|
memset(&sigdata, 0, sizeof(sigdata));
|
||||||
memset(&pkgdata, 0, sizeof(pkgdata));
|
memset(&filedata, 0, sizeof(filedata));
|
||||||
|
|
||||||
err = gpgme_new(&ctx);
|
err = gpgme_new(&ctx);
|
||||||
CHECK_ERR();
|
CHECK_ERR();
|
||||||
|
|
||||||
/* create our necessary data objects to verify the signature */
|
/* create our necessary data objects to verify the signature */
|
||||||
/* first the package itself */
|
file = fopen(path, "rb");
|
||||||
pkgfile = fopen(pkgpath, "rb");
|
if(file == NULL) {
|
||||||
if(pkgfile == NULL) {
|
pm_errno = PM_ERR_NOT_A_FILE;
|
||||||
pm_errno = PM_ERR_PKG_OPEN;
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
err = gpgme_data_new_from_stream(&pkgdata, pkgfile);
|
err = gpgme_data_new_from_stream(&filedata, file);
|
||||||
CHECK_ERR();
|
CHECK_ERR();
|
||||||
|
|
||||||
/* next create data object for the signature */
|
/* next create data object for the signature */
|
||||||
@ -145,7 +144,7 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
|
|||||||
CHECK_ERR();
|
CHECK_ERR();
|
||||||
|
|
||||||
/* here's where the magic happens */
|
/* here's where the magic happens */
|
||||||
err = gpgme_op_verify(ctx, sigdata, pkgdata, NULL);
|
err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
|
||||||
CHECK_ERR();
|
CHECK_ERR();
|
||||||
result = gpgme_op_verify_result(ctx);
|
result = gpgme_op_verify_result(ctx);
|
||||||
gpgsig = result->signatures;
|
gpgsig = result->signatures;
|
||||||
@ -168,34 +167,34 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
|
|||||||
|
|
||||||
if(gpgsig->summary & GPGME_SIGSUM_VALID) {
|
if(gpgsig->summary & GPGME_SIGSUM_VALID) {
|
||||||
/* good signature, continue */
|
/* good signature, continue */
|
||||||
_alpm_log(PM_LOG_DEBUG, _("Package %s has a valid signature.\n"),
|
_alpm_log(PM_LOG_DEBUG, _("File %s has a valid signature.\n"),
|
||||||
pkgpath);
|
path);
|
||||||
} else if(gpgsig->summary & GPGME_SIGSUM_GREEN) {
|
} else if(gpgsig->summary & GPGME_SIGSUM_GREEN) {
|
||||||
/* 'green' signature, not sure what to do here */
|
/* 'green' signature, not sure what to do here */
|
||||||
_alpm_log(PM_LOG_WARNING, _("Package %s has a green signature.\n"),
|
_alpm_log(PM_LOG_WARNING, _("File %s has a green signature.\n"),
|
||||||
pkgpath);
|
path);
|
||||||
} else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) {
|
} else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) {
|
||||||
pm_errno = PM_ERR_SIG_UNKNOWN;
|
pm_errno = PM_ERR_SIG_UNKNOWN;
|
||||||
_alpm_log(PM_LOG_WARNING, _("Package %s has a signature from an unknown key.\n"),
|
_alpm_log(PM_LOG_WARNING, _("File %s has a signature from an unknown key.\n"),
|
||||||
pkgpath);
|
path);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
} else {
|
} else {
|
||||||
/* we'll capture everything else here */
|
/* we'll capture everything else here */
|
||||||
pm_errno = PM_ERR_SIG_INVALID;
|
pm_errno = PM_ERR_SIG_INVALID;
|
||||||
_alpm_log(PM_LOG_ERROR, _("Package %s has an invalid signature.\n"),
|
_alpm_log(PM_LOG_ERROR, _("File %s has an invalid signature.\n"),
|
||||||
pkgpath);
|
path);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
gpgme_data_release(sigdata);
|
gpgme_data_release(sigdata);
|
||||||
gpgme_data_release(pkgdata);
|
gpgme_data_release(filedata);
|
||||||
gpgme_release(ctx);
|
gpgme_release(ctx);
|
||||||
if(sigfile) {
|
if(sigfile) {
|
||||||
fclose(sigfile);
|
fclose(sigfile);
|
||||||
}
|
}
|
||||||
if(pkgfile) {
|
if(file) {
|
||||||
fclose(pkgfile);
|
fclose(file);
|
||||||
}
|
}
|
||||||
if(err != GPG_ERR_NO_ERROR) {
|
if(err != GPG_ERR_NO_ERROR) {
|
||||||
_alpm_log(PM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(err));
|
_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));
|
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: */
|
/* vim: set ts=2 sw=2 noet: */
|
||||||
|
@ -21,7 +21,17 @@
|
|||||||
|
|
||||||
#include "alpm.h"
|
#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 */
|
#endif /* _ALPM_SIGNING_H */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user