I note that rpm 3.0.3 recognises the compatibility between PGP 2 and PGP 5 as I and maybe others have suggested. (Bug report #4780, for example.) The same kind of compatibility exists between GPG and the PGP version. Signatures generated by a PGP version can be verified by GPG, and signatures generated by GPG can be verified by PGP, if the algorithm is supported (RSA for PGP 2; RSA and DSS for PGP 5; DSS and ELG for GPG). Please find enclosed for your consideration a patch to make rpm utilize this compatibility. They are also available as ftp://ftp.carmen.se/pub/rpm/rpm.gpg My modified rpm packages are also available there. I've expanded rpmDetectPGPVersion() to look for the GPG also. Since there isn't any macro like %_pgpbin to look for, I had to try to execute "gpg --version", and decide depending on exit status. There are a few points where it could be discussed what the best choice is. My choices are definitiely not obviously the best. One issue is to know what program to use. The order of preference is not obvious. While PGP 5 supports everything PGP 2 supports, there is no such relation between PGP 5 and GPG. GPG supports ELG, PGP 5 RSA, and both DSS. I've rather arbitrarily choosen to try GPG first. You may have different preferences. Maybe it would be better to introduce another macro to choose what version of PGP/GPG to use for signing? The values are the same as used for the (now obsolete) %_signature macro. Reusing it would lead to confusion, and the name isn't really good for the new meaning; but maybe a %_pgpversion macro should be introduced. Maybe the lookup algorithm could be used as a fallback? Another issue is what name to use for these signatures. (In user messages, in macro names, etc.) I've used "PGP" in all cases, in recognition of that program being the first. But perhaps the name should be omitted, and only the name "signature" or "sig" for short, should be used throughout. =========================================================== --- lib/rpmlib.h.orig Thu Sep 23 19:01:00 1999 +++ lib/rpmlib.h Tue Oct 26 10:04:33 1999 @@ -590,7 +590,7 @@ #define RPMSIGTAG_PGP 1002 #define RPMSIGTAG_LEMD5_2 1003 #define RPMSIGTAG_MD5 1004 -#define RPMSIGTAG_GPG 1005 +#define RPMSIGTAG_GPG 1005 /* XXX legacy use only */ #define RPMSIGTAG_PGP5 1006 /* XXX legacy use only */ /* Signature tags by Public Key Algorithm (RFC 2440) */ @@ -715,7 +715,6 @@ #define CHECKSIG_PGP (1 << 0) #define CHECKSIG_MD5 (1 << 1) -#define CHECKSIG_GPG (1 << 2) int rpmCheckSig(int flags, const char **argv); int rpmReSign(int add, char *passPhrase, const char **argv); --- lib/rpmchecksig.c.orig Wed Sep 22 20:13:32 1999 +++ lib/rpmchecksig.c Tue Oct 26 10:04:33 1999 @@ -280,14 +280,11 @@ while (headerNextIterator(sigIter, &tag, &type, &ptr, &count)) { switch (tag) { case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_GPG: /* XXX legacy */ case RPMSIGTAG_PGP: if (!(flags & CHECKSIG_PGP)) continue; break; - case RPMSIGTAG_GPG: - if (!(flags & CHECKSIG_GPG)) - continue; - break; case RPMSIGTAG_LEMD5_2: case RPMSIGTAG_LEMD5_1: case RPMSIGTAG_MD5: @@ -318,6 +315,7 @@ res2 = 1; break; case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_GPG: /* XXX legacy */ case RPMSIGTAG_PGP: switch (res3) { /* Do not consider these a failure */ @@ -325,7 +323,9 @@ case RPMSIG_NOTTRUSTED: { int offset = 7; strcat(buffer, "(PGP) "); - tempKey = strstr(result, "Key ID"); + tempKey = strstr(result, "key ID"); + if (tempKey == NULL) + tempKey = strstr(result, "Key ID"); if (tempKey == NULL) { tempKey = strstr(result, "keyid:"); offset = 9; @@ -346,22 +346,6 @@ break; } break; - case RPMSIGTAG_GPG: - /* Do not consider this a failure */ - switch (res3) { - case RPMSIG_NOKEY: - strcat(buffer, "(GPG) "); - strcat(missingKeys, " GPG#"); - tempKey = strstr(result, "key ID"); - if (tempKey) - strncat(missingKeys, tempKey+7, 8); - break; - default: - strcat(buffer, "GPG "); - res2 = 1; - break; - } - break; default: strcat(buffer, "?UnknownSignatureType? "); res2 = 1; @@ -382,11 +366,9 @@ strcat(buffer, "md5 "); break; case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_GPG: /* XXX legacy */ case RPMSIGTAG_PGP: strcat(buffer, "pgp "); - break; - case RPMSIGTAG_GPG: - strcat(buffer, "gpg "); default: strcat(buffer, "??? "); --- lib/signature.h.orig Tue Sep 21 20:34:56 1999 +++ lib/signature.h Tue Oct 26 10:04:33 1999 @@ -56,15 +56,17 @@ int rpmLookupSignatureType(int action); /* Utility to read a pass phrase from the user */ -char *rpmGetPassPhrase(const char *prompt, const int sigTag); +char *rpmGetPassPhrase(const char *prompt); /* >0 is a valid PGP version */ +/* GPG means GPG v1. Presumably PGP won't reach version 101, so no + conflict will arise. */ typedef enum pgpVersion_e { - PGP_NOTDETECTED = -1, PGP_UNKNOWN = 0, PGP_2 = 2, PGP_5 = 5 + PGP_NOTDETECTED = -1, PGP_UNKNOWN = 0, PGP_2 = 2, PGP_5 = 5, GPG = 101 } pgpVersion; -/* Return path to pgp executable of given type, or NULL when not found */ -const char *rpmDetectPGPVersion(/*@out@*/pgpVersion *pgpVersion); +/* Return type of PGP, and path if PGP_2 or PGP_5 */ +pgpVersion rpmDetectPGPVersion(/*@out@*/const char **pgpPath); #ifdef __cplusplus } --- lib/signature.c.orig Tue Sep 21 20:34:56 1999 +++ lib/signature.c Tue Oct 26 11:11:04 1999 @@ -48,8 +48,8 @@ rc = RPMSIGTAG_PGP; else if (!strcasecmp(name, "pgp5")) /* XXX legacy */ rc = RPMSIGTAG_PGP; - else if (!strcasecmp(name, "gpg")) - rc = RPMSIGTAG_GPG; + else if (!strcasecmp(name, "gpg")) /* XXX legacy */ + rc = RPMSIGTAG_PGP; else rc = -1; /* Invalid %_signature spec in macro file */ xfree(name); @@ -61,7 +61,7 @@ /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */ /* executable of the requested version, or NULL when none found. */ -const char * rpmDetectPGPVersion(pgpVersion *pgpVer) +pgpVersion rpmDetectPGPVersion(const char **pgpPath) { /* Actually this should support having more then one pgp version. */ /* At the moment only one version is possible since we only */ @@ -73,14 +73,23 @@ if (saved_pgp_version == PGP_UNKNOWN) { char *pgpvbin; struct stat statbuf; + int pid, pstatus; - if (!pgpbin || ! (pgpvbin = (char *)alloca(strlen(pgpbin) + 2))) { - saved_pgp_version = -1; - return NULL; + if (!(pid = fork())) { + close(STDOUT_FILENO); + execlp("gpg", "gpg", "--version", NULL); + _exit(RPMERR_EXEC); } + + (void)waitpid(pid, &pstatus, 0); + + if (!pgpbin || ! (pgpvbin = (char *)alloca(strlen(pgpbin) + 2))) + return saved_pgp_version = -1; sprintf(pgpvbin, "%sv", pgpbin); - if (stat(pgpvbin, &statbuf) == 0) + if (WIFEXITED(pstatus) && WEXITSTATUS(pstatus) == 0) + saved_pgp_version = GPG; + else if (stat(pgpvbin, &statbuf) == 0) saved_pgp_version = PGP_5; else if (stat(pgpbin, &statbuf) == 0) saved_pgp_version = PGP_2; @@ -88,9 +97,10 @@ saved_pgp_version = PGP_NOTDETECTED; } - if (pgpbin && pgpVer) - *pgpVer = saved_pgp_version; - return pgpbin; + if (pgpbin && (saved_pgp_version==PGP_2 || saved_pgp_version==PGP_5) + && pgpPath) + *pgpPath = pgpbin; + return saved_pgp_version; } static int checkSize(FD_t fd, int size, int sigsize) @@ -248,7 +258,7 @@ /* dosetenv("PGPPASS", passPhrase, 1); */ - if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { + if ((pgpVer = rpmDetectPGPVersion(&path)) > 0 && path != NULL) { switch(pgpVer) { case PGP_2: execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off", @@ -258,6 +268,7 @@ execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off", name, "-b", file, "-o", sigfile, NULL); break; + case GPG: case PGP_UNKNOWN: case PGP_NOTDETECTED: break; @@ -328,7 +339,11 @@ if (!(pid = fork())) { const char *gpg_path = rpmExpand("%{_gpg_path}", NULL); - const char *name = rpmExpand("%{_gpg_name}", NULL); + const char *name = rpmExpand("%{_pgp_name}", NULL); + + /* Support _gpg_name for backward compatibility. */ + if (!name) + name = rpmExpand("%{_gpg_name}", NULL); close(STDIN_FILENO); dup2(inpipe[0], 3); @@ -405,15 +420,23 @@ headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16); break; case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_GPG: /* XXX legacy */ case RPMSIGTAG_PGP: - rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n")); - ret = makePGPSignature(file, &sig, &size, passPhrase); - if (ret == 0) - headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size); - break; - case RPMSIGTAG_GPG: - rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n")); - ret = makeGPGSignature(file, &sig, &size, passPhrase); + switch (rpmDetectPGPVersion(NULL)) { + case PGP_2: + case PGP_5: + rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n")); + ret = makePGPSignature(file, &sig, &size, passPhrase); + break; + case GPG: + rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n")); + ret = makeGPGSignature(file, &sig, &size, passPhrase); + break; + default: + rpmError(RPMERR_SIGGEN, _("no pgp version found")); + ret = 1; + break; + } if (ret == 0) headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size); break; @@ -486,7 +509,7 @@ pgpVersion pgpVer; /* What version do we have? */ - if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) { + if ((pgpVer = rpmDetectPGPVersion(&path)) <= 0 || path == NULL) { errno = ENOENT; rpmError(RPMERR_EXEC, _("Could not run pgp. Use --nopgp to skip PGPchecks.")); @@ -544,6 +567,7 @@ execlp(path, "pgp", "+batchmode=on", "+verbose=0", sigfile, datafile, NULL); break; + case GPG: case PGP_UNKNOWN: case PGP_NOTDETECTED: break; @@ -648,7 +672,7 @@ return res; } -static int checkPassPhrase(const char *passPhrase, const int sigTag) +static int checkPassPhrase(const char *passPhrase) { int passPhrasePipe[2]; int pid, status; @@ -673,10 +697,13 @@ } dup2(passPhrasePipe[0], 3); - switch (sigTag) { - case RPMSIGTAG_GPG: + switch (rpmDetectPGPVersion(NULL)) { + case GPG: { const char *gpg_path = rpmExpand("%{_gpg_path}", NULL); - const char *name = rpmExpand("%{_gpg_name}", NULL); + const char *name = rpmExpand("%{_pgp_name}", NULL); + /* Support _gpg_name for backward compatibility. */ + if (!name) + name = rpmExpand("%{_gpg_name}", NULL); if (gpg_path && *gpg_path != '%') dosetenv("GNUPGHOME", gpg_path, 1); execlp("gpg", "gpg", @@ -686,8 +713,8 @@ rpmError(RPMERR_EXEC, _("Couldn't exec gpg")); _exit(RPMERR_EXEC); } /*@notreached@*/ break; - case RPMSIGTAG_PGP5: /* XXX legacy */ - case RPMSIGTAG_PGP: + case PGP_2: + case PGP_5: { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL); const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL); const char *path; @@ -697,7 +724,8 @@ if (pgp_path && *pgp_path != '%') dosetenv("PGPPATH", pgp_path, 1); - if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { + pgpVer = rpmDetectPGPVersion(&path); + if (path != NULL) { switch(pgpVer) { case PGP_2: execlp(path, "pgp", "+batchmode=on", "+verbose=0", @@ -707,6 +735,7 @@ execlp(path,"pgps", "+batchmode=on", "+verbose=0", name, "-f", NULL); break; + case GPG: case PGP_UNKNOWN: case PGP_NOTDETECTED: break; @@ -736,47 +765,30 @@ return 0; } -char *rpmGetPassPhrase(const char *prompt, const int sigTag) +char *rpmGetPassPhrase(const char *prompt) { char *pass; int aok; - switch (sigTag) { - case RPMSIGTAG_GPG: - { const char *name = rpmExpand("%{_gpg_name}", NULL); - aok = (name && *name != '%'); - xfree(name); - } - if (!aok) { - rpmError(RPMERR_SIGGEN, - _("You must set \"%%_gpg_name\" in your macro file")); - return NULL; - } - break; - case RPMSIGTAG_PGP5: /* XXX legacy */ - case RPMSIGTAG_PGP: - { const char *name = rpmExpand("%{_pgp_name}", NULL); - aok = (name && *name != '%'); - xfree(name); - } - if (!aok) { - rpmError(RPMERR_SIGGEN, - _("You must set \"%%_pgp_name\" in your macro file")); - return NULL; - } - break; - default: - /* Currently the calling function (rpm.c:main) is checking this and - * doing a better job. This section should never be accessed. - */ - rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file")); + { const char *name = rpmExpand("%{_pgp_name}", NULL); + aok = (name && *name != '%'); + xfree(name); + } + /* Support _gpg_name for backward compatibility. */ + if (!aok) { + const char *name = rpmExpand("%{_gpg_name}", NULL); + aok = (name && *name != '%'); + xfree(name); + } + if (!aok) { + rpmError(RPMERR_SIGGEN, + _("You must set \"%%_pgp_name\" in your macro file")); return NULL; - /*@notreached@*/ break; } pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ; - if (checkPassPhrase(pass, sigTag)) + if (checkPassPhrase(pass)) return NULL; return pass; @@ -803,11 +815,18 @@ } break; case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_GPG: /* XXX legacy */ case RPMSIGTAG_PGP: - return verifyPGPSignature(file, sig, count, result); - /*@notreached@*/ break; - case RPMSIGTAG_GPG: - return verifyGPGSignature(file, sig, count, result); + switch (rpmDetectPGPVersion(NULL)) { + case PGP_2: + case PGP_5: + return verifyPGPSignature(file, sig, count, result); + case GPG: + return verifyGPGSignature(file, sig, count, result); + default: + rpmError(RPMERR_EXEC, _("no pgp version found")); + break; + } /*@notreached@*/ break; default: sprintf(result, "Do not know how to verify sig type %d\n", sigTag); --- rpm.c.orig Tue Sep 21 20:34:55 1999 +++ rpm.c Tue Oct 26 10:04:33 1999 @@ -46,7 +46,6 @@ static int initdb; static int justdb; static int noDeps; -static int noGpg; static int noMd5; static int noOrder; static int noPgp; @@ -105,7 +104,7 @@ { "install", '\0', 0, 0, GETOPT_INSTALL, NULL, NULL}, { "justdb", '\0', 0, &justdb, 0, NULL, NULL}, { "nodeps", '\0', 0, &noDeps, 0, NULL, NULL}, - { "nogpg", '\0', 0, &noGpg, 0, NULL, NULL}, + { "nogpg", '\0', 0, &noPgp, 0, NULL, NULL}, { "nomd5", '\0', 0, &noMd5, 0, NULL, NULL}, { "noorder", '\0', 0, &noOrder, 0, NULL, NULL}, { "nopgp", '\0', 0, &noPgp, 0, NULL, NULL}, @@ -227,7 +226,7 @@ puts(_(" rpm {--recompile} [--rcfile <file>] [-v] source1.rpm ... sourceN.rpm")); puts(_(" rpm {--resign} [--rcfile <file>] package1 package2 ... packageN")); puts(_(" rpm {--addsign} [--rcfile <file>] package1 package2 ... packageN")); - puts(_(" rpm {--checksig -K} [--nopgp] [--nogpg] [--nomd5] [--rcfile <file>]")); + puts(_(" rpm {--checksig -K} [--nopgp] [--nomd5] [--rcfile <file>]")); puts(_(" package1 ... packageN")); puts(_(" rpm {--rebuilddb} [--rcfile <file>] [--dbpath <dir>]")); puts(_(" rpm {--querytags}")); @@ -457,7 +456,7 @@ printHelpLine( " --rmsource ", _("remove sources and spec file when done")); printHelpLine( " --sign ", - _("generate PGP/GPG signature")); + _("generate PGP signature")); printHelpLine(_(" --buildroot <dir> "), _("use <dir> as the build root")); printHelpLine(_(" --target=<platform>+"), @@ -482,8 +481,6 @@ _("verify package signature")); printHelpLine( " --nopgp ", _("skip any PGP signatures")); - printHelpLine( " --nogpg ", - _("skip any GPG signatures")); printHelpLine( " --nomd5 ", _("skip any MD5 signatures")); printHelpLine( " --querytags ", @@ -525,7 +522,6 @@ int p[2]; rpmRelocation * relocations = NULL; int numRelocations = 0; - int sigTag; int upgrade = 0; int probFilter = 0; @@ -552,7 +548,6 @@ initdb = 0; justdb = 0; noDeps = 0; - noGpg = 0; noMd5 = 0; noOrder = 0; noPgp = 0; @@ -1030,9 +1025,6 @@ if (noPgp && bigMode != MODE_CHECKSIG) argerror(_("--nopgp may only be used during signature checking")); - if (noGpg && bigMode != MODE_CHECKSIG) - argerror(_("--nogpg may only be used during signature checking")); - if (noMd5 && bigMode != MODE_CHECKSIG && bigMode != MODE_VERIFY) argerror(_("--nomd5 may only be used during signature checking and " "package verification")); @@ -1072,17 +1064,15 @@ if (errors) return errors; if (poptPeekArg(optCon)) { - switch (sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) { + switch (rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) { case 0: break; case RPMSIGTAG_PGP: - if ((sigTag == RPMSIGTAG_PGP || sigTag == RPMSIGTAG_PGP5) && - !rpmDetectPGPVersion(NULL)) { + if (rpmDetectPGPVersion(NULL) <= 0) { fprintf(stderr, _("pgp not found: ")); exit(EXIT_FAILURE); - } /* fall through */ - case RPMSIGTAG_GPG: - passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag); + } + passPhrase = rpmGetPassPhrase(_("Enter pass phrase: ")); if (passPhrase == NULL) { fprintf(stderr, _("Pass phrase check failed\n")); exit(EXIT_FAILURE); @@ -1145,7 +1135,6 @@ if (!poptPeekArg(optCon)) argerror(_("no packages given for signature check")); if (!noPgp) checksigFlags |= CHECKSIG_PGP; - if (!noGpg) checksigFlags |= CHECKSIG_GPG; if (!noMd5) checksigFlags |= CHECKSIG_MD5; ec = rpmCheckSig(checksigFlags, (const char **)poptGetArgs(optCon)); /* XXX don't overflow single byte exit status */ --- macros.in.orig Tue Sep 21 20:34:55 1999 +++ macros.in Tue Oct 26 10:04:33 1999 @@ -99,7 +99,6 @@ #%_excludedocs #%_ftpport #%_ftpproxy -#%_gpg_name #%_gpg_path #%_httpport #%_httpproxy
Thanks for the patch. Could you reply to this message with the patch attached? I hate html :=(
Soon after rpm-4.0.3, the manner in which packages are digitally signed and verified is gonna change, Basically, DSA is going to be implemented directly in rpm, so there's little reason to keep this bug open anymore.