/** * Remember current key id. * @param dig container * @return 0 if new keyid, otherwise 1 */ static int pgpStashKeyid(pgpDig dig) /*@globals nextkeyid, nkeyids, keyids @*/ /*@modifies nextkeyid, nkeyids, keyids @*/ { pgpDigParams sigp = pgpGetSignature(dig); const void * sig = pgpGetSig(dig); unsigned int keyid; unsigned int i; if (sig == NULL || dig == NULL || sigp == NULL) return 0; keyid = pgpGrab(sigp->signid+4, 4); if (keyid == 0) return 0; if (keyids != NULL) for (i = 0; i < nkeyids; i++) { if (keyid == keyids[i]) return 1; } if (nkeyids < nkeyids_max) { nkeyids++; keyids = (unsigned int *) xrealloc(keyids, nkeyids * sizeof(*keyids)); } if (keyids) /* XXX can't happen */ keyids[nextkeyid] = keyid; nextkeyid++; nextkeyid %= nkeyids_max; return 0; }
/** * Remember current key id. * @param dig OpenPGP packet containter * @return 0 if new keyid, otherwise 1 */ static int stashKeyid(pgpDig dig) { pgpDigParams sigp = dig ? &dig->signature : NULL; unsigned int keyid; int i; if (dig == NULL || sigp == NULL) return 0; keyid = pgpGrab(sigp->signid+4, 4); if (keyid == 0) return 0; if (keyids != NULL) for (i = 0; i < nkeyids; i++) { if (keyid == keyids[i]) return 1; } if (nkeyids < nkeyids_max) { nkeyids++; keyids = xrealloc(keyids, nkeyids * sizeof(*keyids)); } if (keyids) /* XXX can't happen */ keyids[nextkeyid] = keyid; nextkeyid++; nextkeyid %= nkeyids_max; return 0; }
/** \ingroup rpmpgp * Decode length from 1, 2, or 5 octet body length encoding, used in * new format packet headers and V4 signature subpackets. * @param s pointer to length encoding buffer * @param slen buffer size * @retval *lenp decoded length * @return no. of bytes used to encode the length, 0 on error */ static inline size_t pgpLen(const uint8_t *s, size_t slen, size_t * lenp) { size_t dlen = 0; size_t lenlen = 0; /* * Callers can only ensure we'll always have the first byte, beyond * that the required size is not known until we decode it so we need * to check if we have enough bytes to read the size as we go. */ if (*s < 192) { lenlen = 1; dlen = *s; } else if (*s < 255 && slen > 2) { lenlen = 2; dlen = (((s[0]) - 192) << 8) + s[1] + 192; } else if (slen > 5) { lenlen = 5; dlen = pgpGrab(s+1, 4); } if (lenlen) *lenp = dlen; return lenlen; }
/** \ingroup rpmpgp * Return hex formatted representation of a multiprecision integer. * @param p bytes * @return hex formatted string (malloc'ed) */ static inline char * pgpMpiStr(const uint8_t *p) { char *str = NULL; char *hex = pgpHexStr(p+2, pgpMpiLen(p)-2); rasprintf(&str, "[%4u]: %s", pgpGrab(p, (size_t) 2), hex); free(hex); return str; }
rpmRC rpmkuFindPubkey(pgpDigParams sigp, /*@out@*/ rpmiob * iobp) { if (iobp != NULL) *iobp = NULL; #if defined(HAVE_KEYUTILS_H) if (_kuCache) { /*@observer@*/ static const char krprefix[] = "rpm:gpg:pubkey:"; key_serial_t keyring = (key_serial_t) _kuKeyring; char krfp[32]; char * krn = (char *) alloca(strlen(krprefix) + sizeof("12345678")); long key; int xx; (void) snprintf(krfp, sizeof(krfp), "%08X", pgpGrab(sigp->signid+4, 4)); krfp[sizeof(krfp)-1] = '\0'; *krn = '\0'; (void) stpcpy( stpcpy(krn, krprefix), krfp); key = keyctl_search(keyring, "user", krn, 0); xx = keyctl_read(key, NULL, 0); if (xx > 0) { rpmiob iob = rpmiobNew(xx); xx = keyctl_read(key, (char *)iob->b, iob->blen); if (xx > 0) { #ifdef NOTYET pubkeysource = xstrdup(krn); _kuCache = 0; /* XXX don't bother caching. */ #endif } else iob = rpmiobFree(iob); if (iob != NULL && iobp != NULL) { *iobp = iob; return RPMRC_OK; } else { iob = rpmiobFree(iob); return RPMRC_NOTFOUND; } } else return RPMRC_NOTFOUND; } else #endif /* HAVE_KEYUTILS_H */ return RPMRC_NOTFOUND; }
rpmRC rpmkuStorePubkey(pgpDigParams sigp, /*@only@*/ rpmiob iob) { #if defined(HAVE_KEYUTILS_H) if (_kuCache) { /*@observer@*/ static const char krprefix[] = "rpm:gpg:pubkey:"; key_serial_t keyring = (key_serial_t) _kuKeyring; char krfp[32]; char * krn = (char *) alloca(strlen(krprefix) + sizeof("12345678")); (void) snprintf(krfp, sizeof(krfp), "%08X", pgpGrab(sigp->signid+4, 4)); krfp[sizeof(krfp)-1] = '\0'; *krn = '\0'; (void) stpcpy( stpcpy(krn, krprefix), krfp); /*@-moduncon -noeffectuncon @*/ (void) add_key("user", krn, iob->b, iob->blen, keyring); /*@=moduncon =noeffectuncon @*/ } #endif /* HAVE_KEYUTILS_H */ iob = rpmiobFree(iob); return RPMRC_OK; }
/** * Display signature fingerprint and time. * @param td tag data container * @return formatted string */ static char * pgpsigFormat(rpmtd td) { char * val = NULL; if (rpmtdType(td) != RPM_BIN_TYPE) { val = xstrdup(_("(not a blob)")); } else { pgpDigParams sigp = NULL; if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) { val = xstrdup(_("(not an OpenPGP signature)")); } else { char dbuf[BUFSIZ]; char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid)); unsigned int dateint = pgpGrab(sigp->time, sizeof(sigp->time)); time_t date = dateint; struct tm * tms = localtime(&date); unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) { snprintf(dbuf, sizeof(dbuf), _("Invalid date %u"), dateint); dbuf[sizeof(dbuf)-1] = '\0'; } rasprintf(&val, "%s/%s, %s, Key ID %s", pgpValString(PGPVAL_PUBKEYALGO, key_algo), pgpValString(PGPVAL_HASHALGO, hash_algo), dbuf, keyid); free(keyid); pgpDigParamsFree(sigp); } } return val; }
static unsigned int getKeyid(pgpDigParams sigp) { return (sigp != NULL) ? pgpGrab(sigp->signid+4, 4) : 0; }
rpmRC rpmnsProbeSignature(void * _ts, const char * fn, const char * sigfn, const char * pubfn, const char * pubid, /*@unused@*/ int flags) { rpmts ts = (rpmts) _ts; pgpDig dig = rpmtsDig(ts); pgpDigParams sigp = pgpGetSignature(dig); pgpDigParams pubp = pgpGetPubkey(dig); rpmuint8_t * sigpkt = NULL; size_t sigpktlen = 0; DIGEST_CTX ctx = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int xx; rpmhkp hkp = NULL; pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); size_t pleft; int validate = 1; SPEW((stderr, "==> check(%s, %s, %s, %s)\n", fn, (sigfn ? sigfn : "(null)"), (pubfn ? pubfn : "(null)"), (pubid ? pubid : "(null)"))); /* Choose signature location: clearsign from fn if sigfn is NULL */ assert(fn && *fn); if (!(sigfn && *sigfn)) sigfn = fn; /* Load the signature from the file. */ { const char * _sigfn = rpmExpand(sigfn, NULL); xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen); if (xx != PGPARMOR_SIGNATURE) { SPEW((stderr, "==> pgpReadPkts(%s) SIG %p[%u] ret %d\n", _sigfn, sigpkt, (unsigned)sigpktlen, xx)); _sigfn = _free(_sigfn); goto exit; } _sigfn = _free(_sigfn); } pleft = sigpktlen; xx = pgpPktLen(sigpkt, pleft, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (xx) goto exit; if (sigp->version != (rpmuint8_t)3 && sigp->version != (rpmuint8_t)4) { SPEW((stderr, "==> unverifiable V%u\n", (unsigned)sigp->version)); goto exit; } if (ts->hkp == NULL) ts->hkp = rpmhkpNew(NULL, 0); hkp = rpmhkpLink(ts->hkp); /* Load the pubkey. Use pubfn if specified, otherwise rpmdb keyring. */ if (pubfn && *pubfn) { const char * _pubfn = rpmExpand(pubfn, NULL); /*@-type@*/ hkp->pkt = _free(hkp->pkt); /* XXX memleaks */ hkp->pktlen = 0; xx = pgpReadPkts(_pubfn, &hkp->pkt, &hkp->pktlen); /*@=type@*/ if (xx != PGPARMOR_PUBKEY) { SPEW((stderr, "==> pgpReadPkts(%s) PUB %p[%u] rc %d\n", _pubfn, hkp->pkt, (unsigned)hkp->pktlen, xx)); _pubfn = _free(_pubfn); goto exit; } _pubfn = _free(_pubfn); /* Split the result into packet array. */ hkp->pkts = _free(hkp->pkts); /* XXX memleaks */ hkp->npkts = 0; xx = pgpGrabPkts(hkp->pkt, hkp->pktlen, &hkp->pkts, &hkp->npkts); #ifdef DYING _rpmhkpDumpDig(__FUNCTION__, dig, NULL); #endif if (!xx) (void) pgpPubkeyFingerprint(hkp->pkt, hkp->pktlen, hkp->keyid); memcpy(pubp->signid, hkp->keyid, sizeof(pubp->signid));/* XXX useless */ /* Validate pubkey self-signatures (if any). */ /* XXX TODO: only validate once, then cache using rpmku */ /* XXX need at least 3 packets to validate a pubkey */ if (validate && hkp->npkts >= 3) { #ifdef DYING pgpPrtPkts(hkp->pkt, hkp->pktlen, NULL, 1); #endif xx = rpmhkpValidate(hkp, NULL); switch (xx) { case RPMRC_OK: break; case RPMRC_NOTFOUND: case RPMRC_FAIL: /* XXX remap to NOTFOUND? */ case RPMRC_NOTTRUSTED: case RPMRC_NOKEY: default: SPEW((stderr, "\t<-- rpmhkpValidate() rc %d\n", xx)); rc = (rpmRC)xx; goto exit; } } /* Retrieve parameters from pubkey/subkey packet(s). */ xx = rpmhkpFindKey(hkp, dig, sigp->signid, sigp->pubkey_algo); if (xx) { SPEW((stderr, "\t<-- rpmhkpFindKey() rc %d\n", xx)); goto exit; } } else { rc = (rpmRC)pgpFindPubkey(dig); if (rc != RPMRC_OK) { SPEW((stderr, "\t<-- pgpFindPubkey() rc %d\n", rc)); goto exit; } } /* Is this the requested pubkey? */ if (pubid && *pubid) { size_t ns = strlen(pubid); const char * s; char * t; size_t i; /* At least 8 hex digits please. */ for (i = 0, s = pubid; *s && isxdigit(*s); s++, i++) {}; if (!(*s == '\0' && i > 8 && (i%2) == 0)) { SPEW((stderr, "==> invalid pubid: %s\n", pubid)); goto exit; } /* Truncate to key id size. */ s = pubid; if (ns > 16) { s += (ns - 16); ns = 16; } ns >>= 1; t = (char *) memset(alloca(ns), 0, ns); for (i = 0; i < ns; i++) t[i] = (char)((nibble(s[2*i]) << 4) | nibble(s[2*i+1])); /* Compare the pubkey id. */ s = (const char *)pubp->signid; xx = memcmp(t, s + (8 - ns), ns); #ifdef DYING /* XXX HACK: V4 RSA key id's are wonky atm. */ if (pubp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA) xx = 0; #endif if (xx) { SPEW((stderr, "==> mismatched: pubkey id (%08x %08x) != %s\n", pgpGrab(pubp->signid, 4), pgpGrab(pubp->signid+4, 4), pubid)); goto exit; } }
static rpmRC rpmsinfoInit(rpmtd td, const char *origin, struct rpmsinfo_s *sinfo, char **msg) { rpmRC rc = RPMRC_FAIL; const void *data = NULL; const struct vfytag_s *tinfo; const struct vfyinfo_s *vinfo; rpm_count_t dlen = 0; int ix; if ((ix = sinfoLookup(td->tag)) == -1) { /* anything unknown just falls through for now */ rc = RPMRC_OK; goto exit; } vinfo = &rpmvfyitems[ix]; tinfo = &rpmvfytags[ix]; assert(tinfo->tag == vinfo->tag); *sinfo = rpmvfyitems[ix].vi; /* struct assignment */ if (tinfo->tagtype && tinfo->tagtype != td->type) { rasprintf(msg, _("%s tag %u: invalid type %u"), origin, td->tag, td->type); goto exit; } if (tinfo->tagcount && tinfo->tagcount != td->count) { rasprintf(msg, _("%s: tag %u: invalid count %u"), origin, td->tag, td->count); goto exit; } switch (td->type) { case RPM_STRING_TYPE: case RPM_STRING_ARRAY_TYPE: data = rpmtdGetString(td); if (data) dlen = strlen(data); break; case RPM_BIN_TYPE: data = td->data; dlen = td->count; break; } /* MD5 has data length of 16, everything else is (much) larger */ if (sinfo->hashalgo && (data == NULL || dlen < 16)) { rasprintf(msg, _("%s tag %u: invalid data %p (%u)"), origin, td->tag, data, dlen); goto exit; } if (td->type == RPM_STRING_TYPE && td->size == 0) td->size = dlen + 1; if (tinfo->tagsize && (td->flags & RPMTD_IMMUTABLE) && tinfo->tagsize != td->size) { rasprintf(msg, _("%s tag %u: invalid size %u"), origin, td->tag, td->size); goto exit; } if (sinfo->type == RPMSIG_SIGNATURE_TYPE) { if (pgpPrtParams(data, dlen, PGPTAG_SIGNATURE, &sinfo->sig)) { rasprintf(msg, _("%s tag %u: invalid OpenPGP signature"), origin, td->tag); goto exit; } sinfo->hashalgo = pgpDigParamsAlgo(sinfo->sig, PGPVAL_HASHALGO); sinfo->keyid = pgpGrab(sinfo->sig->signid+4, 4); } else if (sinfo->type == RPMSIG_DIGEST_TYPE) { if (td->type == RPM_BIN_TYPE) { sinfo->dig = pgpHexStr(data, dlen); } else { if (!validHex(data, dlen)) { rasprintf(msg, _("%s: tag %u: invalid hex"), origin, td->tag); goto exit; } sinfo->dig = xstrdup(data); } } if (sinfo->hashalgo) sinfo->id = (td->tag << 16) | rpmtdGetIndex(td); rc = RPMRC_OK; exit: return rc; }
/* Build pubkey header. */ static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp) { Header h = headerNew(); const char * afmt = "%{pubkeys:armor}"; const char * group = "Public Keys"; const char * license = "pubkey"; const char * buildhost = "localhost"; const char * userid; rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL); uint32_t zero = 0; uint32_t keytime = 0; pgpDig dig = NULL; pgpDigParams pubp = NULL; char * d = NULL; char * enc = NULL; char * n = NULL; char * u = NULL; char * v = NULL; char * r = NULL; char * evr = NULL; int rc = -1; if ((enc = rpmPubkeyBase64(key)) == NULL) goto exit; if ((dig = rpmPubkeyDig(key)) == NULL) goto exit; if ((pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY)) == NULL) goto exit; /* Build header elements. */ v = pgpHexStr(pubp->signid, sizeof(pubp->signid)); r = pgpHexStr(pubp->time, sizeof(pubp->time)); userid = pubp->userid ? pubp->userid : "none"; keytime = pgpGrab(pubp->time, sizeof(pubp->time)); rasprintf(&n, "gpg(%s)", v+8); rasprintf(&u, "gpg(%s)", userid); rasprintf(&evr, "%d:%s-%s", pubp->version, v, r); headerPutString(h, RPMTAG_PUBKEYS, enc); if ((d = headerFormat(h, afmt, NULL)) == NULL) goto exit; headerPutString(h, RPMTAG_NAME, "gpg-pubkey"); headerPutString(h, RPMTAG_VERSION, v+8); headerPutString(h, RPMTAG_RELEASE, r); headerPutString(h, RPMTAG_DESCRIPTION, d); headerPutString(h, RPMTAG_GROUP, group); headerPutString(h, RPMTAG_LICENSE, license); headerPutString(h, RPMTAG_SUMMARY, u); headerPutString(h, RPMTAG_PACKAGER, userid); headerPutUint32(h, RPMTAG_SIZE, &zero, 1); headerPutString(h, RPMTAG_PROVIDENAME, u); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_PROVIDENAME, n); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION); headerPutString(h, RPMTAG_BUILDHOST, buildhost); headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1); headerPutString(h, RPMTAG_SOURCERPM, "(none)"); /* Reload the lot to immutable region and stomp sha1 digest on it */ h = headerReload(h, RPMTAG_HEADERIMMUTABLE); if (h != NULL) { char *sha1 = NULL; unsigned int blen = 0; const void *blob = headerExport(h, &blen); /* XXX FIXME: bah, this code is repeated in way too many places */ DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, blob, blen); rpmDigestFinal(ctx, (void **)&sha1, NULL, 1); if (sha1) { headerPutString(h, RPMTAG_SHA1HEADER, sha1); *hdrp = headerLink(h); rc = 0; } free(sha1); } exit: headerFree(h); pgpFreeDig(dig); free(n); free(u); free(v); free(r); free(evr); free(enc); free(d); return rc; }