1
0
mirror of https://github.com/moparisthebest/pacman synced 2024-12-23 00:08:50 -05:00

Revamp signing checks

This ensures we are actually making correct use of the information gpgme
is returning to us. Marginal being allowed was obvious before, but
Unknown should deal with trust level, and not the presence or lack
thereof of a public key to validate the signature with.

Return status and validity information in two separate values so check
methods and the frontend can use them independently. For now, we treat
expired keys as valid, while expired signatures are invalid.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2011-07-22 10:48:13 -05:00
parent aecd0740cf
commit 66d9995711
3 changed files with 127 additions and 59 deletions

View File

@ -104,15 +104,26 @@ typedef enum _alpm_siglevel_t {
} alpm_siglevel_t; } alpm_siglevel_t;
/** /**
* PGP signature verification return codes * PGP signature verification status return codes
*/ */
typedef enum _alpm_sigstatus_t { typedef enum _alpm_sigstatus_t {
ALPM_SIGSTATUS_VALID = 0, ALPM_SIGSTATUS_VALID,
ALPM_SIGSTATUS_MARGINAL, ALPM_SIGSTATUS_KEY_EXPIRED,
ALPM_SIGSTATUS_UNKNOWN, ALPM_SIGSTATUS_SIG_EXPIRED,
ALPM_SIGSTATUS_BAD ALPM_SIGSTATUS_KEY_UNKNOWN,
ALPM_SIGSTATUS_INVALID
} alpm_sigstatus_t; } alpm_sigstatus_t;
/**
* PGP signature verification status return codes
*/
typedef enum _alpm_sigvalidity_t {
ALPM_SIGVALIDITY_FULL,
ALPM_SIGVALIDITY_MARGINAL,
ALPM_SIGVALIDITY_NEVER,
ALPM_SIGVALIDITY_UNKNOWN
} alpm_sigvalidity_t;
/* /*
* Structures * Structures
*/ */
@ -202,6 +213,7 @@ typedef struct _alpm_backup_t {
typedef struct _alpm_sigresult_t { typedef struct _alpm_sigresult_t {
int count; int count;
alpm_sigstatus_t *status; alpm_sigstatus_t *status;
alpm_sigvalidity_t *validity;
char **uid; char **uid;
} alpm_sigresult_t; } alpm_sigresult_t;

View File

@ -305,8 +305,9 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
_alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount); _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount);
result->status = calloc(sigcount, sizeof(alpm_sigstatus_t)); result->status = calloc(sigcount, sizeof(alpm_sigstatus_t));
result->validity = calloc(sigcount, sizeof(alpm_sigvalidity_t));
result->uid = calloc(sigcount, sizeof(char*)); result->uid = calloc(sigcount, sizeof(char*));
if(!result->status || !result->uid) { if(!result->status || !result->validity || !result->uid) {
handle->pm_errno = ALPM_ERR_MEMORY; handle->pm_errno = ALPM_ERR_MEMORY;
goto error; goto error;
} }
@ -316,6 +317,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
gpgsig = gpgsig->next, sigcount++) { gpgsig = gpgsig->next, sigcount++) {
alpm_list_t *summary_list, *summary; alpm_list_t *summary_list, *summary;
alpm_sigstatus_t status; alpm_sigstatus_t status;
alpm_sigvalidity_t validity;
gpgme_key_t key; gpgme_key_t key;
_alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr); _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr);
@ -335,6 +337,8 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
if(gpg_err_code(err) == GPG_ERR_EOF) { if(gpg_err_code(err) == GPG_ERR_EOF) {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n"); _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
err = GPG_ERR_NO_ERROR; err = GPG_ERR_NO_ERROR;
STRDUP(result->uid[sigcount], gpgsig->fpr,
handle->pm_errno = ALPM_ERR_MEMORY; goto error);
} else { } else {
CHECK_ERR(); CHECK_ERR();
if(key->uids) { if(key->uids) {
@ -346,34 +350,52 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
gpgme_key_unref(key); gpgme_key_unref(key);
} }
if(gpgsig->summary & GPGME_SIGSUM_VALID) { switch(gpg_err_code(gpgsig->status)) {
/* definite good signature */ /* good cases */
_alpm_log(handle, ALPM_LOG_DEBUG, "result: valid signature\n"); case GPG_ERR_NO_ERROR:
status = ALPM_SIGSTATUS_VALID; status = ALPM_SIGSTATUS_VALID;
} else if(gpgsig->summary & GPGME_SIGSUM_GREEN) { break;
/* good signature */ case GPG_ERR_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "result: green signature\n"); status = ALPM_SIGSTATUS_KEY_EXPIRED;
status = ALPM_SIGSTATUS_VALID; break;
} else if(gpgsig->summary & GPGME_SIGSUM_RED) { /* bad cases */
/* definite bad signature, error */ case GPG_ERR_SIG_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "result: red signature\n"); status = ALPM_SIGSTATUS_SIG_EXPIRED;
status = ALPM_SIGSTATUS_BAD; break;
} else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) { case GPG_ERR_NO_PUBKEY:
_alpm_log(handle, ALPM_LOG_DEBUG, "result: signature from unknown key\n"); status = ALPM_SIGSTATUS_KEY_UNKNOWN;
status = ALPM_SIGSTATUS_UNKNOWN; break;
} else if(gpgsig->summary & GPGME_SIGSUM_KEY_EXPIRED) { case GPG_ERR_BAD_SIGNATURE:
_alpm_log(handle, ALPM_LOG_DEBUG, "result: key expired\n"); default:
status = ALPM_SIGSTATUS_BAD; status = ALPM_SIGSTATUS_INVALID;
} else if(gpgsig->summary & GPGME_SIGSUM_SIG_EXPIRED) { break;
_alpm_log(handle, ALPM_LOG_DEBUG, "result: signature expired\n"); }
status = ALPM_SIGSTATUS_BAD;
if(status == ALPM_SIGSTATUS_VALID
|| status == ALPM_SIGSTATUS_KEY_EXPIRED) {
switch(gpgsig->validity) {
case GPGME_VALIDITY_ULTIMATE:
case GPGME_VALIDITY_FULL:
validity = ALPM_SIGVALIDITY_FULL;
break;
case GPGME_VALIDITY_MARGINAL:
validity = ALPM_SIGVALIDITY_MARGINAL;
break;
case GPGME_VALIDITY_NEVER:
validity = ALPM_SIGVALIDITY_NEVER;
break;
case GPGME_VALIDITY_UNKNOWN:
case GPGME_VALIDITY_UNDEFINED:
default:
validity = ALPM_SIGVALIDITY_UNKNOWN;
break;
}
} else { } else {
/* we'll capture everything else here */ validity = ALPM_SIGVALIDITY_NEVER;
_alpm_log(handle, ALPM_LOG_DEBUG, "result: invalid signature\n");
status = ALPM_SIGSTATUS_BAD;
} }
result->status[sigcount] = status; result->status[sigcount] = status;
result->validity[sigcount] = validity;
} }
ret = 0; ret = 0;
@ -429,31 +451,45 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
/* ret will already be -1 */ /* ret will already be -1 */
} else { } else {
int num; int num;
for(num = 0; num < result.count; num++) { for(num = 0; !ret && num < result.count; num++) {
/* fallthrough in this case block is on purpose. if one allows unknown
* signatures, then a marginal signature should be allowed as well, and
* if neither of these are allowed we fall all the way through to bad. */
switch(result.status[num]) { switch(result.status[num]) {
case ALPM_SIGSTATUS_VALID: case ALPM_SIGSTATUS_VALID:
case ALPM_SIGSTATUS_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n"); _alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n");
switch(result.validity[num]) {
case ALPM_SIGVALIDITY_FULL:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is fully trusted\n");
break;
case ALPM_SIGVALIDITY_MARGINAL:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is marginal trust\n");
if(!marginal) {
ret = -1;
}
break;
case ALPM_SIGVALIDITY_UNKNOWN:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is unknown trust\n");
if(!unknown) {
ret = -1;
}
break;
case ALPM_SIGVALIDITY_NEVER:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature should never be trusted\n");
ret = -1;
break;
}
break; break;
case ALPM_SIGSTATUS_MARGINAL: case ALPM_SIGSTATUS_SIG_EXPIRED:
if(marginal) { case ALPM_SIGSTATUS_KEY_UNKNOWN:
_alpm_log(handle, ALPM_LOG_DEBUG, "allowing marginal signature\n"); case ALPM_SIGSTATUS_INVALID:
break; _alpm_log(handle, ALPM_LOG_DEBUG, "signature is not valid\n");
}
case ALPM_SIGSTATUS_UNKNOWN:
if(unknown) {
_alpm_log(handle, ALPM_LOG_DEBUG, "allowing unknown signature\n");
break;
}
case ALPM_SIGSTATUS_BAD:
default:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is invalid\n");
handle->pm_errno = invalid_err;
ret = -1; ret = -1;
break;
} }
} }
if(ret) {
handle->pm_errno = invalid_err;
}
} }
alpm_sigresult_cleanup(&result); alpm_sigresult_cleanup(&result);

