2 * \file lib/rpmchecksig.c
3 * Verify the signature of a package.
10 #include <rpm/rpmlib.h> /* RPMSIGTAG & related */
11 #include <rpm/rpmpgp.h>
12 #include <rpm/rpmcli.h>
13 #include <rpm/rpmfileutil.h> /* rpmMkTemp() */
14 #include <rpm/rpmsq.h>
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmlog.h>
17 #include <rpm/rpmstring.h>
18 #include <rpm/rpmkeyring.h>
20 #include "rpmio/rpmio_internal.h" /* fdSetBundle() */
21 #include "lib/rpmlead.h"
22 #include "lib/header_internal.h"
23 #include "lib/rpmvs.h"
29 static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)
31 char const * const pgpmark = "-----BEGIN PGP ";
32 size_t marklen = strlen(pgpmark);
35 char *start = strstr(buf, pgpmark);
43 /* Read pgp packet. */
44 if (pgpParsePkts(start, &pkt, &pktlen) == PGPARMOR_PUBKEY) {
47 /* Iterate over certificates in pkt */
49 if (pgpPubKeyCertLen(pkti, pktlen, &certlen)) {
50 rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
56 /* Import pubkey certificate. */
57 if (rpmtsImportPubkey(ts, pkti, certlen) != RPMRC_OK) {
58 rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
66 rpmlog(RPMLOG_ERR, _("%s: key %d not an armored public key.\n"),
71 /* See if there are more keys in the buffer */
72 if (start && start + marklen < buf + blen) {
73 start = strstr(start + marklen, pgpmark);
80 } while (start != NULL);
85 int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv)
88 for (ARGV_const_t arg = argv; arg && *arg; arg++) {
89 const char *fn = *arg;
95 /* If arg looks like a keyid, then attempt keyserver retrieve. */
96 if (rstreqn(fn, "0x", 2)) {
97 const char * s = fn + 2;
99 for (i = 0; *s && isxdigit(*s); s++, i++)
101 if (i == 8 || i == 16) {
102 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
108 /* Read the file and try to import all contained keys */
109 iorc = rpmioSlurp(fn, &buf, &blen);
110 if (iorc || buf == NULL || blen < 64) {
111 rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, iorc);
114 res += doImport(ts, fn, (char *)buf, blen);
123 static int readFile(FD_t fd, char **msg)
125 unsigned char buf[4*BUFSIZ];
128 /* Read the payload from the package. */
129 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
131 rasprintf(msg, _("Fread failed: %s"), Fstrerror(fd));
141 static rpmRC formatVerbose(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata)
143 char *vsmsg = rpmsinfoMsg(sinfo, sigres, result);
144 rpmlog(RPMLOG_NOTICE, " %s\n", vsmsg);
149 /* Failures are uppercase, in parenthesis if NOKEY. Otherwise lowercase. */
150 static rpmRC formatDefault(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata)
152 struct vfydata_s *vd = cbdata;
153 vd->seen |= sinfo->type;
154 if (sigres != RPMRC_OK)
155 vd->bad |= sinfo->type;
159 rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags flags, FD_t fd,
160 rpmsinfoCb cb, void *cbdata, Header *hdrp)
164 rpmRC xx, rc = RPMRC_FAIL; /* assume failure */
167 struct hdrblob_s sigblob, blob;
168 struct rpmvs_s *sigset = NULL;
171 rpmDigestBundle bundle = fdGetBundle(fd, 1); /* freed with fd */
173 memset(&blob, 0, sizeof(blob));
174 memset(&sigblob, 0, sizeof(sigblob));
176 if ((xx = rpmLeadRead(fd, &leadtype, &msg)) != RPMRC_OK) {
177 /* Avoid message spew on manifests */
178 if (xx == RPMRC_NOTFOUND)
184 /* Read the signature header. Might not be in a contiguous region. */
185 if (hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, &sigblob, &msg))
188 sigset = rpmvsCreate(&sigblob, flags);
190 /* Initialize digests ranging over the header */
191 rpmvsInitDigests(sigset, RPMSIG_HEADER, bundle);
193 /* Read the header from the package. */
194 if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, &blob, &msg))
197 /* Fish interesting tags from the main header. This is a bit hacky... */
198 if (!(flags & (RPMVSF_NOPAYLOAD|RPMVSF_NEEDPAYLOAD)))
199 rpmvsAppend(sigset, &blob, RPMTAG_PAYLOADDIGEST);
201 /* Initialize digests ranging over the payload only */
202 rpmvsInitDigests(sigset, RPMSIG_PAYLOAD, bundle);
204 /* Verify header signatures and digests */
205 failed += rpmvsVerifyItems(sigset, (RPMSIG_HEADER), bundle, keyring, cb, cbdata);
207 /* Unless disabled, read the file, generating digest(s) on the fly. */
208 if (!(flags & RPMVSF_NEEDPAYLOAD)) {
209 if (readFile(fd, &msg))
213 /* Verify signatures and digests ranging over the payload */
214 failed += rpmvsVerifyItems(sigset, (RPMSIG_PAYLOAD), bundle,
215 keyring, cb, cbdata);
216 failed += rpmvsVerifyItems(sigset, (RPMSIG_HEADER|RPMSIG_PAYLOAD), bundle,
217 keyring, cb, cbdata);
220 /* Finally import the headers and do whatever required retrofits etc */
222 if (hdrblobImport(&sigblob, 0, &sigh, &msg))
224 if (hdrblobImport(&blob, 0, &h, &msg))
227 /* Append (and remap) signature tags to the metadata. */
228 headerMergeLegacySigs(h, sigh);
229 applyRetrofits(h, leadtype);
231 /* Bump reference count for return. */
232 *hdrp = headerLink(h);
238 if (rc && msg != NULL)
239 rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
249 static int rpmpkgVerifySigs(rpmKeyring keyring, rpmVSFlags flags,
250 FD_t fd, const char *fn)
253 if (rpmIsVerbose()) {
254 rpmlog(RPMLOG_NOTICE, "%s:\n", fn);
255 rc = rpmpkgRead(keyring, flags, fd, formatVerbose, NULL, NULL);
257 struct vfydata_s vd = { 0, 0 };
258 rpmlog(RPMLOG_NOTICE, "%s:", fn);
259 rc = rpmpkgRead(keyring, flags, fd, formatDefault, &vd, NULL);
260 if (vd.seen & RPMSIG_DIGEST_TYPE) {
261 rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ?
262 _("DIGESTS") : _("digests"));
264 if (vd.seen & RPMSIG_SIGNATURE_TYPE) {
265 rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?
266 _("SIGNATURES") : _("signatures"));
268 rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
273 /* Wrapper around rpmkVerifySigs to preserve API */
274 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
276 int rc = 1; /* assume failure */
277 if (ts && qva && fd && fn) {
278 rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
279 rc = rpmpkgVerifySigs(keyring, qva->qva_flags, fd, fn);
280 rpmKeyringFree(keyring);
285 int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
289 rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
290 rpmVSFlags vsflags = 0;
292 if (rpmcliQueryFlags & QUERY_DIGEST)
293 vsflags |= _RPMVSF_NODIGESTS;
294 if (rpmcliQueryFlags & QUERY_SIGNATURE)
295 vsflags |= _RPMVSF_NOSIGNATURES;
297 while ((arg = *argv++) != NULL) {
298 FD_t fd = Fopen(arg, "r.ufdio");
299 if (fd == NULL || Ferror(fd)) {
300 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
303 } else if (rpmpkgVerifySigs(keyring, vsflags, fd, arg)) {
310 rpmKeyringFree(keyring);