solv_parse_sig: clear return values at the beginning
[platform/upstream/libsolv.git] / ext / repo_pubkey.c
1 /*
2  * Copyright (c) 2007-2013, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo_pubkey
10  *
11  * support for pubkey reading
12  *
13  */
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <limits.h>
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <assert.h>
24 #include <stdint.h>
25 #include <errno.h>
26
27 #include <rpm/rpmio.h>
28 #include <rpm/rpmpgp.h>
29 #ifndef RPM5
30 #include <rpm/header.h>
31 #endif
32 #include <rpm/rpmdb.h>
33
34 #include "pool.h"
35 #include "repo.h"
36 #include "hash.h"
37 #include "util.h"
38 #include "queue.h"
39 #include "chksum.h"
40 #include "repo_rpmdb.h"
41 #ifdef ENABLE_PGPVRFY
42 #include "solv_pgpvrfy.h"
43 #endif
44
45 static void 
46 setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
47 {
48   if (str[solv_validutf8(str)])
49     {    
50       char *ustr = solv_latin1toutf8(str);      /* not utf8, assume latin1 */
51       repodata_set_str(repodata, handle, tag, ustr);
52       solv_free(ustr);
53     }    
54   else 
55     repodata_set_str(repodata, handle, tag, str);
56 }
57
58 static char *
59 r64dec1(char *p, unsigned int *vp, int *eofp)
60 {
61   int i, x;
62   unsigned int v = 0;
63
64   for (i = 0; i < 4; )
65     {
66       x = *p++;
67       if (!x)
68         return 0;
69       if (x >= 'A' && x <= 'Z')
70         x -= 'A';
71       else if (x >= 'a' && x <= 'z')
72         x -= 'a' - 26;
73       else if (x >= '0' && x <= '9')
74         x -= '0' - 52;
75       else if (x == '+')
76         x = 62;
77       else if (x == '/')
78         x = 63;
79       else if (x == '=')
80         {
81           x = 0;
82           if (i == 0)
83             {
84               *eofp = 3;
85               *vp = 0;
86               return p - 1;
87             }
88           *eofp += 1;
89         }
90       else
91         continue;
92       v = v << 6 | x;
93       i++;
94     }
95   *vp = v;
96   return p;
97 }
98
99 static unsigned int
100 crc24(unsigned char *p, int len)
101 {
102   unsigned int crc = 0xb704ceL;
103   int i;
104
105   while (len--)
106     {
107       crc ^= (*p++) << 16;
108       for (i = 0; i < 8; i++)
109         if ((crc <<= 1) & 0x1000000)
110           crc ^= 0x1864cfbL;
111     }
112   return crc & 0xffffffL;
113 }
114
115 static unsigned char *
116 unarmor(char *pubkey, int *pktlp, char *startstr, char *endstr)
117 {
118   char *p;
119   int l, eof;
120   unsigned char *buf, *bp;
121   unsigned int v;
122
123   *pktlp = 0;
124   if (!pubkey)
125     return 0;
126   l = strlen(startstr);
127   while (strncmp(pubkey, startstr, l) != 0)
128     {
129       pubkey = strchr(pubkey, '\n');
130       if (!pubkey)
131         return 0;
132       pubkey++;
133     }
134   pubkey = strchr(pubkey, '\n');
135   if (!pubkey++)
136     return 0;
137   /* skip header lines */
138   for (;;)
139     {
140       while (*pubkey == ' ' || *pubkey == '\t')
141         pubkey++;
142       if (*pubkey == '\n')
143         break;
144       pubkey = strchr(pubkey, '\n');
145       if (!pubkey++)
146         return 0;
147     }
148   pubkey++;
149   p = strchr(pubkey, '=');
150   if (!p)
151     return 0;
152   l = p - pubkey;
153   bp = buf = solv_malloc(l * 3 / 4 + 4);
154   eof = 0;
155   while (!eof)
156     {
157       pubkey = r64dec1(pubkey, &v, &eof);
158       if (!pubkey)
159         {
160           solv_free(buf);
161           return 0;
162         }
163       *bp++ = v >> 16;
164       *bp++ = v >> 8;
165       *bp++ = v;
166     }
167   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
168     pubkey++;
169   bp -= eof;
170   if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0)
171     {
172       solv_free(buf);
173       return 0;
174     }
175   if (v != crc24(buf, bp - buf))
176     {
177       solv_free(buf);
178       return 0;
179     }
180   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
181     pubkey++;
182   if (strncmp(pubkey, endstr, strlen(endstr)) != 0)
183     {
184       solv_free(buf);
185       return 0;
186     }
187   *pktlp = bp - buf;
188   return buf;
189 }
190
191 struct pgpsig {
192   int type;
193   Id hashalgo;
194   unsigned char issuer[8];
195   int haveissuer;
196   unsigned int created;
197   unsigned int expires;
198   unsigned int keyexpires;
199   unsigned char *sigdata;
200   int sigdatal;
201   int mpioff;
202 };
203
204 static Id
205 pgphashalgo2type(int algo)
206 {
207   if (algo == 1)
208     return REPOKEY_TYPE_MD5;
209   if (algo == 2)
210     return REPOKEY_TYPE_SHA1;
211   if (algo == 8)
212     return REPOKEY_TYPE_SHA256;
213   return 0;
214 }
215
216 static void
217 createsigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, void *h)
218 {
219   int type = sig->type;
220   unsigned char b[6];
221   const unsigned char *cs;
222   int csl;
223
224   if (!sig->mpioff || l <= sig->mpioff)
225     return;
226   if ((type >= 0x10 && type <= 0x13) || type == 0x1f || type == 0x18 || type == 0x20 || type == 0x28)
227     {
228       b[0] = 0x99;
229       b[1] = pubkeyl >> 8;
230       b[2] = pubkeyl;
231       solv_chksum_add(h, b, 3);
232       solv_chksum_add(h, pubkey, pubkeyl);
233     }
234   if ((type >= 0x10 && type <= 0x13))
235     {
236       if (p[0] != 3)
237         {
238           b[0] = 0xb4;
239           b[1] = useridl >> 24;
240           b[2] = useridl >> 16;
241           b[3] = useridl >> 8;
242           b[4] = useridl;
243           solv_chksum_add(h, b, 5);
244         }
245       solv_chksum_add(h, userid, useridl);
246     }
247   /* add trailer */
248   if (p[0] == 3)
249     solv_chksum_add(h, p + 2, 5);
250   else
251     {
252       int hl = 6 + (p[4] << 8 | p[5]);
253       solv_chksum_add(h, p, hl);
254       b[0] = 4;
255       b[1] = 0xff;
256       b[2] = hl >> 24;
257       b[3] = hl >> 16;
258       b[4] = hl >> 8;
259       b[5] = hl;
260       solv_chksum_add(h, b, 6);
261     }
262   cs = solv_chksum_get(h, &csl);
263   if (cs[0] == p[sig->mpioff - 2] && cs[1] == p[sig->mpioff - 1])
264     {
265       int ml = l - sig->mpioff;
266       sig->sigdata = solv_malloc(2 + csl + ml);
267       sig->sigdatal = 2 + csl + ml;
268       sig->sigdata[0] = p[0] == 3 ? p[15] : p[2];
269       sig->sigdata[1] = p[0] == 3 ? p[16] : p[3];
270       memcpy(sig->sigdata + 2, cs, csl);
271       memcpy(sig->sigdata + 2 + csl, p + sig->mpioff, ml);
272     }
273 }
274
275 static void
276 parsesigpacket(struct pgpsig *sig, unsigned char *p, int l)
277 {
278   sig->type = -1;
279   if (p[0] == 3)
280     {
281       /* printf("V3 signature packet\n"); */
282       if (l <= 19 || p[1] != 5)
283         return;
284       sig->type = p[2];
285       sig->haveissuer = 1;
286       memcpy(sig->issuer, p + 7, 8);
287       sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
288       sig->hashalgo = p[16];
289       sig->mpioff = 19;
290     }
291   else if (p[0] == 4)
292     {
293       int j, ql, x;
294       unsigned char *q;
295
296       /* printf("V4 signature packet\n"); */
297       if (l < 6)
298         return;
299       sig->type = p[1];
300       sig->hashalgo = p[3];
301       q = p + 4;
302       sig->keyexpires = -1;
303       for (j = 0; q && j < 2; j++)
304         {
305           if (q + 2 > p + l)
306             {
307               q = 0;
308               break;
309             }
310           ql = q[0] << 8 | q[1];
311           q += 2;
312           if (q + ql > p + l)
313             {
314               q = 0;
315               break;
316             }
317           while (ql)
318             {
319               int sl;
320               /* decode sub-packet length */
321               x = *q++;
322               ql--;
323               if (x < 192)
324                 sl = x;
325               else if (x == 255)
326                 {
327                   if (ql < 4 || q[0] != 0)
328                     {
329                       q = 0;
330                       break;
331                     }
332                   sl = q[1] << 16 | q[2] << 8 | q[3];
333                   q += 4;
334                   ql -= 4;
335                 }
336               else
337                 {
338                   if (ql < 1)
339                     {
340                       q = 0;
341                       break;
342                     }
343                   sl = ((x - 192) << 8) + *q++ + 192;
344                   ql--;
345                 }
346               if (ql < sl)
347                 {
348                   q = 0;
349                   break;
350                 }
351               x = q[0] & 127;
352               /* printf("%d SIGSUB %d %d\n", j, x, sl); */
353               if (x == 16 && sl == 9 && !sig->haveissuer)
354                 {
355                   sig->haveissuer = 1;
356                   memcpy(sig->issuer, q + 1, 8);
357                 }
358               if (x == 2 && j == 0)
359                 sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
360               if (x == 3 && j == 0)
361                 sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
362               if (x == 9 && j == 0)
363                 sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
364               q += sl;
365               ql -= sl;
366             }
367         }
368       if (q && q - p + 2 < l)
369         sig->mpioff = q - p + 2;
370     }
371 }
372
373 static int
374 parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp)
375 {
376   unsigned char *op = p;
377   int x, l;
378
379   if (!pl)
380     return 0;
381   x = *p++;
382   pl--;
383   if (!(x & 128) || pl <= 0)
384     return 0;
385   if ((x & 64) == 0)
386     {
387       *tagp = (x & 0x3c) >> 2;          /* old format */
388       x = 1 << (x & 3);
389       if (x > 4 || pl < x || (x == 4 && p[0]))
390         return 0;
391       pl -= x;
392       for (l = 0; x--;)
393         l = l << 8 | *p++;
394     }
395   else
396     {
397       *tagp = (x & 0x3f);               /* new format */
398       x = *p++;
399       pl--;
400       if (x < 192)
401         l = x;
402       else if (x >= 192 && x < 224)
403         {
404           if (pl <= 0)
405             return 0;
406           l = ((x - 192) << 8) + *p++ + 192;
407           pl--;
408         }
409       else if (x == 255)
410         {
411           if (pl <= 4 || p[0] != 0)     /* sanity: p[0] must be zero */
412             return 0;
413           l = p[1] << 16 | p[2] << 8 | p[3];
414           p += 4;
415           pl -= 4;
416         }
417       else
418         return 0;
419     }
420   if (l > pl)
421     return 0;
422   *pktlp = l;
423   return p - op;
424 }
425
426
427 static void
428 parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
429 {
430   int tag, l;
431   unsigned char keyid[8];
432   unsigned int kcr = 0, maxex = 0, maxsigcr = 0;
433   unsigned char *pubkey = 0;
434   int pubkeyl = 0;
435   unsigned char *userid = 0;
436   int useridl = 0;
437   unsigned char *pubdata = 0;
438   int pubdatal = 0;
439
440   for (; pl; p += l, pl -= l)
441     {
442       int hl = parsepkgheader(p, pl, &tag, &l);
443       if (!hl)
444         break;
445       p += hl;
446       pl -= hl;
447       if (tag == 6)
448         {
449           if (pubkey)
450             break;      /* one key at a time, please */
451           pubkey = solv_malloc(l);
452           if (l)
453             memcpy(pubkey, p, l);
454           pubkeyl = l;
455           if (p[0] == 3 && l >= 10)
456             {
457               unsigned int ex;
458               void *h;
459               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
460               ex = 0;
461               if (p[5] || p[6])
462                 {
463                   ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
464                   if (ex > maxex)
465                     maxex = ex;
466                 }
467               memset(keyid, 0, 8);
468               if (p[7] == 1)    /* RSA */
469                 {
470                   int ql, ql2;
471                   unsigned char fp[16];
472                   char fpx[32 + 1];
473                   unsigned char *q;
474
475                   ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
476                   if (ql >= 8 && 10 + ql + 2 <= l)
477                     {
478                       memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
479                       q = p + 10 + ql;
480                       ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
481                       if (10 + ql + 2 + ql2 <= l)
482                         {
483                           /* fingerprint is the md5 over the two MPI bodies */
484                           h = solv_chksum_create(REPOKEY_TYPE_MD5);
485                           solv_chksum_add(h, p + 10, ql);
486                           solv_chksum_add(h, q + 2, ql2);
487                           solv_chksum_free(h, fp);
488                           solv_bin2hex(fp, 16, fpx);
489                           repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
490                         }
491                     }
492                   pubdata = p + 7;
493                   pubdatal = l - 7;
494                 }
495             }
496           else if (p[0] == 4 && l >= 6)
497             {
498               void *h;
499               unsigned char hdr[3];
500               unsigned char fp[20];
501               char fpx[40 + 1];
502
503               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
504               hdr[0] = 0x99;
505               hdr[1] = l >> 8;
506               hdr[2] = l;
507               /* fingerprint is the sha1 over the packet */
508               h = solv_chksum_create(REPOKEY_TYPE_SHA1);
509               solv_chksum_add(h, hdr, 3);
510               solv_chksum_add(h, p, l);
511               solv_chksum_free(h, fp);
512               solv_bin2hex(fp, 20, fpx);
513               repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
514               memcpy(keyid, fp + 12, 8);        /* keyid is last 64 bits of fingerprint */
515               pubdata = p + 5;
516               pubdatal = l - 5;
517             }
518         }
519       if (tag == 2)
520         {
521           struct pgpsig sig;
522           Id htype;
523           if (!pubdata)
524             continue;
525           memset(&sig, 0, sizeof(sig));
526           parsesigpacket(&sig, p, l);
527           if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
528             continue;
529           if (sig.type >= 0x10 && sig.type <= 0x13 && !userid)
530             continue;
531           htype = pgphashalgo2type(sig.hashalgo);
532           if (htype && sig.mpioff)
533             {
534               void *h = solv_chksum_create(htype);
535               createsigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h);
536               solv_chksum_free(h, 0);
537             }
538           if (!memcmp(keyid, sig.issuer, 8))
539             {
540 #ifdef ENABLE_PGPVRFY
541               /* found self sig, verify */
542               if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
543 #endif
544                 {
545                   if (sig.keyexpires && maxex != -1)
546                     {
547                       if (sig.keyexpires == -1)
548                         maxex = -1;
549                       else if (sig.keyexpires + kcr > maxex)
550                         maxex = sig.keyexpires + kcr;
551                     }
552                   if (sig.created > maxsigcr)
553                     maxsigcr = sig.created;
554                 }
555             }
556           else
557             {
558               char issuerstr[17];
559               Id shandle = repodata_new_handle(data);
560               solv_bin2hex(sig.issuer, 8, issuerstr);
561               repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
562               if (sig.created)
563                 repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
564               if (sig.expires)
565                 repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
566               if (sig.sigdata)
567                 repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
568               repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle);
569             }
570           solv_free(sig.sigdata);
571         }
572       if (tag == 13)
573         {
574           userid = solv_realloc(userid, l);
575           if (l)
576             memcpy(userid, p, l);
577           useridl = l;
578         }
579     }
580   if (kcr)
581     repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, kcr);
582   if (maxex && maxex != -1)
583     repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex);
584   s->name = pool_str2id(s->repo->pool, "gpg-pubkey", 1);
585   s->evr = 1;
586   s->arch = 1;
587   if (userid && useridl)
588     {
589       char *useridstr = solv_malloc(useridl + 1);
590       memcpy(useridstr, userid, useridl);
591       useridstr[useridl] = 0;
592       setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, useridstr);
593       free(useridstr);
594     }
595   if (pubdata)
596     {
597       char keyidstr[17];
598       solv_bin2hex(keyid, 8, keyidstr);
599       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyidstr);
600     }
601   if (pubdata)
602     {
603       /* build rpm-style evr */
604       char evr[8 + 1 + 8 + 1];
605       solv_bin2hex(keyid + 4, 4, evr);
606       sprintf(evr + 8, "-%08x", maxsigcr);
607       s->evr = pool_str2id(s->repo->pool, evr, 1);
608       /* set data blob */
609       repodata_set_binary(data, s - s->repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
610     }
611   solv_free(pubkey);
612   solv_free(userid);
613 }
614
615
616 #ifdef ENABLE_RPMDB
617
618 /* this is private to rpm, but rpm lacks an interface to retrieve
619  * the values. Sigh. */
620 struct pgpDigParams_s {
621     const char * userid;
622     const unsigned char * hash;
623 #ifndef HAVE_PGPDIGGETPARAMS
624     const char * params[4];
625 #endif
626     unsigned char tag;
627     unsigned char version;               /*!< version number. */
628     unsigned char time[4];               /*!< time that the key was created. */
629     unsigned char pubkey_algo;           /*!< public key algorithm. */
630     unsigned char hash_algo;
631     unsigned char sigtype;
632     unsigned char hashlen;
633     unsigned char signhash16[2];
634     unsigned char signid[8];
635     unsigned char saved;
636 };
637
638 #ifndef HAVE_PGPDIGGETPARAMS
639 struct pgpDig_s {
640     struct pgpDigParams_s signature;
641     struct pgpDigParams_s pubkey;
642 };
643 #endif
644
645
646 /* only rpm knows how to do the release calculation, we don't dare
647  * to recreate all the bugs in libsolv */
648 static void
649 parsekeydata_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl)
650 {
651   Pool *pool = s->repo->pool;
652   struct pgpDigParams_s *digpubkey;
653   pgpDig dig = 0;
654   char keyid[16 + 1];
655   char evrbuf[8 + 1 + 8 + 1];
656   unsigned int btime;
657
658 #ifndef RPM5
659   dig = pgpNewDig();
660 #else
661   dig = pgpDigNew(RPMVSF_DEFAULT, 0);
662 #endif
663   (void) pgpPrtPkts(pkts, pktsl, dig, 0);
664 #ifdef HAVE_PGPDIGGETPARAMS
665   digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
666 #else
667   digpubkey = &dig->pubkey;
668 #endif
669   if (digpubkey)
670     {
671       btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3];
672       solv_bin2hex(digpubkey->signid, 8, keyid);
673       solv_bin2hex(digpubkey->signid + 4, 4, evrbuf);
674       evrbuf[8] = '-';
675       solv_bin2hex(digpubkey->time, 4, evrbuf + 9);
676       s->evr = pool_str2id(pool, evrbuf, 1);
677       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid);
678       if (digpubkey->userid)
679         setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid);
680       if (btime)
681         repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime);
682     }
683 #ifndef RPM5
684   (void)pgpFreeDig(dig);
685 #else
686   (void)pgpDigFree(dig);
687 #endif
688 }
689
690 #endif  /* ENABLE_RPMDB */
691
692 static int
693 pubkey2solvable(Solvable *s, Repodata *data, char *pubkey)
694 {
695   unsigned char *pkts;
696   int pktsl;
697
698   pkts = unarmor(pubkey, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----");
699   if (!pkts)
700     {
701       pool_error(s->repo->pool, 0, "unarmor failure");
702       return 0;
703     }
704   setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey);
705   parsekeydata(s, data, pkts, pktsl);
706 #ifdef ENABLE_RPMDB
707   parsekeydata_rpm(s, data, pkts, pktsl);
708 #endif
709   solv_free((void *)pkts);
710   return 1;
711 }
712
713 #ifdef ENABLE_RPMDB
714
715 int
716 repo_add_rpmdb_pubkeys(Repo *repo, int flags)
717 {
718   Pool *pool = repo->pool;
719   Queue q;
720   int i;
721   char *str;
722   Repodata *data;
723   Solvable *s;
724   const char *rootdir = 0;
725   void *state;
726
727   data = repo_add_repodata(repo, flags);
728   if (flags & REPO_USE_ROOTDIR)
729     rootdir = pool_get_rootdir(pool);
730   state = rpm_state_create(repo->pool, rootdir);
731   queue_init(&q);
732   rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
733   for (i = 0; i < q.count; i++)
734     {
735       void *handle;
736       unsigned long long itime;
737
738       handle = rpm_byrpmdbid(state, q.elements[i]);
739       if (!handle)
740         continue;
741       str = rpm_query(handle, SOLVABLE_DESCRIPTION);
742       if (!str)
743         continue;
744       s = pool_id2solvable(pool, repo_add_solvable(repo));
745       pubkey2solvable(s, data, str);
746       solv_free(str);
747       itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
748       if (itime)
749         repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, itime);
750       if (!repo->rpmdbid)
751         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
752       repo->rpmdbid[s - pool->solvables - repo->start] = q.elements[i];
753     }
754   queue_free(&q);
755   rpm_state_free(state);
756   if (!(flags & REPO_NO_INTERNALIZE))
757     repodata_internalize(data);
758   return 0;
759 }
760
761 #endif
762
763 static char *
764 solv_slurp(FILE *fp, int *lenp)
765 {
766   int l, ll;
767   char *buf = 0;
768   int bufl = 0;
769
770   for (l = 0; ; l += ll)
771     {
772       if (bufl - l < 4096)
773         {
774           bufl += 4096;
775           buf = solv_realloc(buf, bufl);
776         }
777       ll = fread(buf + l, 1, bufl - l, fp);
778       if (ll < 0)
779         {
780           buf = solv_free(buf);
781           l = 0;
782           break;
783         }
784       if (ll == 0)
785         {
786           buf[l] = 0;   /* always zero-terminate */
787           break;
788         }
789     }
790   if (lenp)
791     *lenp = l;
792   return buf;
793 }
794
795 Id
796 repo_add_pubkey(Repo *repo, const char *key, int flags)
797 {
798   Pool *pool = repo->pool;
799   Repodata *data;
800   Solvable *s;
801   char *buf;
802   FILE *fp;
803
804   data = repo_add_repodata(repo, flags);
805   buf = 0;
806   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0)
807     {
808       pool_error(pool, -1, "%s: %s", key, strerror(errno));
809       return 0;
810     }
811   if ((buf = solv_slurp(fp, 0)) == 0)
812     {
813       pool_error(pool, -1, "%s: %s", key, strerror(errno));
814       fclose(fp);
815       return 0;
816     }
817   fclose(fp);
818   s = pool_id2solvable(pool, repo_add_solvable(repo));
819   if (!pubkey2solvable(s, data, buf))
820     {
821       repo_free_solvable(repo, s - pool->solvables, 1);
822       solv_free(buf);
823       return 0;
824     }
825   solv_free(buf);
826   if (!(flags & REPO_NO_INTERNALIZE))
827     repodata_internalize(data);
828   return s - pool->solvables;
829 }
830
831 static int
832 is_sig_packet(unsigned char *sig, int sigl)
833 {
834   if (!sigl)
835     return 0;
836   if ((sig[0] & 0x80) == 0 || (sig[0] & 0x40 ? sig[0] & 0x3f : sig[0] >> 2 & 0x0f) != 2)
837     return 0;
838   return 1;
839 }
840
841 Id
842 solv_parse_sig(FILE *fp, unsigned char **sigpkgp, int *sigpkglp, char *keyidstr)
843 {
844   unsigned char *sig;
845   int sigl, hl, tag, pktl;
846   struct pgpsig pgpsig;
847   Id htype;
848
849   if (sigpkgp)
850     {
851       *sigpkgp = 0;
852       *sigpkglp = 0;
853     }
854   if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0)
855     return 0;
856   if (!is_sig_packet(sig, sigl))
857     {
858       /* not a raw sig, check armored */
859       unsigned char *nsig;
860       nsig = unarmor((char *)sig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----");
861       solv_free(sig);
862       if (!nsig)
863         return 0;
864       sig = nsig;
865       if (!is_sig_packet(sig, sigl))
866         {
867           solv_free(sig);
868           return 0;
869         }
870     }
871   hl = parsepkgheader(sig, sigl, &tag, &pktl);
872   if (!hl || tag != 2)
873     {
874       solv_free(sig);
875       return 0;
876     }
877   memset(&pgpsig, 0, sizeof(pgpsig));
878   parsesigpacket(&pgpsig, sig + hl, pktl);
879   htype = pgphashalgo2type(pgpsig.hashalgo);
880   if (pgpsig.type != 0 || !htype)
881     {
882       solv_free(sig);
883       return 0;
884     }
885   if (sigpkgp)
886     {
887       *sigpkgp = sig + hl;
888       *sigpkglp = pktl;
889     }
890   else
891     solv_free(sig);
892   if (keyidstr)
893     solv_bin2hex(pgpsig.issuer, 8, keyidstr);
894   return htype;
895 }
896
897 #ifdef ENABLE_PGPVRFY
898 int
899 solv_verify_sig(const unsigned char *pubdata, int pubdatal, unsigned char *sigpkg, int sigpkgl, void *chk)
900 {
901   struct pgpsig pgpsig;
902   int res;
903   Id htype;
904
905   memset(&pgpsig, 0, sizeof(pgpsig));
906   parsesigpacket(&pgpsig, sigpkg, sigpkgl);
907   if (pgpsig.type != 0)
908     return 0;
909   htype = pgphashalgo2type(pgpsig.hashalgo);
910   if (htype != solv_chksum_get_type(chk))
911      return 0;  /* wrong hash type? */
912   createsigdata(&pgpsig, sigpkg, sigpkgl, 0, 0, 0, 0, chk);
913   if (!pgpsig.sigdata)
914     return 0;
915   res = solv_pgpvrfy(pubdata, pubdatal, pgpsig.sigdata, pgpsig.sigdatal);
916   solv_free(pgpsig.sigdata);
917   return res;
918 }
919 #endif
920