4 * Copyright (c) 2008-2011 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/>.
27 #include <locale.h> /* setlocale() */
41 #define CHECK_ERR(void) do { \
42 if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { goto error; } \
45 static const char *string_validity(gpgme_validity_t validity
)
48 case GPGME_VALIDITY_UNKNOWN
:
50 case GPGME_VALIDITY_UNDEFINED
:
52 case GPGME_VALIDITY_NEVER
:
54 case GPGME_VALIDITY_MARGINAL
:
56 case GPGME_VALIDITY_FULL
:
58 case GPGME_VALIDITY_ULTIMATE
:
64 static void sigsum_test_bit(gpgme_sigsum_t sigsum
, alpm_list_t
**summary
,
65 gpgme_sigsum_t bit
, const char *value
)
68 *summary
= alpm_list_add(*summary
, (void *)value
);
72 static alpm_list_t
*list_sigsum(gpgme_sigsum_t sigsum
)
74 alpm_list_t
*summary
= NULL
;
75 /* The docs say this can be a bitmask...not sure I believe it, but we'll code
76 * for it anyway and show all possible flags in the returned string. */
78 /* The signature is fully valid. */
79 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_VALID
, "valid");
80 /* The signature is good. */
81 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_GREEN
, "green");
82 /* The signature is bad. */
83 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_RED
, "red");
84 /* One key has been revoked. */
85 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_REVOKED
, "key revoked");
86 /* One key has expired. */
87 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_EXPIRED
, "key expired");
88 /* The signature has expired. */
89 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SIG_EXPIRED
, "sig expired");
90 /* Can't verify: key missing. */
91 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_MISSING
, "key missing");
92 /* CRL not available. */
93 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_MISSING
, "crl missing");
94 /* Available CRL is too old. */
95 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_TOO_OLD
, "crl too old");
96 /* A policy was not met. */
97 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_BAD_POLICY
, "bad policy");
98 /* A system error occured. */
99 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SYS_ERROR
, "sys error");
102 summary
= alpm_list_add(summary
, (void *)"(empty)");
107 static int init_gpgme(alpm_handle_t
*handle
)
110 const char *version
, *sigdir
;
112 gpgme_engine_info_t enginfo
;
115 /* we already successfully initialized the library */
119 sigdir
= alpm_option_get_gpgdir(handle
);
121 if (_alpm_access(handle
, sigdir
, "pubring.gpg", R_OK
)
122 || _alpm_access(handle
, sigdir
, "trustdb.gpg", R_OK
)) {
123 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
124 _alpm_log(handle
, ALPM_LOG_DEBUG
, "Signature verification will fail!\n");
127 /* calling gpgme_check_version() returns the current version and runs
128 * some internal library setup code */
129 version
= gpgme_check_version(NULL
);
130 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME version: %s\n", version
);
131 gpgme_set_locale(NULL
, LC_CTYPE
, setlocale(LC_CTYPE
, NULL
));
133 gpgme_set_locale(NULL
, LC_MESSAGES
, setlocale(LC_MESSAGES
, NULL
));
136 * The GPGME library installs a SIGPIPE signal handler automatically if
137 * the default signal hander is in use. The only time we set a handler
138 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
139 * we do this, we can let GPGME do its automagic. However, if we install
140 * a library-wide SIGPIPE handler, we will have to be careful.
143 /* check for OpenPGP support (should be a no-brainer, but be safe) */
144 err
= gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP
);
147 /* set and check engine information */
148 err
= gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP
, NULL
, sigdir
);
150 err
= gpgme_get_engine_info(&enginfo
);
152 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME engine info: file=%s, home=%s\n",
153 enginfo
->file_name
, enginfo
->home_dir
);
159 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
160 RET_ERR(handle
, ALPM_ERR_GPGME
, 1);
164 * Decode a loaded signature in base64 form.
165 * @param base64_data the signature to attempt to decode
166 * @param data the decoded data; must be freed by the caller
167 * @param data_len the length of the returned data
168 * @return 0 on success, 1 on failure to properly decode
170 static int decode_signature(const char *base64_data
,
171 unsigned char **data
, int *data_len
) {
172 unsigned char *usline
;
175 len
= strlen(base64_data
);
176 usline
= (unsigned char *)base64_data
;
177 int ret
, destlen
= 0;
178 /* get the necessary size for the buffer by passing 0 */
179 ret
= base64_decode(NULL
, &destlen
, usline
, len
);
180 if(ret
!= 0 && ret
!= POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL
) {
183 /* alloc our memory and repeat the call to decode */
184 MALLOC(*data
, (size_t)destlen
, goto error
);
185 ret
= base64_decode(*data
, &destlen
, usline
, len
);
199 * Check the PGP signature for the given file path.
200 * If base64_sig is provided, it will be used as the signature data after
201 * decoding. If base64_sig is NULL, expect a signature file next to path
204 * The return value will be 0 if nothing abnormal happened during the signature
205 * check, and -1 if an error occurred while checking signatures or if a
206 * signature could not be found; pm_errno will be set. Note that "abnormal"
207 * does not include a failed signature; the value in #result should be checked
208 * to determine if the signature(s) are good.
209 * @param handle the context handle
210 * @param path the full path to a file
211 * @param base64_sig optional PGP signature data in base64 encoding
213 * @return 0 in normal cases, -1 if the something failed in the check process
215 int _alpm_gpgme_checksig(alpm_handle_t
*handle
, const char *path
,
216 const char *base64_sig
, alpm_sigresult_t
*result
)
218 int ret
= -1, sigcount
;
221 gpgme_data_t filedata
, sigdata
;
222 gpgme_verify_result_t verify_result
;
223 gpgme_signature_t gpgsig
;
224 char *sigpath
= NULL
;
225 unsigned char *decoded_sigdata
= NULL
;
226 FILE *file
= NULL
, *sigfile
= NULL
;
228 if(!path
|| _alpm_access(handle
, NULL
, path
, R_OK
) != 0) {
229 RET_ERR(handle
, ALPM_ERR_NOT_A_FILE
, -1);
233 RET_ERR(handle
, ALPM_ERR_WRONG_ARGS
, -1);
238 size_t len
= strlen(path
) + 5;
239 CALLOC(sigpath
, len
, sizeof(char), RET_ERR(handle
, ALPM_ERR_MEMORY
, -1));
240 snprintf(sigpath
, len
, "%s.sig", path
);
242 if(!_alpm_access(handle
, NULL
, sigpath
, R_OK
) == 0) {
247 if(init_gpgme(handle
)) {
248 /* pm_errno was set in gpgme_init() */
252 _alpm_log(handle
, ALPM_LOG_DEBUG
, "checking signature for %s\n", path
);
254 memset(&ctx
, 0, sizeof(ctx
));
255 memset(&sigdata
, 0, sizeof(sigdata
));
256 memset(&filedata
, 0, sizeof(filedata
));
258 err
= gpgme_new(&ctx
);
261 /* create our necessary data objects to verify the signature */
262 file
= fopen(path
, "rb");
264 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
267 err
= gpgme_data_new_from_stream(&filedata
, file
);
270 /* next create data object for the signature */
272 /* memory-based, we loaded it from a sync DB */
274 int decode_ret
= decode_signature(base64_sig
,
275 &decoded_sigdata
, &data_len
);
277 handle
->pm_errno
= ALPM_ERR_SIG_INVALID
;
280 err
= gpgme_data_new_from_mem(&sigdata
,
281 (char *)decoded_sigdata
, data_len
, 0);
283 /* file-based, it is on disk */
284 sigfile
= fopen(sigpath
, "rb");
285 if(sigfile
== NULL
) {
286 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
289 err
= gpgme_data_new_from_stream(&sigdata
, sigfile
);
293 /* here's where the magic happens */
294 err
= gpgme_op_verify(ctx
, sigdata
, filedata
, NULL
);
296 verify_result
= gpgme_op_verify_result(ctx
);
298 if(!verify_result
|| !verify_result
->signatures
) {
299 _alpm_log(handle
, ALPM_LOG_DEBUG
, "no signatures returned\n");
300 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
303 for(gpgsig
= verify_result
->signatures
, sigcount
= 0;
304 gpgsig
; gpgsig
= gpgsig
->next
, sigcount
++);
305 _alpm_log(handle
, ALPM_LOG_DEBUG
, "%d signatures returned\n", sigcount
);
307 result
->status
= calloc(sigcount
, sizeof(alpm_sigstatus_t
));
308 result
->uid
= calloc(sigcount
, sizeof(char*));
309 if(!result
->status
|| !result
->uid
) {
310 handle
->pm_errno
= ALPM_ERR_MEMORY
;
313 result
->count
= sigcount
;
315 for(gpgsig
= verify_result
->signatures
, sigcount
= 0; gpgsig
;
316 gpgsig
= gpgsig
->next
, sigcount
++) {
317 alpm_list_t
*summary_list
, *summary
;
318 alpm_sigstatus_t status
;
321 _alpm_log(handle
, ALPM_LOG_DEBUG
, "fingerprint: %s\n", gpgsig
->fpr
);
322 summary_list
= list_sigsum(gpgsig
->summary
);
323 for(summary
= summary_list
; summary
; summary
= summary
->next
) {
324 _alpm_log(handle
, ALPM_LOG_DEBUG
, "summary: %s\n", (const char *)summary
->data
);
326 alpm_list_free(summary_list
);
327 _alpm_log(handle
, ALPM_LOG_DEBUG
, "status: %s\n", gpgme_strerror(gpgsig
->status
));
328 _alpm_log(handle
, ALPM_LOG_DEBUG
, "timestamp: %lu\n", gpgsig
->timestamp
);
329 _alpm_log(handle
, ALPM_LOG_DEBUG
, "exp_timestamp: %lu\n", gpgsig
->exp_timestamp
);
330 _alpm_log(handle
, ALPM_LOG_DEBUG
, "validity: %s; reason: %s\n",
331 string_validity(gpgsig
->validity
),
332 gpgme_strerror(gpgsig
->validity_reason
));
334 err
= gpgme_get_key(ctx
, gpgsig
->fpr
, &key
, 0);
335 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
336 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
337 err
= GPG_ERR_NO_ERROR
;
341 const char *uid
= key
->uids
->uid
;
342 STRDUP(result
->uid
[sigcount
], uid
,
343 handle
->pm_errno
= ALPM_ERR_MEMORY
; goto error
);
344 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key user: %s\n", uid
);
346 gpgme_key_unref(key
);
349 if(gpgsig
->summary
& GPGME_SIGSUM_VALID
) {
350 /* definite good signature */
351 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: valid signature\n");
352 status
= ALPM_SIGSTATUS_VALID
;
353 } else if(gpgsig
->summary
& GPGME_SIGSUM_GREEN
) {
355 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: green signature\n");
356 status
= ALPM_SIGSTATUS_VALID
;
357 } else if(gpgsig
->summary
& GPGME_SIGSUM_RED
) {
358 /* definite bad signature, error */
359 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: red signature\n");
360 status
= ALPM_SIGSTATUS_BAD
;
361 } else if(gpgsig
->summary
& GPGME_SIGSUM_KEY_MISSING
) {
362 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: signature from unknown key\n");
363 status
= ALPM_SIGSTATUS_UNKNOWN
;
364 } else if(gpgsig
->summary
& GPGME_SIGSUM_KEY_EXPIRED
) {
365 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: key expired\n");
366 status
= ALPM_SIGSTATUS_BAD
;
367 } else if(gpgsig
->summary
& GPGME_SIGSUM_SIG_EXPIRED
) {
368 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: signature expired\n");
369 status
= ALPM_SIGSTATUS_BAD
;
371 /* we'll capture everything else here */
372 _alpm_log(handle
, ALPM_LOG_DEBUG
, "result: invalid signature\n");
373 status
= ALPM_SIGSTATUS_BAD
;
376 result
->status
[sigcount
] = status
;
382 gpgme_data_release(sigdata
);
383 gpgme_data_release(filedata
);
392 FREE(decoded_sigdata
);
393 if(gpg_err_code(err
) != GPG_ERR_NO_ERROR
) {
394 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
395 RET_ERR(handle
, ALPM_ERR_GPGME
, -1);
400 int _alpm_gpgme_checksig(alpm_handle_t UNUSED
*handle
, const char UNUSED
*path
,
401 const char UNUSED
*base64_sig
, alpm_sigresult_t UNUSED
*result
)
407 int _alpm_check_pgp_helper(alpm_handle_t
*handle
, const char *path
,
408 const char *base64_sig
, int optional
, int marginal
, int unknown
,
409 enum _alpm_errno_t invalid_err
)
411 alpm_sigresult_t result
;
414 memset(&result
, 0, sizeof(result
));
416 _alpm_log(handle
, ALPM_LOG_DEBUG
, "checking signatures for %s\n", path
);
417 ret
= _alpm_gpgme_checksig(handle
, path
, base64_sig
, &result
);
418 if(ret
&& handle
->pm_errno
== ALPM_ERR_SIG_MISSING
) {
420 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing optional signature\n");
421 handle
->pm_errno
= 0;
424 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing required signature\n");
425 /* ret will already be -1 */
428 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature check failed\n");
429 /* ret will already be -1 */
432 for(num
= 0; num
< result
.count
; num
++) {
433 /* fallthrough in this case block is on purpose. if one allows unknown
434 * signatures, then a marginal signature should be allowed as well, and
435 * if neither of these are allowed we fall all the way through to bad. */
436 switch(result
.status
[num
]) {
437 case ALPM_SIGSTATUS_VALID
:
438 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is valid\n");
440 case ALPM_SIGSTATUS_MARGINAL
:
442 _alpm_log(handle
, ALPM_LOG_DEBUG
, "allowing marginal signature\n");
445 case ALPM_SIGSTATUS_UNKNOWN
:
447 _alpm_log(handle
, ALPM_LOG_DEBUG
, "allowing unknown signature\n");
450 case ALPM_SIGSTATUS_BAD
:
452 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is invalid\n");
453 handle
->pm_errno
= invalid_err
;
459 alpm_sigresult_cleanup(&result
);
464 * Check the PGP signature for the given package file.
465 * @param pkg the package to check
466 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
468 int SYMEXPORT
alpm_pkg_check_pgp_signature(alpm_pkg_t
*pkg
,
469 alpm_sigresult_t
*result
)
471 ASSERT(pkg
!= NULL
, return -1);
472 ASSERT(result
!= NULL
, RET_ERR(pkg
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
473 pkg
->handle
->pm_errno
= 0;
475 return _alpm_gpgme_checksig(pkg
->handle
, alpm_pkg_get_filename(pkg
),
476 pkg
->base64_sig
, result
);
480 * Check the PGP signature for the given database.
481 * @param db the database to check
482 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
484 int SYMEXPORT
alpm_db_check_pgp_signature(alpm_db_t
*db
,
485 alpm_sigresult_t
*result
)
487 ASSERT(db
!= NULL
, return -1);
488 ASSERT(result
!= NULL
, RET_ERR(db
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
489 db
->handle
->pm_errno
= 0;
491 return _alpm_gpgme_checksig(db
->handle
, _alpm_db_path(db
), NULL
, result
);
494 int SYMEXPORT
alpm_sigresult_cleanup(alpm_sigresult_t
*result
)
496 ASSERT(result
!= NULL
, return -1);
497 /* Because it is likely result is on the stack, uid and status may have bogus
498 * values in the struct. Only look at them if count is greater than 0. */
499 if(result
->count
> 0) {
500 free(result
->status
);
503 for(i
= 0; i
< result
->count
; i
++) {
504 free(result
->uid
[i
]);
512 /* vim: set ts=2 sw=2 noet: */