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/>.
25 #include <locale.h> /* setlocale() */
35 #define CHECK_ERR(void) do { \
36 if(err != GPG_ERR_NO_ERROR) { goto error; } \
39 static int gpgme_init(void)
44 gpgme_engine_info_t enginfo
;
49 /* we already successfully initialized the library */
53 if(!alpm_option_get_signaturedir()) {
54 RET_ERR(PM_ERR_SIG_MISSINGDIR
, 1);
57 /* calling gpgme_check_version() returns the current version and runs
58 * some internal library setup code */
59 version
= gpgme_check_version(NULL
);
60 _alpm_log(PM_LOG_DEBUG
, "GPGME version: %s\n", version
);
61 gpgme_set_locale(NULL
, LC_CTYPE
, setlocale(LC_CTYPE
, NULL
));
63 gpgme_set_locale(NULL
, LC_MESSAGES
, setlocale(LC_MESSAGES
, NULL
));
66 * The GPGME library installs a SIGPIPE signal handler automatically if
67 * the default signal hander is in use. The only time we set a handler
68 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
69 * we do this, we can let GPGME do its automagic. However, if we install
70 * a library-wide SIGPIPE handler, we will have to be careful.
73 /* check for OpenPGP support (should be a no-brainer, but be safe) */
74 err
= gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP
);
77 /* set and check engine information */
78 err
= gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP
, NULL
,
79 alpm_option_get_signaturedir());
81 err
= gpgme_get_engine_info(&enginfo
);
83 _alpm_log(PM_LOG_DEBUG
, "GPGME engine info: file=%s, home=%s\n",
84 enginfo
->file_name
, enginfo
->home_dir
);
90 _alpm_log(PM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
91 RET_ERR(PM_ERR_GPGME
, 1);
95 * Check the PGP package signature for the given file.
96 * @param path the full path to a file
97 * @param sig PGP signature data in raw form (already decoded)
98 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
100 int _alpm_gpgme_checksig(const char *path
, const pmpgpsig_t
*sig
)
105 gpgme_data_t filedata
, sigdata
;
106 gpgme_verify_result_t result
;
107 gpgme_signature_t gpgsig
;
108 FILE *file
= NULL
, *sigfile
= NULL
;
112 if(!sig
|| !sig
->data
) {
113 RET_ERR(PM_ERR_SIG_UNKNOWN
, -1);
115 if(!path
|| access(path
, R_OK
) != 0) {
116 RET_ERR(PM_ERR_NOT_A_FILE
, -1);
119 /* pm_errno was set in gpgme_init() */
123 _alpm_log(PM_LOG_DEBUG
, "checking signature for %s\n", path
);
125 memset(&ctx
, 0, sizeof(ctx
));
126 memset(&sigdata
, 0, sizeof(sigdata
));
127 memset(&filedata
, 0, sizeof(filedata
));
129 err
= gpgme_new(&ctx
);
132 /* create our necessary data objects to verify the signature */
133 file
= fopen(path
, "rb");
135 pm_errno
= PM_ERR_NOT_A_FILE
;
139 err
= gpgme_data_new_from_stream(&filedata
, file
);
142 /* next create data object for the signature */
143 err
= gpgme_data_new_from_mem(&sigdata
, (char *)sig
->data
, sig
->len
, 0);
146 /* here's where the magic happens */
147 err
= gpgme_op_verify(ctx
, sigdata
, filedata
, NULL
);
149 result
= gpgme_op_verify_result(ctx
);
150 gpgsig
= result
->signatures
;
151 if(!gpgsig
|| gpgsig
->next
) {
152 _alpm_log(PM_LOG_ERROR
, _("Unexpected number of signatures\n"));
156 _alpm_log(PM_LOG_DEBUG
, "summary=%x\n", gpgsig
->summary
);
157 _alpm_log(PM_LOG_DEBUG
, "fpr=%s\n", gpgsig
->fpr
);
158 _alpm_log(PM_LOG_DEBUG
, "status=%d\n", gpgsig
->status
);
159 _alpm_log(PM_LOG_DEBUG
, "timestamp=%lu\n", gpgsig
->timestamp
);
160 _alpm_log(PM_LOG_DEBUG
, "wrong_key_usage=%u\n", gpgsig
->wrong_key_usage
);
161 _alpm_log(PM_LOG_DEBUG
, "pka_trust=%u\n", gpgsig
->pka_trust
);
162 _alpm_log(PM_LOG_DEBUG
, "chain_model=%u\n", gpgsig
->chain_model
);
163 _alpm_log(PM_LOG_DEBUG
, "validity=%d\n", gpgsig
->validity
);
164 _alpm_log(PM_LOG_DEBUG
, "validity_reason=%d\n", gpgsig
->validity_reason
);
165 _alpm_log(PM_LOG_DEBUG
, "key=%d\n", gpgsig
->pubkey_algo
);
166 _alpm_log(PM_LOG_DEBUG
, "hash=%d\n", gpgsig
->hash_algo
);
168 if(gpgsig
->summary
& GPGME_SIGSUM_VALID
) {
169 /* good signature, continue */
170 _alpm_log(PM_LOG_DEBUG
, _("File %s has a valid signature.\n"),
172 } else if(gpgsig
->summary
& GPGME_SIGSUM_GREEN
) {
173 /* 'green' signature, not sure what to do here */
174 _alpm_log(PM_LOG_WARNING
, _("File %s has a green signature.\n"),
176 } else if(gpgsig
->summary
& GPGME_SIGSUM_KEY_MISSING
) {
177 pm_errno
= PM_ERR_SIG_UNKNOWN
;
178 _alpm_log(PM_LOG_WARNING
, _("File %s has a signature from an unknown key.\n"),
182 /* we'll capture everything else here */
183 pm_errno
= PM_ERR_SIG_INVALID
;
184 _alpm_log(PM_LOG_ERROR
, _("File %s has an invalid signature.\n"),
190 gpgme_data_release(sigdata
);
191 gpgme_data_release(filedata
);
199 if(err
!= GPG_ERR_NO_ERROR
) {
200 _alpm_log(PM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
201 RET_ERR(PM_ERR_GPGME
, -1);
207 * Load the signature from the given path into the provided struct.
208 * @param sigfile the signature to attempt to load
209 * @param pgpsig the struct to place the data in
211 * @return 0 on success, 1 on file not found, -1 on error
213 int _alpm_load_signature(const char *file
, pmpgpsig_t
*pgpsig
) {
218 /* look around for a PGP signature file; load if available */
219 MALLOC(sigfile
, strlen(file
) + 5, RET_ERR(PM_ERR_MEMORY
, -1));
220 sprintf(sigfile
, "%s.sig", file
);
222 if(access(sigfile
, R_OK
) == 0 && stat(sigfile
, &st
) == 0) {
226 if(st
.st_size
> 4096 || (f
= fopen(sigfile
, "rb")) == NULL
) {
230 CALLOC(pgpsig
->data
, st
.st_size
, sizeof(unsigned char),
231 RET_ERR(PM_ERR_MEMORY
, -1));
232 bytes_read
= fread(pgpsig
->data
, sizeof(char), st
.st_size
, f
);
233 if(bytes_read
== (size_t)st
.st_size
) {
234 pgpsig
->len
= bytes_read
;
235 _alpm_log(PM_LOG_DEBUG
, "loaded gpg signature file, location %s\n",
239 _alpm_log(PM_LOG_WARNING
, _("Failed reading PGP signature file %s"),
246 _alpm_log(PM_LOG_DEBUG
, "signature file %s not found\n", sigfile
);
247 /* not fatal...we return a different error code here */
256 * Determines the necessity of checking for a valid PGP signature
257 * @param db the sync database to query
259 * @return signature verification level
261 pgp_verify_t
_alpm_db_get_sigverify_level(pmdb_t
*db
)
264 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, PM_PGP_VERIFY_UNKNOWN
));
266 if(db
->pgp_verify
!= PM_PGP_VERIFY_UNKNOWN
) {
267 return db
->pgp_verify
;
269 return alpm_option_get_default_sigverify();
274 * Check the PGP package signature for the given package file.
275 * @param pkg the package to check
276 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
278 int SYMEXPORT
alpm_pkg_check_pgp_signature(pmpkg_t
*pkg
)
281 ASSERT(pkg
!= NULL
, return 0);
283 return _alpm_gpgme_checksig(alpm_pkg_get_filename(pkg
),
284 alpm_pkg_get_pgpsig(pkg
));
288 * Check the PGP package signature for the given database.
289 * @param db the database to check
290 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
292 int SYMEXPORT
alpm_db_check_pgp_signature(pmdb_t
*db
)
295 ASSERT(db
!= NULL
, return 0);
297 return _alpm_gpgme_checksig(_alpm_db_path(db
),
298 _alpm_db_pgpsig(db
));
301 /* vim: set ts=2 sw=2 noet: */