create a copy of the sig data so that it can be freed later
[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 < 2 || 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 inline int
276 parsesubpkglength(unsigned char *q, int ql, int *pktlp)
277 {
278   int x, sl, hl;
279   /* decode sub-packet length, ql must be > 0 */
280   x = *q++;
281   if (x < 192)
282     {
283       sl = x;
284       hl = 1;
285     }
286   else if (x == 255)
287     {
288       if (ql < 5 || q[0] != 0)
289         return 0;
290       sl = q[1] << 16 | q[2] << 8 | q[3];
291       hl = 5;
292     }
293   else
294     {
295       if (ql < 2)
296         return 0;
297       sl = ((x - 192) << 8) + q[0] + 192;
298       hl = 2;
299     }
300   if (!sl || ql < sl + hl)      /* sub pkg tag is included in length, i.e. sl must not be zero */
301     return 0;
302   *pktlp = sl;
303   return hl;
304 }
305
306 static void
307 parsesigpacket(struct pgpsig *sig, unsigned char *p, int l)
308 {
309   sig->type = -1;
310   if (p[0] == 3)
311     {
312       /* printf("V3 signature packet\n"); */
313       if (l <= 19 || p[1] != 5)
314         return;
315       sig->type = p[2];
316       sig->haveissuer = 1;
317       memcpy(sig->issuer, p + 7, 8);
318       sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
319       sig->hashalgo = p[16];
320       sig->mpioff = 19;
321     }
322   else if (p[0] == 4)
323     {
324       int j, ql, x;
325       unsigned char *q;
326
327       /* printf("V4 signature packet\n"); */
328       if (l < 6)
329         return;
330       sig->type = p[1];
331       sig->hashalgo = p[3];
332       q = p + 4;
333       sig->keyexpires = -1;
334       for (j = 0; q && j < 2; j++)
335         {
336           if (q + 2 > p + l)
337             {
338               q = 0;
339               break;
340             }
341           ql = q[0] << 8 | q[1];
342           q += 2;
343           if (q + ql > p + l)
344             {
345               q = 0;
346               break;
347             }
348           while (ql > 0)
349             {
350               int sl, hl;
351               hl = parsesubpkglength(q, ql, &sl);
352               if (!hl)
353                 {
354                   q = 0;
355                   break;
356                 }
357               q += hl;
358               ql -= hl;
359               x = q[0] & 127;   /* strip critical bit */
360               /* printf("%d SIGSUB %d %d\n", j, x, sl); */
361               if (x == 16 && sl == 9 && !sig->haveissuer)
362                 {
363                   sig->haveissuer = 1;
364                   memcpy(sig->issuer, q + 1, 8);
365                 }
366               if (x == 2 && j == 0)
367                 sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
368               if (x == 3 && j == 0)
369                 sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
370               if (x == 9 && j == 0)
371                 sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
372               q += sl;
373               ql -= sl;
374             }
375         }
376       if (q && q - p + 2 < l)
377         sig->mpioff = q - p + 2;
378     }
379 }
380
381 static int
382 parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp)
383 {
384   unsigned char *op = p;
385   int x, l;
386
387   if (!pl)
388     return 0;
389   x = *p++;
390   pl--;
391   if (!(x & 128) || pl <= 0)
392     return 0;
393   if ((x & 64) == 0)
394     {
395       *tagp = (x & 0x3c) >> 2;          /* old format */
396       x = 1 << (x & 3);
397       if (x > 4 || pl < x || (x == 4 && p[0]))
398         return 0;
399       pl -= x;
400       for (l = 0; x--;)
401         l = l << 8 | *p++;
402     }
403   else
404     {
405       *tagp = (x & 0x3f);               /* new format */
406       x = *p++;
407       pl--;
408       if (x < 192)
409         l = x;
410       else if (x >= 192 && x < 224)
411         {
412           if (pl <= 0)
413             return 0;
414           l = ((x - 192) << 8) + *p++ + 192;
415           pl--;
416         }
417       else if (x == 255)
418         {
419           if (pl <= 4 || p[0] != 0)     /* sanity: p[0] must be zero */
420             return 0;
421           l = p[1] << 16 | p[2] << 8 | p[3];
422           p += 4;
423           pl -= 4;
424         }
425       else
426         return 0;
427     }
428   if (l > pl)
429     return 0;
430   *pktlp = l;
431   return p - op;
432 }
433
434
435 static void
436 parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
437 {
438   int tag, l;
439   unsigned char keyid[8];
440   unsigned int kcr = 0, maxex = 0, maxsigcr = 0;
441   unsigned char *pubkey = 0;
442   int pubkeyl = 0;
443   unsigned char *userid = 0;
444   int useridl = 0;
445   unsigned char *pubdata = 0;
446   int pubdatal = 0;
447
448   for (; pl; p += l, pl -= l)
449     {
450       int hl = parsepkgheader(p, pl, &tag, &l);
451       if (!hl)
452         break;
453       p += hl;
454       pl -= hl;
455       if (tag == 6)
456         {
457           if (pubkey)
458             break;      /* one key at a time, please */
459           pubkey = solv_malloc(l);
460           if (l)
461             memcpy(pubkey, p, l);
462           pubkeyl = l;
463           if (p[0] == 3 && l >= 10)
464             {
465               unsigned int ex;
466               void *h;
467               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
468               ex = 0;
469               if (p[5] || p[6])
470                 {
471                   ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
472                   if (ex > maxex)
473                     maxex = ex;
474                 }
475               memset(keyid, 0, 8);
476               if (p[7] == 1)    /* RSA */
477                 {
478                   int ql, ql2;
479                   unsigned char fp[16];
480                   char fpx[32 + 1];
481                   unsigned char *q;
482
483                   ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
484                   if (ql >= 8 && 10 + ql + 2 <= l)
485                     {
486                       memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
487                       q = p + 10 + ql;
488                       ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
489                       if (10 + ql + 2 + ql2 <= l)
490                         {
491                           /* fingerprint is the md5 over the two MPI bodies */
492                           h = solv_chksum_create(REPOKEY_TYPE_MD5);
493                           solv_chksum_add(h, p + 10, ql);
494                           solv_chksum_add(h, q + 2, ql2);
495                           solv_chksum_free(h, fp);
496                           solv_bin2hex(fp, 16, fpx);
497                           repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
498                         }
499                     }
500                   pubdata = p + 7;
501                   pubdatal = l - 7;
502                 }
503             }
504           else if (p[0] == 4 && l >= 6)
505             {
506               void *h;
507               unsigned char hdr[3];
508               unsigned char fp[20];
509               char fpx[40 + 1];
510
511               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
512               hdr[0] = 0x99;
513               hdr[1] = l >> 8;
514               hdr[2] = l;
515               /* fingerprint is the sha1 over the packet */
516               h = solv_chksum_create(REPOKEY_TYPE_SHA1);
517               solv_chksum_add(h, hdr, 3);
518               solv_chksum_add(h, p, l);
519               solv_chksum_free(h, fp);
520               solv_bin2hex(fp, 20, fpx);
521               repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
522               memcpy(keyid, fp + 12, 8);        /* keyid is last 64 bits of fingerprint */
523               pubdata = p + 5;
524               pubdatal = l - 5;
525             }
526         }
527       if (tag == 2)
528         {
529           struct pgpsig sig;
530           Id htype;
531           if (!pubdata)
532             continue;
533           memset(&sig, 0, sizeof(sig));
534           parsesigpacket(&sig, p, l);
535           if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
536             continue;
537           if (sig.type >= 0x10 && sig.type <= 0x13 && !userid)
538             continue;
539           htype = pgphashalgo2type(sig.hashalgo);
540           if (htype && sig.mpioff)
541             {
542               void *h = solv_chksum_create(htype);
543               createsigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h);
544               solv_chksum_free(h, 0);
545             }
546           if (!memcmp(keyid, sig.issuer, 8))
547             {
548 #ifdef ENABLE_PGPVRFY
549               /* found self sig, verify */
550               if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
551 #endif
552                 {
553                   if (sig.keyexpires && maxex != -1)
554                     {
555                       if (sig.keyexpires == -1)
556                         maxex = -1;
557                       else if (sig.keyexpires + kcr > maxex)
558                         maxex = sig.keyexpires + kcr;
559                     }
560                   if (sig.created > maxsigcr)
561                     maxsigcr = sig.created;
562                 }
563             }
564           else
565             {
566               char issuerstr[17];
567               Id shandle = repodata_new_handle(data);
568               solv_bin2hex(sig.issuer, 8, issuerstr);
569               repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
570               if (sig.created)
571                 repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
572               if (sig.expires)
573                 repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
574               if (sig.sigdata)
575                 repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
576               repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle);
577             }
578           solv_free(sig.sigdata);
579         }
580       if (tag == 13)
581         {
582           userid = solv_realloc(userid, l);
583           if (l)
584             memcpy(userid, p, l);
585           useridl = l;
586         }
587     }
588   if (kcr)
589     repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, kcr);
590   if (maxex && maxex != -1)
591     repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex);
592   s->name = pool_str2id(s->repo->pool, "gpg-pubkey", 1);
593   s->evr = 1;
594   s->arch = 1;
595   if (userid && useridl)
596     {
597       char *useridstr = solv_malloc(useridl + 1);
598       memcpy(useridstr, userid, useridl);
599       useridstr[useridl] = 0;
600       setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, useridstr);
601       free(useridstr);
602     }
603   if (pubdata)
604     {
605       char keyidstr[17];
606       solv_bin2hex(keyid, 8, keyidstr);
607       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyidstr);
608     }
609   if (pubdata)
610     {
611       /* build rpm-style evr */
612       char evr[8 + 1 + 8 + 1];
613       solv_bin2hex(keyid + 4, 4, evr);
614       sprintf(evr + 8, "-%08x", maxsigcr);
615       s->evr = pool_str2id(s->repo->pool, evr, 1);
616       /* set data blob */
617       repodata_set_binary(data, s - s->repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
618     }
619   solv_free(pubkey);
620   solv_free(userid);
621 }
622
623
624 #ifdef ENABLE_RPMDB
625
626 /* this is private to rpm, but rpm lacks an interface to retrieve
627  * the values. Sigh. */
628 struct pgpDigParams_s {
629     const char * userid;
630     const unsigned char * hash;
631 #ifndef HAVE_PGPDIGGETPARAMS
632     const char * params[4];
633 #endif
634     unsigned char tag;
635     unsigned char version;               /*!< version number. */
636     unsigned char time[4];               /*!< time that the key was created. */
637     unsigned char pubkey_algo;           /*!< public key algorithm. */
638     unsigned char hash_algo;
639     unsigned char sigtype;
640     unsigned char hashlen;
641     unsigned char signhash16[2];
642     unsigned char signid[8];
643     unsigned char saved;
644 };
645
646 #ifndef HAVE_PGPDIGGETPARAMS
647 struct pgpDig_s {
648     struct pgpDigParams_s signature;
649     struct pgpDigParams_s pubkey;
650 };
651 #endif
652
653
654 /* only rpm knows how to do the release calculation, we don't dare
655  * to recreate all the bugs in libsolv */
656 static void
657 parsekeydata_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl)
658 {
659   Pool *pool = s->repo->pool;
660   struct pgpDigParams_s *digpubkey;
661   pgpDig dig = 0;
662   char keyid[16 + 1];
663   char evrbuf[8 + 1 + 8 + 1];
664   unsigned int btime;
665
666 #ifndef RPM5
667   dig = pgpNewDig();
668 #else
669   dig = pgpDigNew(RPMVSF_DEFAULT, 0);
670 #endif
671   (void) pgpPrtPkts(pkts, pktsl, dig, 0);
672 #ifdef HAVE_PGPDIGGETPARAMS
673   digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
674 #else
675   digpubkey = &dig->pubkey;
676 #endif
677   if (digpubkey)
678     {
679       btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3];
680       solv_bin2hex(digpubkey->signid, 8, keyid);
681       solv_bin2hex(digpubkey->signid + 4, 4, evrbuf);
682       evrbuf[8] = '-';
683       solv_bin2hex(digpubkey->time, 4, evrbuf + 9);
684       s->evr = pool_str2id(pool, evrbuf, 1);
685       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid);
686       if (digpubkey->userid)
687         setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid);
688       if (btime)
689         repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime);
690     }
691 #ifndef RPM5
692   (void)pgpFreeDig(dig);
693 #else
694   (void)pgpDigFree(dig);
695 #endif
696 }
697
698 #endif  /* ENABLE_RPMDB */
699
700 static int
701 pubkey2solvable(Solvable *s, Repodata *data, char *pubkey)
702 {
703   unsigned char *pkts;
704   int pktsl;
705
706   pkts = unarmor(pubkey, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----");
707   if (!pkts)
708     {
709       pool_error(s->repo->pool, 0, "unarmor failure");
710       return 0;
711     }
712   setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey);
713   parsekeydata(s, data, pkts, pktsl);
714 #ifdef ENABLE_RPMDB
715   parsekeydata_rpm(s, data, pkts, pktsl);
716 #endif
717   solv_free((void *)pkts);
718   return 1;
719 }
720
721 #ifdef ENABLE_RPMDB
722
723 int
724 repo_add_rpmdb_pubkeys(Repo *repo, int flags)
725 {
726   Pool *pool = repo->pool;
727   Queue q;
728   int i;
729   char *str;
730   Repodata *data;
731   Solvable *s;
732   const char *rootdir = 0;
733   void *state;
734
735   data = repo_add_repodata(repo, flags);
736   if (flags & REPO_USE_ROOTDIR)
737     rootdir = pool_get_rootdir(pool);
738   state = rpm_state_create(repo->pool, rootdir);
739   queue_init(&q);
740   rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
741   for (i = 0; i < q.count; i++)
742     {
743       void *handle;
744       unsigned long long itime;
745
746       handle = rpm_byrpmdbid(state, q.elements[i]);
747       if (!handle)
748         continue;
749       str = rpm_query(handle, SOLVABLE_DESCRIPTION);
750       if (!str)
751         continue;
752       s = pool_id2solvable(pool, repo_add_solvable(repo));
753       pubkey2solvable(s, data, str);
754       solv_free(str);
755       itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
756       if (itime)
757         repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, itime);
758       if (!repo->rpmdbid)
759         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
760       repo->rpmdbid[s - pool->solvables - repo->start] = q.elements[i];
761     }
762   queue_free(&q);
763   rpm_state_free(state);
764   if (!(flags & REPO_NO_INTERNALIZE))
765     repodata_internalize(data);
766   return 0;
767 }
768
769 #endif
770
771 static char *
772 solv_slurp(FILE *fp, int *lenp)
773 {
774   int l, ll;
775   char *buf = 0;
776   int bufl = 0;
777
778   for (l = 0; ; l += ll)
779     {
780       if (bufl - l < 4096)
781         {
782           bufl += 4096;
783           buf = solv_realloc(buf, bufl);
784         }
785       ll = fread(buf + l, 1, bufl - l, fp);
786       if (ll < 0)
787         {
788           buf = solv_free(buf);
789           l = 0;
790           break;
791         }
792       if (ll == 0)
793         {
794           buf[l] = 0;   /* always zero-terminate */
795           break;
796         }
797     }
798   if (lenp)
799     *lenp = l;
800   return buf;
801 }
802
803 Id
804 repo_add_pubkey(Repo *repo, const char *key, int flags)
805 {
806   Pool *pool = repo->pool;
807   Repodata *data;
808   Solvable *s;
809   char *buf;
810   FILE *fp;
811
812   data = repo_add_repodata(repo, flags);
813   buf = 0;
814   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0)
815     {
816       pool_error(pool, -1, "%s: %s", key, strerror(errno));
817       return 0;
818     }
819   if ((buf = solv_slurp(fp, 0)) == 0)
820     {
821       pool_error(pool, -1, "%s: %s", key, strerror(errno));
822       fclose(fp);
823       return 0;
824     }
825   fclose(fp);
826   s = pool_id2solvable(pool, repo_add_solvable(repo));
827   if (!pubkey2solvable(s, data, buf))
828     {
829       repo_free_solvable(repo, s - pool->solvables, 1);
830       solv_free(buf);
831       return 0;
832     }
833   solv_free(buf);
834   if (!(flags & REPO_NO_INTERNALIZE))
835     repodata_internalize(data);
836   return s - pool->solvables;
837 }
838
839 static int
840 is_sig_packet(unsigned char *sig, int sigl)
841 {
842   if (!sigl)
843     return 0;
844   if ((sig[0] & 0x80) == 0 || (sig[0] & 0x40 ? sig[0] & 0x3f : sig[0] >> 2 & 0x0f) != 2)
845     return 0;
846   return 1;
847 }
848
849 Id
850 solv_parse_sig(FILE *fp, unsigned char **sigpkgp, int *sigpkglp, char *keyidstr)
851 {
852   unsigned char *sig;
853   int sigl, hl, tag, pktl;
854   struct pgpsig pgpsig;
855   Id htype;
856
857   if (sigpkgp)
858     {
859       *sigpkgp = 0;
860       *sigpkglp = 0;
861     }
862   if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0)
863     return 0;
864   if (!is_sig_packet(sig, sigl))
865     {
866       /* not a raw sig, check armored */
867       unsigned char *nsig;
868       nsig = unarmor((char *)sig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----");
869       solv_free(sig);
870       if (!nsig)
871         return 0;
872       sig = nsig;
873       if (!is_sig_packet(sig, sigl))
874         {
875           solv_free(sig);
876           return 0;
877         }
878     }
879   hl = parsepkgheader(sig, sigl, &tag, &pktl);
880   if (!hl || tag != 2 || !pktl)
881     {
882       solv_free(sig);
883       return 0;
884     }
885   memset(&pgpsig, 0, sizeof(pgpsig));
886   parsesigpacket(&pgpsig, sig + hl, pktl);
887   htype = pgphashalgo2type(pgpsig.hashalgo);
888   if (pgpsig.type != 0 || !htype)
889     {
890       solv_free(sig);
891       return 0;
892     }
893   if (sigpkgp)
894     {
895       *sigpkgp = solv_malloc(pktl);
896       memcpy(*sigpkgp, sig + hl, pktl);
897       *sigpkglp = pktl;
898     }
899   solv_free(sig);
900   if (keyidstr)
901     solv_bin2hex(pgpsig.issuer, 8, keyidstr);
902   return htype;
903 }
904
905 #ifdef ENABLE_PGPVRFY
906 int
907 solv_verify_sig(const unsigned char *pubdata, int pubdatal, unsigned char *sigpkg, int sigpkgl, void *chk)
908 {
909   struct pgpsig pgpsig;
910   int res;
911   Id htype;
912
913   memset(&pgpsig, 0, sizeof(pgpsig));
914   parsesigpacket(&pgpsig, sigpkg, sigpkgl);
915   if (pgpsig.type != 0)
916     return 0;
917   htype = pgphashalgo2type(pgpsig.hashalgo);
918   if (htype != solv_chksum_get_type(chk))
919      return 0;  /* wrong hash type? */
920   createsigdata(&pgpsig, sigpkg, sigpkgl, 0, 0, 0, 0, chk);
921   if (!pgpsig.sigdata)
922     return 0;
923   res = solv_pgpvrfy(pubdata, pubdatal, pgpsig.sigdata, pgpsig.sigdatal);
924   solv_free(pgpsig.sigdata);
925   return res;
926 }
927 #endif
928