4 * Copyright (c) 2008-2012 Pacman Development Team <pacman-dev@archlinux.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include <locale.h> /* setlocale() */
39 #define CHECK_ERR(void) do { \
40 if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { goto error; } \
44 * Return a statically allocated validity string based on the GPGME validity
45 * code. This is mainly for debug purposes and is not translated.
46 * @param validity a validity code returned by GPGME
47 * @return a string such as "marginal"
49 static const char *string_validity(gpgme_validity_t validity
)
52 case GPGME_VALIDITY_UNKNOWN
:
54 case GPGME_VALIDITY_UNDEFINED
:
56 case GPGME_VALIDITY_NEVER
:
58 case GPGME_VALIDITY_MARGINAL
:
60 case GPGME_VALIDITY_FULL
:
62 case GPGME_VALIDITY_ULTIMATE
:
68 static void sigsum_test_bit(gpgme_sigsum_t sigsum
, alpm_list_t
**summary
,
69 gpgme_sigsum_t bit
, const char *value
)
72 *summary
= alpm_list_add(*summary
, (void *)value
);
77 * Calculate a set of strings to represent the given GPGME signature summary
78 * value. This is a bitmask so you may get any number of strings back.
79 * @param sigsum a GPGME signature summary bitmask
80 * @return the list of signature summary strings
82 static alpm_list_t
*list_sigsum(gpgme_sigsum_t sigsum
)
84 alpm_list_t
*summary
= NULL
;
85 /* The docs say this can be a bitmask...not sure I believe it, but we'll code
86 * for it anyway and show all possible flags in the returned string. */
88 /* The signature is fully valid. */
89 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_VALID
, "valid");
90 /* The signature is good. */
91 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_GREEN
, "green");
92 /* The signature is bad. */
93 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_RED
, "red");
94 /* One key has been revoked. */
95 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_REVOKED
, "key revoked");
96 /* One key has expired. */
97 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_EXPIRED
, "key expired");
98 /* The signature has expired. */
99 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SIG_EXPIRED
, "sig expired");
100 /* Can't verify: key missing. */
101 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_MISSING
, "key missing");
102 /* CRL not available. */
103 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_MISSING
, "crl missing");
104 /* Available CRL is too old. */
105 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_TOO_OLD
, "crl too old");
106 /* A policy was not met. */
107 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_BAD_POLICY
, "bad policy");
108 /* A system error occured. */
109 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SYS_ERROR
, "sys error");
112 summary
= alpm_list_add(summary
, (void *)"(empty)");
118 * Initialize the GPGME library.
119 * This can be safely called multiple times; however it is not thread-safe.
120 * @param handle the context handle
121 * @return 0 on success, -1 on error
123 static int init_gpgme(alpm_handle_t
*handle
)
126 const char *version
, *sigdir
;
128 gpgme_engine_info_t enginfo
;
131 /* we already successfully initialized the library */
135 sigdir
= handle
->gpgdir
;
137 if(_alpm_access(handle
, sigdir
, "pubring.gpg", R_OK
)
138 || _alpm_access(handle
, sigdir
, "trustdb.gpg", R_OK
)) {
139 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
140 _alpm_log(handle
, ALPM_LOG_DEBUG
, "Signature verification will fail!\n");
141 _alpm_log(handle
, ALPM_LOG_WARNING
,
142 _("Public keyring not found; have you run '%s'?\n"),
143 "pacman-key --init");
146 /* calling gpgme_check_version() returns the current version and runs
147 * some internal library setup code */
148 version
= gpgme_check_version(NULL
);
149 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME version: %s\n", version
);
150 gpgme_set_locale(NULL
, LC_CTYPE
, setlocale(LC_CTYPE
, NULL
));
152 gpgme_set_locale(NULL
, LC_MESSAGES
, setlocale(LC_MESSAGES
, NULL
));
155 * The GPGME library installs a SIGPIPE signal handler automatically if
156 * the default signal hander is in use. The only time we set a handler
157 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
158 * we do this, we can let GPGME do its automagic. However, if we install
159 * a library-wide SIGPIPE handler, we will have to be careful.
162 /* check for OpenPGP support (should be a no-brainer, but be safe) */
163 err
= gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP
);
166 /* set and check engine information */
167 err
= gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP
, NULL
, sigdir
);
169 err
= gpgme_get_engine_info(&enginfo
);
171 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME engine info: file=%s, home=%s\n",
172 enginfo
->file_name
, enginfo
->home_dir
);
178 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
179 RET_ERR(handle
, ALPM_ERR_GPGME
, -1);
183 * Determine if we have a key is known in our local keyring.
184 * @param handle the context handle
185 * @param fpr the fingerprint key ID to look up
186 * @return 1 if key is known, 0 if key is unknown, -1 on error
188 static int key_in_keychain(alpm_handle_t
*handle
, const char *fpr
)
195 memset(&ctx
, 0, sizeof(ctx
));
196 err
= gpgme_new(&ctx
);
199 _alpm_log(handle
, ALPM_LOG_DEBUG
, "looking up key %s locally\n", fpr
);
201 err
= gpgme_get_key(ctx
, fpr
, &key
, 0);
202 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
203 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
205 } else if(gpg_err_code(err
) == GPG_ERR_NO_ERROR
) {
206 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup success, key exists\n");
209 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
211 gpgme_key_unref(key
);
219 * Search for a GPG key in a remote location.
220 * This requires GPGME to call the gpg binary and have a keyserver previously
221 * defined in a gpg.conf configuration file.
222 * @param handle the context handle
223 * @param fpr the fingerprint key ID to look up
224 * @param pgpkey storage location for the given key if found
225 * @return 1 on success, 0 on key not found, -1 on error
227 static int key_search(alpm_handle_t
*handle
, const char *fpr
,
228 alpm_pgpkey_t
*pgpkey
)
232 gpgme_keylist_mode_t mode
;
238 /* gpg2 goes full retard here. For key searches ONLY, we need to prefix the
239 * key fingerprint with 0x, or the lookup will fail. */
240 fpr_len
= strlen(fpr
);
241 MALLOC(full_fpr
, fpr_len
+ 3, RET_ERR(handle
, ALPM_ERR_MEMORY
, -1));
242 sprintf(full_fpr
, "0x%s", fpr
);
244 memset(&ctx
, 0, sizeof(ctx
));
245 err
= gpgme_new(&ctx
);
248 mode
= gpgme_get_keylist_mode(ctx
);
249 /* using LOCAL and EXTERN together doesn't work for GPG 1.X. Ugh. */
250 mode
&= ~GPGME_KEYLIST_MODE_LOCAL
;
251 mode
|= GPGME_KEYLIST_MODE_EXTERN
;
252 err
= gpgme_set_keylist_mode(ctx
, mode
);
255 _alpm_log(handle
, ALPM_LOG_DEBUG
, "looking up key %s remotely\n", fpr
);
257 err
= gpgme_get_key(ctx
, full_fpr
, &key
, 0);
258 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
259 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
260 /* Try an alternate lookup using the 8 character fingerprint value, since
261 * busted-ass keyservers can't support lookups using subkeys with the full
262 * value as of now. This is why 2012 is not the year of PGP encryption. */
264 const char *short_fpr
= memcpy(&full_fpr
[fpr_len
- 8], "0x", 2);
265 _alpm_log(handle
, ALPM_LOG_DEBUG
,
266 "looking up key %s remotely\n", short_fpr
);
267 err
= gpgme_get_key(ctx
, short_fpr
, &key
, 0);
268 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
269 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
277 if(gpg_err_code(err
) != GPG_ERR_NO_ERROR
) {
281 /* should only get here if key actually exists */
283 if(key
->subkeys
->fpr
) {
284 pgpkey
->fingerprint
= key
->subkeys
->fpr
;
285 } else if(key
->subkeys
->keyid
) {
286 pgpkey
->fingerprint
= key
->subkeys
->keyid
;
288 pgpkey
->uid
= key
->uids
->uid
;
289 pgpkey
->name
= key
->uids
->name
;
290 pgpkey
->email
= key
->uids
->email
;
291 pgpkey
->created
= key
->subkeys
->timestamp
;
292 pgpkey
->expires
= key
->subkeys
->expires
;
293 pgpkey
->length
= key
->subkeys
->length
;
294 pgpkey
->revoked
= key
->subkeys
->revoked
;
296 switch (key
->subkeys
->pubkey_algo
) {
300 pgpkey
->pubkey_algo
= 'R';
304 pgpkey
->pubkey_algo
= 'D';
311 pgpkey
->pubkey_algo
= 'E';
319 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
327 * Import a key into the local keyring.
328 * @param handle the context handle
329 * @param key the key to import, likely retrieved from #key_search
330 * @return 0 on success, -1 on error
332 static int key_import(alpm_handle_t
*handle
, alpm_pgpkey_t
*key
)
337 gpgme_import_result_t result
;
340 if(_alpm_access(handle
, handle
->gpgdir
, "pubring.gpg", W_OK
)) {
341 /* no chance of import succeeding if pubring isn't writable */
342 _alpm_log(handle
, ALPM_LOG_ERROR
, _("keyring is not writable\n"));
346 memset(&ctx
, 0, sizeof(ctx
));
347 err
= gpgme_new(&ctx
);
350 _alpm_log(handle
, ALPM_LOG_DEBUG
, "importing key\n");
354 err
= gpgme_op_import_keys(ctx
, keys
);
356 result
= gpgme_op_import_result(ctx
);
358 /* we know we tried to import exactly one key, so check for this */
359 if(result
->considered
!= 1 || !result
->imports
) {
360 _alpm_log(handle
, ALPM_LOG_DEBUG
, "could not import key, 0 results\n");
362 } else if(result
->imports
->result
!= GPG_ERR_NO_ERROR
) {
363 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
375 * Decode a loaded signature in base64 form.
376 * @param base64_data the signature to attempt to decode
377 * @param data the decoded data; must be freed by the caller
378 * @param data_len the length of the returned data
379 * @return 0 on success, -1 on failure to properly decode
381 static int decode_signature(const char *base64_data
,
382 unsigned char **data
, size_t *data_len
) {
383 size_t len
= strlen(base64_data
);
384 unsigned char *usline
= (unsigned char *)base64_data
;
385 /* reasonable allocation of expected length is 3/4 of encoded length */
386 size_t destlen
= len
* 3 / 4;
387 MALLOC(*data
, destlen
, goto error
);
388 if(base64_decode(*data
, &destlen
, usline
, len
)) {
402 * Check the PGP signature for the given file path.
403 * If base64_sig is provided, it will be used as the signature data after
404 * decoding. If base64_sig is NULL, expect a signature file next to path
407 * The return value will be 0 if nothing abnormal happened during the signature
408 * check, and -1 if an error occurred while checking signatures or if a
409 * signature could not be found; pm_errno will be set. Note that "abnormal"
410 * does not include a failed signature; the value in siglist should be checked
411 * to determine if the signature(s) are good.
412 * @param handle the context handle
413 * @param path the full path to a file
414 * @param base64_sig optional PGP signature data in base64 encoding
415 * @param siglist a pointer to storage for signature results
416 * @return 0 in normal cases, -1 if the something failed in the check process
418 int _alpm_gpgme_checksig(alpm_handle_t
*handle
, const char *path
,
419 const char *base64_sig
, alpm_siglist_t
*siglist
)
421 int ret
= -1, sigcount
;
422 gpgme_error_t err
= 0;
424 gpgme_data_t filedata
, sigdata
;
425 gpgme_verify_result_t verify_result
;
426 gpgme_signature_t gpgsig
;
427 char *sigpath
= NULL
;
428 unsigned char *decoded_sigdata
= NULL
;
429 FILE *file
= NULL
, *sigfile
= NULL
;
431 if(!path
|| _alpm_access(handle
, NULL
, path
, R_OK
) != 0) {
432 RET_ERR(handle
, ALPM_ERR_NOT_A_FILE
, -1);
436 RET_ERR(handle
, ALPM_ERR_WRONG_ARGS
, -1);
441 sigpath
= _alpm_sigpath(handle
, path
);
442 if(_alpm_access(handle
, NULL
, sigpath
, R_OK
) != 0
443 || (sigfile
= fopen(sigpath
, "rb")) == NULL
) {
444 _alpm_log(handle
, ALPM_LOG_DEBUG
, "sig path %s could not be opened\n",
446 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
451 /* does the file we are verifying exist? */
452 file
= fopen(path
, "rb");
454 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
458 if(init_gpgme(handle
)) {
459 /* pm_errno was set in gpgme_init() */
463 _alpm_log(handle
, ALPM_LOG_DEBUG
, "checking signature for %s\n", path
);
465 memset(&ctx
, 0, sizeof(ctx
));
466 memset(&sigdata
, 0, sizeof(sigdata
));
467 memset(&filedata
, 0, sizeof(filedata
));
469 err
= gpgme_new(&ctx
);
472 /* create our necessary data objects to verify the signature */
473 err
= gpgme_data_new_from_stream(&filedata
, file
);
476 /* next create data object for the signature */
478 /* memory-based, we loaded it from a sync DB */
480 int decode_ret
= decode_signature(base64_sig
,
481 &decoded_sigdata
, &data_len
);
483 handle
->pm_errno
= ALPM_ERR_SIG_INVALID
;
486 err
= gpgme_data_new_from_mem(&sigdata
,
487 (char *)decoded_sigdata
, data_len
, 0);
489 /* file-based, it is on disk */
490 err
= gpgme_data_new_from_stream(&sigdata
, sigfile
);
494 /* here's where the magic happens */
495 err
= gpgme_op_verify(ctx
, sigdata
, filedata
, NULL
);
497 verify_result
= gpgme_op_verify_result(ctx
);
499 if(!verify_result
|| !verify_result
->signatures
) {
500 _alpm_log(handle
, ALPM_LOG_DEBUG
, "no signatures returned\n");
501 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
504 for(gpgsig
= verify_result
->signatures
, sigcount
= 0;
505 gpgsig
; gpgsig
= gpgsig
->next
, sigcount
++);
506 _alpm_log(handle
, ALPM_LOG_DEBUG
, "%d signatures returned\n", sigcount
);
508 CALLOC(siglist
->results
, sigcount
, sizeof(alpm_sigresult_t
),
509 handle
->pm_errno
= ALPM_ERR_MEMORY
; goto gpg_error
);
510 siglist
->count
= sigcount
;
512 for(gpgsig
= verify_result
->signatures
, sigcount
= 0; gpgsig
;
513 gpgsig
= gpgsig
->next
, sigcount
++) {
514 alpm_list_t
*summary_list
, *summary
;
515 alpm_sigstatus_t status
;
516 alpm_sigvalidity_t validity
;
518 alpm_sigresult_t
*result
;
520 _alpm_log(handle
, ALPM_LOG_DEBUG
, "fingerprint: %s\n", gpgsig
->fpr
);
521 summary_list
= list_sigsum(gpgsig
->summary
);
522 for(summary
= summary_list
; summary
; summary
= summary
->next
) {
523 _alpm_log(handle
, ALPM_LOG_DEBUG
, "summary: %s\n", (const char *)summary
->data
);
525 alpm_list_free(summary_list
);
526 _alpm_log(handle
, ALPM_LOG_DEBUG
, "status: %s\n", gpgme_strerror(gpgsig
->status
));
527 _alpm_log(handle
, ALPM_LOG_DEBUG
, "timestamp: %lu\n", gpgsig
->timestamp
);
528 _alpm_log(handle
, ALPM_LOG_DEBUG
, "exp_timestamp: %lu\n", gpgsig
->exp_timestamp
);
529 _alpm_log(handle
, ALPM_LOG_DEBUG
, "validity: %s; reason: %s\n",
530 string_validity(gpgsig
->validity
),
531 gpgme_strerror(gpgsig
->validity_reason
));
533 result
= siglist
->results
+ sigcount
;
534 err
= gpgme_get_key(ctx
, gpgsig
->fpr
, &key
, 0);
535 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
536 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
537 err
= GPG_ERR_NO_ERROR
;
538 /* we dupe the fpr in this case since we have no key to point at */
539 STRDUP(result
->key
.fingerprint
, gpgsig
->fpr
,
540 handle
->pm_errno
= ALPM_ERR_MEMORY
; goto gpg_error
);
544 result
->key
.data
= key
;
545 result
->key
.fingerprint
= key
->subkeys
->fpr
;
546 result
->key
.uid
= key
->uids
->uid
;
547 result
->key
.name
= key
->uids
->name
;
548 result
->key
.email
= key
->uids
->email
;
549 result
->key
.created
= key
->subkeys
->timestamp
;
550 result
->key
.expires
= key
->subkeys
->expires
;
551 _alpm_log(handle
, ALPM_LOG_DEBUG
,
552 "key: %s, %s, owner_trust %s, disabled %d\n",
553 key
->subkeys
->fpr
, key
->uids
->uid
,
554 string_validity(key
->owner_trust
), key
->disabled
);
558 switch(gpg_err_code(gpgsig
->status
)) {
560 case GPG_ERR_NO_ERROR
:
561 status
= ALPM_SIGSTATUS_VALID
;
563 case GPG_ERR_KEY_EXPIRED
:
564 status
= ALPM_SIGSTATUS_KEY_EXPIRED
;
567 case GPG_ERR_SIG_EXPIRED
:
568 status
= ALPM_SIGSTATUS_SIG_EXPIRED
;
570 case GPG_ERR_NO_PUBKEY
:
571 status
= ALPM_SIGSTATUS_KEY_UNKNOWN
;
573 case GPG_ERR_BAD_SIGNATURE
:
575 status
= ALPM_SIGSTATUS_INVALID
;
578 /* special case: key disabled is not returned in above status code */
579 if(result
->key
.data
&& key
->disabled
) {
580 status
= ALPM_SIGSTATUS_KEY_DISABLED
;
583 switch(gpgsig
->validity
) {
584 case GPGME_VALIDITY_ULTIMATE
:
585 case GPGME_VALIDITY_FULL
:
586 validity
= ALPM_SIGVALIDITY_FULL
;
588 case GPGME_VALIDITY_MARGINAL
:
589 validity
= ALPM_SIGVALIDITY_MARGINAL
;
591 case GPGME_VALIDITY_NEVER
:
592 validity
= ALPM_SIGVALIDITY_NEVER
;
594 case GPGME_VALIDITY_UNKNOWN
:
595 case GPGME_VALIDITY_UNDEFINED
:
597 validity
= ALPM_SIGVALIDITY_UNKNOWN
;
601 result
->status
= status
;
602 result
->validity
= validity
;
608 gpgme_data_release(sigdata
);
609 gpgme_data_release(filedata
);
620 FREE(decoded_sigdata
);
621 if(gpg_err_code(err
) != GPG_ERR_NO_ERROR
) {
622 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
623 RET_ERR(handle
, ALPM_ERR_GPGME
, -1);
628 #else /* HAVE_LIBGPGME */
629 static int key_in_keychain(alpm_handle_t UNUSED
*handle
, const char UNUSED
*fpr
)
633 int _alpm_gpgme_checksig(alpm_handle_t UNUSED
*handle
, const char UNUSED
*path
,
634 const char UNUSED
*base64_sig
, alpm_siglist_t UNUSED
*siglist
)
638 #endif /* HAVE_LIBGPGME */
641 * Form a signature path given a file path.
642 * Caller must free the result.
643 * @param handle the context handle
644 * @param path the full path to a file
645 * @return the path with '.sig' appended, NULL on errors
647 char *_alpm_sigpath(alpm_handle_t
*handle
, const char *path
)
655 len
= strlen(path
) + 5;
656 CALLOC(sigpath
, len
, sizeof(char), RET_ERR(handle
, ALPM_ERR_MEMORY
, NULL
));
657 sprintf(sigpath
, "%s.sig", path
);
662 * Helper for checking the PGP signature for the given file path.
663 * This wraps #_alpm_gpgme_checksig in a slightly friendlier manner to simplify
664 * handling of optional signatures and marginal/unknown trust levels and
665 * handling the correct error code return values.
666 * @param handle the context handle
667 * @param path the full path to a file
668 * @param base64_sig optional PGP signature data in base64 encoding
669 * @param optional whether signatures are optional (e.g., missing OK)
670 * @param marginal whether signatures with marginal trust are acceptable
671 * @param unknown whether signatures with unknown trust are acceptable
672 * @param sigdata a pointer to storage for signature results
673 * @return 0 on success, -1 on error (consult pm_errno or sigdata)
675 int _alpm_check_pgp_helper(alpm_handle_t
*handle
, const char *path
,
676 const char *base64_sig
, int optional
, int marginal
, int unknown
,
677 alpm_siglist_t
**sigdata
)
679 alpm_siglist_t
*siglist
;
682 CALLOC(siglist
, 1, sizeof(alpm_siglist_t
),
683 RET_ERR(handle
, ALPM_ERR_MEMORY
, -1));
685 ret
= _alpm_gpgme_checksig(handle
, path
, base64_sig
, siglist
);
686 if(ret
&& handle
->pm_errno
== ALPM_ERR_SIG_MISSING
) {
688 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing optional signature\n");
689 handle
->pm_errno
= 0;
692 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing required signature\n");
693 /* ret will already be -1 */
696 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature check failed\n");
697 /* ret will already be -1 */
700 for(num
= 0; !ret
&& num
< siglist
->count
; num
++) {
701 switch(siglist
->results
[num
].status
) {
702 case ALPM_SIGSTATUS_VALID
:
703 case ALPM_SIGSTATUS_KEY_EXPIRED
:
704 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is valid\n");
705 switch(siglist
->results
[num
].validity
) {
706 case ALPM_SIGVALIDITY_FULL
:
707 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is fully trusted\n");
709 case ALPM_SIGVALIDITY_MARGINAL
:
710 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is marginal trust\n");
715 case ALPM_SIGVALIDITY_UNKNOWN
:
716 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is unknown trust\n");
721 case ALPM_SIGVALIDITY_NEVER
:
722 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature should never be trusted\n");
727 case ALPM_SIGSTATUS_SIG_EXPIRED
:
728 case ALPM_SIGSTATUS_KEY_UNKNOWN
:
729 case ALPM_SIGSTATUS_KEY_DISABLED
:
730 case ALPM_SIGSTATUS_INVALID
:
731 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is not valid\n");
741 alpm_siglist_cleanup(siglist
);
749 * Examine a signature result list and take any appropriate or necessary
750 * actions. This may include asking the user to import a key or simply printing
751 * helpful failure messages so the user can take action out of band.
752 * @param handle the context handle
753 * @param identifier a friendly name for the signed resource; usually a
754 * database or package name
755 * @param siglist a pointer to storage for signature results
756 * @param optional whether signatures are optional (e.g., missing OK)
757 * @param marginal whether signatures with marginal trust are acceptable
758 * @param unknown whether signatures with unknown trust are acceptable
759 * @return 0 if all signatures are OK, -1 on errors, 1 if we should retry the
762 int _alpm_process_siglist(alpm_handle_t
*handle
, const char *identifier
,
763 alpm_siglist_t
*siglist
, int optional
, int marginal
, int unknown
)
768 if(!optional
&& siglist
->count
== 0) {
769 _alpm_log(handle
, ALPM_LOG_ERROR
,
770 _("%s: missing required signature\n"), identifier
);
773 for(i
= 0; i
< siglist
->count
; i
++) {
774 alpm_sigresult_t
*result
= siglist
->results
+ i
;
775 const char *name
= result
->key
.uid
? result
->key
.uid
: result
->key
.fingerprint
;
776 switch(result
->status
) {
777 case ALPM_SIGSTATUS_VALID
:
778 case ALPM_SIGSTATUS_KEY_EXPIRED
:
779 switch(result
->validity
) {
780 case ALPM_SIGVALIDITY_FULL
:
782 case ALPM_SIGVALIDITY_MARGINAL
:
784 _alpm_log(handle
, ALPM_LOG_ERROR
,
785 _("%s: signature from \"%s\" is marginal trust\n"),
787 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
790 case ALPM_SIGVALIDITY_UNKNOWN
:
792 _alpm_log(handle
, ALPM_LOG_ERROR
,
793 _("%s: signature from \"%s\" is unknown trust\n"),
795 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
798 case ALPM_SIGVALIDITY_NEVER
:
799 _alpm_log(handle
, ALPM_LOG_ERROR
,
800 _("%s: signature from \"%s\" should never be trusted\n"),
805 case ALPM_SIGSTATUS_KEY_UNKNOWN
:
806 /* ensure this key is still actually unknown; we may have imported it
807 * on an earlier call to this function. */
808 if(key_in_keychain(handle
, result
->key
.fingerprint
) == 1) {
811 _alpm_log(handle
, ALPM_LOG_ERROR
,
812 _("%s: key \"%s\" is unknown\n"), identifier
, name
);
816 alpm_pgpkey_t fetch_key
;
817 memset(&fetch_key
, 0, sizeof(fetch_key
));
819 if(key_search(handle
, result
->key
.fingerprint
, &fetch_key
) == 1) {
820 _alpm_log(handle
, ALPM_LOG_DEBUG
,
821 "unknown key, found %s on keyserver\n", fetch_key
.uid
);
822 if(!_alpm_access(handle
, handle
->gpgdir
, "pubring.gpg", W_OK
)) {
823 QUESTION(handle
, ALPM_QUESTION_IMPORT_KEY
,
824 &fetch_key
, NULL
, NULL
, &answer
);
826 if(key_import(handle
, &fetch_key
) == 0) {
829 _alpm_log(handle
, ALPM_LOG_ERROR
,
830 _("key \"%s\" could not be imported\n"), fetch_key
.uid
);
834 /* keyring directory was not writable, so we don't even try */
835 _alpm_log(handle
, ALPM_LOG_WARNING
,
836 _("key %s, \"%s\" found on keyserver, keyring is not writable\n"),
837 fetch_key
.fingerprint
, fetch_key
.uid
);
840 _alpm_log(handle
, ALPM_LOG_ERROR
,
841 _("key \"%s\" could not be looked up remotely\n"), name
);
843 gpgme_key_unref(fetch_key
.data
);
847 case ALPM_SIGSTATUS_KEY_DISABLED
:
848 _alpm_log(handle
, ALPM_LOG_ERROR
,
849 _("%s: key \"%s\" is disabled\n"), identifier
, name
);
851 case ALPM_SIGSTATUS_SIG_EXPIRED
:
852 _alpm_log(handle
, ALPM_LOG_ERROR
,
853 _("%s: signature from \"%s\" is expired\n"), identifier
, name
);
855 case ALPM_SIGSTATUS_INVALID
:
856 _alpm_log(handle
, ALPM_LOG_ERROR
,
857 _("%s: signature from \"%s\" is invalid\n"),
867 * Check the PGP signature for the given package file.
868 * @param pkg the package to check
869 * @param siglist a pointer to storage for signature results
870 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
872 int SYMEXPORT
alpm_pkg_check_pgp_signature(alpm_pkg_t
*pkg
,
873 alpm_siglist_t
*siglist
)
875 ASSERT(pkg
!= NULL
, return -1);
876 ASSERT(siglist
!= NULL
, RET_ERR(pkg
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
877 pkg
->handle
->pm_errno
= 0;
879 return _alpm_gpgme_checksig(pkg
->handle
, pkg
->filename
,
880 pkg
->base64_sig
, siglist
);
884 * Check the PGP signature for the given database.
885 * @param db the database to check
886 * @param siglist a pointer to storage for signature results
887 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
889 int SYMEXPORT
alpm_db_check_pgp_signature(alpm_db_t
*db
,
890 alpm_siglist_t
*siglist
)
892 ASSERT(db
!= NULL
, return -1);
893 ASSERT(siglist
!= NULL
, RET_ERR(db
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
894 db
->handle
->pm_errno
= 0;
896 return _alpm_gpgme_checksig(db
->handle
, _alpm_db_path(db
), NULL
, siglist
);
900 * Clean up and free a signature result list.
901 * Note that this does not free the siglist object itself in case that
902 * was allocated on the stack; this is the responsibility of the caller.
903 * @param siglist a pointer to storage for signature results
904 * @return 0 on success, -1 on error
906 int SYMEXPORT
alpm_siglist_cleanup(alpm_siglist_t
*siglist
)
908 ASSERT(siglist
!= NULL
, return -1);
910 for(num
= 0; num
< siglist
->count
; num
++) {
911 alpm_sigresult_t
*result
= siglist
->results
+ num
;
912 if(result
->key
.data
) {
914 gpgme_key_unref(result
->key
.data
);
917 free(result
->key
.fingerprint
);
921 free(siglist
->results
);
923 siglist
->results
= NULL
;
928 /* vim: set ts=2 sw=2 noet: */