signing: move key import confirmation before key_search

Ask the user whether they want to import a missing key before even doing
a search on the keyserver. This will be useful for getting Web Key
Directory support in place: for a WKD, looking up and importing a key
are a single action, so the current key_search -> QUESTION -> key_import
workflow does not apply.

Since only the ID of the package signing key is available before
key_search, we display the packager variable in addition to the key ID
for user convenience.

Signed-off-by: Jonas Witschel <diabonas@archlinux.org>
Signed-off-by: Allan McRae <allan@archlinux.org>
This commit is contained in:
Jonas Witschel 2019-10-02 16:40:54 +02:00 committed by Allan McRae
parent 0c4a8ae24b
commit 80e2e1c7c9
5 changed files with 61 additions and 40 deletions

View file

@ -731,6 +731,8 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
{ {
int validation = 0; int validation = 0;
char *sigpath; char *sigpath;
alpm_pkg_t *pkg_temp;
char *packager;
CHECK_HANDLE(handle, return -1); CHECK_HANDLE(handle, return -1);
ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
@ -755,9 +757,17 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
for(k = keys; k; k = k->next) { for(k = keys; k; k = k->next) {
char *key = k->data; char *key = k->data;
if(_alpm_key_in_keychain(handle, key) == 0) { if(_alpm_key_in_keychain(handle, key) == 0) {
if(_alpm_key_import(handle, key) == -1) { pkg_temp = _alpm_pkg_load_internal(handle, filename, full);
if(pkg_temp) {
packager = pkg_temp->packager;
_alpm_pkg_free(pkg_temp);
} else {
packager = NULL;
}
if(_alpm_key_import(handle, packager, key) == -1) {
fail = 1; fail = 1;
} }
free(packager);
} }
} }
FREELIST(keys); FREELIST(keys);

View file

@ -433,42 +433,45 @@ gpg_error:
/** /**
* Import a key defined by a fingerprint into the local keyring. * Import a key defined by a fingerprint into the local keyring.
* @param handle the context handle * @param handle the context handle
* @param uid a user ID of the key to import
* @param fpr the fingerprint key ID to import * @param fpr the fingerprint key ID to import
* @return 0 on success, -1 on error * @return 0 on success, -1 on error
*/ */
int _alpm_key_import(alpm_handle_t *handle, const char *fpr) int _alpm_key_import(alpm_handle_t *handle, const char *uid, const char *fpr)
{ {
int ret = -1; int ret = -1;
alpm_pgpkey_t fetch_key; alpm_pgpkey_t fetch_key;
memset(&fetch_key, 0, sizeof(fetch_key));
if(key_search(handle, fpr, &fetch_key) == 1) { if(_alpm_access(handle, handle->gpgdir, "pubring.gpg", W_OK)) {
_alpm_log(handle, ALPM_LOG_DEBUG, /* no chance of import succeeding if pubring isn't writable */
"unknown key, found %s on keyserver\n", fetch_key.uid); _alpm_log(handle, ALPM_LOG_ERROR, _("keyring is not writable\n"));
if(!_alpm_access(handle, handle->gpgdir, "pubring.gpg", W_OK)) { return -1;
alpm_question_import_key_t question = { }
memset(&fetch_key, 0, sizeof(fetch_key));
STRDUP(fetch_key.uid, uid, return -1);
STRDUP(fetch_key.fingerprint, fpr, return -1);
alpm_question_import_key_t question = {
.type = ALPM_QUESTION_IMPORT_KEY, .type = ALPM_QUESTION_IMPORT_KEY,
.import = 0, .import = 0,
.key = &fetch_key .key = &fetch_key
}; };
QUESTION(handle, &question); QUESTION(handle, &question);
if(question.import) { if(question.import) {
if(key_import(handle, &fetch_key) == 0) { if(key_search(handle, fpr, &fetch_key) == 1) {
ret = 0; _alpm_log(handle, ALPM_LOG_DEBUG,
} else { _("key \"%s\" on keyserver\n"), fetch_key.uid);
_alpm_log(handle, ALPM_LOG_ERROR, if(key_import(handle, &fetch_key) == 0) {
_("key \"%s\" could not be imported\n"), fetch_key.uid); ret = 0;
} } else {
_alpm_log(handle, ALPM_LOG_ERROR,
_("key \"%s\" could not be imported\n"), fetch_key.uid);
} }
} else { } else {
/* keyring directory was not writable, so we don't even try */ _alpm_log(handle, ALPM_LOG_ERROR,
_alpm_log(handle, ALPM_LOG_WARNING, _("key \"%s\" could not be looked up remotely\n"), fpr);
_("key %s, \"%s\" found on keyserver, keyring is not writable\n"),
fetch_key.fingerprint, fetch_key.uid);
} }
} else {
_alpm_log(handle, ALPM_LOG_ERROR,
_("key \"%s\" could not be looked up remotely\n"), fpr);
} }
gpgme_key_unref(fetch_key.data); gpgme_key_unref(fetch_key.data);
@ -714,7 +717,8 @@ int _alpm_key_in_keychain(alpm_handle_t UNUSED *handle, const char UNUSED *fpr)
return -1; return -1;
} }
int _alpm_key_import(alpm_handle_t UNUSED *handle, const char UNUSED *fpr) int _alpm_key_import(alpm_handle_t UNUSED *handle, const char UNUSED *uid,
const char UNUSED *fpr)
{ {
return -1; return -1;
} }
@ -900,7 +904,7 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
_alpm_log(handle, ALPM_LOG_ERROR, _alpm_log(handle, ALPM_LOG_ERROR,
_("%s: key \"%s\" is unknown\n"), identifier, name); _("%s: key \"%s\" is unknown\n"), identifier, name);
if(_alpm_key_import(handle, result->key.fingerprint) == 0) { if(_alpm_key_import(handle, result->key.uid, result->key.fingerprint) == 0) {
retry = 1; retry = 1;
} }

View file

@ -32,6 +32,6 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
alpm_siglist_t *siglist, int optional, int marginal, int unknown); alpm_siglist_t *siglist, int optional, int marginal, int unknown);
int _alpm_key_in_keychain(alpm_handle_t *handle, const char *fpr); int _alpm_key_in_keychain(alpm_handle_t *handle, const char *fpr);
int _alpm_key_import(alpm_handle_t *handle, const char *fpr); int _alpm_key_import(alpm_handle_t *handle, const char *uid, const char *fpr);
#endif /* ALPM_SIGNING_H */ #endif /* ALPM_SIGNING_H */

