From c30d127e8780dc678168ee121b9f2eeb1a8aaafa Mon Sep 17 00:00:00 2001 From: wangbiao Date: Thu, 16 Nov 2023 18:17:42 +0900 Subject: Upgrade version to 4.14 Change-Id: I21bf1a3a7c25cbec43022202cf2e5865b603a309 Signed-off-by: wangbiao --- rpmio/rpmpgp.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 302 insertions(+), 68 deletions(-) (limited to 'rpmio/rpmpgp.c') diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c index e70cf706b..15cce2275 100644 --- a/rpmio/rpmpgp.c +++ b/rpmio/rpmpgp.c @@ -248,6 +248,19 @@ static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val) fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val); } +static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen) +{ + if (!_print) return; + if (pre && *pre) + fprintf(stderr, "%s", pre); + if (plen == 4) { + time_t t = pgpGrab(p, plen); + fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t); + } else { + pgpPrtHex("", p+1, plen-1); + } +} + /** \ingroup rpmpgp * Return hex formatted representation of a multiprecision integer. * @param p bytes @@ -384,15 +397,24 @@ unsigned int pgpCRC(const uint8_t *octets, size_t len) return crc & 0xffffff; } +static int pgpVersion(const uint8_t *h, size_t hlen, uint8_t *version) +{ + if (hlen < 1) + return -1; + + *version = h[0]; + return 0; +} + static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype, pgpDigParams _digp) { const uint8_t *p = h; - size_t plen, i; + size_t plen = 0, i; while (hlen > 0) { i = pgpLen(p, hlen, &plen); - if (i == 0 || i + plen > hlen) + if (i == 0 || plen < 1 || i + plen > hlen) break; p += i; @@ -423,23 +445,22 @@ static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype, if (!(_digp->saved & PGPDIG_SAVED_TIME) && (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE)) { + if (plen-1 != sizeof(_digp->time)) + break; _digp->saved |= PGPDIG_SAVED_TIME; - memcpy(_digp->time, p+1, sizeof(_digp->time)); + _digp->time = pgpGrab(p+1, sizeof(_digp->time)); } case PGPSUBTYPE_SIG_EXPIRE_TIME: case PGPSUBTYPE_KEY_EXPIRE_TIME: - if ((plen - 1) == 4) { - time_t t = pgpGrab(p+1, plen-1); - if (_print) - fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t); - } else - pgpPrtHex("", p+1, plen-1); + pgpPrtTime(" ", p+1, plen-1); break; case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */ if (!(_digp->saved & PGPDIG_SAVED_ID) && (sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE)) { + if (plen-1 != sizeof(_digp->signid)) + break; _digp->saved |= PGPDIG_SAVED_ID; memcpy(_digp->signid, p+1, sizeof(_digp->signid)); } @@ -499,11 +520,15 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, int i; pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo); - for (i = 0; p < pend && i < sigalg->mpis; i++, p += pgpMpiLen(p)) { + for (i = 0; i < sigalg->mpis && p + 2 <= pend; i++) { + int mpil = pgpMpiLen(p); + if (p + mpil > pend) + break; if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) { - if (sigalg->setmpi(sigalg, i, p, pend)) + if (sigalg->setmpi(sigalg, i, p)) break; } + p += mpil; } /* Does the size and number of MPI's match our expectations? */ @@ -519,18 +544,33 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, return rc; } +static int pgpGet(const uint8_t *s, size_t nbytes, const uint8_t *send, + unsigned int *valp) +{ + int rc = -1; + + if (s + nbytes <= send) { + *valp = pgpGrab(s, nbytes); + rc = 0; + } + + return rc; +} + static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, pgpDigParams _digp) { - uint8_t version = h[0]; + uint8_t version = 0; uint8_t * p; - size_t plen; - int rc; + unsigned int plen; + int rc = 1; + + if (pgpVersion(h, hlen, &version)) + return rc; switch (version) { case 3: { pgpPktSigV3 v = (pgpPktSigV3)h; - time_t t; if (hlen <= sizeof(*v) || v->hashlen != 5) return 1; @@ -540,9 +580,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, pgpPrtVal(" ", pgpHashTbl, v->hash_algo); pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype); pgpPrtNL(); - t = pgpGrab(v->time, sizeof(v->time)); - if (_print) - fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t); + pgpPrtTime(" ", v->time, sizeof(v->time)); pgpPrtNL(); pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid)); plen = pgpGrab(v->signhash16, sizeof(v->signhash16)); @@ -554,7 +592,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, _digp->hashlen = v->hashlen; _digp->sigtype = v->sigtype; _digp->hash = memcpy(xmalloc(v->hashlen), &v->sigtype, v->hashlen); - memcpy(_digp->time, v->time, sizeof(_digp->time)); + _digp->time = pgpGrab(v->time, sizeof(v->time)); memcpy(_digp->signid, v->signid, sizeof(_digp->signid)); _digp->pubkey_algo = v->pubkey_algo; _digp->hash_algo = v->hash_algo; @@ -577,7 +615,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, pgpPrtNL(); p = &v->hashlen[0]; - plen = pgpGrab(v->hashlen, sizeof(v->hashlen)); + if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen)) + return 1; p += sizeof(v->hashlen); if ((p + plen) > (h + hlen)) @@ -591,7 +630,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, return 1; p += plen; - plen = pgpGrab(p,2); + if (pgpGet(p, 2, h + hlen, &plen)) + return 1; p += 2; if ((p + plen) > (h + hlen)) @@ -601,7 +641,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, return 1; p += plen; - plen = pgpGrab(p,2); + if (pgpGet(p, 2, h + hlen, &plen)) + return 1; pgpPrtHex(" signhash16", p, 2); pgpPrtNL(); @@ -620,6 +661,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); } break; default: + rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version); rc = 1; break; } @@ -650,9 +692,13 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo, int i; pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo); - for (i = 0; p < pend && i < keyalg->mpis; i++, p += pgpMpiLen(p)) { - if (keyalg->setmpi(keyalg, i, p, pend)) + for (i = 0; i < keyalg->mpis && p + 2 <= pend; i++) { + int mpil = pgpMpiLen(p); + if (p + mpil > pend) + break; + if (keyalg->setmpi(keyalg, i, p)) break; + p += mpil; } /* Does the size and number of MPI's match our expectations? */ @@ -660,7 +706,9 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo, rc = 0; /* We can't handle more than one key at a time */ - if (rc == 0 && keyp->alg == NULL && keyp->tag == PGPTAG_PUBLIC_KEY) + if (rc == 0 && keyp->alg == NULL && (keyp->tag == PGPTAG_PUBLIC_KEY || + keyp->tag == PGPTAG_PUBLIC_SUBKEY)) + keyp->alg = keyalg; else pgpDigAlgFree(keyalg); @@ -671,11 +719,13 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo, static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, pgpDigParams _digp) { - uint8_t version = *h; + uint8_t version = 0; const uint8_t * p = NULL; - time_t t; int rc = 1; + if (pgpVersion(h, hlen, &version)) + return rc; + /* We only permit V4 keys, V3 keys are long long since deprecated */ switch (version) { case 4: @@ -684,14 +734,13 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, if (hlen > sizeof(*v)) { pgpPrtVal("V4 ", pgpTagTbl, tag); pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo); - t = pgpGrab(v->time, sizeof(v->time)); - if (_print) - fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t); + pgpPrtTime(" ", v->time, sizeof(v->time)); pgpPrtNL(); - if (_digp->tag == tag) { + /* If _digp->hash is not NULL then signature is already loaded */ + if (_digp->hash == NULL) { _digp->version = v->version; - memcpy(_digp->time, v->time, sizeof(_digp->time)); + _digp->time = pgpGrab(v->time, sizeof(v->time)); _digp->pubkey_algo = v->pubkey_algo; } @@ -699,6 +748,8 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp); } } break; + default: + rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), h[0]); } return rc; } @@ -716,14 +767,19 @@ static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen, return 0; } -static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid) +int pgpPubkeyFingerprint(const uint8_t *h, size_t hlen, + uint8_t **fp, size_t *fplen) { int rc = -1; /* assume failure */ const uint8_t *se; const uint8_t *pend = h + hlen; + uint8_t version = 0; + + if (pgpVersion(h, hlen, &version)) + return rc; /* We only permit V4 keys, V3 keys are long long since deprecated */ - switch (h[0]) { + switch (version) { case 4: { pgpPktKeyV4 v = (pgpPktKeyV4) (h); int mpis = -1; @@ -747,8 +803,8 @@ static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid) /* Does the size and number of MPI's match our expectations? */ if (se == pend && mpis == 0) { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); - uint8_t * d = NULL; - size_t dlen; + uint8_t *d = NULL; + size_t dlen = 0; int i = se - h; uint8_t in[3] = { 0x99, (i >> 8), i }; @@ -756,42 +812,42 @@ static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid) (void) rpmDigestUpdate(ctx, h, i); (void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0); - if (d) { - memcpy(keyid, (d + (dlen-8)), 8); - free(d); + if (dlen == 20) { rc = 0; + *fp = d; + *fplen = dlen; + } else { + free(d); } } } break; + default: + rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version); + } + return rc; +} + +static int getKeyID(const uint8_t *h, size_t hlen, pgpKeyID_t keyid) +{ + uint8_t *fp = NULL; + size_t fplen = 0; + int rc = pgpPubkeyFingerprint(h, hlen, &fp, &fplen); + if (fp && fplen > 8) { + memcpy(keyid, (fp + (fplen-8)), 8); + free(fp); } return rc; } -int pgpPubkeyFingerprint(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid) +int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid) { struct pgpPkt p; if (decodePkt(pkt, pktlen, &p)) return -1; - return getFingerprint(p.body, p.blen, keyid); -} - -int pgpExtractPubkeyFingerprint(const char * b64pkt, pgpKeyID_t keyid) -{ - uint8_t * pkt; - size_t pktlen; - int rc = -1; /* assume failure */ - - if (rpmBase64Decode(b64pkt, (void **)&pkt, &pktlen) == 0) { - if (pgpPubkeyFingerprint(pkt, pktlen, keyid) == 0) { - /* if there ever was a bizarre return code for success... */ - rc = 8; - } - free(pkt); - } - return rc; + return getKeyID(p.body, p.blen, keyid); } static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp) @@ -803,8 +859,8 @@ static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp) rc = pgpPrtSig(p->tag, p->body, p->blen, _digp); break; case PGPTAG_PUBLIC_KEY: - /* Get the public key fingerprint. */ - if (!getFingerprint(p->body, p->blen, _digp->signid)) + /* Get the public key Key ID. */ + if (!getKeyID(p->body, p->blen, _digp->signid)) _digp->saved |= PGPDIG_SAVED_ID; else memset(_digp->signid, 0, sizeof(_digp->signid)); @@ -813,12 +869,14 @@ static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp) case PGPTAG_USER_ID: rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp); break; + case PGPTAG_RESERVED: + rc = -1; + break; case PGPTAG_COMMENT: case PGPTAG_COMMENT_OLD: case PGPTAG_PUBLIC_SUBKEY: case PGPTAG_SECRET_KEY: case PGPTAG_SECRET_SUBKEY: - case PGPTAG_RESERVED: case PGPTAG_PUBLIC_SESSION_KEY: case PGPTAG_SYMMETRIC_SESSION_KEY: case PGPTAG_COMPRESSED_DATA: @@ -903,6 +961,8 @@ int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2) int rc = 1; /* assume different, eg if either is NULL */ if (p1 && p2) { /* XXX Should we compare something else too? */ + if (p1->tag != p2->tag) + goto exit; if (p1->hash_algo != p2->hash_algo) goto exit; if (p1->pubkey_algo != p2->pubkey_algo) @@ -913,6 +973,8 @@ int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2) goto exit; if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0) goto exit; + if (p1->userid && p2->userid && strcmp(p1->userid, p2->userid) != 0) + goto exit; /* Parameters match ... at least for our purposes */ rc = 0; @@ -937,36 +999,128 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype) return algo; } +static pgpDigParams pgpDigParamsNew(uint8_t tag) +{ + pgpDigParams digp = xcalloc(1, sizeof(*digp)); + digp->tag = tag; + return digp; +} + +static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag) +{ + int rc = -1; + if (pkt->tag == exptag) { + uint8_t head[] = { + 0x99, + (pkt->blen >> 8), + (pkt->blen ), + }; + + rpmDigestUpdate(hash, head, 3); + rpmDigestUpdate(hash, pkt->body, pkt->blen); + rc = 0; + } + return rc; +} + +static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig, + const struct pgpPkt *all, int i) +{ + int rc = -1; + DIGEST_CTX hash = NULL; + + switch (selfsig->sigtype) { + case PGPSIGTYPE_SUBKEY_BINDING: + hash = rpmDigestInit(selfsig->hash_algo, 0); + if (hash) { + rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY); + if (!rc) + rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY); + } + break; + default: + /* ignore types we can't handle */ + rc = 0; + break; + } + + if (hash && rc == 0) + rc = pgpVerifySignature(key, selfsig, hash); + + rpmDigestFinal(hash, NULL, NULL, 0); + + return rc; +} + int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, pgpDigParams * ret) { const uint8_t *p = pkts; const uint8_t *pend = pkts + pktlen; pgpDigParams digp = NULL; - struct pgpPkt pkt; + pgpDigParams selfsig = NULL; + int i = 0; + int alloced = 16; /* plenty for normal cases */ + struct pgpPkt *all = xmalloc(alloced * sizeof(*all)); int rc = -1; /* assume failure */ + int expect = 0; + int prevtag = 0; while (p < pend) { - if (decodePkt(p, (pend - p), &pkt)) + struct pgpPkt *pkt = &all[i]; + if (decodePkt(p, (pend - p), pkt)) break; if (digp == NULL) { - if (pkttype && pkt.tag != pkttype) { + if (pkttype && pkt->tag != pkttype) { break; } else { - digp = xcalloc(1, sizeof(*digp)); - digp->tag = pkt.tag; + digp = pgpDigParamsNew(pkt->tag); } } - if (pgpPrtPkt(&pkt, digp)) + if (expect) { + if (pkt->tag != expect) + break; + selfsig = pgpDigParamsNew(pkt->tag); + } + + if (pgpPrtPkt(pkt, selfsig ? selfsig : digp)) break; - p += (pkt.body - pkt.head) + pkt.blen; + if (selfsig) { + /* subkeys must be followed by binding signature */ + if (prevtag == PGPTAG_PUBLIC_SUBKEY) { + if (selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING) + break; + } + + int xx = pgpVerifySelf(digp, selfsig, all, i); + + selfsig = pgpDigParamsFree(selfsig); + if (xx) + break; + expect = 0; + } + + if (pkt->tag == PGPTAG_PUBLIC_SUBKEY) + expect = PGPTAG_SIGNATURE; + prevtag = pkt->tag; + + i++; + p += (pkt->body - pkt->head) + pkt->blen; + if (pkttype == PGPTAG_SIGNATURE) + break; + + if (alloced <= i) { + alloced *= 2; + all = xrealloc(all, alloced * sizeof(*all)); + } } - rc = (digp && (p == pend)) ? 0 : -1; + rc = (digp && (p == pend) && expect == 0) ? 0 : -1; + free(all); if (ret && rc == 0) { *ret = digp; } else { @@ -975,6 +1129,63 @@ int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, return rc; } +int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen, + pgpDigParams mainkey, pgpDigParams **subkeys, + int *subkeysCount) +{ + const uint8_t *p = pkts; + const uint8_t *pend = pkts + pktlen; + pgpDigParams *digps = NULL; + int count = 0; + int alloced = 10; + struct pgpPkt pkt; + int rc, i; + + digps = xmalloc(alloced * sizeof(*digps)); + + while (p < pend) { + if (decodePkt(p, (pend - p), &pkt)) + break; + + p += (pkt.body - pkt.head) + pkt.blen; + + if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) { + if (count == alloced) { + alloced <<= 1; + digps = xrealloc(digps, alloced * sizeof(*digps)); + } + + digps[count] = xcalloc(1, sizeof(**digps)); + digps[count]->tag = PGPTAG_PUBLIC_SUBKEY; + /* Copy UID from main key to subkey */ + digps[count]->userid = xstrdup(mainkey->userid); + + if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) { + pgpDigParamsFree(digps[count]); + continue; + } + + if (pgpPrtKey(pkt.tag, pkt.body, pkt.blen, digps[count])) { + pgpDigParamsFree(digps[count]); + continue; + } + count++; + } + } + rc = (p == pend) ? 0 : -1; + + if (rc == 0) { + *subkeys = xrealloc(digps, count * sizeof(*digps)); + *subkeysCount = count; + } else { + for (i = 0; i < count; i++) + pgpDigParamsFree(digps[i]); + free(digps); + } + + return rc; +} + int pgpPrtPkts(const uint8_t * pkts, size_t pktlen, pgpDig dig, int printing) { int rc; @@ -1230,6 +1441,29 @@ pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen) return ec; } +int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen) +{ + const uint8_t *p = pkts; + const uint8_t *pend = pkts + pktslen; + struct pgpPkt pkt; + + while (p < pend) { + if (decodePkt(p, (pend - p), &pkt)) + return -1; + + if (pkt.tag == PGPTAG_PUBLIC_KEY && pkts != p) { + *certlen = p - pkts; + return 0; + } + + p += (pkt.body - pkt.head) + pkt.blen; + } + + *certlen = pktslen; + + return 0; +} + char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns) { char *buf = NULL, *val = NULL; -- cgit v1.2.3