X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ext%2Frepo_pubkey.c;h=eb838394854714c70987fc16cfa1b905c23f6fcc;hb=6a68988035ea989055076d81b7ab53c7015c8c32;hp=3dffa20e5b34ccfea01309751c8c7608b65d3a62;hpb=35fccc4f9a65ab937ddf7c70926637e1ece3f43a;p=platform%2Fupstream%2Flibsolv.git diff --git a/ext/repo_pubkey.c b/ext/repo_pubkey.c index 3dffa20..eb83839 100644 --- a/ext/repo_pubkey.c +++ b/ext/repo_pubkey.c @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include #include @@ -23,6 +21,7 @@ #include #include #include +#include #include #include @@ -100,7 +99,7 @@ r64dec1(char *p, unsigned int *vp, int *eofp) static unsigned int crc24(unsigned char *p, int len) { - unsigned int crc = 0xb704ceL; + unsigned int crc = 0xb704ce; int i; while (len--) @@ -108,19 +107,20 @@ crc24(unsigned char *p, int len) crc ^= (*p++) << 16; for (i = 0; i < 8; i++) if ((crc <<= 1) & 0x1000000) - crc ^= 0x1864cfbL; + crc ^= 0x1864cfb; } - return crc & 0xffffffL; + return crc & 0xffffff; } -static unsigned char * -unarmor(char *pubkey, int *pktlp, char *startstr, char *endstr) +static int +unarmor(char *pubkey, unsigned char **pktp, int *pktlp, const char *startstr, const char *endstr) { - char *p; + char *p, *pubkeystart = pubkey; int l, eof; unsigned char *buf, *bp; unsigned int v; + *pktp = 0; *pktlp = 0; if (!pubkey) return 0; @@ -185,10 +185,54 @@ unarmor(char *pubkey, int *pktlp, char *startstr, char *endstr) solv_free(buf); return 0; } + p = strchr(pubkey, '\n'); + if (!p) + p = pubkey + strlen(pubkey); + *pktp = buf; *pktlp = bp - buf; - return buf; + return (p ? p + 1 : pubkey + strlen(pubkey)) - pubkeystart; } +#define ARMOR_NLAFTER 16 + +static char * +armor(unsigned char *pkt, int pktl, const char *startstr, const char *endstr, const char *version) +{ + static const char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *str = solv_malloc(strlen(startstr) + strlen(endstr) + strlen(version) + (pktl / 3) * 4 + (pktl / (ARMOR_NLAFTER * 3)) + 30); + char *p = str; + int a, b, c, i; + unsigned int v; + + v = crc24(pkt, pktl); + sprintf(p, "%s\nVersion: %s\n\n", startstr, version); + p += strlen(p); + for (i = -1; pktl > 0; pktl -= 3) + { + if (++i == ARMOR_NLAFTER) + { + i = 0; + *p++ = '\n'; + } + a = *pkt++; + b = pktl > 1 ? *pkt++ : 0; + c = pktl > 2 ? *pkt++ : 0; + *p++ = bintoasc[a >> 2]; + *p++ = bintoasc[(a & 3) << 4 | b >> 4]; + *p++ = pktl > 1 ? bintoasc[(b & 15) << 2 | c >> 6] : '='; + *p++ = pktl > 2 ? bintoasc[c & 63] : '='; + } + *p++ = '\n'; + *p++ = '='; + *p++ = bintoasc[v >> 18 & 0x3f]; + *p++ = bintoasc[v >> 12 & 0x3f]; + *p++ = bintoasc[v >> 6 & 0x3f]; + *p++ = bintoasc[v & 0x3f]; + sprintf(p, "\n%s\n", endstr); + return str; +} + +/* internal representation of a signature */ struct pgpsig { int type; Id hashalgo; @@ -211,18 +255,27 @@ pgphashalgo2type(int algo) return REPOKEY_TYPE_SHA1; if (algo == 8) return REPOKEY_TYPE_SHA256; + if (algo == 9) + return REPOKEY_TYPE_SHA384; + if (algo == 10) + return REPOKEY_TYPE_SHA512; + if (algo == 11) + return REPOKEY_TYPE_SHA224; return 0; } +/* hash the pubkey/userid data for self-sig verification + * hash the final trailer + * create a "sigdata" block suitable for a call to solv_pgpverify */ static void -createsigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, void *h) +pgpsig_makesigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, Chksum *h) { int type = sig->type; unsigned char b[6]; const unsigned char *cs; int csl; - if (sig->mpioff < 2 || l <= sig->mpioff) + if (!h || sig->mpioff < 2 || l <= sig->mpioff) return; if ((type >= 0x10 && type <= 0x13) || type == 0x1f || type == 0x18 || type == 0x20 || type == 0x28) { @@ -273,6 +326,10 @@ createsigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey } } +/* parse the header of a subpacket contained in a signature packet + * returns: length of the packet header, 0 if there was an error + * *pktlp is set to the packet length, the tag is the first byte. + */ static inline int parsesubpkglength(unsigned char *q, int ql, int *pktlp) { @@ -304,9 +361,11 @@ parsesubpkglength(unsigned char *q, int ql, int *pktlp) return hl; } +/* parse a signature packet, initializing the pgpsig struct */ static void -parsesigpacket(struct pgpsig *sig, unsigned char *p, int l) +pgpsig_init(struct pgpsig *sig, unsigned char *p, int l) { + memset(sig, 0, sizeof(*sig)); sig->type = -1; if (p[0] == 3) { @@ -379,6 +438,10 @@ parsesigpacket(struct pgpsig *sig, unsigned char *p, int l) } } +/* parse a pgp packet header + * returns: length of the packet header, 0 if there was an error + * *tagp and *pktlp is set to the packet tag and the packet length + */ static int parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp) { @@ -432,39 +495,97 @@ parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp) return p - op; } - -static void -parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) +/* parse the first pubkey (possible creating new packages for the subkeys) + * returns the number of parsed bytes. + * if flags contains ADD_WITH_SUBKEYS, all subkeys will be added as new + * solvables as well */ +static int +parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) { + Repo *repo = s->repo; + unsigned char *pstart = p; int tag, l; unsigned char keyid[8]; + char subkeyofstr[17]; unsigned int kcr = 0, maxex = 0, maxsigcr = 0; unsigned char *pubkey = 0; int pubkeyl = 0; + int insubkey = 0; unsigned char *userid = 0; int useridl = 0; unsigned char *pubdata = 0; int pubdatal = 0; - for (; pl; p += l, pl -= l) + *subkeyofstr = 0; + for (; ; p += l, pl -= l) { int hl = parsepkgheader(p, pl, &tag, &l); - if (!hl) - break; + if (!hl || (pubkey && (tag == 6 || tag == 14))) + { + /* finish old key */ + if (kcr) + repodata_set_num(data, s - repo->pool->solvables, SOLVABLE_BUILDTIME, kcr); + if (maxex && maxex != -1) + repodata_set_num(data, s - repo->pool->solvables, PUBKEY_EXPIRES, maxex); + s->name = pool_str2id(s->repo->pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1); + s->evr = 1; + s->arch = 1; + if (userid && useridl) + { + char *useridstr = solv_malloc(useridl + 1); + memcpy(useridstr, userid, useridl); + useridstr[useridl] = 0; + setutf8string(data, s - repo->pool->solvables, SOLVABLE_SUMMARY, useridstr); + free(useridstr); + } + if (pubdata) + { + char keyidstr[17]; + char evr[8 + 1 + 8 + 1]; + solv_bin2hex(keyid, 8, keyidstr); + repodata_set_str(data, s - repo->pool->solvables, PUBKEY_KEYID, keyidstr); + /* build rpm-style evr */ + strcpy(evr, keyidstr + 8); + sprintf(evr + 8, "-%08x", maxsigcr); + s->evr = pool_str2id(repo->pool, evr, 1); + } + if (insubkey && *subkeyofstr) + repodata_set_str(data, s - repo->pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr); + if (pubdata) /* set data blob */ + repodata_set_binary(data, s - repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal); + if (!pl) + break; + if (!hl) + { + p = 0; /* parse error */ + break; + } + if (tag == 6 || (tag == 14 && !(flags & ADD_WITH_SUBKEYS))) + break; + if (tag == 14 && pubdata && !insubkey) + solv_bin2hex(keyid, 8, subkeyofstr); + /* create new solvable for subkey */ + s = pool_id2solvable(repo->pool, repo_add_solvable(repo)); + } p += hl; pl -= hl; - if (tag == 6) + if (!pubkey && tag != 6) + continue; + if (tag == 6 || (tag == 14 && (flags & ADD_WITH_SUBKEYS) != 0)) /* Public-Key Packet */ { - if (pubkey) - break; /* one key at a time, please */ - pubkey = solv_malloc(l); - if (l) - memcpy(pubkey, p, l); - pubkeyl = l; + if (tag == 6) + { + pubkey = solv_memdup(p, l); + pubkeyl = l; + } + else + insubkey = 1; + pubdata = 0; + pubdatal = 0; if (p[0] == 3 && l >= 10) { unsigned int ex; - void *h; + Chksum *h; maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; ex = 0; if (p[5] || p[6]) @@ -504,7 +625,7 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) } else if (p[0] == 4 && l >= 6) { - void *h; + Chksum *h; unsigned char hdr[3]; unsigned char fp[20]; char fpx[40 + 1]; @@ -525,14 +646,13 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) pubdatal = l - 5; } } - if (tag == 2) + if (tag == 2) /* Signature Packet */ { struct pgpsig sig; Id htype; if (!pubdata) continue; - memset(&sig, 0, sizeof(sig)); - parsesigpacket(&sig, p, l); + pgpsig_init(&sig, p, l); if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f)) continue; if (sig.type >= 0x10 && sig.type <= 0x13 && !userid) @@ -540,8 +660,8 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) htype = pgphashalgo2type(sig.hashalgo); if (htype && sig.mpioff) { - void *h = solv_chksum_create(htype); - createsigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h); + Chksum *h = solv_chksum_create(htype); + pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h); solv_chksum_free(h, 0); } if (!memcmp(keyid, sig.issuer, 8)) @@ -562,7 +682,7 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) maxsigcr = sig.created; } } - else + else if (flags & ADD_WITH_KEYSIGNATURES) { char issuerstr[17]; Id shandle = repodata_new_handle(data); @@ -578,7 +698,7 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) } solv_free(sig.sigdata); } - if (tag == 13) + if (tag == 13 && !insubkey) /* User ID Packet */ { userid = solv_realloc(userid, l); if (l) @@ -586,39 +706,9 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) useridl = l; } } - if (kcr) - repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, kcr); - if (maxex && maxex != -1) - repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex); - s->name = pool_str2id(s->repo->pool, "gpg-pubkey", 1); - s->evr = 1; - s->arch = 1; - if (userid && useridl) - { - char *useridstr = solv_malloc(useridl + 1); - memcpy(useridstr, userid, useridl); - useridstr[useridl] = 0; - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, useridstr); - free(useridstr); - } - if (pubdata) - { - char keyidstr[17]; - solv_bin2hex(keyid, 8, keyidstr); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyidstr); - } - if (pubdata) - { - /* build rpm-style evr */ - char evr[8 + 1 + 8 + 1]; - solv_bin2hex(keyid + 4, 4, evr); - sprintf(evr + 8, "-%08x", maxsigcr); - s->evr = pool_str2id(s->repo->pool, evr, 1); - /* set data blob */ - repodata_set_binary(data, s - s->repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal); - } solv_free(pubkey); solv_free(userid); + return p ? p - pstart : 0; } @@ -655,7 +745,7 @@ struct pgpDig_s { /* only rpm knows how to do the release calculation, we don't dare * to recreate all the bugs in libsolv */ static void -parsekeydata_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl) +parsepubkey_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl) { Pool *pool = s->repo->pool; struct pgpDigParams_s *digpubkey; @@ -698,24 +788,43 @@ parsekeydata_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl) #endif /* ENABLE_RPMDB */ +/* parse an ascii armored pubkey + * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */ static int -pubkey2solvable(Solvable *s, Repodata *data, char *pubkey) +pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags) { - unsigned char *pkts; - int pktsl; + unsigned char *pkts, *pkts_orig; + int pktsl, pl = 0, tag, l, hl; - pkts = unarmor(pubkey, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"); - if (!pkts) + if (!unarmor(pubkey, &pkts, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) { - pool_error(s->repo->pool, 0, "unarmor failure"); + pool_error(pool, 0, "unarmor failure"); return 0; } - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey); - parsekeydata(s, data, pkts, pktsl); + pkts_orig = pkts; + tag = 6; + while (pktsl) + { + if (tag == 6) + { + setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey); + pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags); #ifdef ENABLE_RPMDB - parsekeydata_rpm(s, data, pkts, pktsl); + parsepubkey_rpm(pool->solvables + p, data, pkts, pktsl); #endif - solv_free((void *)pkts); + if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS)) + break; + } + pkts += pl; + pktsl -= pl; + hl = parsepkgheader(pkts, pktsl, &tag, &l); + if (!hl) + break; + pl = l + hl; + if (tag == 6) + p = repo_add_solvable(pool->solvables[p].repo); + } + solv_free((void *)pkts_orig); return 1; } @@ -729,7 +838,6 @@ repo_add_rpmdb_pubkeys(Repo *repo, int flags) int i; char *str; Repodata *data; - Solvable *s; const char *rootdir = 0; void *state; @@ -741,6 +849,7 @@ repo_add_rpmdb_pubkeys(Repo *repo, int flags) rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q); for (i = 0; i < q.count; i++) { + Id p, p2; void *handle; unsigned long long itime; @@ -750,15 +859,23 @@ repo_add_rpmdb_pubkeys(Repo *repo, int flags) str = rpm_query(handle, SOLVABLE_DESCRIPTION); if (!str) continue; - s = pool_id2solvable(pool, repo_add_solvable(repo)); - pubkey2solvable(s, data, str); + p = repo_add_solvable(repo); + if (!pubkey2solvable(pool, p, data, str, flags)) + { + solv_free(str); + repo_free_solvable(repo, p, 1); + continue; + } solv_free(str); itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0); - if (itime) - repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, itime); - if (!repo->rpmdbid) - repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); - repo->rpmdbid[s - pool->solvables - repo->start] = q.elements[i]; + for (p2 = p; p2 < pool->nsolvables; p2++) + { + if (itime) + repodata_set_num(data, p2, SOLVABLE_INSTALLTIME, itime); + if (!repo->rpmdbid) + repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); + repo->rpmdbid[p2 - repo->start] = q.elements[i]; + } } queue_free(&q); rpm_state_free(state); @@ -802,39 +919,45 @@ solv_slurp(FILE *fp, int *lenp) } Id -repo_add_pubkey(Repo *repo, const char *key, int flags) +repo_add_pubkey(Repo *repo, const char *keyfile, int flags) { Pool *pool = repo->pool; Repodata *data; - Solvable *s; + Id p; char *buf; FILE *fp; data = repo_add_repodata(repo, flags); buf = 0; - if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0) + if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keyfile) : keyfile, "r")) == 0) { - pool_error(pool, -1, "%s: %s", key, strerror(errno)); + pool_error(pool, -1, "%s: %s", keyfile, strerror(errno)); return 0; } if ((buf = solv_slurp(fp, 0)) == 0) { - pool_error(pool, -1, "%s: %s", key, strerror(errno)); + pool_error(pool, -1, "%s: %s", keyfile, strerror(errno)); fclose(fp); return 0; } fclose(fp); - s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!pubkey2solvable(s, data, buf)) + p = repo_add_solvable(repo); + if (!pubkey2solvable(pool, p, data, buf, flags)) { - repo_free_solvable(repo, s - pool->solvables, 1); + repo_free_solvable(repo, p, 1); solv_free(buf); return 0; } + if (!(flags & REPO_NO_LOCATION)) + { + Id p2; + for (p2 = p; p2 < pool->nsolvables; p2++) + repodata_set_location(data, p2, 0, 0, keyfile); + } solv_free(buf); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); - return s - pool->solvables; + return p; } static int @@ -847,29 +970,150 @@ is_sig_packet(unsigned char *sig, int sigl) return 1; } -Id -solv_parse_sig(FILE *fp, unsigned char **sigpktp, int *sigpktlp, char *keyidstr) +static int +is_pubkey_packet(unsigned char *pkt, int pktl) +{ + if (!pktl) + return 0; + if ((pkt[0] & 0x80) == 0 || (pkt[0] & 0x40 ? pkt[0] & 0x3f : pkt[0] >> 2 & 0x0f) != 6) + return 0; + return 1; +} + +static void +add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int pbufl, int flags) +{ + Id p = repo_add_solvable(repo); + char *solvversion = pool_tmpjoin(pool, "libsolv-", LIBSOLV_VERSION_STRING, 0); + char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion); + setutf8string(data, p, SOLVABLE_DESCRIPTION, descr); + parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags); +#ifdef ENABLE_RPMDB + parsepubkey_rpm(pool->solvables + p, data, pbuf, pbufl); +#endif +} + +int +repo_add_keyring(Repo *repo, FILE *fp, int flags) { + Pool *pool = repo->pool; + Repodata *data; + unsigned char *buf, *p, *pbuf; + int bufl, l, pl, pbufl; + + data = repo_add_repodata(repo, flags); + buf = (unsigned char *)solv_slurp(fp, &bufl); + if (buf && !is_pubkey_packet(buf, bufl)) + { + /* assume ascii armored */ + unsigned char *nbuf = 0, *ubuf; + int nl, ubufl; + bufl = 0; + for (l = 0; (nl = unarmor((char *)buf + l, &ubuf, &ubufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) != 0; l += nl) + { + /* found another block. concat. */ + nbuf = solv_realloc(nbuf, bufl + ubufl); + if (ubufl) + memcpy(nbuf + bufl, ubuf, ubufl); + bufl += ubufl; + solv_free(ubuf); + } + solv_free(buf); + buf = nbuf; + } + /* now split into pubkey parts, ignoring the packets we don't know */ + pbuf = 0; + pbufl = 0; + for (p = buf; bufl; p += pl, bufl -= pl) + { + int tag; + int hl = parsepkgheader(p, bufl, &tag, &pl); + if (!hl) + break; + pl += hl; + if (tag == 6) + { + /* found new pubkey! flush old */ + if (pbufl) + { + add_one_pubkey(pool, repo, data, pbuf, pbufl, flags); + pbuf = solv_free(pbuf); + pbufl = 0; + } + } + if (tag != 6 && !pbufl) + continue; + if (tag != 6 && tag != 2 && tag != 13 && tag != 14 && tag != 17) + continue; + /* we want that packet. concat. */ + pbuf = solv_realloc(pbuf, pbufl + pl); + memcpy(pbuf + pbufl, p, pl); + pbufl += pl; + } + if (pbufl) + add_one_pubkey(pool, repo, data, pbuf, pbufl, flags); + solv_free(pbuf); + solv_free(buf); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +int +repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags) +{ + Pool *pool = repo->pool; + Repodata *data; + int i, nent, sl; + struct dirent **namelist; + char *rkeydir; + + data = repo_add_repodata(repo, flags); + nent = scandir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keydir) : keydir, &namelist, 0, alphasort); + if (nent == -1) + return pool_error(pool, -1, "%s: %s", keydir, strerror(errno)); + rkeydir = pool_prepend_rootdir(pool, keydir); + sl = suffix ? strlen(suffix) : 0; + for (i = 0; i < nent; i++) + { + const char *dn = namelist[i]->d_name; + int l; + if (*dn == '.' && !(flags & ADD_KEYDIR_WITH_DOTFILES)) + continue; + l = strlen(dn); + if (sl && (l < sl || strcmp(dn + l - sl, suffix) != 0)) + continue; + repo_add_pubkey(repo, pool_tmpjoin(pool, rkeydir, "/", dn), flags | REPO_REUSE_REPODATA); + } + solv_free(rkeydir); + for (i = 0; i < nent; i++) + solv_free(namelist[i]); + solv_free(namelist); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +Solvsig * +solvsig_create(FILE *fp) +{ + Solvsig *ss; unsigned char *sig; int sigl, hl, tag, pktl; struct pgpsig pgpsig; - Id htype; - if (sigpktp) - { - *sigpktp = 0; - *sigpktlp = 0; - } if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0) return 0; if (!is_sig_packet(sig, sigl)) { /* not a raw sig, check armored */ unsigned char *nsig; - nsig = unarmor((char *)sig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----"); + if (!unarmor((char *)sig, &nsig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----")) + { + solv_free(sig); + return 0; + } solv_free(sig); - if (!nsig) - return 0; sig = nsig; if (!is_sig_packet(sig, sigl)) { @@ -883,51 +1127,121 @@ solv_parse_sig(FILE *fp, unsigned char **sigpktp, int *sigpktlp, char *keyidstr) solv_free(sig); return 0; } - memset(&pgpsig, 0, sizeof(pgpsig)); - parsesigpacket(&pgpsig, sig + hl, pktl); - htype = pgphashalgo2type(pgpsig.hashalgo); - if (pgpsig.type != 0 || !htype || !pgpsig.haveissuer) + pgpsig_init(&pgpsig, sig + hl, pktl); + if (pgpsig.type != 0 || !pgpsig.haveissuer) { solv_free(sig); return 0; } - if (sigpktp) + ss = solv_calloc(1, sizeof(*ss)); + ss->sigpkt = solv_memdup(sig + hl, pktl); + ss->sigpktl = pktl; + solv_free(sig); + solv_bin2hex(pgpsig.issuer, 8, ss->keyid); + ss->htype = pgphashalgo2type(pgpsig.hashalgo); + ss->created = pgpsig.created; + ss->expires = pgpsig.expires; + return ss; +} + +void +solvsig_free(Solvsig *ss) +{ + solv_free(ss->sigpkt); + solv_free(ss); +} + +static int +repo_find_all_pubkeys_cmp(const void *va, const void *vb, void *dp) +{ + Pool *pool = dp; + Id a = *(Id *)va; + Id b = *(Id *)vb; + /* cannot use evrcmp, as rpm says '0' > 'a' */ + return strcmp(pool_id2str(pool, pool->solvables[b].evr), pool_id2str(pool, pool->solvables[a].evr)); +} + +void +repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q) +{ + Id p; + Solvable *s; + + queue_empty(q); + if (!keyid) + return; + queue_init(q); + FOR_REPO_SOLVABLES(repo, p, s) { - *sigpktp = solv_malloc(pktl); - memcpy(*sigpktp, sig + hl, pktl); - *sigpktlp = pktl; + const char *kidstr, *evr = pool_id2str(s->repo->pool, s->evr); + + if (!evr || strncmp(evr, keyid + 8, 8) != 0) + continue; + kidstr = solvable_lookup_str(s, PUBKEY_KEYID); + if (kidstr && !strcmp(kidstr, keyid)) + queue_push(q, p); } - solv_free(sig); - if (keyidstr) - solv_bin2hex(pgpsig.issuer, 8, keyidstr); - return htype; + if (q->count > 1) + solv_sort(q->elements, q->count, sizeof(Id), repo_find_all_pubkeys_cmp, repo->pool); +} + +Id +repo_find_pubkey(Repo *repo, const char *keyid) +{ + Queue q; + Id p; + queue_init(&q); + repo_find_all_pubkeys(repo, keyid, &q); + p = q.count ? q.elements[0] : 0; + queue_free(&q); + return p; } #ifdef ENABLE_PGPVRFY -int -solv_verify_sig(const unsigned char *pubdata, int pubdatal, unsigned char *sigpkt, int sigpktl, void *chk) +/* warning: does not check key expiry/revokation, same as with gpgv or rpm */ +/* returns the Id of the pubkey that verified the signature */ +Id +repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid) +{ + Id p; + Queue q; + int i; + + if (!sigdata || !keyid) + return 0; + queue_init(&q); + repo_find_all_pubkeys(repo, keyid, &q); + for (i = 0; i < q.count; i++) + { + int pubdatal; + const unsigned char *pubdata = repo_lookup_binary(repo, q.elements[i], PUBKEY_DATA, &pubdatal); + if (pubdata && solv_pgpvrfy(pubdata, pubdatal, sigdata, sigdatal)) + break; + } + p = i < q.count? q.elements[i] : 0; + queue_free(&q); + return p; +} + +Id +solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk) { struct pgpsig pgpsig; - int res; - Id htype; void *chk2; + Id p; - memset(&pgpsig, 0, sizeof(pgpsig)); - parsesigpacket(&pgpsig, sigpkt, sigpktl); - if (pgpsig.type != 0) + if (!chk || solv_chksum_isfinished(chk)) return 0; - htype = pgphashalgo2type(pgpsig.hashalgo); - if (htype != solv_chksum_get_type(chk)) - return 0; /* wrong hash type? */ + pgpsig_init(&pgpsig, ss->sigpkt, ss->sigpktl); chk2 = solv_chksum_create_clone(chk); - createsigdata(&pgpsig, sigpkt, sigpktl, 0, 0, 0, 0, chk2); + pgpsig_makesigdata(&pgpsig, ss->sigpkt, ss->sigpktl, 0, 0, 0, 0, chk2); solv_chksum_free(chk2, 0); if (!pgpsig.sigdata) return 0; - res = solv_pgpvrfy(pubdata, pubdatal, pgpsig.sigdata, pgpsig.sigdatal); + p = repo_verify_sigdata(repo, pgpsig.sigdata, pgpsig.sigdatal, ss->keyid); solv_free(pgpsig.sigdata); - return res; + return p; } #endif