Imported Upstream version 0.7.22
[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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <assert.h>
22 #include <stdint.h>
23 #include <errno.h>
24 #include <dirent.h>
25
26 #include <rpm/rpmio.h>
27 #include <rpm/rpmpgp.h>
28 #ifndef RPM5
29 #include <rpm/header.h>
30 #endif
31 #include <rpm/rpmdb.h>
32
33 #include "pool.h"
34 #include "repo.h"
35 #include "hash.h"
36 #include "util.h"
37 #include "queue.h"
38 #include "chksum.h"
39 #include "repo_rpmdb.h"
40 #include "repo_pubkey.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 = 0xb704ce;
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 ^= 0x1864cfb;
111     }
112   return crc & 0xffffff;
113 }
114
115 static int
116 unarmor(char *pubkey, unsigned char **pktp, int *pktlp, const char *startstr, const char *endstr)
117 {
118   char *p, *pubkeystart = pubkey;
119   int l, eof;
120   unsigned char *buf, *bp;
121   unsigned int v;
122
123   *pktp = 0;
124   *pktlp = 0;
125   if (!pubkey)
126     return 0;
127   l = strlen(startstr);
128   while (strncmp(pubkey, startstr, l) != 0)
129     {
130       pubkey = strchr(pubkey, '\n');
131       if (!pubkey)
132         return 0;
133       pubkey++;
134     }
135   pubkey = strchr(pubkey, '\n');
136   if (!pubkey++)
137     return 0;
138   /* skip header lines */
139   for (;;)
140     {
141       while (*pubkey == ' ' || *pubkey == '\t')
142         pubkey++;
143       if (*pubkey == '\n')
144         break;
145       pubkey = strchr(pubkey, '\n');
146       if (!pubkey++)
147         return 0;
148     }
149   pubkey++;
150   p = strchr(pubkey, '=');
151   if (!p)
152     return 0;
153   l = p - pubkey;
154   bp = buf = solv_malloc(l * 3 / 4 + 4);
155   eof = 0;
156   while (!eof)
157     {
158       pubkey = r64dec1(pubkey, &v, &eof);
159       if (!pubkey)
160         {
161           solv_free(buf);
162           return 0;
163         }
164       *bp++ = v >> 16;
165       *bp++ = v >> 8;
166       *bp++ = v;
167     }
168   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
169     pubkey++;
170   bp -= eof;
171   if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0)
172     {
173       solv_free(buf);
174       return 0;
175     }
176   if (v != crc24(buf, bp - buf))
177     {
178       solv_free(buf);
179       return 0;
180     }
181   while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
182     pubkey++;
183   if (strncmp(pubkey, endstr, strlen(endstr)) != 0)
184     {
185       solv_free(buf);
186       return 0;
187     }
188   p = strchr(pubkey, '\n');
189   if (!p)
190     p = pubkey + strlen(pubkey);
191   *pktp = buf;
192   *pktlp = bp - buf;
193   return (p ? p + 1 : pubkey + strlen(pubkey)) - pubkeystart;
194 }
195
196 #define ARMOR_NLAFTER   16
197
198 static char *
199 armor(unsigned char *pkt, int pktl, const char *startstr, const char *endstr, const char *version)
200 {
201   static const char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
202   char *str = solv_malloc(strlen(startstr) + strlen(endstr) + strlen(version) + (pktl / 3) * 4 + (pktl / (ARMOR_NLAFTER * 3)) + 30);
203   char *p = str;
204   int a, b, c, i;
205   unsigned int v;
206
207   v = crc24(pkt, pktl);
208   sprintf(p, "%s\nVersion: %s\n\n", startstr, version);
209   p += strlen(p);
210   for (i = -1; pktl > 0; pktl -= 3)
211     {
212       if (++i == ARMOR_NLAFTER)
213         {
214           i = 0;
215           *p++ = '\n';
216         }
217       a = *pkt++;
218       b = pktl > 1 ? *pkt++ : 0;
219       c = pktl > 2 ? *pkt++ : 0;
220       *p++ = bintoasc[a >> 2];
221       *p++ = bintoasc[(a & 3) << 4 | b >> 4];
222       *p++ = pktl > 1 ? bintoasc[(b & 15) << 2 | c >> 6] : '=';
223       *p++ = pktl > 2 ? bintoasc[c & 63] : '=';
224     }
225   *p++ = '\n';
226   *p++ = '=';
227   *p++ = bintoasc[v >> 18 & 0x3f];
228   *p++ = bintoasc[v >> 12 & 0x3f];
229   *p++ = bintoasc[v >>  6 & 0x3f];
230   *p++ = bintoasc[v       & 0x3f];
231   sprintf(p, "\n%s\n", endstr);
232   return str;
233 }
234
235 /* internal representation of a signature */
236 struct pgpsig {
237   int type;
238   Id hashalgo;
239   unsigned char issuer[8];
240   int haveissuer;
241   unsigned int created;
242   unsigned int expires;
243   unsigned int keyexpires;
244   unsigned char *sigdata;
245   int sigdatal;
246   int mpioff;
247 };
248
249 static Id
250 pgphashalgo2type(int algo)
251 {
252   if (algo == 1)
253     return REPOKEY_TYPE_MD5;
254   if (algo == 2)
255     return REPOKEY_TYPE_SHA1;
256   if (algo == 8)
257     return REPOKEY_TYPE_SHA256;
258   if (algo == 9)
259     return REPOKEY_TYPE_SHA384;
260   if (algo == 10)
261     return REPOKEY_TYPE_SHA512;
262   if (algo == 11)
263     return REPOKEY_TYPE_SHA224;
264   return 0;
265 }
266
267 /* hash the pubkey/userid data for self-sig verification
268  * hash the final trailer
269  * create a "sigdata" block suitable for a call to solv_pgpverify */
270 static void
271 pgpsig_makesigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, Chksum *h)
272 {
273   int type = sig->type;
274   unsigned char b[10];
275   const unsigned char *cs;
276   int csl;
277
278   if (!h || sig->mpioff < 2 || l <= sig->mpioff)
279     return;
280   if (p[0] != 3 && p[0] != 4 && p[0] != 5)
281     return;     /* unsupported signature version */
282   if ((type >= 0x10 && type <= 0x13) || type == 0x1f || type == 0x18 || type == 0x20 || type == 0x28)
283     {
284       if (p[0] == 4)
285         {
286           b[0] = 0x99;
287           b[1] = pubkeyl >> 8;
288           b[2] = pubkeyl;
289           solv_chksum_add(h, b, 3);
290         }
291       else if (p[0] == 5)
292         {
293           b[0] = 0x9a;
294           b[1] = pubkeyl >> 24;
295           b[2] = pubkeyl >> 16;
296           b[3] = pubkeyl >> 8;
297           b[4] = pubkeyl;
298           solv_chksum_add(h, b, 5);
299         }
300       solv_chksum_add(h, pubkey, pubkeyl);
301     }
302   if ((type >= 0x10 && type <= 0x13))
303     {
304       if (p[0] != 3)
305         {
306           b[0] = 0xb4;
307           b[1] = useridl >> 24;
308           b[2] = useridl >> 16;
309           b[3] = useridl >> 8;
310           b[4] = useridl;
311           solv_chksum_add(h, b, 5);
312         }
313       solv_chksum_add(h, userid, useridl);
314     }
315   /* add trailer */
316   if (p[0] == 3)
317     solv_chksum_add(h, p + 2, 5);
318   else if (p[0] == 4)
319     {
320       int hl = 6 + (p[4] << 8 | p[5]);
321       solv_chksum_add(h, p, hl);
322       b[0] = 4;
323       b[1] = 0xff;
324       b[2] = hl >> 24;
325       b[3] = hl >> 16;
326       b[4] = hl >> 8;
327       b[5] = hl;
328       solv_chksum_add(h, b, 6);
329     }
330   else if (p[0] == 5)
331     {
332       int hl = 6 + (p[4] << 8 | p[5]);
333       solv_chksum_add(h, p, hl);
334       if (type == 0 || type == 1)
335         {
336           memset(b, 0, 6);
337           solv_chksum_add(h, b, 6);
338         }
339       hl += 6;
340       b[0] = 5;
341       b[1] = 0xff;
342       b[2] = b[3] = b[4] = b[5] = 0;
343       b[6] = hl >> 24;
344       b[7] = hl >> 16;
345       b[8] = hl >> 8;
346       b[9] = hl;
347       solv_chksum_add(h, b, 10);
348     }
349   else
350     return;
351   cs = solv_chksum_get(h, &csl);
352   if (cs[0] == p[sig->mpioff - 2] && cs[1] == p[sig->mpioff - 1])
353     {
354       int ml = l - sig->mpioff;
355       sig->sigdata = solv_malloc(2 + csl + ml);
356       sig->sigdatal = 2 + csl + ml;
357       sig->sigdata[0] = p[0] == 3 ? p[15] : p[2];
358       sig->sigdata[1] = p[0] == 3 ? p[16] : p[3];
359       memcpy(sig->sigdata + 2, cs, csl);
360       memcpy(sig->sigdata + 2 + csl, p + sig->mpioff, ml);
361     }
362 }
363
364 /* parse the header of a subpacket contained in a signature packet
365  * returns: length of the packet header, 0 if there was an error
366  * *pktlp is set to the packet length, the tag is the first byte.
367  */
368 static inline int
369 parsesubpkglength(unsigned char *q, int ql, int *pktlp)
370 {
371   int x, sl, hl;
372   /* decode sub-packet length, ql must be > 0 */
373   x = *q++;
374   if (x < 192)
375     {
376       sl = x;
377       hl = 1;
378     }
379   else if (x == 255)
380     {
381       if (ql < 5 || q[0] != 0)
382         return 0;
383       sl = q[1] << 16 | q[2] << 8 | q[3];
384       hl = 5;
385     }
386   else
387     {
388       if (ql < 2)
389         return 0;
390       sl = ((x - 192) << 8) + q[0] + 192;
391       hl = 2;
392     }
393   if (!sl || ql < sl + hl)      /* sub pkg tag is included in length, i.e. sl must not be zero */
394     return 0;
395   *pktlp = sl;
396   return hl;
397 }
398
399 /* parse a signature packet, initializing the pgpsig struct */
400 static void
401 pgpsig_init(struct pgpsig *sig, unsigned char *p, int l)
402 {
403   memset(sig, 0, sizeof(*sig));
404   sig->type = -1;
405   if (p[0] == 3)
406     {
407       /* printf("V3 signature packet\n"); */
408       if (l <= 19 || p[1] != 5)
409         return;
410       sig->type = p[2];
411       sig->haveissuer = 1;
412       memcpy(sig->issuer, p + 7, 8);
413       sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
414       sig->hashalgo = p[16];
415       sig->mpioff = 19;
416     }
417   else if (p[0] == 4)
418     {
419       int j, ql, x;
420       unsigned char *q;
421
422       /* printf("V4 signature packet\n"); */
423       if (l < 6)
424         return;
425       sig->type = p[1];
426       sig->hashalgo = p[3];
427       q = p + 4;
428       sig->keyexpires = -1;
429       for (j = 0; q && j < 2; j++)
430         {
431           if (q + 2 > p + l)
432             {
433               q = 0;
434               break;
435             }
436           ql = q[0] << 8 | q[1];
437           q += 2;
438           if (q + ql > p + l)
439             {
440               q = 0;
441               break;
442             }
443           while (ql > 0)
444             {
445               int sl, hl;
446               hl = parsesubpkglength(q, ql, &sl);
447               if (!hl)
448                 {
449                   q = 0;
450                   break;
451                 }
452               q += hl;
453               ql -= hl;
454               x = q[0] & 127;   /* strip critical bit */
455               /* printf("%d SIGSUB %d %d\n", j, x, sl); */
456               if (x == 16 && sl == 9 && !sig->haveissuer)
457                 {
458                   sig->haveissuer = 1;
459                   memcpy(sig->issuer, q + 1, 8);
460                 }
461               if (x == 2 && j == 0)
462                 sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
463               if (x == 3 && j == 0)
464                 sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
465               if (x == 9 && j == 0)
466                 sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
467               q += sl;
468               ql -= sl;
469             }
470         }
471       if (q && q - p + 2 < l)
472         sig->mpioff = q - p + 2;
473     }
474 }
475
476 /* parse a pgp packet header
477  * returns: length of the packet header, 0 if there was an error
478  * *tagp and *pktlp is set to the packet tag and the packet length
479  */
480 static int
481 parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp)
482 {
483   unsigned char *op = p;
484   int x, l;
485
486   if (!pl)
487     return 0;
488   x = *p++;
489   pl--;
490   if (!(x & 128) || pl <= 0)
491     return 0;
492   if ((x & 64) == 0)
493     {
494       *tagp = (x & 0x3c) >> 2;          /* old format */
495       x = 1 << (x & 3);
496       if (x > 4 || pl < x || (x == 4 && p[0]))
497         return 0;
498       pl -= x;
499       for (l = 0; x--;)
500         l = l << 8 | *p++;
501     }
502   else
503     {
504       *tagp = (x & 0x3f);               /* new format */
505       x = *p++;
506       pl--;
507       if (x < 192)
508         l = x;
509       else if (x >= 192 && x < 224)
510         {
511           if (pl <= 0)
512             return 0;
513           l = ((x - 192) << 8) + *p++ + 192;
514           pl--;
515         }
516       else if (x == 255)
517         {
518           if (pl <= 4 || p[0] != 0)     /* sanity: p[0] must be zero */
519             return 0;
520           l = p[1] << 16 | p[2] << 8 | p[3];
521           p += 4;
522           pl -= 4;
523         }
524       else
525         return 0;
526     }
527   if (l > pl)
528     return 0;
529   *pktlp = l;
530   return p - op;
531 }
532
533 /* parse the first pubkey (possible creating new packages for the subkeys)
534  * returns the number of parsed bytes.
535  * if flags contains ADD_WITH_SUBKEYS, all subkeys will be added as new
536  * solvables as well */
537 static int
538 parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags)
539 {
540   Repo *repo = s->repo;
541   Pool *pool = repo->pool;
542   unsigned char *pstart = p;
543   int tag, l;
544   unsigned char keyid[8];
545   char subkeyofstr[17];
546   unsigned int kcr = 0, maxex = 0, maxsigcr = 0, rpmsigcr = 0;
547   unsigned char *pubkey = 0;
548   int pubkeyl = 0;
549   int insubkey = 0;
550   unsigned char *userid = 0;
551   int useridl = 0;
552   unsigned char *pubdata = 0;
553   int pubdatal = 0;
554
555   *subkeyofstr = 0;
556   for (; ; p += l, pl -= l)
557     {
558       int hl = parsepkgheader(p, pl, &tag, &l);
559       if (!hl || (pubkey && (tag == 6 || tag == 14)))
560         {
561           /* finish old key */
562           if (kcr)
563             repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, kcr);
564           if (maxex && maxex != -1)
565             repodata_set_num(data, s - pool->solvables, PUBKEY_EXPIRES, maxex);
566           s->name = pool_str2id(pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1);
567           s->evr = 1;
568           s->arch = 1;
569           if (userid && useridl)
570             {
571               char *useridstr = solv_malloc(useridl + 1);
572               memcpy(useridstr, userid, useridl);
573               useridstr[useridl] = 0;
574               setutf8string(data, s - pool->solvables, SOLVABLE_SUMMARY, useridstr);
575               free(useridstr);
576             }
577           if (pubdata)
578             {
579               char keyidstr[17];
580               char evr[8 + 1 + 8 + 1];
581               solv_bin2hex(keyid, 8, keyidstr);
582               repodata_set_str(data, s - pool->solvables, PUBKEY_KEYID, keyidstr);
583               /* build rpm-style evr */
584               strcpy(evr, keyidstr + 8);
585               sprintf(evr + 8, "-%08x", (flags & USE_RPM_PUBKEY_BUILTTIME) ? rpmsigcr : maxsigcr);
586               s->evr = pool_str2id(pool, evr, 1);
587             }
588           if (insubkey && *subkeyofstr)
589             repodata_set_str(data, s - pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr);
590           if (pubdata)          /* set data blob */
591             repodata_set_binary(data, s - pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
592           if (!pl)
593             break;
594           if (!hl)
595             {
596               p = 0;    /* parse error */
597               break;
598             }
599           if (tag == 6 || (tag == 14 && !(flags & ADD_WITH_SUBKEYS)))
600             break;
601           if (tag == 14 && pubdata && !insubkey)
602             solv_bin2hex(keyid, 8, subkeyofstr);
603           /* create new solvable for subkey */
604           s = pool_id2solvable(pool, repo_add_solvable(repo));
605         }
606       p += hl;
607       pl -= hl;
608       if (!pubkey && tag != 6)
609         continue;
610       if (tag == 6 || (tag == 14 && (flags & ADD_WITH_SUBKEYS) != 0))           /* Public-Key Packet */
611         {
612           if (tag == 6)
613             {
614               pubkey = solv_memdup(p, l);
615               pubkeyl = l;
616             }
617           else
618             insubkey = 1;
619           pubdata = 0;
620           pubdatal = 0;
621           if (p[0] == 3 && l >= 10)
622             {
623               unsigned int ex;
624               Chksum *h;
625               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
626               ex = 0;
627               if (p[5] || p[6])
628                 {
629                   ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
630                   if (ex > maxex)
631                     maxex = ex;
632                 }
633               memset(keyid, 0, 8);
634               if (p[7] == 1)    /* RSA */
635                 {
636                   int ql, ql2;
637                   unsigned char fp[16];
638                   char fpx[32 + 1];
639                   unsigned char *q;
640
641                   ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
642                   if (ql >= 8 && 10 + ql + 2 <= l)
643                     {
644                       memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
645                       q = p + 10 + ql;
646                       ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
647                       if (10 + ql + 2 + ql2 <= l)
648                         {
649                           /* fingerprint is the md5 over the two MPI bodies */
650                           h = solv_chksum_create(REPOKEY_TYPE_MD5);
651                           solv_chksum_add(h, p + 10, ql);
652                           solv_chksum_add(h, q + 2, ql2);
653                           solv_chksum_free(h, fp);
654                           solv_bin2hex(fp, 16, fpx);
655                           repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx);
656                         }
657                     }
658                   pubdata = p + 7;
659                   pubdatal = l - 7;
660                 }
661             }
662           else if (p[0] == 4 && l >= 6)
663             {
664               Chksum *h;
665               unsigned char hdr[3];
666               unsigned char fp[20];
667               char fpx[20 * 2 + 1];
668
669               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
670               hdr[0] = 0x99;
671               hdr[1] = l >> 8;
672               hdr[2] = l;
673               /* fingerprint is the sha1 over the packet */
674               h = solv_chksum_create(REPOKEY_TYPE_SHA1);
675               solv_chksum_add(h, hdr, 3);
676               solv_chksum_add(h, p, l);
677               solv_chksum_free(h, fp);
678               solv_bin2hex(fp, 20, fpx);
679               repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx);
680               memcpy(keyid, fp + (20 - 8), 8);  /* keyid is last 64 bits of fingerprint */
681               pubdata = p + 5;
682               pubdatal = l - 5;
683             }
684           else if (p[0] == 5 && l >= 6)
685             {
686               Chksum *h;
687               unsigned char hdr[5];
688               unsigned char fp[32];
689               char fpx[32 * 2 + 1];
690
691               maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
692               hdr[0] = 0x9a;
693               hdr[1] = l >> 24;
694               hdr[2] = l >> 16;
695               hdr[3] = l >> 8;
696               hdr[4] = l;
697               /* fingerprint is the sha256 over the packet */
698               h = solv_chksum_create(REPOKEY_TYPE_SHA256);
699               solv_chksum_add(h, hdr, 5);
700               solv_chksum_add(h, p, l);
701               solv_chksum_free(h, fp);
702               solv_bin2hex(fp, 32, fpx);
703               repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx);
704               memcpy(keyid, fp + (32 - 8), 8);  /* keyid is last 64 bits of fingerprint */
705               pubdata = p + 5;
706               pubdatal = l - 5;
707             }
708         }
709       if (tag == 2)             /* Signature Packet */
710         {
711           struct pgpsig sig;
712           Id htype;
713           if (!pubdata)
714             continue;
715           pgpsig_init(&sig, p, l);
716           if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
717             continue;
718           if (sig.type >= 0x10 && sig.type <= 0x13 && !userid)
719             continue;
720           htype = pgphashalgo2type(sig.hashalgo);
721           if (htype && sig.mpioff)
722             {
723               Chksum *h = solv_chksum_create(htype);
724               pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h);
725               solv_chksum_free(h, 0);
726             }
727           if (!rpmsigcr)
728             rpmsigcr = sig.created;
729           if (!memcmp(keyid, sig.issuer, 8))
730             {
731 #ifdef ENABLE_PGPVRFY
732               /* found self sig, verify */
733               if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
734 #endif
735                 {
736                   if (sig.keyexpires && maxex != -1)
737                     {
738                       if (sig.keyexpires == -1)
739                         maxex = -1;
740                       else if (sig.keyexpires + kcr > maxex)
741                         maxex = sig.keyexpires + kcr;
742                     }
743                   if (sig.created > maxsigcr)
744                     maxsigcr = sig.created;
745                 }
746             }
747           else if (flags & ADD_WITH_KEYSIGNATURES)
748             {
749               char issuerstr[17];
750               Id shandle = repodata_new_handle(data);
751               solv_bin2hex(sig.issuer, 8, issuerstr);
752               repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
753               if (sig.created)
754                 repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
755               if (sig.expires)
756                 repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
757               if (sig.sigdata)
758                 repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
759               repodata_add_flexarray(data, s - pool->solvables, PUBKEY_SIGNATURES, shandle);
760             }
761           solv_free(sig.sigdata);
762         }
763       if (tag == 13 && !insubkey)               /* User ID Packet */
764         {
765           userid = solv_realloc(userid, l);
766           if (l)
767             memcpy(userid, p, l);
768           useridl = l;
769         }
770     }
771   solv_free(pubkey);
772   solv_free(userid);
773   return p ? p - pstart : 0;
774 }
775
776 /* parse an ascii armored pubkey
777  * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */
778 static int
779 pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags)
780 {
781   unsigned char *pkts, *pkts_orig;
782   int pktsl, pl = 0, tag, l, hl;
783
784   if (!unarmor(pubkey, &pkts, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"))
785     {
786       pool_error(pool, 0, "unarmor failure");
787       return 0;
788     }
789   pkts_orig = pkts;
790   tag = 6;
791   while (pktsl)
792     {
793       if (tag == 6)
794         {
795           setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey);
796           pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags);
797           if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS))
798             break;
799         }
800       pkts += pl;
801       pktsl -= pl;
802       hl = parsepkgheader(pkts, pktsl, &tag, &l);
803       if (!hl)
804         break;
805       pl = l + hl;
806       if (tag == 6)
807         p = repo_add_solvable(pool->solvables[p].repo);
808     }
809   solv_free((void *)pkts_orig);
810   return 1;
811 }
812
813 #ifdef ENABLE_RPMDB
814
815 int
816 repo_add_rpmdb_pubkeys(Repo *repo, int flags)
817 {
818   Pool *pool = repo->pool;
819   Queue q;
820   int i;
821   char *str;
822   Repodata *data;
823   const char *rootdir = 0;
824   void *state;
825
826   data = repo_add_repodata(repo, flags);
827   if (flags & REPO_USE_ROOTDIR)
828     rootdir = pool_get_rootdir(pool);
829   state = rpm_state_create(repo->pool, rootdir);
830   queue_init(&q);
831   rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
832   for (i = 0; i < q.count; i++)
833     {
834       Id p, p2;
835       void *handle;
836       unsigned long long itime;
837
838       handle = rpm_byrpmdbid(state, q.elements[i]);
839       if (!handle)
840         continue;
841       str = rpm_query(handle, SOLVABLE_DESCRIPTION);
842       if (!str)
843         continue;
844       p = repo_add_solvable(repo);
845       if (!pubkey2solvable(pool, p, data, str, flags))
846         {
847           solv_free(str);
848           repo_free_solvable(repo, p, 1);
849           continue;
850         }
851       solv_free(str);
852       itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
853       for (p2 = p; p2 < pool->nsolvables; p2++)
854         {
855           if (itime)
856             repodata_set_num(data, p2, SOLVABLE_INSTALLTIME, itime);
857           if (!repo->rpmdbid)
858             repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
859           repo->rpmdbid[p2 - repo->start] = q.elements[i];
860         }
861     }
862   queue_free(&q);
863   rpm_state_free(state);
864   if (!(flags & REPO_NO_INTERNALIZE))
865     repodata_internalize(data);
866   return 0;
867 }
868
869 #endif
870
871 static char *
872 solv_slurp(FILE *fp, int *lenp)
873 {
874   int l, ll;
875   char *buf = 0;
876   int bufl = 0;
877
878   for (l = 0; ; l += ll)
879     {
880       if (bufl - l < 4096)
881         {
882           bufl += 4096;
883           buf = solv_realloc(buf, bufl);
884         }
885       ll = fread(buf + l, 1, bufl - l, fp);
886       if (ll < 0)
887         {
888           buf = solv_free(buf);
889           l = 0;
890           break;
891         }
892       if (ll == 0)
893         {
894           buf[l] = 0;   /* always zero-terminate */
895           break;
896         }
897     }
898   if (lenp)
899     *lenp = l;
900   return buf;
901 }
902
903 Id
904 repo_add_pubkey(Repo *repo, const char *keyfile, int flags)
905 {
906   Pool *pool = repo->pool;
907   Repodata *data;
908   Id p;
909   char *buf;
910   FILE *fp;
911
912   data = repo_add_repodata(repo, flags);
913   buf = 0;
914   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keyfile) : keyfile, "r")) == 0)
915     {
916       pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
917       return 0;
918     }
919   if ((buf = solv_slurp(fp, 0)) == 0)
920     {
921       pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
922       fclose(fp);
923       return 0;
924     }
925   fclose(fp);
926   p = repo_add_solvable(repo);
927   if (!pubkey2solvable(pool, p, data, buf, flags))
928     {
929       repo_free_solvable(repo, p, 1);
930       solv_free(buf);
931       return 0;
932     }
933   if (!(flags & REPO_NO_LOCATION))
934     {
935       Id p2;
936       for (p2 = p; p2 < pool->nsolvables; p2++)
937         repodata_set_location(data, p2, 0, 0, keyfile);
938     }
939   solv_free(buf);
940   if (!(flags & REPO_NO_INTERNALIZE))
941     repodata_internalize(data);
942   return p;
943 }
944
945 static int
946 is_sig_packet(unsigned char *sig, int sigl)
947 {
948   if (!sigl)
949     return 0;
950   if ((sig[0] & 0x80) == 0 || (sig[0] & 0x40 ? sig[0] & 0x3f : sig[0] >> 2 & 0x0f) != 2)
951     return 0;
952   return 1;
953 }
954
955 static int
956 is_pubkey_packet(unsigned char *pkt, int pktl)
957 {
958   if (!pktl)
959     return 0;
960   if ((pkt[0] & 0x80) == 0 || (pkt[0] & 0x40 ? pkt[0] & 0x3f : pkt[0] >> 2 & 0x0f) != 6)
961     return 0;
962   return 1;
963 }
964
965 static void
966 add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int pbufl, int flags)
967 {
968   Id p = repo_add_solvable(repo);
969   char *solvversion = pool_tmpjoin(pool, "libsolv-", LIBSOLV_VERSION_STRING, 0);
970   char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion);
971   setutf8string(data, p, SOLVABLE_DESCRIPTION, descr);
972   parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags);
973 }
974
975 int
976 repo_add_keyring(Repo *repo, FILE *fp, int flags)
977 {
978   Pool *pool = repo->pool;
979   Repodata *data;
980   unsigned char *buf, *p, *pbuf;
981   int bufl, l, pl, pbufl;
982
983   data = repo_add_repodata(repo, flags);
984   buf = (unsigned char *)solv_slurp(fp, &bufl);
985   if (buf && !is_pubkey_packet(buf, bufl))
986     {
987       /* assume ascii armored */
988       unsigned char *nbuf = 0, *ubuf;
989       int nl, ubufl;
990       bufl = 0;
991       for (l = 0; (nl = unarmor((char *)buf + l, &ubuf, &ubufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) != 0; l += nl)
992         {
993           /* found another block. concat. */
994           nbuf = solv_realloc(nbuf, bufl + ubufl);
995           if (ubufl)
996             memcpy(nbuf + bufl, ubuf, ubufl);
997           bufl += ubufl;
998           solv_free(ubuf);
999         }
1000       solv_free(buf);
1001       buf = nbuf;
1002     }
1003   /* now split into pubkey parts, ignoring the packets we don't know */
1004   pbuf = 0;
1005   pbufl = 0;
1006   for (p = buf; bufl; p += pl, bufl -= pl)
1007     {
1008       int tag;
1009       int hl = parsepkgheader(p, bufl, &tag, &pl);
1010       if (!hl)
1011         break;
1012       pl += hl;
1013       if (tag == 6)
1014         {
1015           /* found new pubkey! flush old */
1016           if (pbufl)
1017             {
1018               add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
1019               pbuf = solv_free(pbuf);
1020               pbufl = 0;
1021             }
1022         }
1023       if (tag != 6 && !pbufl)
1024         continue;
1025       if (tag != 6 && tag != 2 && tag != 13 && tag != 14 && tag != 17)
1026         continue;
1027       /* we want that packet. concat. */
1028       pbuf = solv_realloc(pbuf, pbufl + pl);
1029       memcpy(pbuf + pbufl, p, pl);
1030       pbufl += pl;
1031     }
1032   if (pbufl)
1033     add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
1034   solv_free(pbuf);
1035   solv_free(buf);
1036   if (!(flags & REPO_NO_INTERNALIZE))
1037     repodata_internalize(data);
1038   return 0;
1039 }
1040
1041 int
1042 repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags)
1043 {
1044   Pool *pool = repo->pool;
1045   Repodata *data;
1046   int i, nent, sl;
1047   struct dirent **namelist;
1048   char *rkeydir;
1049
1050   data = repo_add_repodata(repo, flags);
1051   nent = scandir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keydir) : keydir, &namelist, 0, alphasort);
1052   if (nent == -1)
1053     return pool_error(pool, -1, "%s: %s", keydir, strerror(errno));
1054   rkeydir = pool_prepend_rootdir(pool, keydir);
1055   sl = suffix ? strlen(suffix) : 0;
1056   for (i = 0; i < nent; i++)
1057     {
1058       const char *dn = namelist[i]->d_name;
1059       int l;
1060       if (*dn == '.' && !(flags & ADD_KEYDIR_WITH_DOTFILES))
1061         continue;
1062       l = strlen(dn);
1063       if (sl && (l < sl || strcmp(dn + l - sl, suffix) != 0))
1064         continue;
1065       repo_add_pubkey(repo, pool_tmpjoin(pool, rkeydir, "/", dn), flags | REPO_REUSE_REPODATA);
1066     }
1067   solv_free(rkeydir);
1068   for (i = 0; i < nent; i++)
1069     solv_free(namelist[i]);
1070   solv_free(namelist);
1071   if (!(flags & REPO_NO_INTERNALIZE))
1072     repodata_internalize(data);
1073   return 0;
1074 }
1075
1076 Solvsig *
1077 solvsig_create(FILE *fp)
1078 {
1079   Solvsig *ss;
1080   unsigned char *sig;
1081   int sigl, hl, tag, pktl;
1082   struct pgpsig pgpsig;
1083
1084   if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0)
1085     return 0;
1086   if (!is_sig_packet(sig, sigl))
1087     {
1088       /* not a raw sig, check armored */
1089       unsigned char *nsig;
1090       if (!unarmor((char *)sig, &nsig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----"))
1091         {
1092           solv_free(sig);
1093           return 0;
1094         }
1095       solv_free(sig);
1096       sig = nsig;
1097       if (!is_sig_packet(sig, sigl))
1098         {
1099           solv_free(sig);
1100           return 0;
1101         }
1102     }
1103   hl = parsepkgheader(sig, sigl, &tag, &pktl);
1104   if (!hl || tag != 2 || !pktl)
1105     {
1106       solv_free(sig);
1107       return 0;
1108     }
1109   pgpsig_init(&pgpsig, sig + hl, pktl);
1110   if (pgpsig.type != 0 || !pgpsig.haveissuer)
1111     {
1112       solv_free(sig);
1113       return 0;
1114     }
1115   ss = solv_calloc(1, sizeof(*ss));
1116   ss->sigpkt = solv_memdup(sig + hl, pktl);
1117   ss->sigpktl = pktl;
1118   solv_free(sig);
1119   solv_bin2hex(pgpsig.issuer, 8, ss->keyid);
1120   ss->htype = pgphashalgo2type(pgpsig.hashalgo);
1121   ss->created = pgpsig.created;
1122   ss->expires = pgpsig.expires;
1123   return ss;
1124 }
1125
1126 void
1127 solvsig_free(Solvsig *ss)
1128 {
1129   solv_free(ss->sigpkt);
1130   solv_free(ss);
1131 }
1132
1133 static int
1134 repo_find_all_pubkeys_cmp(const void *va, const void *vb, void *dp)
1135 {
1136   Pool *pool = dp;
1137   Id a = *(Id *)va;
1138   Id b = *(Id *)vb;
1139   /* cannot use evrcmp, as rpm says '0' > 'a' */
1140   return strcmp(pool_id2str(pool, pool->solvables[b].evr), pool_id2str(pool, pool->solvables[a].evr));
1141 }
1142
1143 void
1144 repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q)
1145 {
1146   Id p;
1147   Solvable *s;
1148   size_t keyidlen;
1149
1150   queue_empty(q);
1151   if (!keyid)
1152     return;
1153   keyidlen = strlen(keyid);
1154   if (keyidlen < 8 || keyidlen > 64)
1155     return;
1156   FOR_REPO_SOLVABLES(repo, p, s)
1157     {
1158       const char *kidstr, *evr = pool_id2str(s->repo->pool, s->evr);
1159
1160       if (!evr || strncmp(evr, keyid + keyidlen - 8, 8) != 0)
1161         continue;
1162       kidstr = solvable_lookup_str(s, keyidlen >= 32 ? PUBKEY_FINGERPRINT : PUBKEY_KEYID);
1163       if (kidstr && !strcmp(kidstr, keyid))
1164         queue_push(q, p);
1165     }
1166   if (q->count > 1)
1167     solv_sort(q->elements, q->count, sizeof(Id), repo_find_all_pubkeys_cmp, repo->pool);
1168 }
1169
1170 Id
1171 repo_find_pubkey(Repo *repo, const char *keyid)
1172 {
1173   Queue q;
1174   Id p;
1175   queue_init(&q);
1176   repo_find_all_pubkeys(repo, keyid, &q);
1177   p = q.count ? q.elements[0] : 0;
1178   queue_free(&q);
1179   return p;
1180 }
1181
1182 #ifdef ENABLE_PGPVRFY
1183
1184 /* warning: does not check key expiry/revokation, same as with gpgv or rpm */
1185 /* returns the Id of the pubkey that verified the signature */
1186 Id
1187 repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid)
1188 {
1189   Id p;
1190   Queue q;
1191   int i;
1192
1193   if (!sigdata || !keyid)
1194     return 0;
1195   queue_init(&q);
1196   repo_find_all_pubkeys(repo, keyid, &q);
1197   for (i = 0; i < q.count; i++)
1198     {
1199       int pubdatal;
1200       const unsigned char *pubdata = repo_lookup_binary(repo, q.elements[i], PUBKEY_DATA, &pubdatal);
1201       if (pubdata && solv_pgpvrfy(pubdata, pubdatal, sigdata, sigdatal))
1202         break;
1203     }
1204   p = i < q.count? q.elements[i] : 0;
1205   queue_free(&q);
1206   return p;
1207 }
1208
1209 Id
1210 solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk)
1211 {
1212   struct pgpsig pgpsig;
1213   void *chk2;
1214   Id p;
1215
1216   if (!chk || solv_chksum_isfinished(chk))
1217     return 0;
1218   pgpsig_init(&pgpsig, ss->sigpkt, ss->sigpktl);
1219   chk2 = solv_chksum_create_clone(chk);
1220   pgpsig_makesigdata(&pgpsig, ss->sigpkt, ss->sigpktl, 0, 0, 0, 0, chk2);
1221   solv_chksum_free(chk2, 0);
1222   if (!pgpsig.sigdata)
1223     return 0;
1224   p = repo_verify_sigdata(repo, pgpsig.sigdata, pgpsig.sigdatal, ss->keyid);
1225   solv_free(pgpsig.sigdata);
1226   return p;
1227 }
1228
1229 #endif
1230