2 * \file lib/rpmchecksig.c
3 * Verify the signature of a package.
8 #include <rpm/rpmpgp.h>
9 #include "rpmio/rpmio_internal.h" /* for fd*Digest() */
10 #include <rpm/rpmcli.h>
12 #include <rpm/rpmdb.h>
14 #include <rpm/rpmts.h>
16 #include <rpm/rpmlog.h>
17 #include "lib/rpmlead.h"
18 #include "lib/signature.h"
19 #include <rpm/rpmfileutil.h> /* rpmMkTempFile() */
26 static int manageFile(FD_t *fdp,
33 if (fdp == NULL) /* programmer error */
36 /* close and reset *fdp to NULL */
37 if (*fdp && (fnp == NULL || *fnp == NULL)) {
43 /* open a file and set *fdp */
44 if (*fdp == NULL && fnp != NULL && *fnp != NULL) {
45 fd = Fopen(*fnp, ((flags & O_WRONLY) ? "w.ufdio" : "r.ufdio"));
46 if (fd == NULL || Ferror(fd)) {
47 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), *fnp,
55 /* open a temp file */
56 if (*fdp == NULL && (fnp == NULL || *fnp == NULL)) {
58 if (rpmMkTempFile(NULL, (fnp ? &fn : NULL), &fd)) {
59 rpmlog(RPMLOG_ERR, _("rpmMkTempFile failed\n"));
64 *fdp = fdLink(fd, RPMDBG_M("manageFile return"));
65 fd = fdFree(fd, RPMDBG_M("manageFile return"));
70 if (*fdp != NULL && fnp != NULL && *fnp != NULL)
73 /* XXX never reached */
78 * Copy header+payload, calculating digest(s) on the fly.
80 static int copyFile(FD_t *sfdp, const char **sfnp,
81 FD_t *tfdp, const char **tfnp)
83 unsigned char buf[BUFSIZ];
87 if (manageFile(sfdp, sfnp, O_RDONLY, 0))
89 if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC, 0))
92 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
94 if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
95 rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), *tfnp,
101 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), *sfnp, Fstrerror(*sfdp));
104 if (Fflush(*tfdp) != 0) {
105 rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), *tfnp,
112 if (*sfdp) (void) manageFile(sfdp, NULL, 0, rc);
113 if (*tfdp) (void) manageFile(tfdp, NULL, 0, rc);
118 * Retrieve signer fingerprint from an OpenPGP signature tag.
119 * @param sig signature header
120 * @param sigtag signature tag
121 * @retval signid signer fingerprint
122 * @return 0 on success
124 static int getSignid(Header sig, int sigtag, pgpKeyID_t signid)
128 rpm_count_t pktlen = 0;
131 if (headerGetEntry(sig, sigtag, &pkttyp, &pkt, &pktlen) && pkt != NULL) {
132 pgpDig dig = pgpNewDig();
134 if (!pgpPrtPkts(pkt, pktlen, dig, 0)) {
135 memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
139 dig = pgpFreeDig(dig);
141 pkt = headerFreeData(pkt, pkttyp);
146 * Create/modify elements in signature header.
147 * @param ts transaction set
148 * @param qva mode flags and parameters
149 * @param argv array of package file names (NULL terminated)
150 * @return 0 on success
152 static int rpmReSign(rpmts ts,
153 QVA_t qva, const char ** argv)
159 const char *rpm, *trpm;
160 const char *sigtarget = NULL;
167 int res = EXIT_FAILURE;
168 int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
174 while ((rpm = *argv++) != NULL)
177 fprintf(stdout, "%s:\n", rpm);
179 if (manageFile(&fd, &rpm, O_RDONLY, 0))
184 if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
185 rc = rpmLeadCheck(lead, rpm);
188 if (rc != RPMRC_OK) {
189 lead = rpmLeadFree(lead);
194 rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
197 rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
198 (msg && *msg ? msg : "\n"));
204 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), rpm);
211 /* Write the header and archive to a temp file */
212 /* ASSERT: ofd == NULL && sigtarget == NULL */
213 if (copyFile(&fd, &rpm, &ofd, &sigtarget))
215 /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
216 /* ASSERT: fd == NULL && ofd == NULL */
218 /* Dump the immutable region (if present). */
219 if (headerGetEntry(sigh, RPMTAG_HEADERSIGNATURES, &uht, &uh, &uhc)) {
229 uh = headerFreeData(uh, uht);
233 oh = headerCopyLoad(uh);
234 for (hi = headerInitIterator(oh);
235 headerNextIterator(hi, &tag, &type, &ptr, &count);
236 ptr = headerFreeData(ptr, type))
239 xx = headerAddEntry(nh, tag, type, ptr, count);
241 hi = headerFreeIterator(hi);
244 sigh = headerFree(sigh);
245 sigh = headerLink(nh);
249 /* Eliminate broken digest values. */
250 xx = headerRemoveEntry(sigh, RPMSIGTAG_LEMD5_1);
251 xx = headerRemoveEntry(sigh, RPMSIGTAG_LEMD5_2);
252 xx = headerRemoveEntry(sigh, RPMSIGTAG_BADSHA1_1);
253 xx = headerRemoveEntry(sigh, RPMSIGTAG_BADSHA1_2);
255 /* Toss and recalculate header+payload size and digests. */
256 xx = headerRemoveEntry(sigh, RPMSIGTAG_SIZE);
257 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
258 xx = headerRemoveEntry(sigh, RPMSIGTAG_MD5);
259 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
260 xx = headerRemoveEntry(sigh, RPMSIGTAG_SHA1);
261 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase);
263 if (deleting) { /* Nuke all the signature tags. */
264 xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
265 xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
266 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP5);
267 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
268 xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
269 } else /* If gpg/pgp is configured, replace the signature. */
270 if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
271 pgpKeyID_t oldsignid, newsignid;
273 /* Grab the old signature fingerprint (if any) */
274 memset(oldsignid, 0, sizeof(oldsignid));
275 xx = getSignid(sigh, sigtag, oldsignid);
279 xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
282 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
285 xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
288 xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
292 xx = headerRemoveEntry(sigh, sigtag);
293 xx = rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase);
295 /* If package was previously signed, check for same signer. */
296 memset(newsignid, 0, sizeof(newsignid));
297 if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
299 /* Grab the new signature fingerprint */
300 xx = getSignid(sigh, sigtag, newsignid);
302 /* If same signer, skip resigning the package. */
303 if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
305 rpmlog(RPMLOG_WARNING,
306 _("%s: was already signed by key ID %s, skipping\n"),
307 rpm, pgpHexStr(newsignid+4, sizeof(newsignid)-4));
309 /* Clean up intermediate target */
310 xx = unlink(sigtarget);
311 sigtarget = _free(sigtarget);
317 /* Reallocate the signature into one contiguous region. */
318 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
319 if (sigh == NULL) /* XXX can't happen */
322 /* Write the lead/signature of the output rpm */
324 strcat(tmprpm, ".XXXXXX");
325 #if defined(HAVE_MKSTEMP)
326 (void) close(mkstemp(tmprpm));
328 (void) mktemp(tmprpm);
332 if (manageFile(&ofd, &trpm, O_WRONLY|O_CREAT|O_TRUNC, 0))
335 rc = rpmLeadWrite(ofd, lead);
336 lead = rpmLeadFree(lead);
337 if (rc != RPMRC_OK) {
338 rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
343 if (rpmWriteSignature(ofd, sigh)) {
344 rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
349 /* Append the header and archive from the temp file */
350 /* ASSERT: fd == NULL && ofd != NULL */
351 if (copyFile(&fd, &sigtarget, &ofd, &trpm))
353 /* Both fd and ofd are now closed. */
354 /* ASSERT: fd == NULL && ofd == NULL */
356 /* Move final target into place. */
358 xx = rename(trpm, rpm);
361 /* Clean up intermediate target */
362 xx = unlink(sigtarget);
363 sigtarget = _free(sigtarget);
369 if (fd) (void) manageFile(&fd, NULL, 0, res);
370 if (ofd) (void) manageFile(&ofd, NULL, 0, res);
372 sigh = rpmFreeSignature(sigh);
375 xx = unlink(sigtarget);
376 sigtarget = _free(sigtarget);
378 if (tmprpm[0] != '\0') {
387 * Import public key(s).
388 * @todo Implicit --update policy for gpg-pubkey headers.
389 * @param ts transaction set
390 * @param qva mode flags and parameters
391 * @param argv array of pubkey file names (NULL terminated)
392 * @return 0 on success
394 static int rpmcliImportPubkeys(const rpmts ts,
399 const unsigned char * pkt = NULL;
406 if (argv == NULL) return res;
408 while ((fn = *argv++) != NULL) {
414 /* If arg looks like a keyid, then attempt keyserver retrieve. */
415 if (fn[0] == '0' && fn[1] == 'x') {
418 for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
420 if (i == 8 || i == 16) {
421 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
427 /* Read pgp packet. */
428 if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
429 rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, rc);
433 if (rc != PGPARMOR_PUBKEY) {
434 rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
439 /* Import pubkey packet(s). */
440 if ((rpmrc = rpmtsImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
441 rpmlog(RPMLOG_ERR, _("%s: import failed.\n"), fn);
454 static unsigned char header_magic[8] = {
455 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
459 * @todo If the GPG key was known available, the md5 digest could be skipped.
461 static int readFile(FD_t fd, const char * fn, pgpDig dig)
463 unsigned char buf[4*BUFSIZ];
469 /* Read the header from the package. */
470 { Header h = headerRead(fd, HEADER_MAGIC_YES);
472 rpmlog(RPMLOG_ERR, _("%s: headerRead failed\n"), fn);
476 dig->nbytes += headerSizeof(h, HEADER_MAGIC_YES);
478 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
483 if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
487 rpmlog(RPMLOG_ERR, _("%s: headerGetEntry failed\n"), fn);
490 dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
491 (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
492 (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
493 dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
494 (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
495 (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
496 uh = headerFreeData(uh, uht);
501 /* Read the payload from the package. */
502 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
503 dig->nbytes += count;
505 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
508 fdStealDigest(fd, dig);
516 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd,
522 char missingKeys[7164], * m;
523 char untrustedKeys[7164], * u;
536 int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
537 int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
540 rpmlead lead = rpmLeadNew();
541 if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
542 rc = rpmLeadCheck(lead, fn);
544 lead = rpmLeadFree(lead);
546 if (rc != RPMRC_OK) {
553 rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
556 rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
557 (msg && *msg ? msg : "\n"));
564 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
572 /* Grab a hint of what needs doing to avoid duplication. */
574 if (sigtag == 0 && !nosignatures) {
575 if (headerIsEntry(sigh, RPMSIGTAG_DSA))
576 sigtag = RPMSIGTAG_DSA;
577 else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
578 sigtag = RPMSIGTAG_RSA;
579 else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
580 sigtag = RPMSIGTAG_GPG;
581 else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
582 sigtag = RPMSIGTAG_PGP;
584 if (sigtag == 0 && !nodigests) {
585 if (headerIsEntry(sigh, RPMSIGTAG_MD5))
586 sigtag = RPMSIGTAG_MD5;
587 else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
588 sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
592 sigp = rpmtsSignature(ts);
594 /* XXX RSA needs the hash_algo, so decode early. */
595 if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP) {
596 xx = headerGetEntry(sigh, sigtag, &sigtype, (void **)&sig, &siglen);
597 xx = pgpPrtPkts(sig, siglen, dig, 0);
598 sig = headerFreeData(sig, sigtype);
599 /* XXX assume same hash_algo in header-only and header+payload */
600 if ((headerIsEntry(sigh, RPMSIGTAG_PGP)
601 || headerIsEntry(sigh, RPMSIGTAG_PGP5))
602 && dig->signature.hash_algo != PGPHASHALGO_MD5)
603 fdInitDigest(fd, dig->signature.hash_algo, 0);
606 if (headerIsEntry(sigh, RPMSIGTAG_PGP)
607 || headerIsEntry(sigh, RPMSIGTAG_PGP5)
608 || headerIsEntry(sigh, RPMSIGTAG_MD5))
609 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
610 if (headerIsEntry(sigh, RPMSIGTAG_GPG))
611 fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
613 /* Read the file, generating digest(s) on the fly. */
614 if (dig == NULL || sigp == NULL || readFile(fd, fn, dig)) {
621 m = missingKeys; *m = '\0';
622 u = untrustedKeys; *u = '\0';
623 sprintf(b, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
626 for (hi = headerInitIterator(sigh);
627 headerNextIterator(hi, &sigtag, &sigtype, &sig, &siglen) != 0;
628 (void) rpmtsSetSig(ts, sigtag, sigtype, NULL, siglen))
631 if (sig == NULL) /* XXX can't happen */
634 (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
636 /* Clean up parameters from previous sigtag. */
643 case RPMSIGTAG_PGP5: /* XXX legacy */
647 xx = pgpPrtPkts(sig, siglen, dig,
648 (_print_pkts & rpmIsDebug()));
650 if (sigp->version != 3 && sigp->version != 4) {
651 rpmlog(RPMLOG_NOTICE,
652 _("skipping package %s with unverifiable V%u signature\n"),
661 /* XXX Don't bother with header sha1 if header dsa. */
662 if (!nosignatures && sigtag == RPMSIGTAG_DSA)
665 case RPMSIGTAG_LEMD5_2:
666 case RPMSIGTAG_LEMD5_1:
671 * Don't bother with md5 if pgp, as RSA/MD5 is more reliable
672 * than the -- now unsupported -- legacy md5 breakage.
674 if (!nosignatures && sigtag == RPMSIGTAG_PGP)
682 res3 = rpmVerifySignature(ts, result);
685 if (rpmIsVerbose()) {
687 b = stpcpy(b, result);
693 b = stpcpy(b, "SIZE ");
697 b = stpcpy(b, "SHA1 ");
700 case RPMSIGTAG_LEMD5_2:
701 case RPMSIGTAG_LEMD5_1:
703 b = stpcpy(b, "MD5 ");
707 b = stpcpy(b, "RSA ");
710 case RPMSIGTAG_PGP5: /* XXX legacy */
715 case RPMRC_NOTTRUSTED:
717 b = stpcpy(b, "(MD5) (PGP) ");
718 tempKey = strstr(result, "ey ID");
719 if (tempKey == NULL) {
720 tempKey = strstr(result, "keyid:");
724 if (res3 == RPMRC_NOKEY) {
725 m = stpcpy(m, " PGP#");
726 m = stpncpy(m, tempKey + offset, 8);
729 u = stpcpy(u, " PGP#");
730 u = stpncpy(u, tempKey + offset, 8);
736 b = stpcpy(b, "MD5 PGP ");
742 b = stpcpy(b, "(SHA1) DSA ");
746 /* Do not consider this a failure */
749 b = stpcpy(b, "(GPG) ");
750 m = stpcpy(m, " GPG#");
751 tempKey = strstr(result, "ey ID");
753 m = stpncpy(m, tempKey+6, 8);
759 b = stpcpy(b, "GPG ");
765 b = stpcpy(b, "?UnknownSignatureType? ");
771 if (rpmIsVerbose()) {
773 b = stpcpy(b, result);
777 b = stpcpy(b, "size ");
780 b = stpcpy(b, "sha1 ");
782 case RPMSIGTAG_LEMD5_2:
783 case RPMSIGTAG_LEMD5_1:
785 b = stpcpy(b, "md5 ");
788 b = stpcpy(b, "rsa ");
790 case RPMSIGTAG_PGP5: /* XXX legacy */
792 b = stpcpy(b, "(md5) pgp ");
795 b = stpcpy(b, "(sha1) dsa ");
798 b = stpcpy(b, "gpg ");
801 b = stpcpy(b, "??? ");
807 hi = headerFreeIterator(hi);
812 if (rpmIsVerbose()) {
813 rpmlog(RPMLOG_NOTICE, "%s", buf);
815 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
817 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
819 (missingKeys[0] != '\0') ? _(") ") : "",
820 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
822 (untrustedKeys[0] != '\0') ? _(")") : "");
826 if (rpmIsVerbose()) {
827 rpmlog(RPMLOG_NOTICE, "%s", buf);
829 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
831 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
833 (missingKeys[0] != '\0') ? _(") ") : "",
834 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
836 (untrustedKeys[0] != '\0') ? _(")") : "");
843 sigh = rpmFreeSignature(sigh);
848 int rpmcliSign(rpmts ts, QVA_t qva, const char ** argv)
854 if (argv == NULL) return res;
856 switch (qva->qva_mode) {
857 case RPMSIGN_CHK_SIGNATURE:
859 case RPMSIGN_IMPORT_PUBKEY:
860 return rpmcliImportPubkeys(ts, qva, argv);
862 case RPMSIGN_NEW_SIGNATURE:
863 case RPMSIGN_ADD_SIGNATURE:
864 case RPMSIGN_DEL_SIGNATURE:
865 return rpmReSign(ts, qva, argv);
873 while ((arg = *argv++) != NULL) {
876 fd = Fopen(arg, "r.ufdio");
877 if (fd == NULL || Ferror(fd)) {
878 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
881 } else if (rpmVerifySignatures(qva, ts, fd, arg)) {
885 if (fd != NULL) xx = Fclose(fd);