View file

@ -47,6 +47,12 @@
#include "diskspace.h" #include "diskspace.h"
#include "signing.h" #include "signing.h"
struct keyinfo_t {
char* uid;
char* keyid;
};
/** Check for new version of pkg in sync repos /** Check for new version of pkg in sync repos
* (only the first occurrence is considered in sync) * (only the first occurrence is considered in sync)
*/ */
@ -872,6 +878,7 @@ static int check_keyring(alpm_handle_t *handle)
size_t current = 0, numtargs; size_t current = 0, numtargs;
alpm_list_t *i, *errors = NULL; alpm_list_t *i, *errors = NULL;
alpm_event_t event; alpm_event_t event;
struct keyinfo_t *keyinfo;
event.type = ALPM_EVENT_KEYRING_START; event.type = ALPM_EVENT_KEYRING_START;
EVENT(handle, &event); EVENT(handle, &event);
@ -905,7 +912,13 @@ static int check_keyring(alpm_handle_t *handle)
char *key = k->data; char *key = k->data;
if(!alpm_list_find_str(errors, key) && if(!alpm_list_find_str(errors, key) &&
_alpm_key_in_keychain(handle, key) == 0) { _alpm_key_in_keychain(handle, key) == 0) {
errors = alpm_list_add(errors, strdup(key)); keyinfo = malloc(sizeof(struct keyinfo_t));
if(!keyinfo) {
break;
}
keyinfo->uid = strdup(pkg->packager);
keyinfo->keyid = strdup(key);
errors = alpm_list_add(errors, keyinfo);
} }
} }
FREELIST(keys); FREELIST(keys);
@ -926,10 +939,13 @@ static int check_keyring(alpm_handle_t *handle)
int fail = 0; int fail = 0;
alpm_list_t *k; alpm_list_t *k;
for(k = errors; k; k = k->next) { for(k = errors; k; k = k->next) {
char *key = k->data; keyinfo = k->data;
if(_alpm_key_import(handle, key) == -1) { if(_alpm_key_import(handle, keyinfo->uid, keyinfo->keyid) == -1) {
fail = 1; fail = 1;
} }
free(keyinfo->uid);
free(keyinfo->keyid);
} }
event.type = ALPM_EVENT_KEY_DOWNLOAD_DONE; event.type = ALPM_EVENT_KEY_DOWNLOAD_DONE;
EVENT(handle, &event); EVENT(handle, &event);

View file

@ -456,17 +456,8 @@ void cb_question(alpm_question_t *question)
case ALPM_QUESTION_IMPORT_KEY: case ALPM_QUESTION_IMPORT_KEY:
{ {
alpm_question_import_key_t *q = &question->import_key; alpm_question_import_key_t *q = &question->import_key;
char created[12]; q->import = yesno(_("Import PGP key %s, \"%s\"?"),
time_t time = (time_t)q->key->created; q->key->fingerprint, q->key->uid);
strftime(created, 12, "%Y-%m-%d", localtime(&time));
if(q->key->revoked) {
q->import = yesno(_("Import PGP key %u%c/%s, \"%s\", created: %s (revoked)?"),
q->key->length, q->key->pubkey_algo, q->key->fingerprint, q->key->uid, created);
} else {
q->import = yesno(_("Import PGP key %u%c/%s, \"%s\", created: %s?"),
q->key->length, q->key->pubkey_algo, q->key->fingerprint, q->key->uid, created);
}
} }
break; break;
} }