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