2 * \file lib/signature.c
5 /* signature.c - RPM signature functions */
9 * Things have been cleaned up wrt PGP. We can now handle
10 * signatures of any length (which means you can use any
11 * size key you like). We also honor PGPPATH finally.
16 #if HAVE_ASM_BYTEORDER_H
17 #include <asm/byteorder.h>
21 #include <rpmmacro.h> /* XXX for rpmGetPath */
26 #include "signature.h"
28 /*@access Header@*/ /* XXX compared with NULL */
30 typedef int (*md5func)(const char * fn, /*@out@*/unsigned char * digest);
32 int rpmLookupSignatureType(int action)
34 static int disabled = 0;
38 case RPMLOOKUPSIG_DISABLE:
41 case RPMLOOKUPSIG_ENABLE:
45 case RPMLOOKUPSIG_QUERY:
48 { const char *name = rpmExpand("%{_signature}", NULL);
49 if (!(name && *name != '%'))
51 else if (!strcasecmp(name, "none"))
53 else if (!strcasecmp(name, "pgp"))
55 else if (!strcasecmp(name, "pgp5")) /* XXX legacy */
57 else if (!strcasecmp(name, "gpg"))
60 rc = -1; /* Invalid %_signature spec in macro file */
67 /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */
68 /* executable of the requested version, or NULL when none found. */
70 const char * rpmDetectPGPVersion(pgpVersion *pgpVer)
72 /* Actually this should support having more then one pgp version. */
73 /* At the moment only one version is possible since we only */
74 /* have one %_pgpbin and one %_pgp_path. */
76 static pgpVersion saved_pgp_version = PGP_UNKNOWN;
77 const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
79 if (saved_pgp_version == PGP_UNKNOWN) {
83 if (!(pgpbin && pgpbin[0] != '%')) {
84 if (pgpbin) xfree(pgpbin);
85 saved_pgp_version = -1;
88 pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
89 (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
91 if (stat(pgpvbin, &statbuf) == 0)
92 saved_pgp_version = PGP_5;
93 else if (stat(pgpbin, &statbuf) == 0)
94 saved_pgp_version = PGP_2;
96 saved_pgp_version = PGP_NOTDETECTED;
100 *pgpVer = saved_pgp_version;
104 static int checkSize(FD_t fd, int size, int sigsize)
106 int headerArchiveSize;
109 fstat(Fileno(fd), &statbuf);
111 if (S_ISREG(statbuf.st_mode)) {
112 headerArchiveSize = statbuf.st_size - sizeof(struct rpmlead) - sigsize;
114 rpmMessage(RPMMESS_DEBUG, _("sigsize : %d\n"), sigsize);
115 rpmMessage(RPMMESS_DEBUG, _("Header + Archive: %d\n"), headerArchiveSize);
116 rpmMessage(RPMMESS_DEBUG, _("expected size : %d\n"), size);
118 return size - headerArchiveSize;
120 rpmMessage(RPMMESS_DEBUG, _("file is not regular -- skipping size check\n"));
125 int rpmReadSignature(FD_t fd, Header *headerp, short sig_type)
127 unsigned char buf[2048];
138 rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
140 case RPMSIG_PGP262_1024:
141 rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
142 /* These are always 256 bytes */
143 if (timedRead(fd, buf, 256) != 256)
146 *headerp = headerNew();
147 headerAddEntry(*headerp, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
152 rpmError(RPMERR_BADSIGTYPE,
153 _("Old (internal-only) signature! How did you get that!?"));
155 /*@notreached@*/ break;
156 case RPMSIG_HEADERSIG:
157 rpmMessage(RPMMESS_DEBUG, _("New Header signature\n"));
158 /* This is a new style signature */
159 h = headerRead(fd, HEADER_MAGIC_YES);
162 sigSize = headerSizeof(h, HEADER_MAGIC_YES);
163 pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
164 rpmMessage(RPMMESS_DEBUG, _("Signature size: %d\n"), sigSize);
165 rpmMessage(RPMMESS_DEBUG, _("Signature pad : %d\n"), pad);
166 if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type, (void **)&archSize, &count)) {
170 if (checkSize(fd, *archSize, sigSize + pad)) {
175 if (timedRead(fd, buf, pad) != pad) {
193 int rpmWriteSignature(FD_t fd, Header header)
196 unsigned char buf[8];
199 rc = headerWrite(fd, header, HEADER_MAGIC_YES);
203 sigSize = headerSizeof(header, HEADER_MAGIC_YES);
204 pad = (8 - (sigSize % 8)) % 8;
206 rpmMessage(RPMMESS_DEBUG, _("Signature size: %d\n"), sigSize);
207 rpmMessage(RPMMESS_DEBUG, _("Signature pad : %d\n"), pad);
209 if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
215 Header rpmNewSignature(void)
217 Header h = headerNew();
221 void rpmFreeSignature(Header h)
226 static int makePGPSignature(const char *file, /*@out@*/void **sig, /*@out@*/int_32 *size,
227 const char *passPhrase)
234 sprintf(sigfile, "%s.sig", file);
236 inpipe[0] = inpipe[1] = 0;
239 if (!(pid = fork())) {
240 const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
241 const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
249 dosetenv("PGPPASSFD", "3", 1);
250 if (pgp_path && *pgp_path != '%')
251 dosetenv("PGPPATH", pgp_path, 1);
253 /* dosetenv("PGPPASS", passPhrase, 1); */
255 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
258 execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off",
259 name, "-sb", file, sigfile, NULL);
262 execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off",
263 name, "-b", file, "-o", sigfile, NULL);
266 case PGP_NOTDETECTED:
270 rpmError(RPMERR_EXEC, _("Couldn't exec pgp (%s)"), path);
275 (void)write(inpipe[1], passPhrase, strlen(passPhrase));
276 (void)write(inpipe[1], "\n", 1);
279 (void)waitpid(pid, &status, 0);
280 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
281 rpmError(RPMERR_SIGGEN, _("pgp failed"));
285 if (stat(sigfile, &statbuf)) {
286 /* PGP failed to write signature */
287 unlink(sigfile); /* Just in case */
288 rpmError(RPMERR_SIGGEN, _("pgp failed to write signature"));
292 *size = statbuf.st_size;
293 rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *size);
294 *sig = xmalloc(*size);
298 fd = Fopen(sigfile, "r.fdio");
299 rc = timedRead(fd, *sig, *size);
304 rpmError(RPMERR_SIGGEN, _("unable to read the signature"));
309 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *size);
314 /* This is an adaptation of the makePGPSignature function to use GPG instead
315 * of PGP to create signatures. I think I've made all the changes necessary,
316 * but this could be a good place to start looking if errors in GPG signature
319 static int makeGPGSignature(const char *file, /*@out@*/void **sig, /*@out@*/int_32 *size,
320 const char *passPhrase)
328 sprintf(sigfile, "%s.sig", file);
330 inpipe[0] = inpipe[1] = 0;
333 if (!(pid = fork())) {
334 const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
335 const char *name = rpmExpand("%{_gpg_name}", NULL);
341 if (gpg_path && *gpg_path != '%')
342 dosetenv("GNUPGHOME", gpg_path, 1);
344 "--batch", "--no-verbose", "--no-armor", "--passphrase-fd", "3",
345 "-u", name, "-sbo", sigfile, file,
347 rpmError(RPMERR_EXEC, _("Couldn't exec gpg"));
351 fpipe = fdopen(inpipe[1], "w");
353 fprintf(fpipe, "%s\n", passPhrase);
356 (void)waitpid(pid, &status, 0);
357 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
358 rpmError(RPMERR_SIGGEN, _("gpg failed"));
362 if (stat(sigfile, &statbuf)) {
363 /* GPG failed to write signature */
364 unlink(sigfile); /* Just in case */
365 rpmError(RPMERR_SIGGEN, _("gpg failed to write signature"));
369 *size = statbuf.st_size;
370 rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *size);
371 *sig = xmalloc(*size);
375 fd = Fopen(sigfile, "r.fdio");
376 rc = timedRead(fd, *sig, *size);
381 rpmError(RPMERR_SIGGEN, _("unable to read the signature"));
386 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *size);
391 int rpmAddSignature(Header header, const char *file, int_32 sigTag, const char *passPhrase)
395 unsigned char buf[16];
401 stat(file, &statbuf);
402 size = statbuf.st_size;
404 headerAddEntry(header, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
407 ret = mdbinfile(file, buf);
409 headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16);
411 case RPMSIGTAG_PGP5: /* XXX legacy */
413 rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n"));
414 ret = makePGPSignature(file, &sig, &size, passPhrase);
416 headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
419 rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n"));
420 ret = makeGPGSignature(file, &sig, &size, passPhrase);
422 headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
429 static rpmVerifySignatureReturn
430 verifySizeSignature(const char *datafile, int_32 size, char *result)
434 stat(datafile, &statbuf);
435 if (size != statbuf.st_size) {
436 sprintf(result, "Header+Archive size mismatch.\n"
437 "Expected %d, saw %d.\n",
438 size, (int)statbuf.st_size);
442 sprintf(result, "Header+Archive size OK: %d bytes\n", size);
446 #define X(_x) (unsigned)((_x) & 0xff)
448 static rpmVerifySignatureReturn
449 verifyMD5Signature(const char *datafile, unsigned char *sig,
450 char *result, md5func fn)
452 unsigned char md5sum[16];
454 fn(datafile, md5sum);
455 if (memcmp(md5sum, sig, 16)) {
456 sprintf(result, "MD5 sum mismatch\n"
457 "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
458 "%02x%02x%02x%02x%02x\n"
459 "Saw : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
460 "%02x%02x%02x%02x%02x\n",
461 X(sig[0]), X(sig[1]), X(sig[2]), X(sig[3]),
462 X(sig[4]), X(sig[5]), X(sig[6]), X(sig[7]),
463 X(sig[8]), X(sig[9]), X(sig[10]), X(sig[11]),
464 X(sig[12]), X(sig[13]), X(sig[14]), X(sig[15]),
465 X(md5sum[0]), X(md5sum[1]), X(md5sum[2]), X(md5sum[3]),
466 X(md5sum[4]), X(md5sum[5]), X(md5sum[6]), X(md5sum[7]),
467 X(md5sum[8]), X(md5sum[9]), X(md5sum[10]), X(md5sum[11]),
468 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
472 sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
473 "%02x%02x%02x%02x%02x\n",
474 X(md5sum[0]), X(md5sum[1]), X(md5sum[2]), X(md5sum[3]),
475 X(md5sum[4]), X(md5sum[5]), X(md5sum[6]), X(md5sum[7]),
476 X(md5sum[8]), X(md5sum[9]), X(md5sum[10]), X(md5sum[11]),
477 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
482 static rpmVerifySignatureReturn
483 verifyPGPSignature(const char *datafile, void *sig, int count, char *result)
485 int pid, status, outpipe[2];
488 unsigned char buf[BUFSIZ];
494 /* What version do we have? */
495 if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
497 rpmError(RPMERR_EXEC,
498 _("Could not run pgp. Use --nopgp to skip PGP checks."));
503 * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
504 * Instead we have to use the text output to detect a bad signature.
509 /* Write out the signature */
510 { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
511 sigfile = tempnam(tmppath, "rpmsig");
514 sfd = Fopen(sigfile, "w.fdio");
515 (void)Fwrite(sig, sizeof(char), count, sfd);
519 outpipe[0] = outpipe[1] = 0;
522 if (!(pid = fork())) {
523 const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
526 close(STDOUT_FILENO); /* XXX unnecessary */
527 dup2(outpipe[1], STDOUT_FILENO);
529 if (pgp_path && *pgp_path != '%')
530 dosetenv("PGPPATH", pgp_path, 1);
534 /* Some output (in particular "This signature applies to */
535 /* another message") is _always_ written to stderr; we */
536 /* want to catch that output, so dup stdout to stderr: */
537 { int save_stderr = dup(2);
539 execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
540 /* Write "Good signature..." to stdout: */
541 "+OutputInformationFD=1",
542 /* Write "WARNING: ... is not trusted to... to stdout: */
543 "+OutputWarningFD=1",
544 sigfile, "-o", datafile, NULL);
545 /* Restore stderr so we can print the error message below. */
546 dup2(save_stderr, 2);
550 execlp(path, "pgp", "+batchmode=on", "+verbose=0",
551 sigfile, datafile, NULL);
554 case PGP_NOTDETECTED:
558 fprintf(stderr, _("exec failed!\n"));
559 rpmError(RPMERR_EXEC,
560 _("Could not run pgp. Use --nopgp to skip PGP checks."));
565 file = fdopen(outpipe[0], "r");
567 while (fgets(buf, 1024, file)) {
568 if (strncmp("File '", buf, 6) &&
569 strncmp("Text is assu", buf, 12) &&
570 strncmp("This signature applies to another message", buf, 41) &&
574 if (!strncmp("WARNING: Can't find the right public key", buf, 40))
576 else if (!strncmp("Signature by unknown keyid:", buf, 27))
578 else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
579 res = RPMSIG_NOTTRUSTED;
580 else if (!strncmp("Good signature", buf, 14))
585 (void)waitpid(pid, &status, 0);
587 if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
594 static rpmVerifySignatureReturn
595 verifyGPGSignature(const char *datafile, void *sig, int count, char *result)
597 int pid, status, outpipe[2];
600 unsigned char buf[8192];
604 /* Write out the signature */
605 { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
606 sigfile = tempnam(tmppath, "rpmsig");
609 sfd = Fopen(sigfile, "w.fdio");
610 (void)Fwrite(sig, sizeof(char), count, sfd);
614 outpipe[0] = outpipe[1] = 0;
617 if (!(pid = fork())) {
618 const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
621 /* gpg version 0.9 sends its output to stderr. */
622 dup2(outpipe[1], STDERR_FILENO);
624 if (gpg_path && *gpg_path != '%')
625 dosetenv("GNUPGHOME", gpg_path, 1);
628 "--batch", "--no-verbose",
629 "--verify", sigfile, datafile,
631 fprintf(stderr, _("exec failed!\n"));
632 rpmError(RPMERR_EXEC,
633 _("Could not run gpg. Use --nogpg to skip GPG checks."));
638 file = fdopen(outpipe[0], "r");
640 while (fgets(buf, 1024, file)) {
642 if (!strncmp("gpg: Can't check signature: Public key not found", buf, 48)) {
648 (void)waitpid(pid, &status, 0);
650 if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
657 static int checkPassPhrase(const char *passPhrase, const int sigTag)
659 int passPhrasePipe[2];
663 passPhrasePipe[0] = passPhrasePipe[1] = 0;
664 pipe(passPhrasePipe);
665 if (!(pid = fork())) {
667 close(STDOUT_FILENO);
668 close(passPhrasePipe[1]);
669 if (! rpmIsVerbose()) {
670 close(STDERR_FILENO);
672 if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
673 dup2(fd, STDIN_FILENO);
676 if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
677 dup2(fd, STDOUT_FILENO);
680 dup2(passPhrasePipe[0], 3);
684 { const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
685 const char *name = rpmExpand("%{_gpg_name}", NULL);
686 if (gpg_path && *gpg_path != '%')
687 dosetenv("GNUPGHOME", gpg_path, 1);
689 "--batch", "--no-verbose", "--passphrase-fd", "3",
690 "-u", name, "-so", "-",
692 rpmError(RPMERR_EXEC, _("Couldn't exec gpg"));
694 } /*@notreached@*/ break;
695 case RPMSIGTAG_PGP5: /* XXX legacy */
697 { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
698 const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
702 dosetenv("PGPPASSFD", "3", 1);
703 if (pgp_path && *pgp_path != '%')
704 dosetenv("PGPPATH", pgp_path, 1);
706 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
709 execlp(path, "pgp", "+batchmode=on", "+verbose=0",
712 case PGP_5: /* XXX legacy */
713 execlp(path,"pgps", "+batchmode=on", "+verbose=0",
717 case PGP_NOTDETECTED:
721 rpmError(RPMERR_EXEC, _("Couldn't exec pgp"));
723 } /*@notreached@*/ break;
724 default: /* This case should have been screened out long ago. */
725 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
726 _exit(RPMERR_SIGGEN);
727 /*@notreached@*/ break;
731 close(passPhrasePipe[0]);
732 (void)write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
733 (void)write(passPhrasePipe[1], "\n", 1);
734 close(passPhrasePipe[1]);
736 (void)waitpid(pid, &status, 0);
737 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
741 /* passPhrase is good */
745 char *rpmGetPassPhrase(const char *prompt, const int sigTag)
752 { const char *name = rpmExpand("%{_gpg_name}", NULL);
753 aok = (name && *name != '%');
757 rpmError(RPMERR_SIGGEN,
758 _("You must set \"%%_gpg_name\" in your macro file"));
762 case RPMSIGTAG_PGP5: /* XXX legacy */
764 { const char *name = rpmExpand("%{_pgp_name}", NULL);
765 aok = (name && *name != '%');
769 rpmError(RPMERR_SIGGEN,
770 _("You must set \"%%_pgp_name\" in your macro file"));
775 /* Currently the calling function (rpm.c:main) is checking this and
776 * doing a better job. This section should never be accessed.
778 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
780 /*@notreached@*/ break;
783 pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
785 if (checkPassPhrase(pass, sigTag))
791 rpmVerifySignatureReturn
792 rpmVerifySignature(const char *file, int_32 sigTag, void *sig, int count,
797 return verifySizeSignature(file, *(int_32 *)sig, result);
798 /*@notreached@*/ break;
800 return verifyMD5Signature(file, sig, result, mdbinfile);
801 /*@notreached@*/ break;
802 case RPMSIGTAG_LEMD5_1:
803 case RPMSIGTAG_LEMD5_2:
804 return verifyMD5Signature(file, sig, result, mdbinfileBroken);
805 /*@notreached@*/ break;
806 case RPMSIGTAG_PGP5: /* XXX legacy */
808 return verifyPGPSignature(file, sig, count, result);
809 /*@notreached@*/ break;
811 return verifyGPGSignature(file, sig, count, result);
812 /*@notreached@*/ break;
814 sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
815 return RPMSIG_UNKNOWN;