View File

@ -678,7 +678,7 @@ void signature_display(const char *title, alpm_sigresult_t *result)
int i; int i;
for(i = 0; i < result->count; i++) { for(i = 0; i < result->count; i++) {
char sigline[PATH_MAX]; char sigline[PATH_MAX];
const char *validity, *name; const char *status, *validity, *name;
/* Don't re-indent the first result */ /* Don't re-indent the first result */
if(i != 0) { if(i != 0) {
int j; int j;
@ -688,22 +688,42 @@ void signature_display(const char *title, alpm_sigresult_t *result)
} }
switch(result->status[i]) { switch(result->status[i]) {
case ALPM_SIGSTATUS_VALID: case ALPM_SIGSTATUS_VALID:
validity = _("Valid signature"); status = _("Valid");
break; break;
case ALPM_SIGSTATUS_MARGINAL: case ALPM_SIGSTATUS_KEY_EXPIRED:
validity = _("Marginal signature"); status = _("Key expired");
break; break;
case ALPM_SIGSTATUS_UNKNOWN: case ALPM_SIGSTATUS_SIG_EXPIRED:
validity = _("Unknown signature"); status = _("Expired");
break; break;
case ALPM_SIGSTATUS_BAD: case ALPM_SIGSTATUS_INVALID:
validity = _("Invalid signature"); status = _("Invalid");
break;
case ALPM_SIGSTATUS_KEY_UNKNOWN:
status = _("Key unknown");
break; break;
default: default:
validity = _("Signature error"); status = _("Signature error");
break;
} }
name = result->uid[i] ? result->uid[i] : _("<Key Unknown>"); switch(result->validity[i]) {
snprintf(sigline, PATH_MAX, _("%s from \"%s\""), validity, name); case ALPM_SIGVALIDITY_FULL:
validity = _("fully trusted");
break;
case ALPM_SIGVALIDITY_MARGINAL:
validity = _("marginal trusted");
break;
case ALPM_SIGVALIDITY_NEVER:
validity = _("never trusted");
break;
case ALPM_SIGVALIDITY_UNKNOWN:
default:
validity = _("unknown trust");
break;
}
name = result->uid[i] ? result->uid[i] : _("{Key Unknown}");
snprintf(sigline, PATH_MAX, _("%s, %s from \"%s\""),
status, validity, name);
indentprint(sigline, len); indentprint(sigline, len);
printf("\n"); printf("\n");
} }