2 * \file lib/signature.c
7 #include "rpmio_internal.h"
9 #include <rpmmacro.h> /* XXX for rpmGetPath() */
13 #include "misc.h" /* XXX for dosetenv() and makeTempFile() */
14 #include "legacy.h" /* XXX for mdbinfile() */
16 #include "signature.h"
19 /*@access rpmTransactionSet@*/
20 /*@access Header@*/ /* XXX compared with NULL */
21 /*@access FD_t@*/ /* XXX compared with NULL */
22 /*@access DIGEST_CTX@*/ /* XXX compared with NULL */
25 int rpmLookupSignatureType(int action)
28 static int disabled = 0;
32 case RPMLOOKUPSIG_DISABLE:
35 case RPMLOOKUPSIG_ENABLE:
38 case RPMLOOKUPSIG_QUERY:
41 { const char *name = rpmExpand("%{?_signature}", NULL);
42 if (!(name && *name != '\0'))
44 else if (!xstrcasecmp(name, "none"))
46 else if (!xstrcasecmp(name, "pgp"))
48 else if (!xstrcasecmp(name, "pgp5")) /* XXX legacy */
50 else if (!xstrcasecmp(name, "gpg"))
53 rc = -1; /* Invalid %_signature spec in macro file */
60 /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */
61 /* executable of the requested version, or NULL when none found. */
63 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
65 /* Actually this should support having more then one pgp version. */
66 /* At the moment only one version is possible since we only */
67 /* have one %_pgpbin and one %_pgp_path. */
69 static pgpVersion saved_pgp_version = PGP_UNKNOWN;
70 const char *pgpbin = rpmGetPath("%{?_pgpbin}", NULL);
72 if (saved_pgp_version == PGP_UNKNOWN) {
76 if (!(pgpbin && pgpbin[0] != '\0')) {
77 pgpbin = _free(pgpbin);
78 saved_pgp_version = -1;
81 pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
82 (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
84 if (stat(pgpvbin, &st) == 0)
85 saved_pgp_version = PGP_5;
86 else if (stat(pgpbin, &st) == 0)
87 saved_pgp_version = PGP_2;
89 saved_pgp_version = PGP_NOTDETECTED;
93 *pgpVer = saved_pgp_version;
99 * @todo rpmio: use fdSize rather than fstat(2) to get file size.
100 * @param fd package file handle
101 * @param siglen signature header size
102 * @param pad signature padding
103 * @param datalen length of header+payload
104 * @return rpmRC return code
106 static inline rpmRC checkSize(FD_t fd, int siglen, int pad, int datalen)
107 /*@globals fileSystem @*/
108 /*@modifies fileSystem @*/
113 if (fstat(Fileno(fd), &st))
116 if (!S_ISREG(st.st_mode)) {
117 rpmMessage(RPMMESS_DEBUG,
118 _("file is not regular -- skipping size check\n"));
123 rc = (((sizeof(struct rpmlead) + siglen + pad + datalen) - st.st_size)
124 ? RPMRC_BADSIZE : RPMRC_OK);
126 rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_DEBUG),
127 _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
128 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
129 (int)sizeof(struct rpmlead), siglen, pad, datalen);
131 rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_DEBUG),
132 _(" Actual size: %12d\n"), (int)st.st_size);
137 rpmRC rpmReadSignature(FD_t fd, Header * headerp, sigType sig_type)
144 rpmRC rc = RPMRC_FAIL; /* assume failure */
151 case RPMSIGTYPE_NONE:
152 rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
155 case RPMSIGTYPE_PGP262_1024:
156 rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
157 /* These are always 256 bytes */
158 if (timedRead(fd, buf, 256) != 256)
161 (void) headerAddEntry(h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
165 case RPMSIGTYPE_MD5_PGP:
166 rpmError(RPMERR_BADSIGTYPE,
167 _("Old (internal-only) signature! How did you get that!?\n"));
169 case RPMSIGTYPE_HEADERSIG:
170 case RPMSIGTYPE_DISABLE:
171 /* This is a new style signature */
172 h = headerRead(fd, HEADER_MAGIC_YES);
177 sigSize = headerSizeof(h, HEADER_MAGIC_YES);
179 /* XXX Legacy headers have a HEADER_IMAGE tag added. */
180 if (headerIsEntry(h, RPMTAG_HEADERIMAGE))
181 sigSize -= (16 + 16);
183 pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
184 if (sig_type == RPMSIGTYPE_HEADERSIG) {
185 if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type,
186 (void **)&archSize, &count))
188 rc = checkSize(fd, sigSize, pad, *archSize);
190 if (pad && timedRead(fd, buf, pad) != pad)
191 rc = RPMRC_SHORTREAD;
197 if (headerp && rc == 0)
198 *headerp = headerLink(h, NULL);
200 h = headerFree(h, NULL);
205 int rpmWriteSignature(FD_t fd, Header h)
207 static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
211 rc = headerWrite(fd, h, HEADER_MAGIC_YES);
215 sigSize = headerSizeof(h, HEADER_MAGIC_YES);
216 pad = (8 - (sigSize % 8)) % 8;
218 if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
221 rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
225 Header rpmNewSignature(void)
227 Header h = headerNew();
231 Header rpmFreeSignature(Header h)
233 return headerFree(h, "FreeSignature");
237 * Generate PGP (aka RSA/MD5) signature(s) for a header+payload file.
238 * @param file header+payload file name
239 * @retval pkt signature packet(s)
240 * @retval pktlen signature packet(s) length
241 * @param passPhrase private key pass phrase
242 * @return 0 on success, 1 on failure
244 static int makePGPSignature(const char * file, /*@out@*/ byte ** pkt,
245 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
246 /*@globals errno, rpmGlobalMacroContext, fileSystem @*/
247 /*@modifies errno, *pkt, *pktlen, rpmGlobalMacroContext, fileSystem @*/
249 char * sigfile = alloca(1024);
257 (void) stpcpy( stpcpy(sigfile, file), ".sig");
259 addMacro(NULL, "__plaintext_filename", NULL, file, -1);
260 addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
262 inpipe[0] = inpipe[1] = 0;
265 if (!(pid = fork())) {
266 const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
270 (void) close(STDIN_FILENO);
271 (void) dup2(inpipe[0], 3);
272 (void) close(inpipe[1]);
274 (void) dosetenv("PGPPASSFD", "3", 1);
275 if (pgp_path && *pgp_path != '\0')
276 (void) dosetenv("PGPPATH", pgp_path, 1);
278 /* dosetenv("PGPPASS", passPhrase, 1); */
280 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
283 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
284 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
286 rc = execve(av[0], av+1, environ);
289 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
290 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
292 rc = execve(av[0], av+1, environ);
295 case PGP_NOTDETECTED:
300 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
305 delMacro(NULL, "__plaintext_filename");
306 delMacro(NULL, "__signature_filename");
308 (void) close(inpipe[0]);
310 (void) write(inpipe[1], passPhrase, strlen(passPhrase));
311 (void) write(inpipe[1], "\n", 1);
312 (void) close(inpipe[1]);
314 (void)waitpid(pid, &status, 0);
315 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
316 rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
320 if (stat(sigfile, &st)) {
321 /* PGP failed to write signature */
322 if (sigfile) (void) unlink(sigfile); /* Just in case */
323 rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
327 *pktlen = st.st_size;
328 rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *pktlen);
329 *pkt = xmalloc(*pktlen);
334 fd = Fopen(sigfile, "r.fdio");
335 if (fd != NULL && !Ferror(fd)) {
336 rc = timedRead(fd, *pkt, *pktlen);
337 if (sigfile) (void) unlink(sigfile);
342 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
347 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *pktlen);
353 * Generate GPG (aka DSA) signature(s) for a header+payload file.
354 * @param file header+payload file name
355 * @retval pkt signature packet(s)
356 * @retval pktlen signature packet(s) length
357 * @param passPhrase private key pass phrase
358 * @return 0 on success, 1 on failure
360 static int makeGPGSignature(const char * file, /*@out@*/ byte ** pkt,
361 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
362 /*@globals rpmGlobalMacroContext, fileSystem @*/
363 /*@modifies *pkt, *pktlen, rpmGlobalMacroContext, fileSystem @*/
365 char * sigfile = alloca(1024);
374 (void) stpcpy( stpcpy(sigfile, file), ".sig");
376 addMacro(NULL, "__plaintext_filename", NULL, file, -1);
377 addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
379 inpipe[0] = inpipe[1] = 0;
382 if (!(pid = fork())) {
383 const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
385 (void) close(STDIN_FILENO);
386 (void) dup2(inpipe[0], 3);
387 (void) close(inpipe[1]);
389 if (gpg_path && *gpg_path != '\0')
390 (void) dosetenv("GNUPGHOME", gpg_path, 1);
392 cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
393 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
395 rc = execve(av[0], av+1, environ);
397 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
402 delMacro(NULL, "__plaintext_filename");
403 delMacro(NULL, "__signature_filename");
405 fpipe = fdopen(inpipe[1], "w");
406 (void) close(inpipe[0]);
408 fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
409 (void) fclose(fpipe);
412 (void) waitpid(pid, &status, 0);
413 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
414 rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
418 if (stat(sigfile, &st)) {
419 /* GPG failed to write signature */
420 if (sigfile) (void) unlink(sigfile); /* Just in case */
421 rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
425 *pktlen = st.st_size;
426 rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlen);
427 *pkt = xmalloc(*pktlen);
432 fd = Fopen(sigfile, "r.fdio");
433 if (fd != NULL && !Ferror(fd)) {
434 rc = timedRead(fd, *pkt, *pktlen);
435 if (sigfile) (void) unlink(sigfile);
440 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
445 rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlen);
451 static unsigned char header_magic[8] = {
452 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
456 * Generate header only signature(s) from a header+payload file.
457 * @param sig signature header
458 * @param file header+payload file name
459 * @param sigTag type of signature(s) to add
460 * @param passPhrase private key pass phrase
461 * @return 0 on success, -1 on failure
463 static int makeHDRSignature(Header sig, const char * file, int_32 sigTag,
464 /*@null@*/ const char * passPhrase)
465 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
466 /*@modifies sig, rpmGlobalMacroContext, fileSystem, internalState @*/
472 const char * fn = NULL;
473 const char * sha1 = NULL;
474 int ret = -1; /* assume failure. */
479 case RPMSIGTAG_PGP5: /* XXX legacy */
483 /*@notreached@*/ break;
485 fd = Fopen(file, "r.fdio");
486 if (fd == NULL || Ferror(fd))
488 h = headerRead(fd, HEADER_MAGIC_YES);
491 (void) Fclose(fd); fd = NULL;
493 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
498 if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
501 h = headerFree(h, NULL);
504 ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
505 (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
506 (void) rpmDigestUpdate(ctx, uh, uhc);
507 (void) rpmDigestFinal(ctx, (void **)&sha1, NULL, 1);
508 uh = headerFreeData(uh, uht);
510 h = headerFree(h, NULL);
514 if (!headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, sha1, 1))
519 fd = Fopen(file, "r.fdio");
520 if (fd == NULL || Ferror(fd))
522 h = headerRead(fd, HEADER_MAGIC_YES);
525 (void) Fclose(fd); fd = NULL;
526 if (makeTempFile(NULL, &fn, &fd))
528 if (headerWrite(fd, h, HEADER_MAGIC_YES))
530 (void) Fclose(fd); fd = NULL;
531 if (makeGPGSignature(fn, &pkt, &pktlen, passPhrase)
532 || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
537 fd = Fopen(file, "r.fdio");
538 if (fd == NULL || Ferror(fd))
540 h = headerRead(fd, HEADER_MAGIC_YES);
543 (void) Fclose(fd); fd = NULL;
544 if (makeTempFile(NULL, &fn, &fd))
546 if (headerWrite(fd, h, HEADER_MAGIC_YES))
548 (void) Fclose(fd); fd = NULL;
549 if (makePGPSignature(fn, &pkt, &pktlen, passPhrase)
550 || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
562 h = headerFree(h, NULL);
563 if (fd) (void) Fclose(fd);
567 int rpmAddSignature(Header sig, const char * file, int_32 sigTag,
568 const char * passPhrase)
573 int ret = -1; /* assume failure. */
577 if (stat(file, &st) != 0)
580 if (!headerAddEntry(sig, sigTag, RPM_INT32_TYPE, &pktlen, 1))
586 pkt = xcalloc(1, pktlen);
587 if (mdbinfile(file, pkt)
588 || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
592 case RPMSIGTAG_PGP5: /* XXX legacy */
594 if (makePGPSignature(file, &pkt, &pktlen, passPhrase)
595 || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
597 #ifdef NOTYET /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
598 /* XXX Piggyback a header-only RSA signature as well. */
599 ret = makeHDRSignature(sig, file, RPMSIGTAG_RSA, passPhrase);
604 if (makeGPGSignature(file, &pkt, &pktlen, passPhrase)
605 || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
607 /* XXX Piggyback a header-only DSA signature as well. */
608 ret = makeHDRSignature(sig, file, RPMSIGTAG_DSA, passPhrase);
613 ret = makeHDRSignature(sig, file, sigTag, passPhrase);
620 static int checkPassPhrase(const char * passPhrase, const int sigTag)
621 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
622 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
624 int passPhrasePipe[2];
629 passPhrasePipe[0] = passPhrasePipe[1] = 0;
630 xx = pipe(passPhrasePipe);
631 if (!(pid = fork())) {
636 xx = close(STDIN_FILENO);
637 xx = close(STDOUT_FILENO);
638 xx = close(passPhrasePipe[1]);
639 if (! rpmIsVerbose())
640 xx = close(STDERR_FILENO);
641 if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
642 xx = dup2(fdno, STDIN_FILENO);
645 if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
646 xx = dup2(fdno, STDOUT_FILENO);
649 xx = dup2(passPhrasePipe[0], 3);
654 { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
656 if (gpg_path && *gpg_path != '\0')
657 (void) dosetenv("GNUPGHOME", gpg_path, 1);
659 cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
660 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
662 rc = execve(av[0], av+1, environ);
664 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
666 } /*@notreached@*/ break;
668 case RPMSIGTAG_PGP5: /* XXX legacy */
670 { const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
674 (void) dosetenv("PGPPASSFD", "3", 1);
675 if (pgp_path && *pgp_path != '\0')
676 xx = dosetenv("PGPPATH", pgp_path, 1);
678 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
681 cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
682 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
684 rc = execve(av[0], av+1, environ);
685 /*@innerbreak@*/ break;
686 case PGP_5: /* XXX legacy */
687 cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
688 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
690 rc = execve(av[0], av+1, environ);
691 /*@innerbreak@*/ break;
693 case PGP_NOTDETECTED:
694 /*@innerbreak@*/ break;
697 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
700 } /*@notreached@*/ break;
701 default: /* This case should have been screened out long ago. */
702 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
703 _exit(RPMERR_SIGGEN);
704 /*@notreached@*/ break;
708 xx = close(passPhrasePipe[0]);
709 xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
710 xx = write(passPhrasePipe[1], "\n", 1);
711 xx = close(passPhrasePipe[1]);
713 (void) waitpid(pid, &status, 0);
715 return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
718 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
726 { const char *name = rpmExpand("%{?_gpg_name}", NULL);
727 aok = (name && *name != '\0');
731 rpmError(RPMERR_SIGGEN,
732 _("You must set \"%%_gpg_name\" in your macro file\n"));
737 case RPMSIGTAG_PGP5: /* XXX legacy */
739 { const char *name = rpmExpand("%{?_pgp_name}", NULL);
740 aok = (name && *name != '\0');
744 rpmError(RPMERR_SIGGEN,
745 _("You must set \"%%_pgp_name\" in your macro file\n"));
750 /* Currently the calling function (rpm.c:main) is checking this and
751 * doing a better job. This section should never be accessed.
753 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
755 /*@notreached@*/ break;
758 pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
760 if (checkPassPhrase(pass, sigTag))
766 static /*@observer@*/ const char * rpmSigString(rpmVerifySignatureReturn res)
771 case RPMSIG_OK: str = "OK"; break;
772 case RPMSIG_BAD: str = "BAD"; break;
773 case RPMSIG_NOKEY: str = "NOKEY"; break;
774 case RPMSIG_NOTTRUSTED: str = "NOTRUSTED"; break;
776 case RPMSIG_UNKNOWN: str = "UNKNOWN"; break;
781 static rpmVerifySignatureReturn
782 verifySizeSignature(const rpmTransactionSet ts, /*@out@*/ char * t)
785 rpmVerifySignatureReturn res;
786 int_32 size = 0x7fffffff;
789 t = stpcpy(t, _("Header+Payload size: "));
791 if (ts->sig == NULL || ts->dig == NULL || ts->dig->nbytes == 0) {
792 res = RPMSIG_NOKEY; /* XXX RPMSIG_ARGS */
794 t = stpcpy(t, rpmSigString(res));
798 memcpy(&size, ts->sig, sizeof(size));
800 if (size != ts->dig->nbytes) {
802 t = stpcpy(t, rpmSigString(res));
803 sprintf(t, " Expected(%d) != (%d)\n", size, ts->dig->nbytes);
806 t = stpcpy(t, rpmSigString(res));
807 sprintf(t, " (%d)", ts->dig->nbytes);
815 static rpmVerifySignatureReturn
816 verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t,
817 /*@null@*/ DIGEST_CTX md5ctx)
820 rpmVerifySignatureReturn res;
821 byte * md5sum = NULL;
825 t = stpcpy(t, _("MD5 digest: "));
827 if (md5ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
828 res = RPMSIG_NOKEY; /* XXX RPMSIG_ARGS */
829 t = stpcpy(t, rpmSigString(res));
833 (void) rpmDigestFinal(rpmDigestDup(md5ctx),
834 (void **)&md5sum, &md5len, 0);
836 if (md5len != ts->siglen || memcmp(md5sum, ts->sig, md5len)) {
838 t = stpcpy(t, rpmSigString(res));
839 t = stpcpy(t, " Expected(");
840 (void) pgpHexCvt(t, ts->sig, ts->siglen);
842 t = stpcpy(t, ") != (");
845 t = stpcpy(t, rpmSigString(res));
848 (void) pgpHexCvt(t, md5sum, md5len);
853 md5sum = _free(md5sum);
859 * Verify header immutable region SHA1 digest.
860 * @param ts transaction set
861 * @retval t verbose success/failure text
863 * @return RPMSIG_OK on success
865 static rpmVerifySignatureReturn
866 verifySHA1Signature(const rpmTransactionSet ts, /*@out@*/ char * t,
867 /*@null@*/ DIGEST_CTX sha1ctx)
870 rpmVerifySignatureReturn res;
871 const char * sha1 = NULL;
874 t = stpcpy(t, _("Header SHA1 digest: "));
876 if (sha1ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
877 res = RPMSIG_NOKEY; /* XXX RPMSIG_ARGS */
878 t = stpcpy(t, rpmSigString(res));
882 (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
883 (void **)&sha1, NULL, 1);
885 if (sha1 == NULL || strlen(sha1) != strlen(ts->sig)) {
887 t = stpcpy(t, rpmSigString(res));
888 t = stpcpy(t, " Expected(");
889 t = stpcpy(t, ts->sig);
890 t = stpcpy(t, ") != (");
893 t = stpcpy(t, rpmSigString(res));
907 * Retrieve pubkey from rpm database.
908 * @param ts rpm transaction
909 * @return RPMSIG_OK on success, RPMSIG_NOKEY if not found
911 static rpmVerifySignatureReturn
912 rpmtsFindPubkey(rpmTransactionSet ts)
913 /*@globals fileSystem, internalState @*/
914 /*@modifies ts, fileSystem, internalState */
916 struct pgpDigParams_s * sigp = NULL;
917 rpmVerifySignatureReturn res;
918 /*@unchecked@*/ /*@only@*/ static const byte * pkpkt = NULL;
919 /*@unchecked@*/ static size_t pkpktlen = 0;
920 /*@unchecked@*/ static byte pksignid[8];
923 if (ts->sig == NULL || ts->dig == NULL) {
927 sigp = &ts->dig->signature;
929 if (pkpkt == NULL || memcmp(sigp->signid, pksignid, sizeof(pksignid))) {
931 rpmdbMatchIterator mi;
934 pkpkt = _free(pkpkt);
936 memset(pksignid, 0, sizeof(pksignid));
938 /* Make sure the database is open. */
939 (void) rpmtsOpenDB(ts, ts->dbmode);
941 /* Retrieve the pubkey that matches the signature. */
942 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
943 while ((h = rpmdbNextIterator(mi)) != NULL) {
944 const char ** pubkeys;
947 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
949 ix = rpmdbGetIteratorFileNum(mi);
951 || b64decode(pubkeys[ix], (void **) &pkpkt, &pkpktlen))
953 pubkeys = headerFreeData(pubkeys, pt);
956 mi = rpmdbFreeIterator(mi);
958 /* Was a matching pubkey found? */
959 if (ix < 0 || pkpkt == NULL) {
965 * Can the pubkey packets be parsed?
966 * Do the parameters match the signature?
968 if (pgpPrtPkts(pkpkt, pkpktlen, NULL, 0)
969 && ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo
971 && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo
973 && !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
975 pkpkt = _free(pkpkt);
981 /* XXX Verify the pubkey signature. */
983 /* Packet looks good, save the signer id. */
984 memcpy(pksignid, sigp->signid, sizeof(pksignid));
986 rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %s\n",
987 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
988 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
989 pgpHexStr(sigp->signid, sizeof(sigp->signid)));
996 const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL);
997 if (pgpReadPkts(pkfn, &pkpkt, &pkpktlen) != PGPARMOR_PUBKEY) {
1007 /* Retrieve parameters from pubkey packet(s). */
1008 xx = pgpPrtPkts(pkpkt, pkpktlen, ts->dig, 0);
1010 /* Do the parameters match the signature? */
1011 if (ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo
1013 && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo
1015 && !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
1020 /* XXX Verify the signature signature. */
1027 * Convert hex to binary nibble.
1028 * @param c hex character
1029 * @return binary nibble
1031 static inline unsigned char nibble(char c)
1034 if (c >= '0' && c <= '9')
1036 if (c >= 'A' && c <= 'F')
1037 return (c - 'A') + 10;
1038 if (c >= 'a' && c <= 'f')
1039 return (c - 'a') + 10;
1044 * Verify PGP (aka RSA/MD5) signature.
1045 * @param ts transaction set
1046 * @retval t verbose success/failure text
1048 * @return RPMSIG_OK on success
1050 static rpmVerifySignatureReturn
1051 verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t,
1052 /*@null@*/ DIGEST_CTX md5ctx)
1053 /*@globals fileSystem, internalState @*/
1054 /*@modifies ts, *t, fileSystem, internalState */
1056 struct pgpDigParams_s * sigp = NULL;
1057 rpmVerifySignatureReturn res;
1061 t = stpcpy(t, _("V3 RSA/MD5 signature: "));
1063 if (md5ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
1064 res = RPMSIG_NOKEY; /* XXX RPMSIG_ARGS */
1067 sigp = &ts->dig->signature;
1069 /* XXX sanity check on ts->sigtag and signature agreement. */
1070 if (!(ts->sigtag == RPMSIGTAG_PGP
1071 && sigp->pubkey_algo == PGPPUBKEYALGO_RSA
1072 && sigp->hash_algo == PGPHASHALGO_MD5))
1078 { DIGEST_CTX ctx = rpmDigestDup(md5ctx);
1082 if (sigp->hash != NULL)
1083 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
1085 #ifdef NOTYET /* XXX not for binary/text document signatures. */
1086 if (sigp->sigtype == 4) {
1087 int nb = ts->dig->nbytes + sigp->hashlen;
1092 memcpy(trailer+2, &nb, sizeof(nb));
1093 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
1097 xx = rpmDigestFinal(ctx, (void **)&ts->dig->md5, &ts->dig->md5len, 1);
1099 /* Compare leading 16 bits of digest for quick check. */
1101 signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]);
1102 signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]);
1103 if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
1110 { const char * prefix = "3020300c06082a864886f70d020505000410";
1111 unsigned int nbits = 1024;
1112 unsigned int nb = (nbits + 7) >> 3;
1113 const char * hexstr;
1116 hexstr = tt = xmalloc(2 * nb + 1);
1117 memset(tt, 'f', (2 * nb));
1118 tt[0] = '0'; tt[1] = '0';
1119 tt[2] = '0'; tt[3] = '1';
1120 tt += (2 * nb) - strlen(prefix) - strlen(ts->dig->md5) - 2;
1121 *tt++ = '0'; *tt++ = '0';
1122 tt = stpcpy(tt, prefix);
1123 tt = stpcpy(tt, ts->dig->md5);
1125 mp32nzero(&ts->dig->rsahm); mp32nsethex(&ts->dig->rsahm, hexstr);
1127 hexstr = _free(hexstr);
1131 /* Retrieve the matching public key. */
1132 res = rpmtsFindPubkey(ts);
1133 if (res != RPMSIG_OK)
1136 if (rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c))
1142 t = stpcpy(t, rpmSigString(res));
1144 t = stpcpy(t, ", key ID ");
1145 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
1148 t = stpcpy(t, "\n");
1153 * Verify GPG (aka DSA) signature.
1154 * @param ts transaction set
1155 * @retval t verbose success/failure text
1157 * @return RPMSIG_OK on success
1159 static rpmVerifySignatureReturn
1160 verifyGPGSignature(rpmTransactionSet ts, /*@out@*/ char * t,
1161 /*@null@*/ DIGEST_CTX sha1ctx)
1162 /*@globals fileSystem, internalState @*/
1163 /*@modifies ts, *t, fileSystem, internalState */
1165 struct pgpDigParams_s * sigp = NULL;
1166 rpmVerifySignatureReturn res;
1170 if (ts->dig != NULL && ts->dig->hdrsha1ctx == sha1ctx)
1171 t = stpcpy(t, _("Header "));
1172 t = stpcpy(t, _("V3 DSA signature: "));
1174 if (sha1ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
1175 res = RPMSIG_NOKEY; /* XXX RPMSIG_ARGS */
1178 sigp = &ts->dig->signature;
1180 /* XXX sanity check on ts->sigtag and signature agreement. */
1181 if (!((ts->sigtag == RPMSIGTAG_GPG || ts->sigtag == RPMSIGTAG_DSA)
1182 && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
1183 && sigp->hash_algo == PGPHASHALGO_SHA1))
1189 { DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
1192 if (sigp->hash != NULL)
1193 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
1195 #ifdef NOTYET /* XXX not for binary/text document signatures. */
1196 if (sigp->sigtype == 4) {
1197 int nb = ts->dig->nbytes + sigp->hashlen;
1202 memcpy(trailer+2, &nb, sizeof(nb));
1203 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
1206 xx = rpmDigestFinal(ctx, (void **)&ts->dig->sha1, &ts->dig->sha1len, 1);
1208 mp32nzero(&ts->dig->hm); mp32nsethex(&ts->dig->hm, ts->dig->sha1);
1210 /* Compare leading 16 bits of digest for quick check. */
1211 signhash16[0] = (*ts->dig->hm.data >> 24) & 0xff;
1212 signhash16[1] = (*ts->dig->hm.data >> 16) & 0xff;
1213 if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
1219 /* Retrieve the matching public key. */
1220 res = rpmtsFindPubkey(ts);
1221 if (res != RPMSIG_OK)
1224 if (dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g,
1225 &ts->dig->hm, &ts->dig->y, &ts->dig->r, &ts->dig->s))
1231 t = stpcpy(t, rpmSigString(res));
1233 t = stpcpy(t, ", key ID ");
1234 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
1237 t = stpcpy(t, "\n");
1241 rpmVerifySignatureReturn
1242 rpmVerifySignature(const rpmTransactionSet ts, char * result)
1244 rpmVerifySignatureReturn res;
1246 if (ts->sig == NULL || ts->siglen <= 0 || ts->dig == NULL) {
1247 sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
1248 return RPMSIG_UNKNOWN;
1251 switch (ts->sigtag) {
1252 case RPMSIGTAG_SIZE:
1253 res = verifySizeSignature(ts, result);
1256 res = verifyMD5Signature(ts, result, ts->dig->md5ctx);
1258 case RPMSIGTAG_SHA1:
1259 res = verifySHA1Signature(ts, result, ts->dig->hdrsha1ctx);
1262 case RPMSIGTAG_PGP5: /* XXX legacy */
1264 res = verifyPGPSignature(ts, result, ts->dig->md5ctx);
1267 res = verifyGPGSignature(ts, result, ts->dig->hdrsha1ctx);
1270 res = verifyGPGSignature(ts, result, ts->dig->sha1ctx);
1272 case RPMSIGTAG_LEMD5_1:
1273 case RPMSIGTAG_LEMD5_2:
1274 sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
1275 res = RPMSIG_UNKNOWN;
1278 sprintf(result, _("Signature: UNKNOWN (%d)\n"), ts->sigtag);
1279 res = RPMSIG_UNKNOWN;