3 #include <rpm/rpmkeyring.h>
5 #include "rpmio/digest.h"
10 struct rpmsinfo_s *sigs;
24 static const struct vfytag_s rpmvfytags[] = {
25 { RPMSIGTAG_SIZE, RPM_BIN_TYPE, 0, 0, },
26 { RPMSIGTAG_PGP, RPM_BIN_TYPE, 0, 0, },
27 { RPMSIGTAG_MD5, RPM_BIN_TYPE, 0, 16, },
28 { RPMSIGTAG_GPG, RPM_BIN_TYPE, 0, 0, },
29 { RPMSIGTAG_PGP5, RPM_BIN_TYPE, 0, 0, },
30 { RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE, 1, 4, },
31 { RPMSIGTAG_RESERVEDSPACE, RPM_BIN_TYPE, 0, 0, },
32 { RPMTAG_DSAHEADER, RPM_BIN_TYPE, 0, 0, },
33 { RPMTAG_RSAHEADER, RPM_BIN_TYPE, 0, 0, },
34 { RPMTAG_SHA1HEADER, RPM_STRING_TYPE, 1, 41, },
35 { RPMSIGTAG_LONGSIZE, RPM_INT64_TYPE, 1, 8, },
36 { RPMSIGTAG_LONGARCHIVESIZE, RPM_INT64_TYPE, 1, 8, },
37 { RPMTAG_SHA256HEADER, RPM_STRING_TYPE, 1, 65, },
38 { RPMTAG_PAYLOADDIGEST, RPM_STRING_ARRAY_TYPE, 0, 0, },
47 static const struct vfyinfo_s rpmvfyitems[] = {
49 { RPMSIG_OTHER_TYPE, 0,
50 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
52 { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSA,
53 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
55 { RPMSIG_DIGEST_TYPE, RPMVSF_NOMD5,
56 (RPMSIG_HEADER|RPMSIG_PAYLOAD), PGPHASHALGO_MD5, }, },
58 { RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSA,
59 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
61 { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSA,
62 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
63 { RPMSIGTAG_PAYLOADSIZE,
64 { RPMSIG_OTHER_TYPE, 0,
65 (RPMSIG_PAYLOAD), 0, }, },
66 { RPMSIGTAG_RESERVEDSPACE,
67 { RPMSIG_OTHER_TYPE, 0,
70 { RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSAHEADER,
71 (RPMSIG_HEADER), 0, }, },
73 { RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSAHEADER,
74 (RPMSIG_HEADER), 0, }, },
76 { RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA1HEADER,
77 (RPMSIG_HEADER), PGPHASHALGO_SHA1, }, },
79 { RPMSIG_OTHER_TYPE, 0,
80 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
81 { RPMSIGTAG_LONGARCHIVESIZE,
82 { RPMSIG_OTHER_TYPE, 0,
83 (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, }, },
84 { RPMTAG_SHA256HEADER,
85 { RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA256HEADER,
86 (RPMSIG_HEADER), PGPHASHALGO_SHA256, }, },
87 { RPMTAG_PAYLOADDIGEST,
88 { RPMSIG_DIGEST_TYPE, RPMVSF_NOPAYLOAD,
89 (RPMSIG_PAYLOAD), PGPHASHALGO_SHA256, }, },
93 static const char *rangeName(int range);
94 static const char * rpmSigString(rpmRC res);
95 static rpmRC rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
96 DIGEST_CTX ctx, char ** result);
98 static int sinfoLookup(rpmTagVal tag)
100 const struct vfyinfo_s *start = &rpmvfyitems[0];
102 for (const struct vfyinfo_s *si = start; si->tag; si++) {
103 if (tag == si->tag) {
111 static int validHex(const char *str, size_t slen)
113 int valid = 0; /* Assume invalid */
116 /* Our hex data is always even sized and at least sha-1 long */
117 if (slen % 2 || slen < 40)
120 for (b = str ; *b != '\0'; b++) {
121 if (strchr("0123456789abcdefABCDEF", *b) == NULL)
130 static rpmRC rpmsinfoInit(rpmtd td, const char *origin,
131 struct rpmsinfo_s *sinfo, char **msg)
133 rpmRC rc = RPMRC_FAIL;
134 const void *data = NULL;
135 const struct vfytag_s *tinfo;
136 const struct vfyinfo_s *vinfo;
137 rpm_count_t dlen = 0;
140 if ((ix = sinfoLookup(td->tag)) == -1) {
141 /* anything unknown just falls through for now */
145 vinfo = &rpmvfyitems[ix];
146 tinfo = &rpmvfytags[ix];
147 assert(tinfo->tag == vinfo->tag);
149 *sinfo = rpmvfyitems[ix].vi; /* struct assignment */
151 if (tinfo->tagtype && tinfo->tagtype != td->type) {
152 rasprintf(msg, _("%s tag %u: invalid type %u"),
153 origin, td->tag, td->type);
157 if (tinfo->tagcount && tinfo->tagcount != td->count) {
158 rasprintf(msg, _("%s: tag %u: invalid count %u"),
159 origin, td->tag, td->count);
164 case RPM_STRING_TYPE:
165 case RPM_STRING_ARRAY_TYPE:
166 data = rpmtdGetString(td);
176 /* MD5 has data length of 16, everything else is (much) larger */
177 if (sinfo->hashalgo && (data == NULL || dlen < 16)) {
178 rasprintf(msg, _("%s tag %u: invalid data %p (%u)"),
179 origin, td->tag, data, dlen);
183 if (td->type == RPM_STRING_TYPE && td->size == 0)
186 if (tinfo->tagsize && (td->flags & RPMTD_IMMUTABLE) &&
187 tinfo->tagsize != td->size) {
188 rasprintf(msg, _("%s tag %u: invalid size %u"),
189 origin, td->tag, td->size);
193 if (sinfo->type == RPMSIG_SIGNATURE_TYPE) {
194 if (pgpPrtParams(data, dlen, PGPTAG_SIGNATURE, &sinfo->sig)) {
195 rasprintf(msg, _("%s tag %u: invalid OpenPGP signature"),
199 sinfo->hashalgo = pgpDigParamsAlgo(sinfo->sig, PGPVAL_HASHALGO);
200 sinfo->keyid = pgpGrab(sinfo->sig->signid+4, 4);
201 } else if (sinfo->type == RPMSIG_DIGEST_TYPE) {
202 if (td->type == RPM_BIN_TYPE) {
203 sinfo->dig = pgpHexStr(data, dlen);
205 if (!validHex(data, dlen)) {
206 rasprintf(msg, _("%s: tag %u: invalid hex"), origin, td->tag);
209 sinfo->dig = xstrdup(data);
214 sinfo->id = (td->tag << 16) | rpmtdGetIndex(td);
222 static void rpmsinfoFini(struct rpmsinfo_s *sinfo)
225 if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
226 pgpDigParamsFree(sinfo->sig);
227 else if (sinfo->type == RPMSIG_DIGEST_TYPE)
230 memset(sinfo, 0, sizeof(*sinfo));
234 static int rpmsinfoDisabled(const struct rpmsinfo_s *sinfo, rpmVSFlags vsflags)
236 if (!(sinfo->type & RPMSIG_VERIFIABLE_TYPE))
238 if (vsflags & sinfo->disabler)
240 if ((vsflags & RPMVSF_NEEDPAYLOAD) && (sinfo->range & RPMSIG_PAYLOAD))
245 static void rpmvsReserve(struct rpmvs_s *vs, int n)
247 if (vs->nsigs + n >= vs->nalloced) {
248 vs->nalloced = (vs->nsigs * 2) + n;
249 vs->rcs = xrealloc(vs->rcs, vs->nalloced * sizeof(*vs->rcs));
250 vs->results = xrealloc(vs->results, vs->nalloced * sizeof(*vs->results));
251 vs->sigs = xrealloc(vs->sigs, vs->nalloced * sizeof(*vs->sigs));
255 const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo)
257 if (sinfo->descr == NULL) {
259 switch (sinfo->type) {
260 case RPMSIG_DIGEST_TYPE:
261 rasprintf(&sinfo->descr, _("%s%s %s"),
262 rangeName(sinfo->range),
263 pgpValString(PGPVAL_HASHALGO, sinfo->hashalgo),
266 case RPMSIG_SIGNATURE_TYPE:
267 t = sinfo->sig ? pgpIdentItem(sinfo->sig) : NULL;
268 rasprintf(&sinfo->descr, _("%s%s"),
269 rangeName(sinfo->range), t ? t : _("signature"));
277 char *rpmsinfoMsg(struct rpmsinfo_s *sinfo, rpmRC rc, const char *emsg)
281 rasprintf(&msg, "%s: %s (%s)",
282 rpmsinfoDescr(sinfo), rpmSigString(rc), emsg);
284 rasprintf(&msg, "%s: %s", rpmsinfoDescr(sinfo), rpmSigString(rc));
289 void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob, rpmTagVal tag)
292 rpmRC rc = hdrblobGet(blob, tag, &td);
294 if (rc == RPMRC_OK) {
295 const char *o = (blob->il > blob->ril) ? _("header") : _("package");
298 rpmvsReserve(sis, rpmtdCount(&td));
300 while ((ix = rpmtdNext(&td)) >= 0) {
301 sis->results[sis->nsigs] = NULL;
302 sis->rcs[sis->nsigs] = rpmsinfoInit(&td, o,
303 &sis->sigs[sis->nsigs],
304 &sis->results[sis->nsigs]);
311 struct rpmvs_s *rpmvsCreate(hdrblob blob, rpmVSFlags vsflags)
313 struct rpmvs_s *sis = xcalloc(1, sizeof(*sis));
315 rpmvsReserve(sis, 2); /* XXX bump this up later */
317 for (const struct vfyinfo_s *si = &rpmvfyitems[0]; si->tag; si++) {
318 if (rpmsinfoDisabled(&si->vi, vsflags))
320 rpmvsAppend(sis, blob, si->tag);
325 struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis)
329 for (int i = 0; i < sis->nsigs; i++) {
330 rpmsinfoFini(&sis->sigs[i]);
331 free(sis->results[i]);
340 void rpmvsInitDigests(struct rpmvs_s *sis, int range, rpmDigestBundle bundle)
342 for (int i = 0; i < sis->nsigs; i++) {
343 struct rpmsinfo_s *sinfo = &sis->sigs[i];
344 if (sinfo->range & range) {
345 if (sis->rcs[i] == RPMRC_OK)
346 rpmDigestBundleAddID(bundle, sinfo->hashalgo, sinfo->id, 0);
351 int rpmvsVerifyItems(rpmPlugins plugins, struct rpmvs_s *sis, int range, rpmDigestBundle bundle,
352 rpmKeyring keyring, rpmsinfoCb cb, void *cbdata)
356 for (int i = 0; i < sis->nsigs; i++) {
357 struct rpmsinfo_s *sinfo = &sis->sigs[i];
359 if (sinfo->range == range) {
360 if (sis->rcs[i] == RPMRC_OK) {
361 DIGEST_CTX ctx = rpmDigestBundleDupCtx(bundle, sinfo->id);
362 sis->results[i] = _free(sis->results[i]);
363 sis->rcs[i] = rpmVerifySignature(keyring, sinfo, ctx, &sis->results[i]);
364 /* Run verify hook for all plugins */
365 sis->rcs[i] = rpmpluginsCallVerify(plugins, keyring, sinfo->id, sinfo->sig, ctx, sis->rcs[i]);
366 rpmDigestFinal(ctx, NULL, NULL, 0);
367 rpmDigestBundleFinal(bundle, sinfo->id, NULL, NULL, 0);
371 sis->rcs[i] = cb(sinfo, sis->rcs[i], sis->results[i], cbdata);
373 if (sis->rcs[i] != RPMRC_OK)
381 static const char * rpmSigString(rpmRC res)
385 case RPMRC_OK: str = "OK"; break;
386 case RPMRC_FAIL: str = "BAD"; break;
387 case RPMRC_NOKEY: str = "NOKEY"; break;
388 case RPMRC_NOTTRUSTED: str = "NOTTRUSTED"; break;
390 case RPMRC_NOTFOUND: str = "UNKNOWN"; break;
395 static const char *rangeName(int range)
398 case RPMSIG_HEADER: return _("Header ");
399 case RPMSIG_PAYLOAD: return _("Payload ");
401 /* trad. output for (RPMSIG_HEADER|RPMSIG_PAYLOAD) range is "" */
405 static rpmRC verifyDigest(struct rpmsinfo_s *sinfo, DIGEST_CTX digctx,
408 rpmRC res = RPMRC_FAIL; /* assume failure */
411 DIGEST_CTX ctx = rpmDigestDup(digctx);
413 if (rpmDigestFinal(ctx, (void **)&dig, &diglen, 1) || diglen == 0)
416 if (strcasecmp(sinfo->dig, dig) == 0) {
419 rasprintf(msg, "Expected %s != %s", sinfo->dig, dig);
428 * Verify DSA/RSA signature.
429 * @param keyring pubkey keyring
430 * @param sinfo OpenPGP signature parameters
431 * @param hashctx digest context
432 * @retval msg verbose success/failure text
433 * @return RPMRC_OK on success
436 verifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
437 DIGEST_CTX hashctx, char **msg)
439 rpmRC res = rpmKeyringVerifySig(keyring, sinfo->sig, hashctx);
445 rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo,
446 DIGEST_CTX ctx, char ** result)
448 rpmRC res = RPMRC_FAIL;
450 if (sinfo->type == RPMSIG_DIGEST_TYPE)
451 res = verifyDigest(sinfo, ctx, result);
452 else if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
453 res = verifySignature(keyring, sinfo, ctx, result);