Update to 4.11.0.1
[platform/upstream/rpm.git] / lib / rpmchecksig.c
1 /** \ingroup rpmcli
2  * \file lib/rpmchecksig.c
3  * Verify the signature of a package.
4  */
5
6 #include "system.h"
7
8 #include <ctype.h>
9
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/rpmdb.h>
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmlog.h>
17 #include <rpm/rpmstring.h>
18 #include <rpm/rpmkeyring.h>
19
20 #include "rpmio/rpmio_internal.h"       /* fdSetBundle() */
21 #include "lib/rpmlead.h"
22 #include "lib/signature.h"
23
24 #include "debug.h"
25
26 int _print_pkts = 0;
27
28 static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)
29 {
30     char const * const pgpmark = "-----BEGIN PGP ";
31     size_t marklen = strlen(pgpmark);
32     int res = 0;
33     int keyno = 1;
34     char *start = strstr(buf, pgpmark);
35
36     do {
37         uint8_t *pkt = NULL;
38         size_t pktlen = 0;
39         
40         /* Read pgp packet. */
41         if (pgpParsePkts(start, &pkt, &pktlen) == PGPARMOR_PUBKEY) {
42             /* Import pubkey packet(s). */
43             if (rpmtsImportPubkey(ts, pkt, pktlen) != RPMRC_OK) {
44                 rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn, keyno);
45                 res++;
46             }
47         } else {
48             rpmlog(RPMLOG_ERR, _("%s: key %d not an armored public key.\n"),
49                    fn, keyno);
50             res++;
51         }
52         
53         /* See if there are more keys in the buffer */
54         if (start && start + marklen < buf + blen) {
55             start = strstr(start + marklen, pgpmark);
56         } else {
57             start = NULL;
58         }
59
60         keyno++;
61         free(pkt);
62     } while (start != NULL);
63
64     return res;
65 }
66
67 int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv)
68 {
69     int res = 0;
70     for (ARGV_const_t arg = argv; arg && *arg; arg++) {
71         const char *fn = *arg;
72         uint8_t *buf = NULL;
73         ssize_t blen = 0;
74         char *t = NULL;
75         int iorc;
76
77         /* If arg looks like a keyid, then attempt keyserver retrieve. */
78         if (rstreqn(fn, "0x", 2)) {
79             const char * s = fn + 2;
80             int i;
81             for (i = 0; *s && isxdigit(*s); s++, i++)
82                 {};
83             if (i == 8 || i == 16) {
84                 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
85                 if (t && *t != '%')
86                     fn = t;
87             }
88         }
89
90         /* Read the file and try to import all contained keys */
91         iorc = rpmioSlurp(fn, &buf, &blen);
92         if (iorc || buf == NULL || blen < 64) {
93             rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, iorc);
94             res++;
95         } else {
96             res += doImport(ts, fn, (char *)buf, blen);
97         }
98         
99         free(t);
100         free(buf);
101     }
102     return res;
103 }
104
105 /**
106  * @todo If the GPG key was known available, the md5 digest could be skipped.
107  */
108 static int readFile(FD_t fd, const char * fn,
109                     rpmDigestBundle plbundle, rpmDigestBundle hdrbundle)
110 {
111     unsigned char buf[4*BUFSIZ];
112     ssize_t count;
113     int rc = 1;
114     Header h = NULL;
115     char *msg = NULL;
116
117     /* Read the header from the package. */
118     if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) {
119         rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), fn, msg);
120         goto exit;
121     }
122
123     if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
124         struct rpmtd_s utd;
125     
126         if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)){
127             rpmlog(RPMLOG_ERR, 
128                     _("%s: Immutable header region could not be read. "
129                     "Corrupted package?\n"), fn);
130             goto exit;
131         }
132         rpmDigestBundleUpdate(hdrbundle, rpm_header_magic, sizeof(rpm_header_magic));
133         rpmDigestBundleUpdate(hdrbundle, utd.data, utd.count);
134         rpmtdFreeData(&utd);
135     }
136
137     /* Read the payload from the package. */
138     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
139     if (count < 0) {
140         rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
141         goto exit;
142     }
143
144     rc = 0;
145
146 exit:
147     free(msg);
148     headerFree(h);
149     return rc;
150 }
151
152 /* 
153  * Figure best available signature. 
154  * XXX TODO: Similar detection in rpmReadPackageFile(), unify these.
155  */
156 static rpmTagVal bestSig(Header sigh, int nosignatures, int nodigests)
157 {
158     rpmTagVal sigtag = 0;
159     if (sigtag == 0 && !nosignatures) {
160         if (headerIsEntry(sigh, RPMSIGTAG_DSA))
161             sigtag = RPMSIGTAG_DSA;
162         else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
163             sigtag = RPMSIGTAG_RSA;
164         else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
165             sigtag = RPMSIGTAG_GPG;
166         else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
167             sigtag = RPMSIGTAG_PGP;
168     }
169     if (sigtag == 0 && !nodigests) {
170         if (headerIsEntry(sigh, RPMSIGTAG_MD5))
171             sigtag = RPMSIGTAG_MD5;
172         else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
173             sigtag = RPMSIGTAG_SHA1;    /* XXX never happens */
174     }
175     return sigtag;
176 }
177
178 static const char *sigtagname(rpmTagVal sigtag, int upper)
179 {
180     const char *n = NULL;
181
182     switch (sigtag) {
183     case RPMSIGTAG_SIZE:
184         n = (upper ? "SIZE" : "size");
185         break;
186     case RPMSIGTAG_SHA1:
187         n = (upper ? "SHA1" : "sha1");
188         break;
189     case RPMSIGTAG_MD5:
190         n = (upper ? "MD5" : "md5");
191         break;
192     case RPMSIGTAG_RSA:
193         n = (upper ? "RSA" : "rsa");
194         break;
195     case RPMSIGTAG_PGP5:        /* XXX legacy */
196     case RPMSIGTAG_PGP:
197         n = (upper ? "(MD5) PGP" : "(md5) pgp");
198         break;
199     case RPMSIGTAG_DSA:
200         n = (upper ? "(SHA1) DSA" : "(sha1) dsa");
201         break;
202     case RPMSIGTAG_GPG:
203         n = (upper ? "GPG" : "gpg");
204         break;
205     default:
206         n = (upper ? "?UnknownSigatureType?" : "???");
207         break;
208     }
209     return n;
210 }
211
212 /* 
213  * Format sigcheck result for output, appending the message spew to buf and
214  * bad/missing keyids to keyprob.
215  *
216  * In verbose mode, just dump it all. Otherwise ok signatures
217  * are dumped lowercase, bad sigs uppercase and for PGP/GPG
218  * if misssing/untrusted key it's uppercase in parenthesis
219  * and stash the key id as <SIGTYPE>#<keyid>. Pfft.
220  */
221 static void formatResult(rpmTagVal sigtag, rpmRC sigres, const char *result,
222                          int havekey, char **keyprob, char **buf)
223 {
224     char *msg = NULL;
225     if (rpmIsVerbose()) {
226         rasprintf(&msg, "    %s", result);
227     } else { 
228         /* Check for missing / untrusted keys in result. */
229         const char *signame = sigtagname(sigtag, (sigres != RPMRC_OK));
230         
231         if (havekey && (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED)) {
232             const char *tempKey = strstr(result, "ey ID");
233             if (tempKey) {
234                 char keyid[sizeof(pgpKeyID_t) + 1];
235                 rstrlcpy(keyid, tempKey + 6, sizeof(keyid));
236                 rstrscat(keyprob, " ", signame, "#", keyid, NULL);
237             }
238         }
239         rasprintf(&msg, (*keyprob ? "(%s) " : "%s "), signame);
240     }
241     rstrcat(buf, msg);
242     free(msg);
243 }
244
245 static int rpmpkgVerifySigs(rpmKeyring keyring, rpmQueryFlags flags,
246                            FD_t fd, const char *fn)
247 {
248
249     char *buf = NULL;
250     char *missingKeys = NULL; 
251     char *untrustedKeys = NULL;
252     struct rpmtd_s sigtd;
253     rpmTagVal sigtag;
254     pgpDigParams sig = NULL;
255     Header sigh = NULL;
256     HeaderIterator hi = NULL;
257     char * msg = NULL;
258     int res = 1; /* assume failure */
259     rpmRC rc;
260     int failed = 0;
261     int nodigests = !(flags & VERIFY_DIGEST);
262     int nosignatures = !(flags & VERIFY_SIGNATURE);
263     rpmDigestBundle plbundle = rpmDigestBundleNew();
264     rpmDigestBundle hdrbundle = rpmDigestBundleNew();
265
266     if ((rc = rpmLeadRead(fd, NULL, NULL, &msg)) != RPMRC_OK) {
267         rpmlog(RPMLOG_ERR, "%s: %s\n", fn, msg);
268         free(msg);
269         goto exit;
270     }
271
272     rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
273     switch (rc) {
274     default:
275         rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
276                     (msg && *msg ? msg : "\n"));
277         msg = _free(msg);
278         goto exit;
279         break;
280     case RPMRC_OK:
281         if (sigh == NULL) {
282             rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
283             goto exit;
284         }
285         break;
286     }
287     msg = _free(msg);
288
289     /* Grab a hint of what needs doing to avoid duplication. */
290     sigtag = bestSig(sigh, nosignatures, nodigests);
291
292     /* XXX RSA needs the hash_algo, so decode early. */
293     if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP ||
294                 sigtag == RPMSIGTAG_DSA || sigtag == RPMSIGTAG_GPG) {
295         unsigned int hashalgo;
296         if (headerGet(sigh, sigtag, &sigtd, HEADERGET_DEFAULT)) {
297             parsePGPSig(&sigtd, "package", fn, &sig);
298             rpmtdFreeData(&sigtd);
299         }
300         if (sig == NULL) goto exit;
301             
302         /* XXX assume same hash_algo in header-only and header+payload */
303         hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
304         rpmDigestBundleAdd(plbundle, hashalgo, RPMDIGEST_NONE);
305         rpmDigestBundleAdd(hdrbundle, hashalgo, RPMDIGEST_NONE);
306     }
307
308     if (headerIsEntry(sigh, RPMSIGTAG_PGP) ||
309                       headerIsEntry(sigh, RPMSIGTAG_PGP5) ||
310                       headerIsEntry(sigh, RPMSIGTAG_MD5)) {
311         rpmDigestBundleAdd(plbundle, PGPHASHALGO_MD5, RPMDIGEST_NONE);
312     }
313     if (headerIsEntry(sigh, RPMSIGTAG_GPG)) {
314         rpmDigestBundleAdd(plbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
315     }
316
317     /* always do sha1 hash of header */
318     rpmDigestBundleAdd(hdrbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
319
320     /* Read the file, generating digest(s) on the fly. */
321     fdSetBundle(fd, plbundle);
322     if (readFile(fd, fn, plbundle, hdrbundle)) {
323         goto exit;
324     }
325
326     rasprintf(&buf, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
327
328     hi = headerInitIterator(sigh);
329     for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) {
330         char *result = NULL;
331         int havekey = 0;
332         DIGEST_CTX ctx = NULL;
333         if (sigtd.data == NULL) /* XXX can't happen */
334             continue;
335
336         /* Clean up parameters from previous sigtag. */
337         sig = pgpDigParamsFree(sig);
338
339         switch (sigtd.tag) {
340         case RPMSIGTAG_GPG:
341         case RPMSIGTAG_PGP5:    /* XXX legacy */
342         case RPMSIGTAG_PGP:
343             havekey = 1;
344         case RPMSIGTAG_RSA:
345         case RPMSIGTAG_DSA:
346             if (nosignatures)
347                  continue;
348             if (parsePGPSig(&sigtd, "package", fn, &sig))
349                 goto exit;
350             ctx = rpmDigestBundleDupCtx(havekey ? plbundle : hdrbundle,
351                                         pgpDigParamsAlgo(sig, PGPVAL_HASHALGO));
352             break;
353         case RPMSIGTAG_SHA1:
354             if (nodigests)
355                  continue;
356             ctx = rpmDigestBundleDupCtx(hdrbundle, PGPHASHALGO_SHA1);
357             break;
358         case RPMSIGTAG_MD5:
359             if (nodigests)
360                  continue;
361             ctx = rpmDigestBundleDupCtx(plbundle, PGPHASHALGO_MD5);
362             break;
363         default:
364             continue;
365             break;
366         }
367
368         rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &result);
369         rpmDigestFinal(ctx, NULL, NULL, 0);
370
371         formatResult(sigtd.tag, rc, result, havekey, 
372                      (rc == RPMRC_NOKEY ? &missingKeys : &untrustedKeys),
373                      &buf);
374         free(result);
375
376         if (rc != RPMRC_OK) {
377             failed = 1;
378         }
379
380     }
381     res = failed;
382
383     if (rpmIsVerbose()) {
384         rpmlog(RPMLOG_NOTICE, "%s", buf);
385     } else {
386         const char *ok = (failed ? _("NOT OK") : _("OK"));
387         rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf, ok,
388                missingKeys ? _(" (MISSING KEYS:") : "",
389                missingKeys ? missingKeys : "",
390                missingKeys ? _(") ") : "",
391                untrustedKeys ? _(" (UNTRUSTED KEYS:") : "",
392                untrustedKeys ? untrustedKeys : "",
393                untrustedKeys ? _(")") : "");
394     }
395     free(missingKeys);
396     free(untrustedKeys);
397
398 exit:
399     free(buf);
400     rpmDigestBundleFree(hdrbundle);
401     rpmDigestBundleFree(plbundle);
402     fdSetBundle(fd, NULL); /* XXX avoid double-free from fd close */
403     sigh = rpmFreeSignature(sigh);
404     hi = headerFreeIterator(hi);
405     pgpDigParamsFree(sig);
406     return res;
407 }
408
409 /* Wrapper around rpmkVerifySigs to preserve API */
410 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
411 {
412     int rc = 1; /* assume failure */
413     if (ts && qva && fd && fn) {
414         rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
415         rc = rpmpkgVerifySigs(keyring, qva->qva_flags, fd, fn);
416         rpmKeyringFree(keyring);
417     }
418     return rc;
419 }
420
421 int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
422 {
423     const char * arg;
424     int res = 0;
425     rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
426     rpmVerifyFlags verifyFlags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
427     
428     verifyFlags &= ~rpmcliQueryFlags;
429
430     while ((arg = *argv++) != NULL) {
431         FD_t fd = Fopen(arg, "r.ufdio");
432         if (fd == NULL || Ferror(fd)) {
433             rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), 
434                      arg, Fstrerror(fd));
435             res++;
436         } else if (rpmpkgVerifySigs(keyring, verifyFlags, fd, arg)) {
437             res++;
438         }
439
440         Fclose(fd);
441         rpmdbCheckSignals();
442     }
443     rpmKeyringFree(keyring);
444     return res;
445 }