2 * \file lib/rpmchecksig.c
3 * Verify the signature of a package.
8 #include <rpm/rpmlib.h> /* RPMSIGTAG & related */
9 #include <rpm/rpmpgp.h>
10 #include <rpm/rpmcli.h>
11 #include <rpm/rpmfileutil.h> /* rpmMkTempFile() */
12 #include <rpm/rpmdb.h>
13 #include <rpm/rpmts.h>
14 #include <rpm/rpmlog.h>
16 #include "rpmio/digest.h"
17 #include "lib/rpmlead.h"
18 #include "lib/signature.h"
24 static int closeFile(FD_t *fdp)
26 if (fdp == NULL || *fdp == NULL)
29 /* close and reset *fdp to NULL */
37 static int manageFile(FD_t *fdp, const char *fn, int flags)
41 if (fdp == NULL || fn == NULL) /* programmer error */
44 /* open a file and set *fdp */
45 if (*fdp == NULL && fn != NULL) {
46 fd = Fopen(fn, ((flags & O_WRONLY) ? "w.ufdio" : "r.ufdio"));
47 if (fd == NULL || Ferror(fd)) {
48 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), fn,
57 if (*fdp != NULL && fn != NULL)
60 /* XXX never reached */
65 * Copy header+payload, calculating digest(s) on the fly.
67 static int copyFile(FD_t *sfdp, const char *sfnp,
68 FD_t *tfdp, const char *tfnp)
70 unsigned char buf[BUFSIZ];
74 if (manageFile(sfdp, sfnp, O_RDONLY))
76 if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC))
79 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
81 if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
82 rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), tfnp,
88 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), sfnp, Fstrerror(*sfdp));
91 if (Fflush(*tfdp) != 0) {
92 rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), tfnp,
99 if (*sfdp) (void) closeFile(sfdp);
100 if (*tfdp) (void) closeFile(tfdp);
105 * Retrieve signer fingerprint from an OpenPGP signature tag.
106 * @param sig signature header
107 * @param sigtag signature tag
108 * @retval signid signer fingerprint
109 * @return 0 on success
111 static int getSignid(Header sig, rpmSigTag sigtag, pgpKeyID_t signid)
113 rpm_data_t pkt = NULL;
114 rpmTagType pkttyp = 0;
115 rpm_count_t pktlen = 0;
118 if (headerGetEntry(sig, sigtag, &pkttyp, &pkt, &pktlen) && pkt != NULL) {
119 pgpDig dig = pgpNewDig();
121 if (!pgpPrtPkts(pkt, pktlen, dig, 0)) {
122 memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
126 dig = pgpFreeDig(dig);
128 pkt = headerFreeData(pkt, pkttyp);
133 * Create/modify elements in signature header.
134 * @param ts transaction set
135 * @param qva mode flags and parameters
136 * @param argv array of package file names (NULL terminated)
137 * @return 0 on success
139 static int rpmReSign(rpmts ts,
140 QVA_t qva, const char ** argv)
146 const char *rpm, *trpm;
147 char *sigtarget = NULL;
154 int res = EXIT_FAILURE;
155 int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
161 while ((rpm = *argv++) != NULL)
164 fprintf(stdout, "%s:\n", rpm);
166 if (manageFile(&fd, rpm, O_RDONLY))
171 if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
172 rc = rpmLeadCheck(lead, rpm);
175 if (rc != RPMRC_OK) {
176 lead = rpmLeadFree(lead);
181 rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
184 rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
185 (msg && *msg ? msg : "\n"));
191 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), rpm);
198 /* ASSERT: ofd == NULL && sigtarget == NULL */
199 if (rpmMkTempFile(NULL, &sigtarget, &ofd)) {
200 rpmlog(RPMLOG_ERR, _("rpmMkTempFile failed\n"));
204 /* Write the header and archive to a temp file */
205 if (copyFile(&fd, rpm, &ofd, sigtarget))
207 /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
208 /* ASSERT: fd == NULL && ofd == NULL */
210 /* Dump the immutable region (if present). */
211 if (headerGetEntry(sigh, RPMTAG_HEADERSIGNATURES, &uht, &uh, &uhc)) {
222 uh = headerFreeData(uh, uht);
226 oh = headerCopyLoad(uh);
227 for (hi = headerInitIterator(oh);
228 headerNextIterator(hi, &tag, &type, &ptr, &count);
229 ptr = headerFreeData(ptr, type))
232 xx = headerAddEntry(nh, tag, type, ptr, count);
234 hi = headerFreeIterator(hi);
237 sigh = headerFree(sigh);
238 sigh = headerLink(nh);
242 /* Eliminate broken digest values. */
243 xx = headerRemoveEntry(sigh, RPMSIGTAG_LEMD5_1);
244 xx = headerRemoveEntry(sigh, RPMSIGTAG_LEMD5_2);
245 xx = headerRemoveEntry(sigh, RPMSIGTAG_BADSHA1_1);
246 xx = headerRemoveEntry(sigh, RPMSIGTAG_BADSHA1_2);
248 /* Toss and recalculate header+payload size and digests. */
249 xx = headerRemoveEntry(sigh, RPMSIGTAG_SIZE);
250 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
251 xx = headerRemoveEntry(sigh, RPMSIGTAG_MD5);
252 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
253 xx = headerRemoveEntry(sigh, RPMSIGTAG_SHA1);
254 xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase);
256 if (deleting) { /* Nuke all the signature tags. */
257 xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
258 xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
259 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP5);
260 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
261 xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
262 } else /* If gpg/pgp is configured, replace the signature. */
263 if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
264 pgpKeyID_t oldsignid, newsignid;
266 /* Grab the old signature fingerprint (if any) */
267 memset(oldsignid, 0, sizeof(oldsignid));
268 xx = getSignid(sigh, sigtag, oldsignid);
272 xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
275 xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
278 xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
281 xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
286 case RPMSIGTAG_LEMD5_1:
287 case RPMSIGTAG_LEMD5_2:
288 case RPMSIGTAG_BADSHA1_1:
289 case RPMSIGTAG_BADSHA1_2:
290 case RPMSIGTAG_PAYLOADSIZE:
295 xx = headerRemoveEntry(sigh, sigtag);
296 xx = rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase);
298 /* If package was previously signed, check for same signer. */
299 memset(newsignid, 0, sizeof(newsignid));
300 if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
302 /* Grab the new signature fingerprint */
303 xx = getSignid(sigh, sigtag, newsignid);
305 /* If same signer, skip resigning the package. */
306 if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
308 rpmlog(RPMLOG_WARNING,
309 _("%s: was already signed by key ID %s, skipping\n"),
310 rpm, pgpHexStr(newsignid+4, sizeof(newsignid)-4));
312 /* Clean up intermediate target */
313 xx = unlink(sigtarget);
314 sigtarget = _free(sigtarget);
320 /* Reallocate the signature into one contiguous region. */
321 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
322 if (sigh == NULL) /* XXX can't happen */
325 /* Write the lead/signature of the output rpm */
327 strcat(tmprpm, ".XXXXXX");
328 #if defined(HAVE_MKSTEMP)
329 (void) close(mkstemp(tmprpm));
331 (void) mktemp(tmprpm);
335 if (manageFile(&ofd, trpm, O_WRONLY|O_CREAT|O_TRUNC))
338 rc = rpmLeadWrite(ofd, lead);
339 lead = rpmLeadFree(lead);
340 if (rc != RPMRC_OK) {
341 rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
346 if (rpmWriteSignature(ofd, sigh)) {
347 rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
352 /* Append the header and archive from the temp file */
353 /* ASSERT: fd == NULL && ofd != NULL */
354 if (copyFile(&fd, sigtarget, &ofd, trpm))
356 /* Both fd and ofd are now closed. */
357 /* ASSERT: fd == NULL && ofd == NULL */
359 /* Move final target into place. */
361 xx = rename(trpm, rpm);
364 /* Clean up intermediate target */
365 xx = unlink(sigtarget);
366 sigtarget = _free(sigtarget);
372 if (fd) (void) closeFile(&fd);
373 if (ofd) (void) closeFile(&ofd);
375 sigh = rpmFreeSignature(sigh);
378 xx = unlink(sigtarget);
379 sigtarget = _free(sigtarget);
381 if (tmprpm[0] != '\0') {
390 * Import public key(s).
391 * @todo Implicit --update policy for gpg-pubkey headers.
392 * @param ts transaction set
393 * @param qva mode flags and parameters
394 * @param argv array of pubkey file names (NULL terminated)
395 * @return 0 on success
397 static int rpmcliImportPubkeys(const rpmts ts,
402 unsigned char * pkt = NULL;
409 if (argv == NULL) return res;
411 while ((fn = *argv++) != NULL) {
417 /* If arg looks like a keyid, then attempt keyserver retrieve. */
418 if (fn[0] == '0' && fn[1] == 'x') {
421 for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
423 if (i == 8 || i == 16) {
424 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
430 /* Read pgp packet. */
431 if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
432 rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, rc);
436 if (rc != PGPARMOR_PUBKEY) {
437 rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
442 /* Import pubkey packet(s). */
443 if ((rpmrc = rpmtsImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
444 rpmlog(RPMLOG_ERR, _("%s: import failed.\n"), fn);
457 static unsigned char const header_magic[8] = {
458 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
462 * @todo If the GPG key was known available, the md5 digest could be skipped.
464 static int readFile(FD_t fd, const char * fn, pgpDig dig)
466 unsigned char buf[4*BUFSIZ];
472 /* Read the header from the package. */
473 { Header h = headerRead(fd, HEADER_MAGIC_YES);
475 rpmlog(RPMLOG_ERR, _("%s: headerRead failed\n"), fn);
479 dig->nbytes += headerSizeof(h, HEADER_MAGIC_YES);
481 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
486 if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
490 rpmlog(RPMLOG_ERR, _("%s: headerGetEntry failed\n"), fn);
493 dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
494 (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
495 (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
496 dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
497 (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
498 (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
499 uh = headerFreeData(uh, uht);
504 /* Read the payload from the package. */
505 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
506 dig->nbytes += count;
508 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
511 fdStealDigest(fd, dig);
519 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd,
525 char missingKeys[7164], * m;
526 char untrustedKeys[7164], * u;
539 int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
540 int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
543 rpmlead lead = rpmLeadNew();
544 if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
545 rc = rpmLeadCheck(lead, fn);
547 lead = rpmLeadFree(lead);
549 if (rc != RPMRC_OK) {
556 rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
559 rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
560 (msg && *msg ? msg : "\n"));
567 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
575 /* Grab a hint of what needs doing to avoid duplication. */
577 if (sigtag == 0 && !nosignatures) {
578 if (headerIsEntry(sigh, RPMSIGTAG_DSA))
579 sigtag = RPMSIGTAG_DSA;
580 else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
581 sigtag = RPMSIGTAG_RSA;
582 else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
583 sigtag = RPMSIGTAG_GPG;
584 else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
585 sigtag = RPMSIGTAG_PGP;
587 if (sigtag == 0 && !nodigests) {
588 if (headerIsEntry(sigh, RPMSIGTAG_MD5))
589 sigtag = RPMSIGTAG_MD5;
590 else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
591 sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
595 sigp = rpmtsSignature(ts);
597 /* XXX RSA needs the hash_algo, so decode early. */
598 if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP) {
599 xx = headerGetEntry(sigh, sigtag, &sigtype, (rpm_data_t *)&sig, &siglen);
600 xx = pgpPrtPkts(sig, siglen, dig, 0);
601 sig = headerFreeData(sig, sigtype);
602 /* XXX assume same hash_algo in header-only and header+payload */
603 if ((headerIsEntry(sigh, RPMSIGTAG_PGP)
604 || headerIsEntry(sigh, RPMSIGTAG_PGP5))
605 && dig->signature.hash_algo != PGPHASHALGO_MD5)
606 fdInitDigest(fd, dig->signature.hash_algo, 0);
609 if (headerIsEntry(sigh, RPMSIGTAG_PGP)
610 || headerIsEntry(sigh, RPMSIGTAG_PGP5)
611 || headerIsEntry(sigh, RPMSIGTAG_MD5))
612 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
613 if (headerIsEntry(sigh, RPMSIGTAG_GPG))
614 fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
616 /* Read the file, generating digest(s) on the fly. */
617 if (dig == NULL || sigp == NULL || readFile(fd, fn, dig)) {
624 m = missingKeys; *m = '\0';
625 u = untrustedKeys; *u = '\0';
626 sprintf(b, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
629 for (hi = headerInitIterator(sigh);
630 headerNextIterator(hi, &sigtag, &sigtype, &sig, &siglen) != 0;
631 (void) rpmtsSetSig(ts, sigtag, sigtype, NULL, siglen))
634 if (sig == NULL) /* XXX can't happen */
637 (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
639 /* Clean up parameters from previous sigtag. */
646 case RPMSIGTAG_PGP5: /* XXX legacy */
650 xx = pgpPrtPkts(sig, siglen, dig,
651 (_print_pkts & rpmIsDebug()));
653 if (sigp->version != 3 && sigp->version != 4) {
654 rpmlog(RPMLOG_NOTICE,
655 _("skipping package %s with unverifiable V%u signature\n"),
664 /* XXX Don't bother with header sha1 if header dsa. */
665 if (!nosignatures && sigtag == RPMSIGTAG_DSA)
668 case RPMSIGTAG_LEMD5_2:
669 case RPMSIGTAG_LEMD5_1:
674 * Don't bother with md5 if pgp, as RSA/MD5 is more reliable
675 * than the -- now unsupported -- legacy md5 breakage.
677 if (!nosignatures && sigtag == RPMSIGTAG_PGP)
685 res3 = rpmVerifySignature(ts, result);
688 if (rpmIsVerbose()) {
690 b = stpcpy(b, result);
696 b = stpcpy(b, "SIZE ");
700 b = stpcpy(b, "SHA1 ");
703 case RPMSIGTAG_LEMD5_2:
704 case RPMSIGTAG_LEMD5_1:
706 b = stpcpy(b, "MD5 ");
710 b = stpcpy(b, "RSA ");
713 case RPMSIGTAG_PGP5: /* XXX legacy */
718 case RPMRC_NOTTRUSTED:
720 b = stpcpy(b, "(MD5) (PGP) ");
721 tempKey = strstr(result, "ey ID");
722 if (tempKey == NULL) {
723 tempKey = strstr(result, "keyid:");
727 if (res3 == RPMRC_NOKEY) {
728 m = stpcpy(m, " PGP#");
729 m = stpncpy(m, tempKey + offset, 8);
732 u = stpcpy(u, " PGP#");
733 u = stpncpy(u, tempKey + offset, 8);
739 b = stpcpy(b, "MD5 PGP ");
745 b = stpcpy(b, "(SHA1) DSA ");
749 /* Do not consider this a failure */
752 b = stpcpy(b, "(GPG) ");
753 m = stpcpy(m, " GPG#");
754 tempKey = strstr(result, "ey ID");
756 m = stpncpy(m, tempKey+6, 8);
762 b = stpcpy(b, "GPG ");
768 b = stpcpy(b, "?UnknownSignatureType? ");
774 if (rpmIsVerbose()) {
776 b = stpcpy(b, result);
780 b = stpcpy(b, "size ");
783 b = stpcpy(b, "sha1 ");
785 case RPMSIGTAG_LEMD5_2:
786 case RPMSIGTAG_LEMD5_1:
788 b = stpcpy(b, "md5 ");
791 b = stpcpy(b, "rsa ");
793 case RPMSIGTAG_PGP5: /* XXX legacy */
795 b = stpcpy(b, "(md5) pgp ");
798 b = stpcpy(b, "(sha1) dsa ");
801 b = stpcpy(b, "gpg ");
804 b = stpcpy(b, "??? ");
810 hi = headerFreeIterator(hi);
815 if (rpmIsVerbose()) {
816 rpmlog(RPMLOG_NOTICE, "%s", buf);
818 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
820 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
822 (missingKeys[0] != '\0') ? _(") ") : "",
823 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
825 (untrustedKeys[0] != '\0') ? _(")") : "");
829 if (rpmIsVerbose()) {
830 rpmlog(RPMLOG_NOTICE, "%s", buf);
832 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
834 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
836 (missingKeys[0] != '\0') ? _(") ") : "",
837 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
839 (untrustedKeys[0] != '\0') ? _(")") : "");
846 sigh = rpmFreeSignature(sigh);
851 int rpmcliSign(rpmts ts, QVA_t qva, const char ** argv)
857 if (argv == NULL) return res;
859 switch (qva->qva_mode) {
860 case RPMSIGN_CHK_SIGNATURE:
862 case RPMSIGN_IMPORT_PUBKEY:
863 return rpmcliImportPubkeys(ts, qva, argv);
865 case RPMSIGN_NEW_SIGNATURE:
866 case RPMSIGN_ADD_SIGNATURE:
867 case RPMSIGN_DEL_SIGNATURE:
868 return rpmReSign(ts, qva, argv);
876 while ((arg = *argv++) != NULL) {
879 fd = Fopen(arg, "r.ufdio");
880 if (fd == NULL || Ferror(fd)) {
881 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
884 } else if (rpmVerifySignatures(qva, ts, fd, arg)) {
888 if (fd != NULL) xx = Fclose(fd);