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 package file.
96 * @param pkgpath the full path to a package 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 *pkgpath
, const pmpgpsig_t
*sig
)
105 gpgme_data_t pkgdata
, sigdata
;
106 gpgme_verify_result_t result
;
107 gpgme_signature_t gpgsig
;
108 FILE *pkgfile
= NULL
, *sigfile
= NULL
;
112 if(!sig
|| !sig
->rawdata
) {
113 RET_ERR(PM_ERR_SIG_UNKNOWN
, -1);
115 if(!pkgpath
|| access(pkgpath
, R_OK
) != 0) {
116 RET_ERR(PM_ERR_PKG_NOT_FOUND
, -1);
119 /* pm_errno was set in gpgme_init() */
123 _alpm_log(PM_LOG_DEBUG
, "checking package signature for %s\n", pkgpath
);
125 memset(&ctx
, 0, sizeof(ctx
));
126 memset(&sigdata
, 0, sizeof(sigdata
));
127 memset(&pkgdata
, 0, sizeof(pkgdata
));
129 err
= gpgme_new(&ctx
);
132 /* create our necessary data objects to verify the signature */
133 /* first the package itself */
134 pkgfile
= fopen(pkgpath
, "rb");
135 if(pkgfile
== NULL
) {
136 pm_errno
= PM_ERR_PKG_OPEN
;
140 err
= gpgme_data_new_from_stream(&pkgdata
, pkgfile
);
143 /* next create data object for the signature */
144 err
= gpgme_data_new_from_mem(&sigdata
, (char*)sig
->rawdata
, sig
->rawlen
, 0);
147 /* here's where the magic happens */
148 err
= gpgme_op_verify(ctx
, sigdata
, pkgdata
, NULL
);
150 result
= gpgme_op_verify_result(ctx
);
151 gpgsig
= result
->signatures
;
152 if (!gpgsig
|| gpgsig
->next
) {
153 _alpm_log(PM_LOG_ERROR
, _("Unexpected number of signatures\n"));
157 fprintf(stdout
, "\nsummary=%x\n", gpgsig
->summary
);
158 fprintf(stdout
, "fpr=%s\n", gpgsig
->fpr
);
159 fprintf(stdout
, "status=%d\n", gpgsig
->status
);
160 fprintf(stdout
, "timestamp=%lu\n", gpgsig
->timestamp
);
161 fprintf(stdout
, "wrong_key_usage=%u\n", gpgsig
->wrong_key_usage
);
162 fprintf(stdout
, "pka_trust=%u\n", gpgsig
->pka_trust
);
163 fprintf(stdout
, "chain_model=%u\n", gpgsig
->chain_model
);
164 fprintf(stdout
, "validity=%d\n", gpgsig
->validity
);
165 fprintf(stdout
, "validity_reason=%d\n", gpgsig
->validity_reason
);
166 fprintf(stdout
, "key=%d\n", gpgsig
->pubkey_algo
);
167 fprintf(stdout
, "hash=%d\n", gpgsig
->hash_algo
);
169 if(gpgsig
->summary
& GPGME_SIGSUM_VALID
) {
170 /* good signature, continue */
171 _alpm_log(PM_LOG_DEBUG
, _("Package %s has a valid signature.\n"),
173 } else if(gpgsig
->summary
& GPGME_SIGSUM_GREEN
) {
174 /* 'green' signature, not sure what to do here */
175 _alpm_log(PM_LOG_WARNING
, _("Package %s has a green signature.\n"),
177 } else if(gpgsig
->summary
& GPGME_SIGSUM_KEY_MISSING
) {
178 pm_errno
= PM_ERR_SIG_UNKNOWN
;
179 _alpm_log(PM_LOG_WARNING
, _("Package %s has a signature from an unknown key.\n"),
183 /* we'll capture everything else here */
184 pm_errno
= PM_ERR_SIG_INVALID
;
185 _alpm_log(PM_LOG_ERROR
, _("Package %s has an invalid signature.\n"),
191 gpgme_data_release(sigdata
);
192 gpgme_data_release(pkgdata
);
200 if(err
!= GPG_ERR_NO_ERROR
) {
201 _alpm_log(PM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
202 RET_ERR(PM_ERR_GPGME
, -1);
208 * Check the PGP package signature for the given package file.
209 * @param pkg the package to check
210 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
212 int SYMEXPORT
alpm_pkg_check_pgp_signature(pmpkg_t
*pkg
)
215 ASSERT(pkg
!= NULL
, return 0);
217 return _alpm_gpgme_checksig(alpm_pkg_get_filename(pkg
),
218 alpm_pkg_get_pgpsig(pkg
));
221 /* vim: set ts=2 sw=2 noet: */