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"
29 /*@access Header@*/ /* XXX compared with NULL */
31 typedef unsigned char byte;
33 typedef int (*md5func)(const char * fn, /*@out@*/ byte * digest);
35 int rpmLookupSignatureType(int action)
37 static int disabled = 0;
41 case RPMLOOKUPSIG_DISABLE:
44 case RPMLOOKUPSIG_ENABLE:
47 case RPMLOOKUPSIG_QUERY:
50 { const char *name = rpmExpand("%{_signature}", NULL);
51 if (!(name && *name != '%'))
53 else if (!xstrcasecmp(name, "none"))
55 else if (!xstrcasecmp(name, "pgp"))
57 else if (!xstrcasecmp(name, "pgp5")) /* XXX legacy */
59 else if (!xstrcasecmp(name, "gpg"))
62 rc = -1; /* Invalid %_signature spec in macro file */
69 /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */
70 /* executable of the requested version, or NULL when none found. */
72 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
74 /* Actually this should support having more then one pgp version. */
75 /* At the moment only one version is possible since we only */
76 /* have one %_pgpbin and one %_pgp_path. */
78 static pgpVersion saved_pgp_version = PGP_UNKNOWN;
79 const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
81 if (saved_pgp_version == PGP_UNKNOWN) {
85 if (!(pgpbin && pgpbin[0] != '%')) {
86 pgpbin = _free(pgpbin);
87 saved_pgp_version = -1;
90 pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
91 (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
93 if (stat(pgpvbin, &st) == 0)
94 saved_pgp_version = PGP_5;
95 else if (stat(pgpbin, &st) == 0)
96 saved_pgp_version = PGP_2;
98 saved_pgp_version = PGP_NOTDETECTED;
101 if (pgpbin && pgpVer)
102 *pgpVer = saved_pgp_version;
107 * Check package size.
108 * @todo rpmio: use fdSize rather than fstat(2) to get file size.
109 * @param fd package file handle
110 * @param siglen signature header size
111 * @param pad signature padding
112 * @param datalen length of header+payload
113 * @return rpmRC return code
115 static inline rpmRC checkSize(FD_t fd, int siglen, int pad, int datalen)
120 if (fstat(Fileno(fd), &st))
123 if (!S_ISREG(st.st_mode)) {
124 rpmMessage(RPMMESS_DEBUG,
125 _("file is not regular -- skipping size check\n"));
129 rc = (((sizeof(struct rpmlead) + siglen + pad + datalen) - st.st_size)
130 ? RPMRC_BADSIZE : RPMRC_OK);
132 rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
133 _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
134 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
135 (int)sizeof(struct rpmlead), siglen, pad, datalen);
136 rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
137 _(" Actual size: %12d\n"), (int)st.st_size);
142 rpmRC rpmReadSignature(FD_t fd, Header * headerp, sigType sig_type)
149 rpmRC rc = RPMRC_FAIL; /* assume failure */
155 case RPMSIGTYPE_NONE:
156 rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
159 case RPMSIGTYPE_PGP262_1024:
160 rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
161 /* These are always 256 bytes */
162 if (timedRead(fd, buf, 256) != 256)
165 headerAddEntry(h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
169 case RPMSIGTYPE_MD5_PGP:
170 rpmError(RPMERR_BADSIGTYPE,
171 _("Old (internal-only) signature! How did you get that!?\n"));
173 case RPMSIGTYPE_HEADERSIG:
174 case RPMSIGTYPE_DISABLE:
175 /* This is a new style signature */
176 h = headerRead(fd, HEADER_MAGIC_YES);
181 sigSize = headerSizeof(h, HEADER_MAGIC_YES);
183 /* XXX Legacy headers have a HEADER_IMAGE tag added. */
184 if (headerIsEntry(h, RPMTAG_HEADERIMAGE))
185 sigSize -= (16 + 16);
187 pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
188 if (sig_type == RPMSIGTYPE_HEADERSIG) {
189 if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type,
190 (void **)&archSize, &count))
192 rc = checkSize(fd, sigSize, pad, *archSize);
194 if (pad && timedRead(fd, buf, pad) != pad)
195 rc = RPMRC_SHORTREAD;
201 if (rc == 0 && headerp)
209 int rpmWriteSignature(FD_t fd, Header h)
211 static byte buf[8] = "\000\000\000\000\000\000\000\000";
215 rc = headerWrite(fd, h, HEADER_MAGIC_YES);
219 sigSize = headerSizeof(h, HEADER_MAGIC_YES);
220 pad = (8 - (sigSize % 8)) % 8;
222 if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
225 rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
229 Header rpmNewSignature(void)
231 Header h = headerNew();
235 void rpmFreeSignature(Header h)
240 static int makePGPSignature(const char * file, /*@out@*/ void ** sig,
241 /*@out@*/ int_32 * size, const char * passPhrase)
243 char * sigfile = alloca(1024);
248 (void) stpcpy( stpcpy(sigfile, file), ".sig");
250 inpipe[0] = inpipe[1] = 0;
253 if (!(pid = fork())) {
254 const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
255 const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
263 dosetenv("PGPPASSFD", "3", 1);
264 if (pgp_path && *pgp_path != '%')
265 dosetenv("PGPPATH", pgp_path, 1);
267 /* dosetenv("PGPPASS", passPhrase, 1); */
269 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
272 execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off",
273 name, "-sb", file, sigfile, NULL);
276 execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off",
277 name, "-b", file, "-o", sigfile, NULL);
280 case PGP_NOTDETECTED:
284 rpmError(RPMERR_EXEC, _("Couldn't exec pgp (%s)\n"), path);
289 (void)write(inpipe[1], passPhrase, strlen(passPhrase));
290 (void)write(inpipe[1], "\n", 1);
293 (void)waitpid(pid, &status, 0);
294 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
295 rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
299 if (stat(sigfile, &st)) {
300 /* PGP failed to write signature */
301 unlink(sigfile); /* Just in case */
302 rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
307 rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *size);
308 *sig = xmalloc(*size);
312 fd = Fopen(sigfile, "r.fdio");
313 rc = timedRead(fd, *sig, *size);
318 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
323 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *size);
328 /* This is an adaptation of the makePGPSignature function to use GPG instead
329 * of PGP to create signatures. I think I've made all the changes necessary,
330 * but this could be a good place to start looking if errors in GPG signature
333 static int makeGPGSignature(const char * file, /*@out@*/ void ** sig,
334 /*@out@*/ int_32 * size, const char * passPhrase)
336 char * sigfile = alloca(1024);
342 (void) stpcpy( stpcpy(sigfile, file), ".sig");
344 inpipe[0] = inpipe[1] = 0;
347 if (!(pid = fork())) {
348 const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
349 const char *name = rpmExpand("%{_gpg_name}", NULL);
355 if (gpg_path && *gpg_path != '%')
356 dosetenv("GNUPGHOME", gpg_path, 1);
358 "--batch", "--no-verbose", "--no-armor", "--passphrase-fd", "3",
359 "-u", name, "-sbo", sigfile, file,
361 rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
365 fpipe = fdopen(inpipe[1], "w");
367 fprintf(fpipe, "%s\n", passPhrase);
370 (void)waitpid(pid, &status, 0);
371 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
372 rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
376 if (stat(sigfile, &st)) {
377 /* GPG failed to write signature */
378 unlink(sigfile); /* Just in case */
379 rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
384 rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *size);
385 *sig = xmalloc(*size);
389 fd = Fopen(sigfile, "r.fdio");
390 rc = timedRead(fd, *sig, *size);
395 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
400 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *size);
405 int rpmAddSignature(Header header, const char * file, int_32 sigTag,
406 const char *passPhrase)
419 headerAddEntry(header, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
422 ret = mdbinfile(file, buf);
424 headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16);
426 case RPMSIGTAG_PGP5: /* XXX legacy */
428 rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n"));
429 ret = makePGPSignature(file, &sig, &size, passPhrase);
431 headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
434 rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n"));
435 ret = makeGPGSignature(file, &sig, &size, passPhrase);
437 headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
444 static rpmVerifySignatureReturn
445 verifySizeSignature(const char * datafile, int_32 size, char * result)
450 if (size != st.st_size) {
451 sprintf(result, "Header+Archive size mismatch.\n"
452 "Expected %d, saw %d.\n",
453 size, (int)st.st_size);
457 sprintf(result, "Header+Archive size OK: %d bytes\n", size);
461 #define X(_x) (unsigned)((_x) & 0xff)
463 static rpmVerifySignatureReturn
464 verifyMD5Signature(const char * datafile, const byte * sig,
465 char * result, md5func fn)
469 fn(datafile, md5sum);
470 if (memcmp(md5sum, sig, 16)) {
471 sprintf(result, "MD5 sum mismatch\n"
472 "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
473 "%02x%02x%02x%02x%02x\n"
474 "Saw : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
475 "%02x%02x%02x%02x%02x\n",
476 X(sig[0]), X(sig[1]), X(sig[2]), X(sig[3]),
477 X(sig[4]), X(sig[5]), X(sig[6]), X(sig[7]),
478 X(sig[8]), X(sig[9]), X(sig[10]), X(sig[11]),
479 X(sig[12]), X(sig[13]), X(sig[14]), X(sig[15]),
480 X(md5sum[0]), X(md5sum[1]), X(md5sum[2]), X(md5sum[3]),
481 X(md5sum[4]), X(md5sum[5]), X(md5sum[6]), X(md5sum[7]),
482 X(md5sum[8]), X(md5sum[9]), X(md5sum[10]), X(md5sum[11]),
483 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
487 sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
488 "%02x%02x%02x%02x%02x\n",
489 X(md5sum[0]), X(md5sum[1]), X(md5sum[2]), X(md5sum[3]),
490 X(md5sum[4]), X(md5sum[5]), X(md5sum[6]), X(md5sum[7]),
491 X(md5sum[8]), X(md5sum[9]), X(md5sum[10]), X(md5sum[11]),
492 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
497 static rpmVerifySignatureReturn
498 verifyPGPSignature(const char * datafile, const void * sig, int count,
501 int pid, status, outpipe[2];
510 /* What version do we have? */
511 if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
513 rpmError(RPMERR_EXEC,
514 _("Could not run pgp. Use --nopgp to skip PGP checks.\n"));
519 * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
520 * Instead we have to use the text output to detect a bad signature.
525 /* Write out the signature */
526 { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
527 sigfile = tempnam(tmppath, "rpmsig");
528 tmppath = _free(tmppath);
530 sfd = Fopen(sigfile, "w.fdio");
531 (void)Fwrite(sig, sizeof(char), count, sfd);
535 outpipe[0] = outpipe[1] = 0;
538 if (!(pid = fork())) {
539 const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
542 close(STDOUT_FILENO); /* XXX unnecessary */
543 dup2(outpipe[1], STDOUT_FILENO);
545 if (pgp_path && *pgp_path != '%')
546 dosetenv("PGPPATH", pgp_path, 1);
550 /* Some output (in particular "This signature applies to */
551 /* another message") is _always_ written to stderr; we */
552 /* want to catch that output, so dup stdout to stderr: */
553 { int save_stderr = dup(2);
555 execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
556 /* Write "Good signature..." to stdout: */
557 "+OutputInformationFD=1",
558 /* Write "WARNING: ... is not trusted to... to stdout: */
559 "+OutputWarningFD=1",
560 sigfile, "-o", datafile, NULL);
561 /* Restore stderr so we can print the error message below. */
562 dup2(save_stderr, 2);
566 execlp(path, "pgp", "+batchmode=on", "+verbose=0",
567 sigfile, datafile, NULL);
570 case PGP_NOTDETECTED:
574 rpmError(RPMERR_EXEC,
575 _("Could not run pgp. Use --nopgp to skip PGP checks.\n"));
580 file = fdopen(outpipe[0], "r");
582 while (fgets(buf, 1024, file)) {
583 if (strncmp("File '", buf, 6) &&
584 strncmp("Text is assu", buf, 12) &&
585 strncmp("This signature applies to another message", buf, 41) &&
589 if (!strncmp("WARNING: Can't find the right public key", buf, 40))
591 else if (!strncmp("Signature by unknown keyid:", buf, 27))
593 else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
594 res = RPMSIG_NOTTRUSTED;
595 else if (!strncmp("Good signature", buf, 14))
600 (void)waitpid(pid, &status, 0);
602 if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
609 static rpmVerifySignatureReturn
610 verifyGPGSignature(const char * datafile, const void * sig, int count,
613 int pid, status, outpipe[2];
620 /* Write out the signature */
621 { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
622 sigfile = tempnam(tmppath, "rpmsig");
623 tmppath = _free(tmppath);
625 sfd = Fopen(sigfile, "w.fdio");
626 (void)Fwrite(sig, sizeof(char), count, sfd);
630 outpipe[0] = outpipe[1] = 0;
633 if (!(pid = fork())) {
634 const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
637 /* gpg version 0.9 sends its output to stderr. */
638 dup2(outpipe[1], STDERR_FILENO);
640 if (gpg_path && *gpg_path != '%')
641 dosetenv("GNUPGHOME", gpg_path, 1);
644 "--batch", "--no-verbose",
645 "--verify", sigfile, datafile,
647 rpmError(RPMERR_EXEC,
648 _("Could not run gpg. Use --nogpg to skip GPG checks.\n"));
653 file = fdopen(outpipe[0], "r");
655 while (fgets(buf, 1024, file)) {
657 if (!xstrncasecmp("gpg: Can't check signature: Public key not found", buf, 48)) {
663 (void)waitpid(pid, &status, 0);
665 if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
672 static int checkPassPhrase(const char * passPhrase, const int sigTag)
674 int passPhrasePipe[2];
678 passPhrasePipe[0] = passPhrasePipe[1] = 0;
679 pipe(passPhrasePipe);
680 if (!(pid = fork())) {
682 close(STDOUT_FILENO);
683 close(passPhrasePipe[1]);
684 if (! rpmIsVerbose()) {
685 close(STDERR_FILENO);
687 if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
688 dup2(fd, STDIN_FILENO);
691 if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
692 dup2(fd, STDOUT_FILENO);
695 dup2(passPhrasePipe[0], 3);
699 { const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
700 const char *name = rpmExpand("%{_gpg_name}", NULL);
701 if (gpg_path && *gpg_path != '%')
702 dosetenv("GNUPGHOME", gpg_path, 1);
704 "--batch", "--no-verbose", "--passphrase-fd", "3",
705 "-u", name, "-so", "-",
707 rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
709 } /*@notreached@*/ break;
710 case RPMSIGTAG_PGP5: /* XXX legacy */
712 { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
713 const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
717 dosetenv("PGPPASSFD", "3", 1);
718 if (pgp_path && *pgp_path != '%')
719 dosetenv("PGPPATH", pgp_path, 1);
721 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
724 execlp(path, "pgp", "+batchmode=on", "+verbose=0",
727 case PGP_5: /* XXX legacy */
728 execlp(path,"pgps", "+batchmode=on", "+verbose=0",
732 case PGP_NOTDETECTED:
736 rpmError(RPMERR_EXEC, _("Couldn't exec pgp\n"));
738 } /*@notreached@*/ break;
739 default: /* This case should have been screened out long ago. */
740 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
741 _exit(RPMERR_SIGGEN);
742 /*@notreached@*/ break;
746 close(passPhrasePipe[0]);
747 (void)write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
748 (void)write(passPhrasePipe[1], "\n", 1);
749 close(passPhrasePipe[1]);
751 (void)waitpid(pid, &status, 0);
752 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
756 /* passPhrase is good */
760 char *rpmGetPassPhrase(const char * prompt, const int sigTag)
767 { const char *name = rpmExpand("%{_gpg_name}", NULL);
768 aok = (name && *name != '%');
772 rpmError(RPMERR_SIGGEN,
773 _("You must set \"%%_gpg_name\" in your macro file\n"));
777 case RPMSIGTAG_PGP5: /* XXX legacy */
779 { const char *name = rpmExpand("%{_pgp_name}", NULL);
780 aok = (name && *name != '%');
784 rpmError(RPMERR_SIGGEN,
785 _("You must set \"%%_pgp_name\" in your macro file\n"));
790 /* Currently the calling function (rpm.c:main) is checking this and
791 * doing a better job. This section should never be accessed.
793 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
795 /*@notreached@*/ break;
798 pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
800 if (checkPassPhrase(pass, sigTag))
806 rpmVerifySignatureReturn
807 rpmVerifySignature(const char * file, int_32 sigTag, const void * sig,
808 int count, char * result)
812 return verifySizeSignature(file, *(int_32 *)sig, result);
813 /*@notreached@*/ break;
815 return verifyMD5Signature(file, sig, result, mdbinfile);
816 /*@notreached@*/ break;
817 case RPMSIGTAG_LEMD5_1:
818 case RPMSIGTAG_LEMD5_2:
819 return verifyMD5Signature(file, sig, result, mdbinfileBroken);
820 /*@notreached@*/ break;
821 case RPMSIGTAG_PGP5: /* XXX legacy */
823 return verifyPGPSignature(file, sig, count, result);
824 /*@notreached@*/ break;
826 return verifyGPGSignature(file, sig, count, result);
827 /*@notreached@*/ break;
829 sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
830 return RPMSIG_UNKNOWN;