Do not load the systemd_inhibit plugin if not booted with systemd.
[rpm.git] / lib / signature.c
1 /** \ingroup signature
2  * \file lib/signature.c
3  */
4
5 #include "system.h"
6
7 #include <inttypes.h>
8 #include <netinet/in.h>
9
10 #include <rpm/rpmtypes.h>
11 #include <rpm/rpmstring.h>
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmkeyring.h>
15
16 #include "lib/rpmlead.h"
17 #include "lib/signature.h"
18 #include "lib/header_internal.h"
19
20 #include "debug.h"
21
22 /* Dumb wrapper around headerPut() for signature header */
23 static int sighdrPut(Header h, rpmTagVal tag, rpmTagType type,
24                      rpm_data_t p, rpm_count_t c)
25 {
26     struct rpmtd_s sigtd;
27     rpmtdReset(&sigtd);
28     sigtd.tag = tag;
29     sigtd.type = type;
30     sigtd.data = p;
31     sigtd.count = c;
32     return headerPut(h, &sigtd, HEADERPUT_DEFAULT);
33 }
34
35 /**
36  * Print package size.
37  * @todo rpmio: use fdSize rather than fstat(2) to get file size.
38  * @param fd                    package file handle
39  * @param siglen                signature header size
40  * @param pad                   signature padding
41  * @param datalen               length of header+payload
42  * @return                      rpmRC return code
43  */
44 static inline rpmRC printSize(FD_t fd, size_t siglen, size_t pad, rpm_loff_t datalen)
45 {
46     struct stat st;
47     int fdno = Fileno(fd);
48
49     if (fstat(fdno, &st) < 0)
50         return RPMRC_FAIL;
51
52     rpmlog(RPMLOG_DEBUG,
53                 "Expected size: %12" PRIu64 \
54                 " = lead(%d)+sigs(%zd)+pad(%zd)+data(%" PRIu64 ")\n",
55                 RPMLEAD_SIZE+siglen+pad+datalen,
56                 RPMLEAD_SIZE, siglen, pad, datalen);
57     rpmlog(RPMLOG_DEBUG,
58                 "  Actual size: %12" PRIu64 "\n", (rpm_loff_t) st.st_size);
59
60     return RPMRC_OK;
61 }
62
63 rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
64 {
65     char *buf = NULL;
66     int32_t block[4];
67     int32_t il;
68     int32_t dl;
69     int32_t * ei = NULL;
70     entryInfo pe;
71     unsigned int nb, uc;
72     int32_t ril = 0;
73     struct indexEntry_s entry;
74     struct entryInfo_s info;
75     unsigned char * dataStart;
76     unsigned char * dataEnd = NULL;
77     Header sigh = NULL;
78     rpmRC rc = RPMRC_FAIL;              /* assume failure */
79     int xx;
80     int i;
81
82     if (sighp)
83         *sighp = NULL;
84
85     if (sig_type != RPMSIGTYPE_HEADERSIG)
86         goto exit;
87
88     memset(block, 0, sizeof(block));
89     if ((xx = Fread(block, 1, sizeof(block), fd)) != sizeof(block)) {
90         rasprintf(&buf, _("sigh size(%d): BAD, read returned %d\n"), 
91                   (int)sizeof(block), xx);
92         goto exit;
93     }
94     if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
95         rasprintf(&buf, _("sigh magic: BAD\n"));
96         goto exit;
97     }
98     il = ntohl(block[2]);
99     if (il < 0 || il > 32) {
100         rasprintf(&buf, 
101                   _("sigh tags: BAD, no. of tags(%d) out of range\n"), il);
102         goto exit;
103     }
104     dl = ntohl(block[3]);
105     if (dl < 0 || dl > 8192) {
106         rasprintf(&buf, 
107                   _("sigh data: BAD, no. of  bytes(%d) out of range\n"), dl);
108         goto exit;
109     }
110
111     memset(&entry, 0, sizeof(entry));
112     memset(&info, 0, sizeof(info));
113
114     nb = (il * sizeof(struct entryInfo_s)) + dl;
115     uc = sizeof(il) + sizeof(dl) + nb;
116     ei = xmalloc(uc);
117     ei[0] = block[2];
118     ei[1] = block[3];
119     pe = (entryInfo) &ei[2];
120     dataStart = (unsigned char *) (pe + il);
121     if ((xx = Fread(pe, 1, nb, fd)) != nb) {
122         rasprintf(&buf,
123                   _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
124         goto exit;
125     }
126     
127     /* Check (and convert) the 1st tag element. */
128     xx = headerVerifyInfo(1, dl, pe, &entry.info, 0);
129     if (xx != -1) {
130         rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
131                   0, entry.info.tag, entry.info.type,
132                   entry.info.offset, entry.info.count);
133         goto exit;
134     }
135
136     /* Is there an immutable header region tag? */
137     if (entry.info.tag == RPMTAG_HEADERSIGNATURES
138        && entry.info.type == RPM_BIN_TYPE
139        && entry.info.count == REGION_TAG_COUNT)
140     {
141
142         /* Is the trailer within the data area? */
143         if (entry.info.offset + REGION_TAG_COUNT > dl) {
144             rasprintf(&buf, 
145                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
146                 entry.info.tag, entry.info.type,
147                 entry.info.offset, entry.info.count);
148             goto exit;
149         }
150
151         /* Is there an immutable header region tag trailer? */
152         dataEnd = dataStart + entry.info.offset;
153         (void) memcpy(&info, dataEnd, REGION_TAG_COUNT);
154         /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
155         if (info.tag == htonl(RPMTAG_HEADERIMAGE)) {
156             rpmTagVal stag = htonl(RPMTAG_HEADERSIGNATURES);
157             info.tag = stag;
158             memcpy(dataEnd, &stag, sizeof(stag));
159         }
160         dataEnd += REGION_TAG_COUNT;
161
162         xx = headerVerifyInfo(1, dl, &info, &entry.info, 1);
163         if (xx != -1 ||
164             !((entry.info.tag == RPMTAG_HEADERSIGNATURES || entry.info.tag == RPMTAG_HEADERIMAGE)
165            && entry.info.type == RPM_BIN_TYPE
166            && entry.info.count == REGION_TAG_COUNT))
167         {
168             rasprintf(&buf,
169                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
170                 entry.info.tag, entry.info.type,
171                 entry.info.offset, entry.info.count);
172             goto exit;
173         }
174         memset(&info, 0, sizeof(info));
175
176         /* Is the no. of tags in the region less than the total no. of tags? */
177         ril = entry.info.offset/sizeof(*pe);
178         if ((entry.info.offset % sizeof(*pe)) || ril > il) {
179             rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
180             goto exit;
181         }
182     }
183
184     /* Sanity check signature tags */
185     memset(&info, 0, sizeof(info));
186     for (i = 1; i < il; i++) {
187         xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0);
188         if (xx != -1) {
189             rasprintf(&buf, 
190                 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
191                 i, entry.info.tag, entry.info.type,
192                 entry.info.offset, entry.info.count);
193             goto exit;
194         }
195     }
196
197     /* OK, blob looks sane, load the header. */
198     sigh = headerImport(ei, uc, 0);
199     if (sigh == NULL) {
200         rasprintf(&buf, _("sigh load: BAD\n"));
201         goto exit;
202     }
203
204     {   size_t sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
205         size_t pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
206         ssize_t trc;
207         struct rpmtd_s sizetag;
208         rpm_loff_t archSize = 0;
209
210         /* Position at beginning of header. */
211         if (pad && (trc = Fread(block, 1, pad, fd)) != pad) {
212             rasprintf(&buf,
213                       _("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc);
214             goto exit;
215         }
216
217         /* Print package component sizes. */
218         if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) {
219             rpm_loff_t *tsize = rpmtdGetUint64(&sizetag);
220             archSize = (tsize) ? *tsize : 0;
221         } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) {
222             rpm_off_t *tsize = rpmtdGetUint32(&sizetag);
223             archSize = (tsize) ? *tsize : 0;
224         }
225         rpmtdFreeData(&sizetag);
226         rc = printSize(fd, sigSize, pad, archSize);
227         if (rc != RPMRC_OK) {
228             rasprintf(&buf,
229                    _("sigh sigSize(%zd): BAD, fstat(2) failed\n"), sigSize);
230             goto exit;
231         }
232     }
233     ei = NULL; /* XXX will be freed with header */
234
235 exit:
236     if (sighp && sigh && rc == RPMRC_OK)
237         *sighp = headerLink(sigh);
238     headerFree(sigh);
239     free(ei);
240
241     if (msg != NULL) {
242         *msg = buf;
243     } else {
244         free(buf);
245     }
246
247     return rc;
248 }
249
250 int rpmWriteSignature(FD_t fd, Header sigh)
251 {
252     static uint8_t buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
253     int sigSize, pad;
254     int rc;
255
256     rc = headerWrite(fd, sigh, HEADER_MAGIC_YES);
257     if (rc)
258         return rc;
259
260     sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
261     pad = (8 - (sigSize % 8)) % 8;
262     if (pad) {
263         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
264             rc = 1;
265     }
266     rpmlog(RPMLOG_DEBUG, "Signature: size(%d)+pad(%d)\n", sigSize, pad);
267     return rc;
268 }
269
270 Header rpmNewSignature(void)
271 {
272     Header sigh = headerNew();
273     return sigh;
274 }
275
276 Header rpmFreeSignature(Header sigh)
277 {
278     return headerFree(sigh);
279 }
280
281 static int makeHDRDigest(Header sigh, const char * file, rpmTagVal sigTag)
282 {
283     Header h = NULL;
284     FD_t fd = NULL;
285     char * SHA1 = NULL;
286     int ret = -1;       /* assume failure. */
287
288     switch (sigTag) {
289     case RPMSIGTAG_SHA1:
290         fd = Fopen(file, "r.fdio");
291         if (fd == NULL || Ferror(fd))
292             goto exit;
293         h = headerRead(fd, HEADER_MAGIC_YES);
294         if (h == NULL)
295             goto exit;
296
297         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
298             DIGEST_CTX ctx;
299             struct rpmtd_s utd;
300         
301             if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)
302                 ||  utd.data == NULL)
303             {
304                 rpmlog(RPMLOG_ERR, 
305                                 _("Immutable header region could not be read. "
306                                 "Corrupted package?\n"));
307                 goto exit;
308             }
309             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
310             (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
311             (void) rpmDigestUpdate(ctx, utd.data, utd.count);
312             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
313             rpmtdFreeData(&utd);
314         } else {
315             rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
316             goto exit;
317         }
318
319         if (SHA1 == NULL)
320             goto exit;
321         if (!sighdrPut(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
322             goto exit;
323         ret = 0;
324         break;
325     default:
326         break;
327     }
328
329 exit:
330     free(SHA1);
331     headerFree(h);
332     if (fd != NULL) (void) Fclose(fd);
333     return ret;
334 }
335
336 int rpmGenDigest(Header sigh, const char * file, rpmTagVal sigTag)
337 {
338     struct stat st;
339     uint8_t * pkt = NULL;
340     size_t pktlen;
341     int ret = -1;       /* assume failure. */
342
343     switch (sigTag) {
344     case RPMSIGTAG_SIZE: {
345         rpm_off_t size;
346         if (stat(file, &st) != 0)
347             break;
348         size = st.st_size;
349         if (!sighdrPut(sigh, sigTag, RPM_INT32_TYPE, &size, 1))
350             break;
351         ret = 0;
352         } break;
353     case RPMSIGTAG_LONGSIZE: {
354         rpm_loff_t size;
355         if (stat(file, &st) != 0)
356             break;
357         size = st.st_size;
358         if (!sighdrPut(sigh, sigTag, RPM_INT64_TYPE, &size, 1))
359             break;
360         ret = 0;
361         } break;
362     case RPMSIGTAG_MD5:
363         pktlen = 16;
364         pkt = xcalloc(pktlen, sizeof(*pkt));
365         if (rpmDoDigest(PGPHASHALGO_MD5, file, 0, pkt, NULL)
366          || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
367             break;
368         ret = 0;
369         break;
370     case RPMSIGTAG_SHA1:
371         ret = makeHDRDigest(sigh, file, sigTag);
372         break;
373     default:
374         break;
375     }
376     free(pkt);
377
378     return ret;
379 }
380
381 static const char * rpmSigString(rpmRC res)
382 {
383     const char * str;
384     switch (res) {
385     case RPMRC_OK:              str = "OK";             break;
386     case RPMRC_FAIL:            str = "BAD";            break;
387     case RPMRC_NOKEY:           str = "NOKEY";          break;
388     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
389     default:
390     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
391     }
392     return str;
393 }
394
395 static rpmRC
396 verifyMD5Digest(rpmtd sigtd, DIGEST_CTX md5ctx, char **msg)
397 {
398     rpmRC res = RPMRC_FAIL; /* assume failure */
399     uint8_t * md5sum = NULL;
400     size_t md5len = 0;
401     char *md5;
402     const char *title = _("MD5 digest:");
403     *msg = NULL;
404     DIGEST_CTX ctx = rpmDigestDup(md5ctx);
405
406     if (ctx == NULL) {
407         rasprintf(msg, "%s %s\n", title, rpmSigString(res));
408         goto exit;
409     }
410
411     (void) rpmDigestFinal(ctx, (void **)&md5sum, &md5len, 0);
412
413     md5 = pgpHexStr(md5sum, md5len);
414     if (md5len != sigtd->count || memcmp(md5sum, sigtd->data, md5len)) {
415         char *hex = rpmtdFormat(sigtd, RPMTD_FORMAT_STRING, NULL);
416         rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
417                   rpmSigString(res), hex, md5);
418         free(hex);
419     } else {
420         res = RPMRC_OK;
421         rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), md5);
422     }
423     free(md5);
424
425 exit:
426     md5sum = _free(md5sum);
427     return res;
428 }
429
430 /**
431  * Verify header immutable region SHA1 digest.
432  * @retval msg          verbose success/failure text
433  * @param sha1ctx
434  * @return              RPMRC_OK on success
435  */
436 static rpmRC
437 verifySHA1Digest(rpmtd sigtd, DIGEST_CTX sha1ctx, char **msg)
438 {
439     rpmRC res = RPMRC_FAIL; /* assume failure */
440     char * SHA1 = NULL;
441     const char *title = _("Header SHA1 digest:");
442     const char *sig = sigtd->data;
443     *msg = NULL;
444     DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
445
446     if (ctx == NULL) {
447         rasprintf(msg, "%s %s\n", title, rpmSigString(res));
448         goto exit;
449     }
450
451     (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
452
453     if (SHA1 == NULL || !rstreq(SHA1, sig)) {
454         rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
455                   rpmSigString(res), sig, SHA1 ? SHA1 : "(nil)");
456     } else {
457         res = RPMRC_OK;
458         rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), SHA1);
459     }
460
461 exit:
462     SHA1 = _free(SHA1);
463     return res;
464 }
465
466 /**
467  * Verify DSA/RSA signature.
468  * @param keyring       pubkey keyring
469  * @param sig           OpenPGP signature parameters
470  * @param hashctx       digest context
471  * @param isHdr         header-only signature?
472  * @retval msg          verbose success/failure text
473  * @return              RPMRC_OK on success
474  */
475 static rpmRC
476 verifySignature(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX hashctx,
477                 int isHdr, char **msg)
478 {
479
480     rpmRC res = rpmKeyringVerifySig(keyring, sig, hashctx);
481
482     char *sigid = pgpIdentItem(sig);
483     rasprintf(msg, "%s%s: %s\n", isHdr ? _("Header ") : "", sigid, 
484                 rpmSigString(res));
485     free(sigid);
486     return res;
487 }
488
489 rpmRC
490 rpmVerifySignature(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
491                    DIGEST_CTX ctx, char ** result)
492 {
493     rpmRC res = RPMRC_NOTFOUND;
494     char *msg = NULL;
495     int hdrsig = 0;
496
497     if (sigtd->data == NULL || sigtd->count <= 0 || ctx == NULL)
498         goto exit;
499
500     switch (sigtd->tag) {
501     case RPMSIGTAG_MD5:
502         res = verifyMD5Digest(sigtd, ctx, &msg);
503         break;
504     case RPMSIGTAG_SHA1:
505         res = verifySHA1Digest(sigtd, ctx, &msg);
506         break;
507     case RPMSIGTAG_RSA:
508     case RPMSIGTAG_DSA:
509         hdrsig = 1;
510         /* fallthrough */
511     case RPMSIGTAG_PGP5:        /* XXX legacy */
512     case RPMSIGTAG_PGP:
513     case RPMSIGTAG_GPG:
514         if (sig != NULL)
515             res = verifySignature(keyring, sig, ctx, hdrsig, &msg);
516         break;
517     default:
518         break;
519     }
520
521 exit:
522     if (res == RPMRC_NOTFOUND) {
523         rasprintf(&msg,
524                   _("Verify signature: BAD PARAMETERS (%d %p %d %p %p)\n"),
525                   sigtd->tag, sigtd->data, sigtd->count, ctx, sig);
526         res = RPMRC_FAIL;
527     }
528
529     if (result) {
530         *result = msg;
531     } else {
532         free(msg);
533     }
534     return res;
535 }