Compare commits

...

5 commits

Author SHA1 Message Date
morganamilo
c7cb6e486b
libalpm: fix importing keys from keyserver
commit 95a7d416ce broke
key_search_keyserver() by removing the `ret = 1` at the end of the
function, causing the caller to allways think the funciton failed even
when it did not. Due to WKD being the primary method to import keys this
was unnoticed.
2025-08-01 09:42:02 +01:00
morganamilo
a0be6f0829
libalpm: reimport expired keys
If the user does not update for a while some of the keys in the keyring
may expire. Pacman does not import new versions of these keys because
they are already in the keying. This leads to users needing to first
update archlinux-keyring to get the new keys.
2025-08-01 09:41:59 +01:00
morganamilo
fff9296478
libalpm: improve error message for expired keys (cont)
Continuation of last commit.

Changes:

error: failed to commit transaction (invalid or corrupted package (PGP signature))

To:

error: failed to commit transaction (package signature has missing or invalid PGP key)
2025-08-01 09:41:56 +01:00
morganamilo
f42b93dd7f
libalpm: improve error message for expired keys
If the user does not update their system for a while some of the package
keys may expire. Pacman gives this message:

error: simdjson: signature from "Bert Peters (packager key)
<bertptrs@archlinux.org>" is unknown trust

While this is technically true it masks the real issue of the key being
expired.

This commit changes that error message to:

error: simdjson: key  "Bert Peters (packager key) <bertptrs@archlinux.org>" (38100C24376CD5F6ED4FF4B46918400C2703040C)
2025-08-01 06:15:06 +01:00
morganamilo
beb6bd80cd
libalpm: set errno when key is missing from keyring
There was no fitting error type for this so add ALPM_ERR_KEY_MISSING.
2025-08-01 04:09:26 +01:00
7 changed files with 64 additions and 17 deletions

View file

@ -242,6 +242,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_DB_INVALID,
/** Database has an invalid signature */
ALPM_ERR_DB_INVALID_SIG,
/** Database is signed by an invalid key */
ALPM_ERR_DB_INVALID_KEY,
/** The localdb is in a newer/older format than libalpm expects */
ALPM_ERR_DB_VERSION,
/** Failed to write to the database */
@ -285,6 +287,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_PKG_INVALID_CHECKSUM,
/** Package has an invalid signature */
ALPM_ERR_PKG_INVALID_SIG,
/** Package is signed by an invalid key */
ALPM_ERR_PKG_INVALID_KEY,
/** Package does not have a signature */
ALPM_ERR_PKG_MISSING_SIG,
/** Cannot open the package file */
@ -300,6 +304,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_SIG_MISSING,
/** Signatures are invalid */
ALPM_ERR_SIG_INVALID,
/** Keys are missing from keyring */
ALPM_ERR_KEY_MISSING,
/* Dependencies */
/** Dependencies could not be satisfied */
ALPM_ERR_UNSATISFIED_DEPS,

View file

