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(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 RET_ERR(handle
, PM_ERR_SIG_MISSINGDIR
, 1);
124 /* calling gpgme_check_version() returns the current version and runs
125 * some internal library setup code */
126 version
= gpgme_check_version(NULL
);
127 _alpm_log(handle
, PM_LOG_DEBUG
, "GPGME version: %s\n", version
);
128 gpgme_set_locale(NULL
, LC_CTYPE
, setlocale(LC_CTYPE
, NULL
));
130 gpgme_set_locale(NULL
, LC_MESSAGES
, setlocale(LC_MESSAGES
, NULL
));
133 * The GPGME library installs a SIGPIPE signal handler automatically if
134 * the default signal hander is in use. The only time we set a handler
135 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
136 * we do this, we can let GPGME do its automagic. However, if we install
137 * a library-wide SIGPIPE handler, we will have to be careful.
140 /* check for OpenPGP support (should be a no-brainer, but be safe) */
141 err
= gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP
);
144 /* set and check engine information */
145 err
= gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP
, NULL
, sigdir
);
147 err
= gpgme_get_engine_info(&enginfo
);
149 _alpm_log(handle
, PM_LOG_DEBUG
, "GPGME engine info: file=%s, home=%s\n",
150 enginfo
->file_name
, enginfo
->home_dir
);
156 _alpm_log(handle
, PM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
157 RET_ERR(handle
, PM_ERR_GPGME
, 1);
161 * Decode a loaded signature in base64 form.
162 * @param base64_data the signature to attempt to decode
163 * @param data the decoded data; must be freed by the caller
164 * @param data_len the length of the returned data
165 * @return 0 on success, 1 on failure to properly decode
167 static int decode_signature(const char *base64_data
,
168 unsigned char **data
, int *data_len
) {
169 unsigned char *usline
;
172 len
= strlen(base64_data
);
173 usline
= (unsigned char *)base64_data
;
174 int ret
, destlen
= 0;
175 /* get the necessary size for the buffer by passing 0 */
176 ret
= base64_decode(NULL
, &destlen
, usline
, len
);
177 if(ret
!= 0 && ret
!= POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL
) {
180 /* alloc our memory and repeat the call to decode */
181 MALLOC(*data
, (size_t)destlen
, goto error
);
182 ret
= base64_decode(*data
, &destlen
, usline
, len
);
196 * Check the PGP signature for the given file path.
197 * If base64_sig is provided, it will be used as the signature data after
198 * decoding. If base64_sig is NULL, expect a signature file next to path
199 * (e.g. "%s.sig"). The return value will be 0 if all checked signatures are
200 * valid, 1 if there was some sort of problem (but not necessarily rejection),
201 * and -1 if an error occurred while checking signatures. If 1 is returned,
202 * pm_errno should be checked to see why the signatures did not pass muster.
203 * @param handle the context handle
204 * @param path the full path to a file
205 * @param base64_sig optional PGP signature data in base64 encoding
206 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
208 int _alpm_gpgme_checksig(alpm_handle_t
*handle
, const char *path
,
209 const char *base64_sig
)
214 gpgme_data_t filedata
, sigdata
;
215 gpgme_verify_result_t result
;
216 gpgme_signature_t gpgsig
;
217 char *sigpath
= NULL
;
218 unsigned char *decoded_sigdata
= NULL
;
219 FILE *file
= NULL
, *sigfile
= NULL
;
221 if(!path
|| access(path
, R_OK
) != 0) {
222 RET_ERR(handle
, PM_ERR_NOT_A_FILE
, -1);
226 size_t len
= strlen(path
) + 5;
227 CALLOC(sigpath
, len
, sizeof(char), RET_ERR(handle
, PM_ERR_MEMORY
, -1));
228 snprintf(sigpath
, len
, "%s.sig", path
);
230 if(!access(sigpath
, R_OK
) == 0) {
232 RET_ERR(handle
, PM_ERR_SIG_UNKNOWN
, -1);
236 if(init_gpgme(handle
)) {
237 /* pm_errno was set in gpgme_init() */
241 _alpm_log(handle
, PM_LOG_DEBUG
, "checking signature for %s\n", path
);
243 memset(&ctx
, 0, sizeof(ctx
));
244 memset(&sigdata
, 0, sizeof(sigdata
));
245 memset(&filedata
, 0, sizeof(filedata
));
247 err
= gpgme_new(&ctx
);
250 /* create our necessary data objects to verify the signature */
251 file
= fopen(path
, "rb");
253 handle
->pm_errno
= PM_ERR_NOT_A_FILE
;
257 err
= gpgme_data_new_from_stream(&filedata
, file
);
260 /* next create data object for the signature */
262 /* memory-based, we loaded it from a sync DB */
264 int decode_ret
= decode_signature(base64_sig
,
265 &decoded_sigdata
, &data_len
);
270 err
= gpgme_data_new_from_mem(&sigdata
,
271 (char *)decoded_sigdata
, data_len
, 0);
273 /* file-based, it is on disk */
274 sigfile
= fopen(sigpath
, "rb");
275 if(sigfile
== NULL
) {
276 handle
->pm_errno
= PM_ERR_NOT_A_FILE
;
280 err
= gpgme_data_new_from_stream(&sigdata
, sigfile
);
284 /* here's where the magic happens */
285 err
= gpgme_op_verify(ctx
, sigdata
, filedata
, NULL
);
287 result
= gpgme_op_verify_result(ctx
);
288 gpgsig
= result
->signatures
;
290 _alpm_log(handle
, PM_LOG_DEBUG
, "no signatures returned\n");
296 alpm_list_t
*summary_list
, *summary
;
298 _alpm_log(handle
, PM_LOG_DEBUG
, "fingerprint: %s\n", gpgsig
->fpr
);
299 summary_list
= list_sigsum(gpgsig
->summary
);
300 for(summary
= summary_list
; summary
; summary
= summary
->next
) {
301 _alpm_log(handle
, PM_LOG_DEBUG
, "summary: %s\n", (const char *)summary
->data
);
303 alpm_list_free(summary_list
);
304 _alpm_log(handle
, PM_LOG_DEBUG
, "status: %s\n", gpgme_strerror(gpgsig
->status
));
305 _alpm_log(handle
, PM_LOG_DEBUG
, "timestamp: %lu\n", gpgsig
->timestamp
);
306 _alpm_log(handle
, PM_LOG_DEBUG
, "exp_timestamp: %lu\n", gpgsig
->exp_timestamp
);
307 _alpm_log(handle
, PM_LOG_DEBUG
, "validity: %s\n",
308 string_validity(gpgsig
->validity
));
309 _alpm_log(handle
, PM_LOG_DEBUG
, "validity_reason: %s\n",
310 gpgme_strerror(gpgsig
->validity_reason
));
311 _alpm_log(handle
, PM_LOG_DEBUG
, "pubkey algo: %s\n",
312 gpgme_pubkey_algo_name(gpgsig
->pubkey_algo
));
313 _alpm_log(handle
, PM_LOG_DEBUG
, "hash algo: %s\n",
314 gpgme_hash_algo_name(gpgsig
->hash_algo
));
317 if(gpgsig
->summary
& GPGME_SIGSUM_VALID
) {
318 /* good signature, continue */
319 _alpm_log(handle
, PM_LOG_DEBUG
, _("File %s has a valid signature.\n"),
321 } else if(gpgsig
->summary
& GPGME_SIGSUM_GREEN
) {
322 /* 'green' signature, not sure what to do here */
323 _alpm_log(handle
, PM_LOG_WARNING
, _("File %s has a green signature.\n"),
325 } else if(gpgsig
->summary
& GPGME_SIGSUM_KEY_MISSING
) {
326 handle
->pm_errno
= PM_ERR_SIG_UNKNOWN
;
327 _alpm_log(handle
, PM_LOG_WARNING
, _("File %s has a signature from an unknown key.\n"),
331 /* we'll capture everything else here */
332 handle
->pm_errno
= PM_ERR_SIG_INVALID
;
333 _alpm_log(handle
, PM_LOG_ERROR
, _("File %s has an invalid signature.\n"),
339 gpgme_data_release(sigdata
);
340 gpgme_data_release(filedata
);
349 FREE(decoded_sigdata
);
350 if(err
!= GPG_ERR_NO_ERROR
) {
351 _alpm_log(handle
, PM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
352 RET_ERR(handle
, PM_ERR_GPGME
, -1);
357 int _alpm_gpgme_checksig(alpm_handle_t
*handle
, const char *path
,
358 const char *base64_sig
)
365 * Determines the necessity of checking for a valid PGP signature
366 * @param db the sync database to query
368 * @return signature verification level
370 pgp_verify_t
_alpm_db_get_sigverify_level(alpm_db_t
*db
)
372 if(db
->pgp_verify
!= PM_PGP_VERIFY_UNKNOWN
) {
373 return db
->pgp_verify
;
375 return alpm_option_get_default_sigverify(db
->handle
);
380 * Check the PGP signature for the given package file.
381 * @param pkg the package to check
382 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
384 int SYMEXPORT
alpm_pkg_check_pgp_signature(alpm_pkg_t
*pkg
)
386 ASSERT(pkg
!= NULL
, return -1);
387 pkg
->handle
->pm_errno
= 0;
389 return _alpm_gpgme_checksig(pkg
->handle
, alpm_pkg_get_filename(pkg
),
394 * Check the PGP signature for the given database.
395 * @param db the database to check
396 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
398 int SYMEXPORT
alpm_db_check_pgp_signature(alpm_db_t
*db
)
400 ASSERT(db
!= NULL
, return -1);
401 db
->handle
->pm_errno
= 0;
403 return _alpm_gpgme_checksig(db
->handle
, _alpm_db_path(db
), NULL
);
406 /* vim: set ts=2 sw=2 noet: */