Imported Upstream version 4.14.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/rpmsq.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/header_internal.h"
23 #include "lib/rpmvs.h"
24
25 #include "debug.h"
26
27 int _print_pkts = 0;
28
29 static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)
30 {
31     char const * const pgpmark = "-----BEGIN PGP ";
32     size_t marklen = strlen(pgpmark);
33     int res = 0;
34     int keyno = 1;
35     char *start = strstr(buf, pgpmark);
36
37     do {
38         uint8_t *pkt = NULL;
39         uint8_t *pkti = NULL;
40         size_t pktlen = 0;
41         size_t certlen;
42         
43         /* Read pgp packet. */
44         if (pgpParsePkts(start, &pkt, &pktlen) == PGPARMOR_PUBKEY) {
45             pkti = pkt;
46
47             /* Iterate over certificates in pkt */
48             while (pktlen > 0) {
49                 if (pgpPubKeyCertLen(pkti, pktlen, &certlen)) {
50                     rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
51                             keyno);
52                     res++;
53                     break;
54                 }
55
56                 /* Import pubkey certificate. */
57                 if (rpmtsImportPubkey(ts, pkti, certlen) != RPMRC_OK) {
58                     rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
59                             keyno);
60                     res++;
61                 }
62                 pkti += certlen;
63                 pktlen -= certlen;
64             }
65         } else {
66             rpmlog(RPMLOG_ERR, _("%s: key %d not an armored public key.\n"),
67                    fn, keyno);
68             res++;
69         }
70         
71         /* See if there are more keys in the buffer */
72         if (start && start + marklen < buf + blen) {
73             start = strstr(start + marklen, pgpmark);
74         } else {
75             start = NULL;
76         }
77
78         keyno++;
79         free(pkt);
80     } while (start != NULL);
81
82     return res;
83 }
84
85 int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv)
86 {
87     int res = 0;
88     for (ARGV_const_t arg = argv; arg && *arg; arg++) {
89         const char *fn = *arg;
90         uint8_t *buf = NULL;
91         ssize_t blen = 0;
92         char *t = NULL;
93         int iorc;
94
95         /* If arg looks like a keyid, then attempt keyserver retrieve. */
96         if (rstreqn(fn, "0x", 2)) {
97             const char * s = fn + 2;
98             int i;
99             for (i = 0; *s && isxdigit(*s); s++, i++)
100                 {};
101             if (i == 8 || i == 16) {
102                 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
103                 if (t && *t != '%')
104                     fn = t;
105             }
106         }
107
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);
112             res++;
113         } else {
114             res += doImport(ts, fn, (char *)buf, blen);
115         }
116         
117         free(t);
118         free(buf);
119     }
120     return res;
121 }
122
123 static int readFile(FD_t fd, char **msg)
124 {
125     unsigned char buf[4*BUFSIZ];
126     ssize_t count;
127
128     /* Read the payload from the package. */
129     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
130     if (count < 0)
131         rasprintf(msg, _("Fread failed: %s"), Fstrerror(fd));
132
133     return (count != 0);
134 }
135
136 struct vfydata_s {
137     int seen;
138     int bad;
139 };
140
141 static rpmRC formatVerbose(struct rpmsinfo_s *sinfo, rpmRC sigres, const char *result, void *cbdata)
142 {
143     char *vsmsg = rpmsinfoMsg(sinfo, sigres, result);
144     rpmlog(RPMLOG_NOTICE, "    %s\n", vsmsg);
145     free(vsmsg);
146     return sigres;
147 }
148
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)
151 {
152     struct vfydata_s *vd = cbdata;
153     vd->seen |= sinfo->type;
154     if (sigres != RPMRC_OK)
155         vd->bad |= sinfo->type;
156     return sigres;
157 }
158
159 rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags flags, FD_t fd,
160                             rpmsinfoCb cb, void *cbdata, Header *hdrp)
161 {
162
163     char * msg = NULL;
164     rpmRC xx, rc = RPMRC_FAIL; /* assume failure */
165     int failed = 0;
166     int leadtype = -1;
167     struct hdrblob_s sigblob, blob;
168     struct rpmvs_s *sigset = NULL;
169     Header h = NULL;
170     Header sigh = NULL;
171     rpmDigestBundle bundle = fdGetBundle(fd, 1); /* freed with fd */
172
173     memset(&blob, 0, sizeof(blob));
174     memset(&sigblob, 0, sizeof(sigblob));
175
176     if ((xx = rpmLeadRead(fd, &leadtype, &msg)) != RPMRC_OK) {
177         /* Avoid message spew on manifests */
178         if (xx == RPMRC_NOTFOUND)
179             msg = _free(msg);
180         rc = xx;
181         goto exit;
182     }
183
184     /* Read the signature header. Might not be in a contiguous region. */
185     if (hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, &sigblob, &msg))
186         goto exit;
187
188     sigset = rpmvsCreate(&sigblob, flags);
189
190     /* Initialize digests ranging over the header */
191     rpmvsInitDigests(sigset, RPMSIG_HEADER, bundle);
192
193     /* Read the header from the package. */
194     if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, &blob, &msg))
195         goto exit;
196
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);
200
201     /* Initialize digests ranging over the payload only */
202     rpmvsInitDigests(sigset, RPMSIG_PAYLOAD, bundle);
203
204     /* Verify header signatures and digests */
205     failed += rpmvsVerifyItems(sigset, (RPMSIG_HEADER), bundle, keyring, cb, cbdata);
206
207     /* Unless disabled, read the file, generating digest(s) on the fly. */
208     if (!(flags & RPMVSF_NEEDPAYLOAD)) {
209         if (readFile(fd, &msg))
210             goto exit;
211     }
212
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);
218
219     if (failed == 0) {
220         /* Finally import the headers and do whatever required retrofits etc */
221         if (hdrp) {
222             if (hdrblobImport(&sigblob, 0, &sigh, &msg))
223                 goto exit;
224             if (hdrblobImport(&blob, 0, &h, &msg))
225                 goto exit;
226
227             /* Append (and remap) signature tags to the metadata. */
228             headerMergeLegacySigs(h, sigh);
229             applyRetrofits(h, leadtype);
230
231             /* Bump reference count for return. */
232             *hdrp = headerLink(h);
233         }
234         rc = RPMRC_OK;
235     }
236
237 exit:
238     if (rc && msg != NULL)
239         rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
240     free(msg);
241     free(sigblob.ei);
242     free(blob.ei);
243     headerFree(h);
244     headerFree(sigh);
245     rpmvsFree(sigset);
246     return rc;
247 }
248
249 static int rpmpkgVerifySigs(rpmKeyring keyring, rpmVSFlags flags,
250                            FD_t fd, const char *fn)
251 {
252     int rc;
253     if (rpmIsVerbose()) {
254         rpmlog(RPMLOG_NOTICE, "%s:\n", fn);
255         rc = rpmpkgRead(keyring, flags, fd, formatVerbose, NULL, NULL);
256     } else {
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"));
263         }
264         if (vd.seen & RPMSIG_SIGNATURE_TYPE) {
265             rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?
266                                         _("SIGNATURES") : _("signatures"));
267         }
268         rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
269     }
270     return rc;
271 }
272
273 /* Wrapper around rpmkVerifySigs to preserve API */
274 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
275 {
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);
281     }
282     return rc;
283 }
284
285 int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
286 {
287     const char * arg;
288     int res = 0;
289     rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
290     rpmVSFlags vsflags = 0;
291
292     if (rpmcliQueryFlags & QUERY_DIGEST)
293         vsflags |= _RPMVSF_NODIGESTS;
294     if (rpmcliQueryFlags & QUERY_SIGNATURE)
295         vsflags |= _RPMVSF_NOSIGNATURES;
296
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"), 
301                      arg, Fstrerror(fd));
302             res++;
303         } else if (rpmpkgVerifySigs(keyring, vsflags, fd, arg)) {
304             res++;
305         }
306
307         Fclose(fd);
308         rpmsqPoll();
309     }
310     rpmKeyringFree(keyring);
311     return res;
312 }