@ -341,15 +341,17 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,
/* even if we don't have a sig, run the check code if level tells us to */
if(level & ALPM_SIG_PACKAGE) {
const char *sig = syncpkg ? syncpkg->base64_sig : NULL;
int ret;
_alpm_log(handle, ALPM_LOG_DEBUG, "sig data: %s\n", sig ? sig : "<from .sig>");
if(!has_sig && !(level & ALPM_SIG_PACKAGE_OPTIONAL)) {
handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG;
return -1;
}
if(_alpm_check_pgp_helper(handle, pkgfile, sig,
ret = _alpm_check_pgp_helper(handle, pkgfile, sig,
level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK,
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) {
handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG;
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata);
if(ret) {
handle->pm_errno = ret == -1 ? ALPM_ERR_PKG_INVALID_SIG : ALPM_ERR_PKG_INVALID_KEY;
return -1;
}
if(validation && has_sig) {
@ -766,6 +768,7 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
if(fail) {
_alpm_log(handle, ALPM_LOG_ERROR, _("required key missing from keyring\n"));
handle->pm_errno = ALPM_ERR_KEY_MISSING;
free(sigpath);
return -1;
}

View file

@ -126,6 +126,7 @@ static int sync_db_validate(alpm_db_t *db)
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
db->handle->pm_errno = ret == -1 ? ALPM_ERR_PKG_INVALID_SIG : ALPM_ERR_PKG_INVALID_KEY;
return 1;
}
}

View file

@ -72,6 +72,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("invalid or corrupted database");
case ALPM_ERR_DB_INVALID_SIG:
return _("invalid or corrupted database (PGP signature)");
case ALPM_ERR_DB_INVALID_KEY:
return _("database signature has missing or invalid PGP key");
case ALPM_ERR_DB_VERSION:
return _("database is incorrect version");
case ALPM_ERR_DB_WRITE:
@ -115,6 +117,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("invalid or corrupted package (checksum)");
case ALPM_ERR_PKG_INVALID_SIG:
return _("invalid or corrupted package (PGP signature)");
case ALPM_ERR_PKG_INVALID_KEY:
return _("package signature has missing or invalid PGP key");
case ALPM_ERR_PKG_MISSING_SIG:
return _("package missing required signature");
case ALPM_ERR_PKG_OPEN:
@ -130,6 +134,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("missing PGP signature");
case ALPM_ERR_SIG_INVALID:
return _("invalid PGP signature");
case ALPM_ERR_KEY_MISSING:
return _("PGP key missing from keyring");
/* Dependencies */
case ALPM_ERR_UNSATISFIED_DEPS:
return _("could not satisfy dependencies");

View file

@ -233,9 +233,14 @@ int _alpm_key_in_keychain(alpm_handle_t *handle, const char *fpr)
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
ret = 0;
} else if(gpg_err_code(gpg_err) == GPG_ERR_NO_ERROR) {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, key exists\n");
handle->known_keys = alpm_list_add(handle->known_keys, strdup(fpr));
ret = 1;
if(key->expired) {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, but key is expired\n");
ret = 0;
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, key exists\n");
handle->known_keys = alpm_list_add(handle->known_keys, strdup(fpr));
ret = 1;
}
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(gpg_err));
}
@ -268,7 +273,7 @@ static int key_import_wkd(alpm_handle_t *handle, const char *email, const char *
CHECK_ERR();
mode = gpgme_get_keylist_mode(ctx);
mode |= GPGME_KEYLIST_MODE_LOCATE;
mode |= GPGME_KEYLIST_MODE_LOCATE_EXTERNAL;
gpg_err = gpgme_set_keylist_mode(ctx, mode);
CHECK_ERR();
@ -279,7 +284,7 @@ static int key_import_wkd(alpm_handle_t *handle, const char *email, const char *
if(fpr && _alpm_key_in_keychain(handle, fpr)) {
ret = 0;
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed: WKD imported wrong fingerprint\n");
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed: WKD imported wrong fingerprint or key expired\n");
}
}
gpgme_key_unref(key);
@ -371,6 +376,7 @@ static int key_search_keyserver(alpm_handle_t *handle, const char *fpr,
pgpkey->expires = key->subkeys->expires;
pgpkey->length = key->subkeys->length;
pgpkey->revoked = key->subkeys->revoked;
ret = 1;
gpg_error:
if(ret != 1) {
@ -792,7 +798,7 @@ char *_alpm_sigpath(alpm_handle_t *handle, const char *path)
* @param marginal whether signatures with marginal trust are acceptable
* @param unknown whether signatures with unknown trust are acceptable
* @param sigdata a pointer to storage for signature results
* @return 0 on success, -1 on error (consult pm_errno or sigdata)
* @return 0 on success, -1 on error, -2 on key error (consult pm_errno or sigdata)
*/
int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
const char *base64_sig, int optional, int marginal, int unknown,
@ -800,6 +806,7 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
{
alpm_siglist_t *siglist;
int ret;
int key_invalid = 0;
CALLOC(siglist, 1, sizeof(alpm_siglist_t),
RET_ERR(handle, ALPM_ERR_MEMORY, -1));
@ -821,8 +828,11 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
size_t num;
for(num = 0; !ret && num < siglist->count; num++) {
switch(siglist->results[num].status) {
case ALPM_SIGSTATUS_VALID:
case ALPM_SIGSTATUS_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "key is expired\n");
key_invalid = 1;
__attribute__((fallthrough));
case ALPM_SIGSTATUS_VALID:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n");
switch(siglist->results[num].validity) {
case ALPM_SIGVALIDITY_FULL:
@ -846,9 +856,12 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
break;
}
break;
case ALPM_SIGSTATUS_SIG_EXPIRED:
case ALPM_SIGSTATUS_KEY_UNKNOWN:
case ALPM_SIGSTATUS_KEY_DISABLED:
case ALPM_SIGSTATUS_SIG_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "key is not valid\n");
key_invalid = 1;
__attribute__((fallthrough));
case ALPM_SIGSTATUS_INVALID:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is not valid\n");
ret = -1;
@ -864,7 +877,7 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
free(siglist);
}
return ret;
return key_invalid ? -2 : ret;
}
/**
@ -897,7 +910,6 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
const char *name = result->key.uid ? result->key.uid : result->key.fingerprint;
switch(result->status) {
case ALPM_SIGSTATUS_VALID:
case ALPM_SIGSTATUS_KEY_EXPIRED:
switch(result->validity) {
case ALPM_SIGVALIDITY_FULL:
break;
@ -923,6 +935,16 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
identifier, name);
break;
}
break;
case ALPM_SIGSTATUS_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_ERROR,
_("%s: key \"%s\" (%s) is expired\n"),
identifier, name, result->key.fingerprint);
if(_alpm_key_import(handle, result->key.uid, result->key.fingerprint) == 0) {
retry = 1;
}
break;
case ALPM_SIGSTATUS_KEY_UNKNOWN:
/* ensure this key is still actually unknown; we may have imported it

View file

@ -975,6 +975,7 @@ static int check_keyring(alpm_handle_t *handle)
EVENT(handle, &event);
if(fail) {
_alpm_log(handle, ALPM_LOG_ERROR, _("required key missing from keyring\n"));
handle->pm_errno = ALPM_ERR_KEY_MISSING;
return -1;
}
}
@ -1053,6 +1054,7 @@ static int check_validity(alpm_handle_t *handle,
_("%s: missing required signature\n"), v->pkg->name);
break;
case ALPM_ERR_PKG_INVALID_SIG:
case ALPM_ERR_PKG_INVALID_KEY:
_alpm_process_siglist(handle, v->pkg->name, v->siglist,
v->siglevel & ALPM_SIG_PACKAGE_OPTIONAL,
v->siglevel & ALPM_SIG_PACKAGE_MARGINAL_OK,

View file

@ -529,10 +529,17 @@ void cb_question(void *ctx, alpm_question_t *question)
case ALPM_QUESTION_CORRUPTED_PKG:
{
alpm_question_corrupted_t *q = &question->corrupted;
q->remove = yesno(_("File %s is corrupted (%s).\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
if(q->reason == ALPM_ERR_PKG_INVALID_KEY || q->reason == ALPM_ERR_DB_INVALID_KEY) {
q->remove = yesno(_("Can't get PGP key for file %s (%s)\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
} else {
q->remove = yesno(_("File %s is corrupted (%s).\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
}
}
break;
case ALPM_QUESTION_IMPORT_KEY: