1 /*
2 * signing.c
3 *
4 * Copyright (c) 2008-2018 Pacman Development Team <pacman-dev@archlinux.org>
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #ifdef HAVE_LIBGPGME
25 #include <locale.h> /* setlocale() */
26 #include <gpgme.h>
27 #endif
28
29 /* libalpm */
30 #include "signing.h"
31 #include "package.h"
32 #include "base64.h"
33 #include "util.h"
34 #include "log.h"
35 #include "alpm.h"
36 #include "handle.h"
37
38 /**
39 * Decode a loaded signature in base64 form.
40 * @param base64_data the signature to attempt to decode
41 * @param data the decoded data; must be freed by the caller
42 * @param data_len the length of the returned data
43 * @return 0 on success, -1 on failure to properly decode
44 */
45
alpm_decode_signature(const char * base64_data,unsigned char ** data,size_t * data_len)46 int SYMEXPORT alpm_decode_signature(const char *base64_data,
47 unsigned char **data, size_t *data_len)
48 {
49 size_t len = strlen(base64_data);
50 unsigned char *usline = (unsigned char *)base64_data;
51 /* reasonable allocation of expected length is 3/4 of encoded length */
52 size_t destlen = len * 3 / 4;
53 MALLOC(*data, destlen, goto error);
54 if(base64_decode(*data, &destlen, usline, len)) {
55 free(*data);
56 goto error;
57 }
58 *data_len = destlen;
59 return 0;
60
61 error:
62 *data = NULL;
63 *data_len = 0;
64 return -1;
65 }
66
67 #ifdef HAVE_LIBGPGME
68 #define CHECK_ERR(void) do { \
69 if(gpg_err_code(gpg_err) != GPG_ERR_NO_ERROR) { goto gpg_error; } \
70 } while(0)
71
72 /**
73 * Return a statically allocated validity string based on the GPGME validity
74 * code. This is mainly for debug purposes and is not translated.
75 * @param validity a validity code returned by GPGME
76 * @return a string such as "marginal"
77 */
string_validity(gpgme_validity_t validity)78 static const char *string_validity(gpgme_validity_t validity)
79 {
80 switch(validity) {
81 case GPGME_VALIDITY_UNKNOWN:
82 return "unknown";
83 case GPGME_VALIDITY_UNDEFINED:
84 return "undefined";
85 case GPGME_VALIDITY_NEVER:
86 return "never";
87 case GPGME_VALIDITY_MARGINAL:
88 return "marginal";
89 case GPGME_VALIDITY_FULL:
90 return "full";
91 case GPGME_VALIDITY_ULTIMATE:
92 return "ultimate";
93 }
94 return "???";
95 }
96
sigsum_test_bit(gpgme_sigsum_t sigsum,alpm_list_t ** summary,gpgme_sigsum_t bit,const char * value)97 static void sigsum_test_bit(gpgme_sigsum_t sigsum, alpm_list_t **summary,
98 gpgme_sigsum_t bit, const char *value)
99 {
100 if(sigsum & bit) {
101 *summary = alpm_list_add(*summary, (void *)value);
102 }
103 }
104
105 /**
106 * Calculate a set of strings to represent the given GPGME signature summary
107 * value. This is a bitmask so you may get any number of strings back.
108 * @param sigsum a GPGME signature summary bitmask
109 * @return the list of signature summary strings
110 */
list_sigsum(gpgme_sigsum_t sigsum)111 static alpm_list_t *list_sigsum(gpgme_sigsum_t sigsum)
112 {
113 alpm_list_t *summary = NULL;
114 /* The docs say this can be a bitmask...not sure I believe it, but we'll code
115 * for it anyway and show all possible flags in the returned string. */
116
117 /* The signature is fully valid. */
118 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_VALID, "valid");
119 /* The signature is good. */
120 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_GREEN, "green");
121 /* The signature is bad. */
122 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_RED, "red");
123 /* One key has been revoked. */
124 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_KEY_REVOKED, "key revoked");
125 /* One key has expired. */
126 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_KEY_EXPIRED, "key expired");
127 /* The signature has expired. */
128 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_SIG_EXPIRED, "sig expired");
129 /* Can't verify: key missing. */
130 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_KEY_MISSING, "key missing");
131 /* CRL not available. */
132 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_CRL_MISSING, "crl missing");
133 /* Available CRL is too old. */
134 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_CRL_TOO_OLD, "crl too old");
135 /* A policy was not met. */
136 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_BAD_POLICY, "bad policy");
137 /* A system error occurred. */
138 sigsum_test_bit(sigsum, &summary, GPGME_SIGSUM_SYS_ERROR, "sys error");
139 /* Fallback case */
140 if(!sigsum) {
141 summary = alpm_list_add(summary, (void *)"(empty)");
142 }
143 return summary;
144 }
145
146 /**
147 * Initialize the GPGME library.
148 * This can be safely called multiple times; however it is not thread-safe.
149 * @param handle the context handle
150 * @return 0 on success, -1 on error
151 */
init_gpgme(alpm_handle_t * handle)152 static int init_gpgme(alpm_handle_t *handle)
153 {
154 static int init = 0;
155 const char *version, *sigdir;
156 gpgme_error_t gpg_err;
157 gpgme_engine_info_t enginfo;
158
159 if(init) {
160 /* we already successfully initialized the library */
161 return 0;
162 }
163
164 sigdir = handle->gpgdir;
165
166 if(_alpm_access(handle, sigdir, "pubring.gpg", R_OK)
167 || _alpm_access(handle, sigdir, "trustdb.gpg", R_OK)) {
168 handle->pm_errno = ALPM_ERR_NOT_A_FILE;
169 _alpm_log(handle, ALPM_LOG_DEBUG, "Signature verification will fail!\n");
170 _alpm_log(handle, ALPM_LOG_WARNING,
171 _("Public keyring not found; have you run '%s'?\n"),
172 "pacman-key --init");
173 }
174
175 /* calling gpgme_check_version() returns the current version and runs
176 * some internal library setup code */
177 version = gpgme_check_version(NULL);
178 _alpm_log(handle, ALPM_LOG_DEBUG, "GPGME version: %s\n", version);
179 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
180 #ifdef LC_MESSAGES
181 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
182 #endif
183 /* NOTE:
184 * The GPGME library installs a SIGPIPE signal handler automatically if
185 * the default signal hander is in use. The only time we set a handler
186 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
187 * we do this, we can let GPGME do its automagic. However, if we install
188 * a library-wide SIGPIPE handler, we will have to be careful.
189 */
190
191 /* check for OpenPGP support (should be a no-brainer, but be safe) */
192 gpg_err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
193 CHECK_ERR();
194
195 /* set and check engine information */
196 gpg_err = gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, NULL, sigdir);
197 CHECK_ERR();
198 gpg_err = gpgme_get_engine_info(&enginfo);
199 CHECK_ERR();
200 _alpm_log(handle, ALPM_LOG_DEBUG, "GPGME engine info: file=%s, home=%s\n",
201 enginfo->file_name, enginfo->home_dir);
202
203 init = 1;
204 return 0;
205
206 gpg_error:
207 _alpm_log(handle, ALPM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(gpg_err));
208 RET_ERR(handle, ALPM_ERR_GPGME, -1);
209 }
210
211 /**
212 * Determine if we have a key is known in our local keyring.
213 * @param handle the context handle
214 * @param fpr the fingerprint key ID to look up
215 * @return 1 if key is known, 0 if key is unknown, -1 on error
216 */
_alpm_key_in_keychain(alpm_handle_t * handle,const char * fpr)217 int _alpm_key_in_keychain(alpm_handle_t *handle, const char *fpr)
218 {
219 gpgme_error_t gpg_err;
220 gpgme_ctx_t ctx;
221 gpgme_key_t key;
222 int ret = -1;
223
224 if(alpm_list_find_str(handle->known_keys, fpr)) {
225 _alpm_log(handle, ALPM_LOG_DEBUG, "key %s found in cache\n", fpr);
226 return 1;
227 }
228
229 if(init_gpgme(handle)) {
230 /* pm_errno was set in gpgme_init() */
231 goto error;
232 }
233
234 memset(&ctx, 0, sizeof(ctx));
235 gpg_err = gpgme_new(&ctx);
236 CHECK_ERR();
237
238 _alpm_log(handle, ALPM_LOG_DEBUG, "looking up key %s locally\n", fpr);
239
240 gpg_err = gpgme_get_key(ctx, fpr, &key, 0);
241 if(gpg_err_code(gpg_err) == GPG_ERR_EOF) {
242 _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
243 ret = 0;
244 } else if(gpg_err_code(gpg_err) == GPG_ERR_NO_ERROR) {
245 _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, key exists\n");
246 handle->known_keys = alpm_list_add(handle->known_keys, strdup(fpr));
247 ret = 1;
248 } else {
249 _alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(gpg_err));
250 }
251 gpgme_key_unref(key);
252
253 gpg_error:
254 gpgme_release(ctx);
255
256 error:
257 return ret;
258 }
259
260 /**
261 * Search for a GPG key in a remote location.
262 * This requires GPGME to call the gpg binary and have a keyserver previously
263 * defined in a gpg.conf configuration file.
264 * @param handle the context handle
265 * @param fpr the fingerprint key ID to look up
266 * @param pgpkey storage location for the given key if found
267 * @return 1 on success, 0 on key not found, -1 on error
268 */
key_search(alpm_handle_t * handle,const char * fpr,alpm_pgpkey_t * pgpkey)269 static int key_search(alpm_handle_t *handle, const char *fpr,
270 alpm_pgpkey_t *pgpkey)
271 {
272 gpgme_error_t gpg_err;
273 gpgme_ctx_t ctx;
274 gpgme_keylist_mode_t mode;
275 gpgme_key_t key;
276 int ret = -1;
277 size_t fpr_len;
278 char *full_fpr;
279
280 /* gpg2 goes full retard here. For key searches ONLY, we need to prefix the
281 * key fingerprint with 0x, or the lookup will fail. */
282 fpr_len = strlen(fpr);
283 MALLOC(full_fpr, fpr_len + 3, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
284 sprintf(full_fpr, "0x%s", fpr);
285
286 memset(&ctx, 0, sizeof(ctx));
287 gpg_err = gpgme_new(&ctx);
288 CHECK_ERR();
289
290 mode = gpgme_get_keylist_mode(ctx);
291 /* using LOCAL and EXTERN together doesn't work for GPG 1.X. Ugh. */
292 mode &= ~GPGME_KEYLIST_MODE_LOCAL;
293 mode |= GPGME_KEYLIST_MODE_EXTERN;
294 gpg_err = gpgme_set_keylist_mode(ctx, mode);
295 CHECK_ERR();
296
297 _alpm_log(handle, ALPM_LOG_DEBUG, "looking up key %s remotely\n", fpr);
298
299 gpg_err = gpgme_get_key(ctx, full_fpr, &key, 0);
300 if(gpg_err_code(gpg_err) == GPG_ERR_EOF) {
301 _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
302 /* Try an alternate lookup using the 8 character fingerprint value, since
303 * busted-ass keyservers can't support lookups using subkeys with the full
304 * value as of now. This is why 2012 is not the year of PGP encryption. */
305 if(fpr_len > 8) {
306 const char *short_fpr = memcpy(&full_fpr[fpr_len - 8], "0x", 2);
307 _alpm_log(handle, ALPM_LOG_DEBUG,
308 "looking up key %s remotely\n", short_fpr);
309 gpg_err = gpgme_get_key(ctx, short_fpr, &key, 0);
310 if(gpg_err_code(gpg_err) == GPG_ERR_EOF) {
311 _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
312 ret = 0;
313 }
314 } else {
315 ret = 0;
316 }
317 }
318
319 CHECK_ERR();
320
321 /* should only get here if key actually exists */
322 pgpkey->data = key;
323 if(key->subkeys->fpr) {
324 pgpkey->fingerprint = key->subkeys->fpr;
325 } else if(key->subkeys->keyid) {
326 pgpkey->fingerprint = key->subkeys->keyid;
327 }
328 pgpkey->uid = key->uids->uid;
329 pgpkey->name = key->uids->name;
330 pgpkey->email = key->uids->email;
331 pgpkey->created = key->subkeys->timestamp;
332 pgpkey->expires = key->subkeys->expires;
333 pgpkey->length = key->subkeys->length;
334 pgpkey->revoked = key->subkeys->revoked;
335
336 /* Initialize with '?', this is overwritten unless public key
337 * algorithm is unknown. */
338 pgpkey->pubkey_algo = '?';
339
340 switch(key->subkeys->pubkey_algo) {
341 case GPGME_PK_RSA:
342 case GPGME_PK_RSA_E:
343 case GPGME_PK_RSA_S:
344 pgpkey->pubkey_algo = 'R';
345 break;
346
347 case GPGME_PK_DSA:
348 pgpkey->pubkey_algo = 'D';
349 break;
350
351 case GPGME_PK_ELG_E:
352 case GPGME_PK_ELG:
353 case GPGME_PK_ECDSA:
354 case GPGME_PK_ECDH:
355 /* value added in gpgme 1.5.0 */
356 #if GPGME_VERSION_NUMBER >= 0x010500
357 case GPGME_PK_ECC:
358 #endif
359 /* value added in gpgme 1.7.0 */
360 #if GPGME_VERSION_NUMBER >= 0x010700
361 case GPGME_PK_EDDSA:
362 #endif
363 pgpkey->pubkey_algo = 'E';
364 break;
365 }
366
367 ret = 1;
368
369 /* We do not want to add a default switch case above to receive
370 * compiler error on new public key algorithm in gpgme. So check
371 * here if we have a valid pubkey_algo. */
372 if (pgpkey->pubkey_algo == '?') {
373 _alpm_log(handle, ALPM_LOG_DEBUG,
374 "unknown public key algorithm: %d\n", key->subkeys->pubkey_algo);
375 }
376
377 gpg_error:
378 if(ret != 1) {
379 _alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(gpg_err));
380 }
381 free(full_fpr);
382 gpgme_release(ctx);
383 return ret;
384 }
385
386 /**
387 * Import a key into the local keyring.
388 * @param handle the context handle
389 * @param key the key to import, likely retrieved from #key_search
390 * @return 0 on success, -1 on error
391 */
key_import(alpm_handle_t * handle,alpm_pgpkey_t * key)392 static int key_import(alpm_handle_t *handle, alpm_pgpkey_t *key)
393 {
394 gpgme_error_t gpg_err;
395 gpgme_ctx_t ctx;
396 gpgme_key_t keys[2];
397 gpgme_import_result_t result;
398 int ret = -1;
399
400 if(_alpm_access(handle, handle->gpgdir, "pubring.gpg", W_OK)) {
401 /* no chance of import succeeding if pubring isn't writable */
402 _alpm_log(handle, ALPM_LOG_ERROR, _("keyring is not writable\n"));
403 return -1;
404 }
405
406 memset(&ctx, 0, sizeof(ctx));
407 gpg_err = gpgme_new(&ctx);
408 CHECK_ERR();
409
410 _alpm_log(handle, ALPM_LOG_DEBUG, "importing key\n");
411
412 keys[0] = key->data;
413 keys[1] = NULL;
414 gpg_err = gpgme_op_import_keys(ctx, keys);
415 CHECK_ERR();
416 result = gpgme_op_import_result(ctx);
417 /* we know we tried to import exactly one key, so check for this */
418 if(result->considered != 1 || !result->imports) {
419 _alpm_log(handle, ALPM_LOG_DEBUG, "could not import key, 0 results\n");
420 ret = -1;
421 } else if(result->imports->result != GPG_ERR_NO_ERROR) {
422 _alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(gpg_err));
423 ret = -1;
424 } else {
425 ret = 0;
426 }
427
428 gpg_error:
429 gpgme_release(ctx);
430 return ret;
431 }
432
433 /**
434 * Import a key defined by a fingerprint into the local keyring.
435 * @param handle the context handle
436 * @param fpr the fingerprint key ID to import
437 * @return 0 on success, -1 on error
438 */
_alpm_key_import(alpm_handle_t * handle,const char * fpr)439 int _alpm_key_import(alpm_handle_t *handle, const char *fpr)
440 {
441 int ret = -1;
442 alpm_pgpkey_t fetch_key;
443 memset(&fetch_key, 0, sizeof(fetch_key));
444
445 if(key_search(handle, fpr, &fetch_key) == 1) {
446 _alpm_log(handle, ALPM_LOG_DEBUG,
447 "unknown key, found %s on keyserver\n", fetch_key.uid);
448 if(!_alpm_access(handle, handle->gpgdir, "pubring.gpg", W_OK)) {
449 alpm_question_import_key_t question = {
450 .type = ALPM_QUESTION_IMPORT_KEY,
451 .import = 0,
452 .key = &fetch_key
453 };
454 QUESTION(handle, &question);
455 if(question.import) {
456 if(key_import(handle, &fetch_key) == 0) {
457 ret = 0;
458 } else {
459 _alpm_log(handle, ALPM_LOG_ERROR,
460 _("key \"%s\" could not be imported\n"), fetch_key.uid);
461 }
462 }
463 } else {
464 /* keyring directory was not writable, so we don't even try */
465 _alpm_log(handle, ALPM_LOG_WARNING,
466 _("key %s, \"%s\" found on keyserver, keyring is not writable\n"),
467 fetch_key.fingerprint, fetch_key.uid);
468 }
469 } else {
470 _alpm_log(handle, ALPM_LOG_ERROR,
471 _("key \"%s\" could not be looked up remotely\n"), fpr);
472 }
473 gpgme_key_unref(fetch_key.data);
474
475 return ret;
476 }
477
478 /**
479 * Check the PGP signature for the given file path.
480 * If base64_sig is provided, it will be used as the signature data after
481 * decoding. If base64_sig is NULL, expect a signature file next to path
482 * (e.g. "%s.sig").
483 *
484 * The return value will be 0 if nothing abnormal happened during the signature
485 * check, and -1 if an error occurred while checking signatures or if a
486 * signature could not be found; pm_errno will be set. Note that "abnormal"
487 * does not include a failed signature; the value in siglist should be checked
488 * to determine if the signature(s) are good.
489 * @param handle the context handle
490 * @param path the full path to a file
491 * @param base64_sig optional PGP signature data in base64 encoding
492 * @param siglist a pointer to storage for signature results
493 * @return 0 in normal cases, -1 if the something failed in the check process
494 */
_alpm_gpgme_checksig(alpm_handle_t * handle,const char * path,const char * base64_sig,alpm_siglist_t * siglist)495 int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
496 const char *base64_sig, alpm_siglist_t *siglist)
497 {
498 int ret = -1, sigcount;
499 gpgme_error_t gpg_err = 0;
500 gpgme_ctx_t ctx;
501 gpgme_data_t filedata, sigdata;
502 gpgme_verify_result_t verify_result;
503 gpgme_signature_t gpgsig;
504 char *sigpath = NULL;
505 unsigned char *decoded_sigdata = NULL;
506 FILE *file = NULL, *sigfile = NULL;
507
508 if(!path || _alpm_access(handle, NULL, path, R_OK) != 0) {
509 RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1);
510 }
511
512 if(!siglist) {
513 RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
514 }
515 siglist->count = 0;
516
517 if(!base64_sig) {
518 sigpath = _alpm_sigpath(handle, path);
519 if(_alpm_access(handle, NULL, sigpath, R_OK) != 0
520 || (sigfile = fopen(sigpath, "rb")) == NULL) {
521 _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n",
522 sigpath);
523 handle->pm_errno = ALPM_ERR_SIG_MISSING;
524 goto error;
525 }
526 }
527
528 /* does the file we are verifying exist? */
529 file = fopen(path, "rb");
530 if(file == NULL) {
531 handle->pm_errno = ALPM_ERR_NOT_A_FILE;
532 goto error;
533 }
534
535 if(init_gpgme(handle)) {
536 /* pm_errno was set in gpgme_init() */
537 goto error;
538 }
539
540 _alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path);
541
542 memset(&ctx, 0, sizeof(ctx));
543 memset(&sigdata, 0, sizeof(sigdata));
544 memset(&filedata, 0, sizeof(filedata));
545
546 gpg_err = gpgme_new(&ctx);
547 CHECK_ERR();
548
549 /* create our necessary data objects to verify the signature */
550 gpg_err = gpgme_data_new_from_stream(&filedata, file);
551 CHECK_ERR();
552
553 /* next create data object for the signature */
554 if(base64_sig) {
555 /* memory-based, we loaded it from a sync DB */
556 size_t data_len;
557 int decode_ret = alpm_decode_signature(base64_sig,
558 &decoded_sigdata, &data_len);
559 if(decode_ret) {
560 handle->pm_errno = ALPM_ERR_SIG_INVALID;
561 goto gpg_error;
562 }
563 gpg_err = gpgme_data_new_from_mem(&sigdata,
564 (char *)decoded_sigdata, data_len, 0);
565 } else {
566 /* file-based, it is on disk */
567 gpg_err = gpgme_data_new_from_stream(&sigdata, sigfile);
568 }
569 CHECK_ERR();
570
571 /* here's where the magic happens */
572 gpg_err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
573 CHECK_ERR();
574 verify_result = gpgme_op_verify_result(ctx);
575 CHECK_ERR();
576 if(!verify_result || !verify_result->signatures) {
577 _alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n");
578 handle->pm_errno = ALPM_ERR_SIG_MISSING;
579 goto gpg_error;
580 }
581 for(gpgsig = verify_result->signatures, sigcount = 0;
582 gpgsig; gpgsig = gpgsig->next, sigcount++);
583 _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount);
584
585 CALLOC(siglist->results, sigcount, sizeof(alpm_sigresult_t),
586 handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
587 siglist->count = sigcount;
588
589 for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig;
590 gpgsig = gpgsig->next, sigcount++) {
591 alpm_list_t *summary_list, *summary;
592 alpm_sigstatus_t status;
593 alpm_sigvalidity_t validity;
594 gpgme_key_t key;
595 alpm_sigresult_t *result;
596
597 _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr);
598 summary_list = list_sigsum(gpgsig->summary);
599 for(summary = summary_list; summary; summary = summary->next) {
600 _alpm_log(handle, ALPM_LOG_DEBUG, "summary: %s\n", (const char *)summary->data);
601 }
602 alpm_list_free(summary_list);
603 _alpm_log(handle, ALPM_LOG_DEBUG, "status: %s\n", gpgme_strerror(gpgsig->status));
604 _alpm_log(handle, ALPM_LOG_DEBUG, "timestamp: %lu\n", gpgsig->timestamp);
605
606 if((time_t)gpgsig->timestamp > time(NULL)) {
607 _alpm_log(handle, ALPM_LOG_DEBUG,
608 "signature timestamp is greater than system time.\n");
609 }
610
611 _alpm_log(handle, ALPM_LOG_DEBUG, "exp_timestamp: %lu\n", gpgsig->exp_timestamp);
612 _alpm_log(handle, ALPM_LOG_DEBUG, "validity: %s; reason: %s\n",
613 string_validity(gpgsig->validity),
614 gpgme_strerror(gpgsig->validity_reason));
615
616 result = siglist->results + sigcount;
617 gpg_err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0);
618 if(gpg_err_code(gpg_err) == GPG_ERR_EOF) {
619 _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
620 gpg_err = GPG_ERR_NO_ERROR;
621 /* we dupe the fpr in this case since we have no key to point at */
622 STRDUP(result->key.fingerprint, gpgsig->fpr,
623 handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
624 } else {
625 CHECK_ERR();
626 if(key->uids) {
627 result->key.data = key;
628 result->key.fingerprint = key->subkeys->fpr;
629 result->key.uid = key->uids->uid;
630 result->key.name = key->uids->name;
631 result->key.email = key->uids->email;
632 result->key.created = key->subkeys->timestamp;
633 result->key.expires = key->subkeys->expires;
634 _alpm_log(handle, ALPM_LOG_DEBUG,
635 "key: %s, %s, owner_trust %s, disabled %d\n",
636 key->subkeys->fpr, key->uids->uid,
637 string_validity(key->owner_trust), key->disabled);
638 }
639 }
640
641 switch(gpg_err_code(gpgsig->status)) {
642 /* good cases */
643 case GPG_ERR_NO_ERROR:
644 status = ALPM_SIGSTATUS_VALID;
645 break;
646 case GPG_ERR_KEY_EXPIRED:
647 status = ALPM_SIGSTATUS_KEY_EXPIRED;
648 break;
649 /* bad cases */
650 case GPG_ERR_SIG_EXPIRED:
651 status = ALPM_SIGSTATUS_SIG_EXPIRED;
652 break;
653 case GPG_ERR_NO_PUBKEY:
654 status = ALPM_SIGSTATUS_KEY_UNKNOWN;
655 break;
656 case GPG_ERR_BAD_SIGNATURE:
657 default:
658 status = ALPM_SIGSTATUS_INVALID;
659 break;
660 }
661 /* special case: key disabled is not returned in above status code */
662 if(result->key.data && key->disabled) {
663 status = ALPM_SIGSTATUS_KEY_DISABLED;
664 }
665
666 switch(gpgsig->validity) {
667 case GPGME_VALIDITY_ULTIMATE:
668 case GPGME_VALIDITY_FULL:
669 validity = ALPM_SIGVALIDITY_FULL;
670 break;
671 case GPGME_VALIDITY_MARGINAL:
672 validity = ALPM_SIGVALIDITY_MARGINAL;
673 break;
674 case GPGME_VALIDITY_NEVER:
675 validity = ALPM_SIGVALIDITY_NEVER;
676 break;
677 case GPGME_VALIDITY_UNKNOWN:
678 case GPGME_VALIDITY_UNDEFINED:
679 default:
680 validity = ALPM_SIGVALIDITY_UNKNOWN;
681 break;
682 }
683
684 result->status = status;
685 result->validity = validity;
686 }
687
688 ret = 0;
689
690 gpg_error:
691 gpgme_data_release(sigdata);
692 gpgme_data_release(filedata);
693 gpgme_release(ctx);
694
695 error:
696 if(sigfile) {
697 fclose(sigfile);
698 }
699 if(file) {
700 fclose(file);
701 }
702 FREE(sigpath);
703 FREE(decoded_sigdata);
704 if(gpg_err_code(gpg_err) != GPG_ERR_NO_ERROR) {
705 _alpm_log(handle, ALPM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(gpg_err));
706 RET_ERR(handle, ALPM_ERR_GPGME, -1);
707 }
708 return ret;
709 }
710
711 #else /* HAVE_LIBGPGME */
_alpm_key_in_keychain(alpm_handle_t UNUSED * handle,const char UNUSED * fpr)712 int _alpm_key_in_keychain(alpm_handle_t UNUSED *handle, const char UNUSED *fpr)
713 {
714 return -1;
715 }
716
_alpm_key_import(alpm_handle_t UNUSED * handle,const char UNUSED * fpr)717 int _alpm_key_import(alpm_handle_t UNUSED *handle, const char UNUSED *fpr)
718 {
719 return -1;
720 }
721
_alpm_gpgme_checksig(alpm_handle_t UNUSED * handle,const char UNUSED * path,const char UNUSED * base64_sig,alpm_siglist_t UNUSED * siglist)722 int _alpm_gpgme_checksig(alpm_handle_t UNUSED *handle, const char UNUSED *path,
723 const char UNUSED *base64_sig, alpm_siglist_t UNUSED *siglist)
724 {
725 return -1;
726 }
727 #endif /* HAVE_LIBGPGME */
728
729 /**
730 * Form a signature path given a file path.
731 * Caller must free the result.
732 * @param handle the context handle
733 * @param path the full path to a file
734 * @return the path with '.sig' appended, NULL on errors
735 */
_alpm_sigpath(alpm_handle_t * handle,const char * path)736 char *_alpm_sigpath(alpm_handle_t *handle, const char *path)
737 {
738 char *sigpath;
739 size_t len;
740
741 if(!path) {
742 return NULL;
743 }
744 len = strlen(path) + 5;
745 CALLOC(sigpath, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
746 sprintf(sigpath, "%s.sig", path);
747 return sigpath;
748 }
749
750 /**
751 * Helper for checking the PGP signature for the given file path.
752 * This wraps #_alpm_gpgme_checksig in a slightly friendlier manner to simplify
753 * handling of optional signatures and marginal/unknown trust levels and
754 * handling the correct error code return values.
755 * @param handle the context handle
756 * @param path the full path to a file
757 * @param base64_sig optional PGP signature data in base64 encoding
758 * @param optional whether signatures are optional (e.g., missing OK)
759 * @param marginal whether signatures with marginal trust are acceptable
760 * @param unknown whether signatures with unknown trust are acceptable
761 * @param sigdata a pointer to storage for signature results
762 * @return 0 on success, -1 on error (consult pm_errno or sigdata)
763 */
_alpm_check_pgp_helper(alpm_handle_t * handle,const char * path,const char * base64_sig,int optional,int marginal,int unknown,alpm_siglist_t ** sigdata)764 int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
765 const char *base64_sig, int optional, int marginal, int unknown,
766 alpm_siglist_t **sigdata)
767 {
768 alpm_siglist_t *siglist;
769 int ret;
770
771 CALLOC(siglist, 1, sizeof(alpm_siglist_t),
772 RET_ERR(handle, ALPM_ERR_MEMORY, -1));
773
774 ret = _alpm_gpgme_checksig(handle, path, base64_sig, siglist);
775 if(ret && handle->pm_errno == ALPM_ERR_SIG_MISSING) {
776 if(optional) {
777 _alpm_log(handle, ALPM_LOG_DEBUG, "missing optional signature\n");
778 handle->pm_errno = ALPM_ERR_OK;
779 ret = 0;
780 } else {
781 _alpm_log(handle, ALPM_LOG_DEBUG, "missing required signature\n");
782 /* ret will already be -1 */
783 }
784 } else if(ret) {
785 _alpm_log(handle, ALPM_LOG_DEBUG, "signature check failed\n");
786 /* ret will already be -1 */
787 } else {
788 size_t num;
789 for(num = 0; !ret && num < siglist->count; num++) {
790 switch(siglist->results[num].status) {
791 case ALPM_SIGSTATUS_VALID:
792 case ALPM_SIGSTATUS_KEY_EXPIRED:
793 _alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n");
794 switch(siglist->results[num].validity) {
795 case ALPM_SIGVALIDITY_FULL:
796 _alpm_log(handle, ALPM_LOG_DEBUG, "signature is fully trusted\n");
797 break;
798 case ALPM_SIGVALIDITY_MARGINAL:
799 _alpm_log(handle, ALPM_LOG_DEBUG, "signature is marginal trust\n");
800 if(!marginal) {
801 ret = -1;
802 }
803 break;
804 case ALPM_SIGVALIDITY_UNKNOWN:
805 _alpm_log(handle, ALPM_LOG_DEBUG, "signature is unknown trust\n");
806 if(!unknown) {
807 ret = -1;
808 }
809 break;
810 case ALPM_SIGVALIDITY_NEVER:
811 _alpm_log(handle, ALPM_LOG_DEBUG, "signature should never be trusted\n");
812 ret = -1;
813 break;
814 }
815 break;
816 case ALPM_SIGSTATUS_SIG_EXPIRED:
817 case ALPM_SIGSTATUS_KEY_UNKNOWN:
818 case ALPM_SIGSTATUS_KEY_DISABLED:
819 case ALPM_SIGSTATUS_INVALID:
820 _alpm_log(handle, ALPM_LOG_DEBUG, "signature is not valid\n");
821 ret = -1;
822 break;
823 }
824 }
825 }
826
827 if(sigdata) {
828 *sigdata = siglist;
829 } else {
830 alpm_siglist_cleanup(siglist);
831 free(siglist);
832 }
833
834 return ret;
835 }
836
837 /**
838 * Examine a signature result list and take any appropriate or necessary
839 * actions. This may include asking the user to import a key or simply printing
840 * helpful failure messages so the user can take action out of band.
841 * @param handle the context handle
842 * @param identifier a friendly name for the signed resource; usually a
843 * database or package name
844 * @param siglist a pointer to storage for signature results
845 * @param optional whether signatures are optional (e.g., missing OK)
846 * @param marginal whether signatures with marginal trust are acceptable
847 * @param unknown whether signatures with unknown trust are acceptable
848 * @return 0 if all signatures are OK, -1 on errors, 1 if we should retry the
849 * validation process
850 */
_alpm_process_siglist(alpm_handle_t * handle,const char * identifier,alpm_siglist_t * siglist,int optional,int marginal,int unknown)851 int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
852 alpm_siglist_t *siglist, int optional, int marginal, int unknown)
853 {
854 size_t i;
855 int retry = 0;
856
857 if(!optional && siglist->count == 0) {
858 _alpm_log(handle, ALPM_LOG_ERROR,
859 _("%s: missing required signature\n"), identifier);
860 }
861
862 for(i = 0; i < siglist->count; i++) {
863 alpm_sigresult_t *result = siglist->results + i;
864 const char *name = result->key.uid ? result->key.uid : result->key.fingerprint;
865 switch(result->status) {
866 case ALPM_SIGSTATUS_VALID:
867 case ALPM_SIGSTATUS_KEY_EXPIRED:
868 switch(result->validity) {
869 case ALPM_SIGVALIDITY_FULL:
870 break;
871 case ALPM_SIGVALIDITY_MARGINAL:
872 if(!marginal) {
873 _alpm_log(handle, ALPM_LOG_ERROR,
874 _("%s: signature from \"%s\" is marginal trust\n"),
875 identifier, name);
876 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
877 }
878 break;
879 case ALPM_SIGVALIDITY_UNKNOWN:
880 if(!unknown) {
881 _alpm_log(handle, ALPM_LOG_ERROR,
882 _("%s: signature from \"%s\" is unknown trust\n"),
883 identifier, name);
884 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
885 }
886 break;
887 case ALPM_SIGVALIDITY_NEVER:
888 _alpm_log(handle, ALPM_LOG_ERROR,
889 _("%s: signature from \"%s\" should never be trusted\n"),
890 identifier, name);
891 break;
892 }
893 break;
894 case ALPM_SIGSTATUS_KEY_UNKNOWN:
895 /* ensure this key is still actually unknown; we may have imported it
896 * on an earlier call to this function. */
897 if(_alpm_key_in_keychain(handle, result->key.fingerprint) == 1) {
898 break;
899 }
900 _alpm_log(handle, ALPM_LOG_ERROR,
901 _("%s: key \"%s\" is unknown\n"), identifier, name);
902
903 if(_alpm_key_import(handle, result->key.fingerprint) == 0) {
904 retry = 1;
905 }
906
907 break;
908 case ALPM_SIGSTATUS_KEY_DISABLED:
909 _alpm_log(handle, ALPM_LOG_ERROR,
910 _("%s: key \"%s\" is disabled\n"), identifier, name);
911 break;
912 case ALPM_SIGSTATUS_SIG_EXPIRED:
913 _alpm_log(handle, ALPM_LOG_ERROR,
914 _("%s: signature from \"%s\" is expired\n"), identifier, name);
915 break;
916 case ALPM_SIGSTATUS_INVALID:
917 _alpm_log(handle, ALPM_LOG_ERROR,
918 _("%s: signature from \"%s\" is invalid\n"),
919 identifier, name);
920 break;
921 }
922 }
923
924 return retry;
925 }
926
927 /**
928 * Check the PGP signature for the given package file.
929 * @param pkg the package to check
930 * @param siglist a pointer to storage for signature results
931 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
932 */
alpm_pkg_check_pgp_signature(alpm_pkg_t * pkg,alpm_siglist_t * siglist)933 int SYMEXPORT alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg,
934 alpm_siglist_t *siglist)
935 {
936 ASSERT(pkg != NULL, return -1);
937 ASSERT(siglist != NULL, RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1));
938 pkg->handle->pm_errno = ALPM_ERR_OK;
939
940 return _alpm_gpgme_checksig(pkg->handle, pkg->filename,
941 pkg->base64_sig, siglist);
942 }
943
944 /**
945 * Check the PGP signature for the given database.
946 * @param db the database to check
947 * @param siglist a pointer to storage for signature results
948 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
949 */
alpm_db_check_pgp_signature(alpm_db_t * db,alpm_siglist_t * siglist)950 int SYMEXPORT alpm_db_check_pgp_signature(alpm_db_t *db,
951 alpm_siglist_t *siglist)
952 {
953 ASSERT(db != NULL, return -1);
954 ASSERT(siglist != NULL, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
955 db->handle->pm_errno = ALPM_ERR_OK;
956
957 return _alpm_gpgme_checksig(db->handle, _alpm_db_path(db), NULL, siglist);
958 }
959
960 /**
961 * Clean up and free a signature result list.
962 * Note that this does not free the siglist object itself in case that
963 * was allocated on the stack; this is the responsibility of the caller.
964 * @param siglist a pointer to storage for signature results
965 * @return 0 on success, -1 on error
966 */
alpm_siglist_cleanup(alpm_siglist_t * siglist)967 int SYMEXPORT alpm_siglist_cleanup(alpm_siglist_t *siglist)
968 {
969 ASSERT(siglist != NULL, return -1);
970 size_t num;
971 for(num = 0; num < siglist->count; num++) {
972 alpm_sigresult_t *result = siglist->results + num;
973 if(result->key.data) {
974 #ifdef HAVE_LIBGPGME
975 gpgme_key_unref(result->key.data);
976 #endif
977 } else {
978 free(result->key.fingerprint);
979 }
980 }
981 if(siglist->count) {
982 free(siglist->results);
983 }
984 siglist->results = NULL;
985 siglist->count = 0;
986 return 0;
987 }
988
989 /* Check to avoid out of boundary reads */
length_check(size_t length,size_t position,size_t a,alpm_handle_t * handle,const char * identifier)990 static size_t length_check(size_t length, size_t position, size_t a,
991 alpm_handle_t *handle, const char *identifier)
992 {
993 if( a == 0 || length - position <= a) {
994 _alpm_log(handle, ALPM_LOG_ERROR,
995 _("%s: signature format error\n"), identifier);
996 return -1;
997 } else {
998 return 0;
999 }
1000 }
1001
parse_subpacket(alpm_handle_t * handle,const char * identifier,const unsigned char * sig,const size_t len,const size_t pos,const size_t plen,alpm_list_t ** keys)1002 static int parse_subpacket(alpm_handle_t *handle, const char *identifier,
1003 const unsigned char *sig, const size_t len, const size_t pos,
1004 const size_t plen, alpm_list_t **keys)
1005 {
1006 size_t slen;
1007 size_t spos = pos;
1008
1009 while(spos < pos + plen) {
1010 if(sig[spos] < 192) {
1011 slen = sig[spos];
1012 spos = spos + 1;
1013 } else if(sig[spos] < 255) {
1014 if(length_check(len, spos, 2, handle, identifier) != 0){
1015 return -1;
1016 }
1017 slen = (sig[spos] << 8) | sig[spos + 1];
1018 spos = spos + 2;
1019 } else {
1020 if(length_check(len, spos, 5, handle, identifier) != 0) {
1021 return -1;
1022 }
1023 slen = (sig[spos + 1] << 24) | (sig[spos + 2] << 16) | (sig[spos + 3] << 8) | sig[spos + 4];
1024 spos = spos + 5;
1025 }
1026 if(sig[spos] == 16) {
1027 /* issuer key ID */
1028 char key[17];
1029 size_t i;
1030 if(length_check(len, spos, 8, handle, identifier) != 0) {
1031 return -1;
1032 }
1033 for (i = 0; i < 8; i++) {
1034 sprintf(&key[i * 2], "%02X", sig[spos + i + 1]);
1035 }
1036 *keys = alpm_list_add(*keys, strdup(key));
1037 break;
1038 }
1039 if(length_check(len, spos, slen, handle, identifier) != 0) {
1040 return -1;
1041 }
1042 spos = spos + slen;
1043 }
1044 return 0;
1045 }
1046
1047 /**
1048 * Extract the Issuer Key ID from a signature
1049 * @param sig PGP signature
1050 * @param len length of signature
1051 * @param keys a pointer to storage for key IDs
1052 * @return 0 on success, -1 on error
1053 */
alpm_extract_keyid(alpm_handle_t * handle,const char * identifier,const unsigned char * sig,const size_t len,alpm_list_t ** keys)1054 int SYMEXPORT alpm_extract_keyid(alpm_handle_t *handle, const char *identifier,
1055 const unsigned char *sig, const size_t len, alpm_list_t **keys)
1056 {
1057 size_t pos, blen, hlen, ulen;
1058 pos = 0;
1059
1060 while(pos < len) {
1061 if(!(sig[pos] & 0x80)) {
1062 _alpm_log(handle, ALPM_LOG_ERROR,
1063 _("%s: signature format error\n"), identifier);
1064 return -1;
1065 }
1066
1067 if(sig[pos] & 0x40) {
1068 /* new packet format */
1069 if(length_check(len, pos, 1, handle, identifier) != 0) {
1070 return -1;
1071 }
1072 pos = pos + 1;
1073
1074 if(sig[pos] < 192) {
1075 if(length_check(len, pos, 1, handle, identifier) != 0) {
1076 return -1;
1077 }
1078 blen = sig[pos];
1079 pos = pos + 1;
1080 } else if (sig[pos] < 224) {
1081 if(length_check(len, pos, 2, handle, identifier) != 0) {
1082 return -1;
1083 }
1084 blen = ((sig[pos] - 192) << 8) + sig[pos + 1] + 192;
1085 pos = pos + 2;
1086 } else if (sig[pos] == 255) {
1087 if(length_check(len, pos, 5, handle, identifier)) {
1088 return -1;
1089 }
1090 blen = (sig[pos + 1] << 24) | (sig[pos + 2] << 16) | (sig[pos + 3] << 8) | sig[pos + 4];
1091 pos = pos + 5;
1092 } else {
1093 /* partial body length not supported */
1094 _alpm_log(handle, ALPM_LOG_ERROR,
1095 _("%s: unsupported signature format\n"), identifier);
1096 return -1;
1097 }
1098 } else {
1099 /* old package format */
1100 switch(sig[pos] & 0x03) {
1101 case 0:
1102 if(length_check(len, pos, 2, handle, identifier) != 0) {
1103 return -1;
1104 }
1105 blen = sig[pos + 1];
1106 pos = pos + 2;
1107 break;
1108
1109 case 1:
1110 if(length_check(len, pos, 3, handle, identifier) != 0) {
1111 return -1;
1112 }
1113 blen = (sig[pos + 1] << 8) | sig[pos + 2];
1114 pos = pos + 3;
1115 break;
1116
1117 case 2:
1118 if(length_check(len, pos, 5, handle, identifier) != 0) {
1119 return -1;
1120 }
1121 blen = (sig[pos + 1] << 24) | (sig[pos + 2] << 16) | (sig[pos + 3] << 8) | sig[pos + 4];
1122 pos = pos + 5;
1123 break;
1124
1125 case 3:
1126 /* partial body length not supported */
1127 _alpm_log(handle, ALPM_LOG_ERROR,
1128 _("%s: unsupported signature format\n"), identifier);
1129 return -1;
1130 }
1131 }
1132
1133 if(sig[pos] != 4) {
1134 /* only support version 4 signature packet format */
1135 _alpm_log(handle, ALPM_LOG_ERROR,
1136 _("%s: unsupported signature format\n"), identifier);
1137 return -1;
1138 }
1139 if(sig[pos + 1] != 0x00) {
1140 /* not a signature of a binary document */
1141 _alpm_log(handle, ALPM_LOG_ERROR,
1142 _("%s: signature format error\n"), identifier);
1143 return -1;
1144 }
1145 pos = pos + 4;
1146
1147 /* pos got changed above, so an explicit check is necessary
1148 * check for 2 as that catches another some lines down */
1149 if(length_check(len, pos, 2, handle, identifier)) {
1150 return -1;
1151 }
1152 hlen = (sig[pos] << 8) | sig[pos + 1];
1153 if(length_check(len, pos, hlen + 2, handle, identifier) != 0) {
1154 return -1;
1155 }
1156 pos = pos + 2;
1157
1158 if(parse_subpacket(handle, identifier, sig, len, pos, hlen, keys) == -1) {
1159 return -1;
1160 }
1161 pos = pos + hlen;
1162
1163 ulen = (sig[pos] << 8) | sig[pos + 1];
1164 if(length_check(len, pos, ulen + 2, handle, identifier) != 0) {
1165 return -1;
1166 }
1167 pos = pos + 2;
1168
1169 if(parse_subpacket(handle, identifier, sig, len, pos, ulen, keys) == -1) {
1170 return -1;
1171 }
1172 pos = pos + (blen - hlen - 8);
1173 }
1174
1175 return 0;
1176 }
1177