Add macro %isu_package to generate ISU Package
[platform/upstream/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 = Freadall(fd, block, sizeof(block))) != 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 = Freadall(fd, pe, nb)) != 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         /* Is the region tag sane? */
139         if (!(entry.info.type == REGION_TAG_TYPE &&
140               entry.info.count == REGION_TAG_COUNT)) {
141             rasprintf(&buf,
142                 _("region tag: BAD, tag %d type %d offset %d count %d\n"),
143                 entry.info.tag, entry.info.type,
144                 entry.info.offset, entry.info.count);
145             goto exit;
146         }
147         
148         /* Is the trailer within the data area? */
149         if (entry.info.offset + REGION_TAG_COUNT > dl) {
150             rasprintf(&buf, 
151                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
152                 entry.info.tag, entry.info.type,
153                 entry.info.offset, entry.info.count);
154             goto exit;
155         }
156
157         /* Is there an immutable header region tag trailer? */
158         dataEnd = dataStart + entry.info.offset;
159         (void) memcpy(&info, dataEnd, REGION_TAG_COUNT);
160         /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
161         if (info.tag == htonl(RPMTAG_HEADERIMAGE)) {
162             rpmTagVal stag = htonl(RPMTAG_HEADERSIGNATURES);
163             info.tag = stag;
164             memcpy(dataEnd, &stag, sizeof(stag));
165         }
166         dataEnd += REGION_TAG_COUNT;
167
168         xx = headerVerifyInfo(1, il * sizeof(*pe), &info, &entry.info, 1);
169         if (xx != -1 ||
170             !((entry.info.tag == RPMTAG_HEADERSIGNATURES || entry.info.tag == RPMTAG_HEADERIMAGE)
171            && entry.info.type == REGION_TAG_TYPE
172            && entry.info.count == REGION_TAG_COUNT))
173         {
174             rasprintf(&buf,
175                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
176                 entry.info.tag, entry.info.type,
177                 entry.info.offset, entry.info.count);
178             goto exit;
179         }
180         memset(&info, 0, sizeof(info));
181
182         /* Is the no. of tags in the region less than the total no. of tags? */
183         ril = entry.info.offset/sizeof(*pe);
184         if ((entry.info.offset % sizeof(*pe)) || ril > il) {
185             rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
186             goto exit;
187         }
188     }
189
190     /* Sanity check signature tags */
191     memset(&info, 0, sizeof(info));
192     for (i = 1; i < il; i++) {
193         xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0);
194         if (xx != -1) {
195             rasprintf(&buf, 
196                 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
197                 i, entry.info.tag, entry.info.type,
198                 entry.info.offset, entry.info.count);
199             goto exit;
200         }
201     }
202
203     /* OK, blob looks sane, load the header. */
204     sigh = headerImport(ei, uc, 0);
205     if (sigh == NULL) {
206         rasprintf(&buf, _("sigh load: BAD\n"));
207         goto exit;
208     }
209
210     {   size_t sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
211         size_t pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
212         ssize_t trc;
213         struct rpmtd_s sizetag;
214         rpm_loff_t archSize = 0;
215
216         /* Position at beginning of header. */
217         if (pad && (trc = Freadall(fd, block, pad)) != pad) {
218             rasprintf(&buf,
219                       _("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc);
220             goto exit;
221         }
222
223         /* Print package component sizes. */
224         if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) {
225             rpm_loff_t *tsize = rpmtdGetUint64(&sizetag);
226             archSize = (tsize) ? *tsize : 0;
227         } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) {
228             rpm_off_t *tsize = rpmtdGetUint32(&sizetag);
229             archSize = (tsize) ? *tsize : 0;
230         }
231         rpmtdFreeData(&sizetag);
232         rc = printSize(fd, sigSize, pad, archSize);
233         if (rc != RPMRC_OK) {
234             rasprintf(&buf,
235                    _("sigh sigSize(%zd): BAD, fstat(2) failed\n"), sigSize);
236             goto exit;
237         }
238     }
239     ei = NULL; /* XXX will be freed with header */
240
241 exit:
242     if (sighp && sigh && rc == RPMRC_OK)
243         *sighp = headerLink(sigh);
244     headerFree(sigh);
245     free(ei);
246
247     if (msg != NULL) {
248         *msg = buf;
249     } else {
250         free(buf);
251     }
252
253     return rc;
254 }
255
256 int rpmWriteSignature(FD_t fd, Header sigh)
257 {
258     static uint8_t buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
259     int sigSize, pad;
260     int rc;
261
262     rc = headerWrite(fd, sigh, HEADER_MAGIC_YES);
263     if (rc)
264         return rc;
265
266     sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
267     pad = (8 - (sigSize % 8)) % 8;
268     if (pad) {
269         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
270             rc = 1;
271     }
272     rpmlog(RPMLOG_DEBUG, "Signature: size(%d)+pad(%d)\n", sigSize, pad);
273     return rc;
274 }
275
276 Header rpmNewSignature(void)
277 {
278     Header sigh = headerNew();
279     return sigh;
280 }
281
282 Header rpmFreeSignature(Header sigh)
283 {
284     return headerFree(sigh);
285 }
286
287 static int makeHDRDigest(Header sigh, const char * file, rpmTagVal sigTag)
288 {
289     Header h = NULL;
290     FD_t fd = NULL;
291     char * SHA1 = NULL;
292     int ret = -1;       /* assume failure. */
293
294     switch (sigTag) {
295     case RPMSIGTAG_SHA1:
296         fd = Fopen(file, "r.fdio");
297         if (fd == NULL || Ferror(fd))
298             goto exit;
299         h = headerRead(fd, HEADER_MAGIC_YES);
300         if (h == NULL)
301             goto exit;
302
303         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
304             DIGEST_CTX ctx;
305             struct rpmtd_s utd;
306         
307             if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)
308                 ||  utd.data == NULL)
309             {
310                 rpmlog(RPMLOG_ERR, 
311                                 _("Immutable header region could not be read. "
312                                 "Corrupted package?\n"));
313                 goto exit;
314             }
315             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
316             (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
317             (void) rpmDigestUpdate(ctx, utd.data, utd.count);
318             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
319             rpmtdFreeData(&utd);
320         } else {
321             rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
322             goto exit;
323         }
324
325         if (SHA1 == NULL)
326             goto exit;
327         if (!sighdrPut(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
328             goto exit;
329         ret = 0;
330         break;
331     default:
332         break;
333     }
334
335 exit:
336     free(SHA1);
337     headerFree(h);
338     if (fd != NULL) (void) Fclose(fd);
339     return ret;
340 }
341
342 int rpmGenDigest(Header sigh, const char * file, rpmTagVal sigTag)
343 {
344     struct stat st;
345     uint8_t * pkt = NULL;
346     size_t pktlen;
347     int ret = -1;       /* assume failure. */
348
349     switch (sigTag) {
350     case RPMSIGTAG_SIZE: {
351         rpm_off_t size;
352         if (stat(file, &st) != 0)
353             break;
354         size = st.st_size;
355         if (!sighdrPut(sigh, sigTag, RPM_INT32_TYPE, &size, 1))
356             break;
357         ret = 0;
358         } break;
359     case RPMSIGTAG_LONGSIZE: {
360         rpm_loff_t size;
361         if (stat(file, &st) != 0)
362             break;
363         size = st.st_size;
364         if (!sighdrPut(sigh, sigTag, RPM_INT64_TYPE, &size, 1))
365             break;
366         ret = 0;
367         } break;
368     case RPMSIGTAG_MD5:
369         pktlen = 16;
370         pkt = xcalloc(pktlen, sizeof(*pkt));
371         if (rpmDoDigest(PGPHASHALGO_MD5, file, 0, pkt, NULL)
372          || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
373             break;
374         ret = 0;
375         break;
376     case RPMSIGTAG_SHA1:
377         ret = makeHDRDigest(sigh, file, sigTag);
378         break;
379     default:
380         break;
381     }
382     free(pkt);
383
384     return ret;
385 }
386
387 static const char * rpmSigString(rpmRC res)
388 {
389     const char * str;
390     switch (res) {
391     case RPMRC_OK:              str = "OK";             break;
392     case RPMRC_FAIL:            str = "BAD";            break;
393     case RPMRC_NOKEY:           str = "NOKEY";          break;
394     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
395     default:
396     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
397     }
398     return str;
399 }
400
401 static rpmRC
402 verifyMD5Digest(rpmtd sigtd, DIGEST_CTX md5ctx, char **msg)
403 {
404     rpmRC res = RPMRC_FAIL; /* assume failure */
405     uint8_t * md5sum = NULL;
406     size_t md5len = 0;
407     char *md5;
408     const char *title = _("MD5 digest:");
409     *msg = NULL;
410     DIGEST_CTX ctx = rpmDigestDup(md5ctx);
411
412     if (ctx == NULL) {
413         rasprintf(msg, "%s %s\n", title, rpmSigString(res));
414         goto exit;
415     }
416
417     (void) rpmDigestFinal(ctx, (void **)&md5sum, &md5len, 0);
418
419     md5 = pgpHexStr(md5sum, md5len);
420     if (md5len != sigtd->count || memcmp(md5sum, sigtd->data, md5len)) {
421         char *hex = rpmtdFormat(sigtd, RPMTD_FORMAT_STRING, NULL);
422         rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
423                   rpmSigString(res), hex, md5);
424         free(hex);
425     } else {
426         res = RPMRC_OK;
427         rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), md5);
428     }
429     free(md5);
430
431 exit:
432     md5sum = _free(md5sum);
433     return res;
434 }
435
436 /**
437  * Verify header immutable region SHA1 digest.
438  * @retval msg          verbose success/failure text
439  * @param sha1ctx
440  * @return              RPMRC_OK on success
441  */
442 static rpmRC
443 verifySHA1Digest(rpmtd sigtd, DIGEST_CTX sha1ctx, char **msg)
444 {
445     rpmRC res = RPMRC_FAIL; /* assume failure */
446     char * SHA1 = NULL;
447     const char *title = _("Header SHA1 digest:");
448     const char *sig = sigtd->data;
449     *msg = NULL;
450     DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
451
452     if (ctx == NULL) {
453         rasprintf(msg, "%s %s\n", title, rpmSigString(res));
454         goto exit;
455     }
456
457     (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
458
459     if (SHA1 == NULL || !rstreq(SHA1, sig)) {
460         rasprintf(msg, "%s %s Expected(%s) != (%s)\n", title,
461                   rpmSigString(res), sig, SHA1 ? SHA1 : "(nil)");
462     } else {
463         res = RPMRC_OK;
464         rasprintf(msg, "%s %s (%s)\n", title, rpmSigString(res), SHA1);
465     }
466
467 exit:
468     SHA1 = _free(SHA1);
469     return res;
470 }
471
472 /**
473  * Verify DSA/RSA signature.
474  * @param keyring       pubkey keyring
475  * @param sig           OpenPGP signature parameters
476  * @param hashctx       digest context
477  * @param isHdr         header-only signature?
478  * @retval msg          verbose success/failure text
479  * @return              RPMRC_OK on success
480  */
481 static rpmRC
482 verifySignature(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX hashctx,
483                 int isHdr, char **msg)
484 {
485
486     rpmRC res = rpmKeyringVerifySig(keyring, sig, hashctx);
487
488     char *sigid = pgpIdentItem(sig);
489     rasprintf(msg, "%s%s: %s\n", isHdr ? _("Header ") : "", sigid, 
490                 rpmSigString(res));
491     free(sigid);
492     return res;
493 }
494
495 rpmRC
496 rpmVerifySignature(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
497                    DIGEST_CTX ctx, char ** result)
498 {
499     rpmRC res = RPMRC_NOTFOUND;
500     char *msg = NULL;
501     int hdrsig = 0;
502
503     if (sigtd->data == NULL || sigtd->count <= 0 || ctx == NULL)
504         goto exit;
505
506     switch (sigtd->tag) {
507     case RPMSIGTAG_MD5:
508         res = verifyMD5Digest(sigtd, ctx, &msg);
509         break;
510     case RPMSIGTAG_SHA1:
511         res = verifySHA1Digest(sigtd, ctx, &msg);
512         break;
513     case RPMSIGTAG_RSA:
514     case RPMSIGTAG_DSA:
515         hdrsig = 1;
516         /* fallthrough */
517     case RPMSIGTAG_PGP5:        /* XXX legacy */
518     case RPMSIGTAG_PGP:
519     case RPMSIGTAG_GPG:
520         if (sig != NULL)
521             res = verifySignature(keyring, sig, ctx, hdrsig, &msg);
522         break;
523     default:
524         break;
525     }
526
527 exit:
528     if (res == RPMRC_NOTFOUND) {
529         rasprintf(&msg,
530                   _("Verify signature: BAD PARAMETERS (%d %p %d %p %p)\n"),
531                   sigtd->tag, sigtd->data, sigtd->count, ctx, sig);
532         res = RPMRC_FAIL;
533     }
534
535     if (result) {
536         *result = msg;
537     } else {
538         free(msg);
539     }
540     return res;
541 }