treat v4 self-sig without key expires as unlimited lifetime
[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)
117 {
118   char *p;
119   int l, eof;
120   unsigned char *buf, *bp;
121   unsigned int v;
122
123   *pktlp = 0;
124   while (strncmp(pubkey, "-----BEGIN PGP PUBLIC KEY BLOCK-----", 36) != 0)
125     {
126       pubkey = strchr(pubkey, '\n');
127       if (!pubkey)
128         return 0;
129       pubkey++;
130     }
131   pubkey = strchr(pubkey, '\n');
132   if (!pubkey++)
133     return 0;
134   /* skip header lines */
135   for (;;)
136     {
137       while (*pubkey == ' ' || *pubkey == '\t')
138         pubkey++;
139       if (*pubkey == '\n')
140         break;
141       pubkey = strchr(pubkey, '\n');
142       if (!pubkey++)
143         return 0;
144     }
145   pubkey++;
146   p = strchr(pubkey, '=');
147   if (!p)
148     return 0;
149   l = p - pubkey;
150   bp = buf = solv_malloc(l * 3 / 4 + 4);
151   eof = 0;
152   while (!eof)
153     {
154       pubkey = r64dec1(pubkey, &v, &eof);
155       if (!pubkey)
156         {
157           solv_free(buf);
158           return 0;
159         }
160       *bp++ = v >> 16;
161       *bp++ = v >> 8;
162       *bp++ = v;
163     }
164   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
165     pubkey++;
166   bp -= eof;
167   if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0)
168     {
169       solv_free(buf);
170       return 0;
171     }
172   if (v != crc24(buf, bp - buf))
173     {
174       solv_free(buf);
175       return 0;
176     }
177   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
178     pubkey++;
179   if (strncmp(pubkey, "-----END PGP PUBLIC KEY BLOCK-----", 34) != 0)
180     {
181       solv_free(buf);
182       return 0;
183     }
184   *pktlp = bp - buf;
185   return buf;
186 }
187
188 struct gpgsig {
189   int type;
190   unsigned char issuer[8];
191   int haveissuer;
192   unsigned int created;
193   unsigned int expires;
194   unsigned int keyexpires;
195   unsigned char *sigdata;
196   int sigdatal;
197 };
198
199 static void
200 parsesigpacket(struct gpgsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl)
201 {
202   sig->type = -1;
203   if (p[0] == 3)
204     {
205       Id htype = 0;
206       /* printf("V3 signature packet\n"); */
207       if (l <= 19 || p[1] != 5)
208         return;
209       if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f)
210         return;
211       sig->type = p[2];
212       sig->haveissuer = 1;
213       memcpy(sig->issuer, p + 7, 8);
214       sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
215       if (p[16] == 1)
216         htype = REPOKEY_TYPE_MD5;
217       else if (p[16] == 2)
218         htype = REPOKEY_TYPE_SHA1;
219       else if (p[16] == 8)
220         htype = REPOKEY_TYPE_SHA256;
221       if (htype && pubkey)
222         {
223           void *h = solv_chksum_create(htype);
224           const unsigned char *cs;
225           unsigned char b[3];
226           int csl;
227
228           if ((p[2] >= 0x10 && p[2] <= 0x13) || p[2] == 0x1f || p[2] == 0x18 || p[2] == 0x20 || p[2] == 0x28)
229             {
230               b[0] = 0x99;
231               b[1] = pubkeyl >> 8;
232               b[2] = pubkeyl;
233               solv_chksum_add(h, b, 3);
234               solv_chksum_add(h, pubkey, pubkeyl);
235             }
236           if (p[2] >= 0x10 && p[2] <= 0x13)
237             solv_chksum_add(h, userid, useridl);
238           solv_chksum_add(h, p + 2, 5);
239           cs = solv_chksum_get(h, &csl);
240           if (cs[0] == p[17] && cs[1] == p[18])
241             {
242               sig->sigdata = solv_malloc(2 + csl + l - 19);
243               sig->sigdatal = 2 + csl + l - 19;
244               sig->sigdata[0] = p[15];
245               sig->sigdata[1] = p[16];
246               memcpy(sig->sigdata + 2, cs, csl);
247               memcpy(sig->sigdata + 2 + csl, p + 19, l - 19);
248             }
249           solv_chksum_free(h, 0);
250         }
251     }
252   else if (p[0] == 4)
253     {
254       int j, ql, x;
255       unsigned char *q;
256       Id htype = 0;
257
258       /* printf("V4 signature packet\n"); */
259       if (l < 6)
260         return;
261       if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f)
262         return;
263       sig->type = p[1];
264       q = p + 4;
265       sig->keyexpires = -1;
266       for (j = 0; q && j < 2; j++)
267         {
268           if (q + 2 > p + l)
269             {
270               q = 0;
271               break;
272             }
273           ql = q[0] << 8 | q[1];
274           q += 2;
275           if (q + ql > p + l)
276             {
277               q = 0;
278               break;
279             }
280           while (ql)
281             {
282               int sl;
283               /* decode sub-packet length */
284               x = *q++;
285               ql--;
286               if (x < 192)
287                 sl = x;
288               else if (x == 255)
289                 {
290                   if (ql < 4 || q[0] != 0)
291                     {
292                       q = 0;
293                       break;
294                     }
295                   sl = q[1] << 16 | q[2] << 8 | q[3];
296                   q += 4;
297                   ql -= 4;
298                 }
299               else
300                 {
301                   if (ql < 1)
302                     {
303                       q = 0;
304                       break;
305                     }
306                   sl = ((x - 192) << 8) + *q++ + 192;
307                   ql--;
308                 }
309               if (ql < sl)
310                 {
311                   q = 0;
312                   break;
313                 }
314               x = q[0] & 127;
315               /* printf("%d SIGSUB %d %d\n", j, x, sl); */
316               if (x == 16 && sl == 9 && !sig->haveissuer)
317                 {
318                   sig->haveissuer = 1;
319                   memcpy(sig->issuer, q + 1, 8);
320                 }
321               if (x == 2 && j == 0)
322                 sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
323               if (x == 3 && j == 0)
324                 sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
325               if (x == 9 && j == 0)
326                 sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
327               q += sl;
328               ql -= sl;
329             }
330         }
331       if (p[3] == 1)
332         htype = REPOKEY_TYPE_MD5;
333       else if (p[3] == 2)
334         htype = REPOKEY_TYPE_SHA1;
335       else if (p[3] == 8)
336         htype = REPOKEY_TYPE_SHA256;
337       if (sig->haveissuer && htype && pubkey && q && q - p + 2 < l)
338         {
339           void *h = solv_chksum_create(htype);
340           unsigned char b[6];
341           const unsigned char *cs;
342           unsigned int hl;
343           int csl, ml = l - (q - p + 2);
344
345           if ((p[1] >= 0x10 && p[1] <= 0x13) || p[1] == 0x1f || p[1] == 0x18 || p[1] == 0x20 || p[1] == 0x28)
346             {
347               b[0] = 0x99;
348               b[1] = pubkeyl >> 8;
349               b[2] = pubkeyl;
350               solv_chksum_add(h, b, 3);
351               solv_chksum_add(h, pubkey, pubkeyl);
352             }
353           if (p[1] >= 0x10 && p[1] <= 0x13)
354             {
355               b[0] = 0xb4;
356               b[1] = useridl >> 24;
357               b[2] = useridl >> 16;
358               b[3] = useridl >> 8;
359               b[4] = useridl;
360               solv_chksum_add(h, b, 5);
361               solv_chksum_add(h, userid, useridl);
362             }
363           hl = 6 + (p[4] << 8 | p[5]);
364           solv_chksum_add(h, p, hl);
365           b[0] = 4;
366           b[1] = 0xff;
367           b[2] = hl >> 24;
368           b[3] = hl >> 16;
369           b[4] = hl >> 8;
370           b[5] = hl;
371           solv_chksum_add(h, b, 6);
372           cs = solv_chksum_get(h, &csl);
373           if (cs[0] == q[0] && cs[1] == q[1])
374             {
375               sig->sigdata = solv_malloc(2 + csl + ml);
376               sig->sigdatal = 2 + csl + ml;
377               sig->sigdata[0] = p[2];
378               sig->sigdata[1] = p[3];
379               memcpy(sig->sigdata + 2, cs, csl);
380               memcpy(sig->sigdata + 2 + csl, q + 2, ml);
381             }
382           solv_chksum_free(h, 0);
383         }
384     }
385 }
386
387 static void
388 parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
389 {
390   int x, tag, l;
391   unsigned char keyid[8];
392   unsigned int kcr = 0, maxex = 0, maxsigcr = 0;
393   unsigned char *pubkey = 0;
394   int pubkeyl = 0;
395   unsigned char *userid = 0;
396   int useridl = 0;
397   unsigned char *pubdata = 0;
398   int pubdatal = 0;
399
400   for (; pl; p += l, pl -= l)
401     {
402       x = *p++;
403       pl--;
404       if (!(x & 128) || pl <= 0)
405         return;
406       if ((x & 64) == 0)
407         {
408           /* old format */
409           tag = (x & 0x3c) >> 2;
410           x &= 3;
411           if (x == 3)
412             return;
413           l = 1 << x;
414           if (pl < l)
415             return;
416           x = 0;
417           while (l--)
418             {
419               x = x << 8 | *p++;
420               pl--;
421             }
422           l = x;
423         }
424       else
425         {
426           tag = (x & 0x3f);
427           x = *p++;
428           pl--;
429           if (x < 192)
430             l = x;
431           else if (x >= 192 && x < 224)
432             {
433               if (pl <= 0)
434                 return;
435               l = ((x - 192) << 8) + *p++ + 192;
436               pl--;
437             }
438           else if (x == 255)
439             {
440               /* sanity: p[0] must be zero */
441               if (pl <= 4 || p[0] != 0)
442                 return;
443               l = p[1] << 16 | p[2] << 8 | p[3];
444               p += 4;
445               pl -= 4;
446             }
447           else
448             return;
449         }
450       if (pl < l)
451         return;
452       if (tag == 6)
453         {
454           if (pubkey)
455             break;      /* one key at a time, please */
456           pubkey = solv_malloc(l);
457           if (l)
458             memcpy(pubkey, p, l);
459           pubkeyl = l;
460           if (p[0] == 3 && l >= 10)
461             {
462               unsigned int ex;
463               void *h;
464               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
465               ex = 0;
466               if (p[5] || p[6])
467                 {
468                   ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
469                   if (ex > maxex)
470                     maxex = ex;
471                 }
472               memset(keyid, 0, 8);
473               if (p[7] == 1)    /* RSA */
474                 {
475                   int ql, ql2;
476                   unsigned char fp[16];
477                   char fpx[32 + 1];
478                   unsigned char *q;
479
480                   ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
481                   if (ql >= 8 && 10 + ql + 2 <= l)
482                     {
483                       memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
484                       q = p + 10 + ql;
485                       ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
486                       if (10 + ql + 2 + ql2 <= l)
487                         {
488                           /* fingerprint is the md5 over the two MPI bodies */
489                           h = solv_chksum_create(REPOKEY_TYPE_MD5);
490                           solv_chksum_add(h, p + 10, ql);
491                           solv_chksum_add(h, q + 2, ql2);
492                           solv_chksum_free(h, fp);
493                           solv_bin2hex(fp, 16, fpx);
494                           repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
495                         }
496                     }
497                   pubdata = p + 7;
498                   pubdatal = l - 7;
499                 }
500             }
501           else if (p[0] == 4 && l >= 6)
502             {
503               void *h;
504               unsigned char hdr[3];
505               unsigned char fp[20];
506               char fpx[40 + 1];
507
508               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
509               hdr[0] = 0x99;
510               hdr[1] = l >> 8;
511               hdr[2] = l;
512               /* fingerprint is the sha1 over the packet */
513               h = solv_chksum_create(REPOKEY_TYPE_SHA1);
514               solv_chksum_add(h, hdr, 3);
515               solv_chksum_add(h, p, l);
516               solv_chksum_free(h, fp);
517               solv_bin2hex(fp, 20, fpx);
518               repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
519               memcpy(keyid, fp + 12, 8);        /* keyid is last 64 bits of fingerprint */
520               pubdata = p + 5;
521               pubdatal = l - 5;
522             }
523         }
524       if (tag == 2)
525         {
526           struct gpgsig sig;
527           if (!pubdata)
528             continue;
529           memset(&sig, 0, sizeof(sig));
530           parsesigpacket(&sig, p, l, pubkey, pubkeyl, userid, useridl);
531           if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
532             {
533               solv_free(sig.sigdata);
534               continue;
535             }
536           if (!memcmp(keyid, sig.issuer, 8))
537             {
538 #ifdef ENABLE_PGPVRFY
539               /* found self sig, verify */
540               if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
541 #endif
542                 {
543                   if (sig.keyexpires && maxex != -1)
544                     {
545                       if (sig.keyexpires == -1)
546                         maxex = -1;
547                       else if (sig.keyexpires + kcr > maxex)
548                         maxex = sig.keyexpires + kcr;
549                     }
550                   if (sig.created > maxsigcr)
551                     maxsigcr = sig.created;
552                 }
553             }
554           else
555             {
556               char issuerstr[17];
557               Id shandle = repodata_new_handle(data);
558               solv_bin2hex(sig.issuer, 8, issuerstr);
559               repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
560               if (sig.created)
561                 repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
562               if (sig.expires)
563                 repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
564               if (sig.sigdata)
565                 repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
566               repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle);
567             }
568           solv_free(sig.sigdata);
569         }
570       if (tag == 13)
571         {
572           userid = solv_realloc(userid, l);
573           if (l)
574             memcpy(userid, p, l);
575           useridl = l;
576         }
577     }
578   if (kcr)
579     repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, kcr);
580   if (maxex && maxex != -1)
581     repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex);
582   s->name = pool_str2id(s->repo->pool, "gpg-pubkey", 1);
583   s->evr = 1;
584   s->arch = 1;
585   if (userid && useridl)
586     {
587       char *useridstr = solv_malloc(useridl + 1);
588       memcpy(useridstr, userid, useridl);
589       useridstr[useridl] = 0;
590       setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, useridstr);
591       free(useridstr);
592     }
593   if (pubdata)
594     {
595       char keyidstr[17];
596       solv_bin2hex(keyid, 8, keyidstr);
597       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyidstr);
598     }
599   if (pubdata)
600     {
601       /* build rpm-style evr */
602       char evr[8 + 1 + 8 + 1];
603       solv_bin2hex(keyid + 4, 4, evr);
604       sprintf(evr + 8, "-%08x", maxsigcr);
605       s->evr = pool_str2id(s->repo->pool, evr, 1);
606       /* set data blob */
607       repodata_set_binary(data, s - s->repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
608     }
609   solv_free(pubkey);
610   solv_free(userid);
611 }
612
613
614 #ifdef ENABLE_RPMDB
615
616 /* this is private to rpm, but rpm lacks an interface to retrieve
617  * the values. Sigh. */
618 struct pgpDigParams_s {
619     const char * userid;
620     const unsigned char * hash;
621 #ifndef HAVE_PGPDIGGETPARAMS
622     const char * params[4];
623 #endif
624     unsigned char tag;
625     unsigned char version;               /*!< version number. */
626     unsigned char time[4];               /*!< time that the key was created. */
627     unsigned char pubkey_algo;           /*!< public key algorithm. */
628     unsigned char hash_algo;
629     unsigned char sigtype;
630     unsigned char hashlen;
631     unsigned char signhash16[2];
632     unsigned char signid[8];
633     unsigned char saved;
634 };
635
636 #ifndef HAVE_PGPDIGGETPARAMS
637 struct pgpDig_s {
638     struct pgpDigParams_s signature;
639     struct pgpDigParams_s pubkey;
640 };
641 #endif
642
643
644 /* only rpm knows how to do the release calculation, we don't dare
645  * to recreate all the bugs in libsolv */
646 static void
647 parsekeydata_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl)
648 {
649   Pool *pool = s->repo->pool;
650   struct pgpDigParams_s *digpubkey;
651   pgpDig dig = 0;
652   char keyid[16 + 1];
653   char evrbuf[8 + 1 + 8 + 1];
654   unsigned int btime;
655
656 #ifndef RPM5
657   dig = pgpNewDig();
658 #else
659   dig = pgpDigNew(RPMVSF_DEFAULT, 0);
660 #endif
661   (void) pgpPrtPkts(pkts, pktsl, dig, 0);
662 #ifdef HAVE_PGPDIGGETPARAMS
663   digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
664 #else
665   digpubkey = &dig->pubkey;
666 #endif
667   if (digpubkey)
668     {
669       btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3];
670       solv_bin2hex(digpubkey->signid, 8, keyid);
671       solv_bin2hex(digpubkey->signid + 4, 4, evrbuf);
672       evrbuf[8] = '-';
673       solv_bin2hex(digpubkey->time, 4, evrbuf + 9);
674       s->evr = pool_str2id(pool, evrbuf, 1);
675       repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid);
676       if (digpubkey->userid)
677         setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid);
678       if (btime)
679         repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime);
680     }
681 #ifndef RPM5
682   (void)pgpFreeDig(dig);
683 #else
684   (void)pgpDigFree(dig);
685 #endif
686 }
687
688 #endif  /* ENABLE_RPMDB */
689
690 static int
691 pubkey2solvable(Solvable *s, Repodata *data, char *pubkey)
692 {
693   unsigned char *pkts;
694   int pktsl;
695
696   pkts = unarmor(pubkey, &pktsl);
697   if (!pkts)
698     {
699       pool_error(s->repo->pool, 0, "unarmor failure");
700       return 0;
701     }
702   setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey);
703   parsekeydata(s, data, pkts, pktsl);
704 #ifdef ENABLE_RPMDB
705   parsekeydata_rpm(s, data, pkts, pktsl);
706 #endif
707   solv_free((void *)pkts);
708   return 1;
709 }
710
711 #ifdef ENABLE_RPMDB
712
713 int
714 repo_add_rpmdb_pubkeys(Repo *repo, int flags)
715 {
716   Pool *pool = repo->pool;
717   Queue q;
718   int i;
719   char *str;
720   Repodata *data;
721   Solvable *s;
722   const char *rootdir = 0;
723   void *state;
724
725   data = repo_add_repodata(repo, flags);
726   if (flags & REPO_USE_ROOTDIR)
727     rootdir = pool_get_rootdir(pool);
728   state = rpm_state_create(repo->pool, rootdir);
729   queue_init(&q);
730   rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
731   for (i = 0; i < q.count; i++)
732     {
733       void *handle;
734       unsigned long long itime;
735
736       handle = rpm_byrpmdbid(state, q.elements[i]);
737       if (!handle)
738         continue;
739       str = rpm_query(handle, SOLVABLE_DESCRIPTION);
740       if (!str)
741         continue;
742       s = pool_id2solvable(pool, repo_add_solvable(repo));
743       pubkey2solvable(s, data, str);
744       solv_free(str);
745       itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
746       if (itime)
747         repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, itime);
748       if (!repo->rpmdbid)
749         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
750       repo->rpmdbid[s - pool->solvables - repo->start] = q.elements[i];
751     }
752   queue_free(&q);
753   rpm_state_free(state);
754   if (!(flags & REPO_NO_INTERNALIZE))
755     repodata_internalize(data);
756   return 0;
757 }
758
759 #endif
760
761 Id
762 repo_add_pubkey(Repo *repo, const char *key, int flags)
763 {
764   Pool *pool = repo->pool;
765   Repodata *data;
766   Solvable *s;
767   char *buf;
768   int bufl, l, ll;
769   FILE *fp;
770
771   data = repo_add_repodata(repo, flags);
772   buf = 0;
773   bufl = 0;
774   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0)
775     {
776       pool_error(pool, -1, "%s: %s", key, strerror(errno));
777       return 0;
778     }
779   for (l = 0; ;)
780     {
781       if (bufl - l < 4096)
782         {
783           bufl += 4096;
784           buf = solv_realloc(buf, bufl);
785         }
786       ll = fread(buf + l, 1, bufl - l, fp);
787       if (ll < 0)
788         {
789           fclose(fp);
790           pool_error(pool, -1, "%s: %s", key, strerror(errno));
791           return 0;
792         }
793       if (ll == 0)
794         break;
795       l += ll;
796     }
797   buf[l] = 0;
798   fclose(fp);
799   s = pool_id2solvable(pool, repo_add_solvable(repo));
800   if (!pubkey2solvable(s, data, buf))
801     {
802       repo_free_solvable(repo, s - pool->solvables, 1);
803       solv_free(buf);
804       return 0;
805     }
806   solv_free(buf);
807   if (!(flags & REPO_NO_INTERNALIZE))
808     repodata_internalize(data);
809   return s - pool->solvables;
810 }
811