This is slightly related to my previous report 4564. It appears there is still some confusion considering the compatiblity between PGP 2 and PGP 5. In the header of an rpm file there are two different kinds of signature tags, RPMSIGTAG_PGP and RPMSIGTAG_PGP5. When creating a signature using PGP 2 the former tag is used, and when signing with PGP 5 the latter. But compatibility doesn't depend on the PGP version used, but on the kind of KEY used. PGP 2 understands only RSA keys. PGP 5 understands both RSA and DSS keys. So if I sign a package with PGP 5 using a RSA key, it will be possible to verify that package with PGP 2. It doesn't make sense to distinguish the signatures depending on which PGP version has been used to sign it. It would make sense to have different kinds of tags for different kinds of keys. But it would require quite some parsing to determine this, and the value of this seems dubious. So below I enclose a suggested patch te remove the distinction between the PGP and PGP5 tag. I have tested this, sending signed packages between a system with PGP 2 and one with PGP 5. On the PGP 2 system I have used both stock rpm 3.0.2 6.0, and my own modified version. The only combination which fails, is when trying to verify a package which has been signed with a DSS key on the PGP 2 system. And that is to be expected. As a further illustration I have put my modified RPM packages on ftp://ftp.carmen.se/rpm These are all signed using PGP 5, and verified with PGP 2. (Except the one with the .dss suffix, that is.) My keys, if you want them, are available as http://www.uddeborg.pp.se/g%f6ran/rsa.asc and http://www.uddeborg.pp.se/g%f6ran/dss.asc respectively. My DSS key is also available from the key servers. The source RPM package contains the patch included below, if you find it more convenient to get it that way. I BELIEVE that GPG is also compatible with PGP on a "common key type" level. But I don't know for sure, and I think I'll wait to install GPG until they release version 1.0, next month according to their home page. So I haven't touched the GPG part of the code in RPM in this patch. Anayway, it would be interesting to see the response to this report before I spend any time on GPG. --- lib/rpmlib.h~ Wed Jun 23 21:39:57 1999 +++ lib/rpmlib.h Tue Aug 24 12:26:34 1999 @@ -578,7 +578,6 @@ rpmErrorCallBackType rpmErrorSetCallback #define RPMSIGTAG_LEMD5_2 1003 #define RPMSIGTAG_MD5 1004 #define RPMSIGTAG_GPG 1005 -#define RPMSIGTAG_PGP5 1006 /**************************************************/ /* */ --- lib/signature.h~ Mon Mar 22 17:38:54 1999 +++ lib/signature.h Tue Aug 24 12:31:29 1999 @@ -54,7 +54,11 @@ int rpmLookupSignatureType(int action); /* Utility to read a pass phrase from the user */ char *rpmGetPassPhrase(const char *prompt, const int sigTag); +/* Possible syntax versions for PGP. */ +#define PGP_2 0 +#define PGP_5 2 + /* Return path to pgp executable of given type, or NULL when not found */ -const char *rpmDetectPGPVersion(int sigType); +const char *rpmDetectPGPVersion(int *pgpVersion); #endif /* H_SIGNATURE */ --- lib/signature.c~ Tue Aug 24 11:05:55 1999 +++ lib/signature.c Tue Aug 24 12:46:29 1999 @@ -24,7 +24,7 @@ typedef int (*md5func)(const char * fn, unsigned char * digest); static int makePGPSignature(const char *file, void **sig, int_32 *size, - const char *passPhrase, int sigTag); + const char *passPhrase); static int makeGPGSignature(const char *file, void **sig, int_32 *size, const char *passPhrase); static int checkSize(FD_t fd, int size, int sigsize); @@ -32,7 +32,7 @@ static int verifySizeSignature(const cha static int verifyMD5Signature(const char *datafile, unsigned char *sig, char *result, md5func fn); static int verifyPGPSignature(const char *datafile, void *sig, - int count, char *result, int sigTag);+ int count, char *result); static int verifyGPGSignature(const char *datafile, void *sig, int count, char *result); static int checkPassPhrase(const char *passPhrase, const int sigTag); @@ -61,8 +61,6 @@ int rpmLookupSignatureType(int action) rc = 0; else if (!strcasecmp(name, "pgp")) rc = RPMSIGTAG_PGP; - else if (!strcasecmp(name, "pgp5")) - rc = RPMSIGTAG_PGP5; else if (!strcasecmp(name, "gpg")) rc = RPMSIGTAG_GPG; else @@ -78,51 +76,40 @@ int rpmLookupSignatureType(int action) /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */ /* executable of the requested version, or NULL when none found. */ -const char * rpmDetectPGPVersion(int sigTag) +const char * rpmDetectPGPVersion(int *pgpVersion) { /* Actually this should support having more then one pgp version. */ /* At the moment only one version is possible since we only */ /* have one %_pgpbin and one %_pgp_path. */ - static int pgp_version; + static int saved_pgp_version; const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL); - if (!pgp_version) + if (!saved_pgp_version) { char *pgpvbin; struct stat statbuf; if (!pgpbin || ! (pgpvbin = (char *)malloc(strlen(pgpbin) + 2))) { - pgp_version = -1; + saved_pgp_version = -1; return NULL; } sprintf(pgpvbin, "%sv", pgpbin); if (stat(pgpvbin, &statbuf) == 0) - pgp_version = 50; + saved_pgp_version = PGP_5; else if (stat(pgpbin, &statbuf) == 0) - pgp_version = 26; + saved_pgp_version = PGP_2; else - pgp_version = -1; + saved_pgp_version = -1; free(pgpvbin); } - switch (sigTag) - { - case RPMSIGTAG_PGP: - if (pgp_version == 26) - return pgpbin; - break; - case RPMSIGTAG_PGP5: - if (pgp_version == 50) - return pgpbin; - break; - default: - break; - } - return NULL; + if (pgpbin && pgpVersion) + *pgpVersion = saved_pgp_version; + return pgpbin; } /* rpmReadSignature() emulates the new style signatures if it finds an */ @@ -248,8 +235,7 @@ int rpmAddSignature(Header header, const headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16); break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: - ret = makePGPSignature(file, &sig, &size, passPhrase, sigTag); + ret = makePGPSignature(file, &sig, &size, passPhrase); if (ret == 0) headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size); break; @@ -264,12 +250,13 @@ int rpmAddSignature(Header header, const } static int makePGPSignature(const char *file, void **sig, int_32 *size, - const char *passPhrase, int sigTag) + const char *passPhrase) { char sigfile[1024]; int pid, status; int inpipe[2]; struct stat statbuf; + int pgpVer; sprintf(sigfile, "%s.sig", file); @@ -290,13 +277,13 @@ static int makePGPSignature(const char * /* dosetenv("PGPPASS", passPhrase, 1); */ - if ((path = rpmDetectPGPVersion(sigTag)) != NULL) { - switch(sigTag) { - case RPMSIGTAG_PGP: + if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { + switch(pgpVer) { + case PGP_2: execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off", name, "-sb", file, sigfile, NULL); break; - case RPMSIGTAG_PGP5: + case PGP_5: execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off", name, "-b", file, "-o", sigfile, NULL); break; @@ -464,8 +451,7 @@ int rpmVerifySignature(const char *file, } break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: - return verifyPGPSignature(file, sig, count, result, sigTag); + return verifyPGPSignature(file, sig, count, result); break; case RPMSIGTAG_GPG: return verifyGPGSignature(file, sig, count, result); @@ -528,7 +514,7 @@ static int verifyMD5Signature(const char } static int verifyPGPSignature(const char *datafile, void *sig, - int count, char *result, int sigTag) + int count, char *result) { int pid, status, outpipe[2]; FD_t sfd; @@ -536,29 +522,24 @@ static int verifyPGPSignature(const char unsigned char buf[8192]; FILE *file; int res = RPMSIG_OK; - int usingPGP5 = 0; const char *path; + int pgpVer; /* What version do we have? */ - if ((path = rpmDetectPGPVersion(RPMSIGTAG_PGP5))/* Use pgp5 if we have it */ - || sigTag == RPMSIGTAG_PGP5) /* ... or request it. */ - { - usingPGP5 = 1; - /* Its sad but true: pgp-5.0 returns also an exit value of 0 */ - /* when it finds a BAD signature. So instead we have to use */ - /* the text output. */ - res = RPMSIG_BAD; - } - else if (! (path = rpmDetectPGPVersion(RPMSIGTAG_PGP)) - || sigTag != RPMSIGTAG_PGP) - path = NULL; /* Fail */ - if (path == NULL) + if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) { errno = ENOENT; rpmError(RPMERR_EXEC, _("Could not run pgp. Use --nopgp to skip PGP checks.")); _exit(RPMERR_EXEC); } + if (pgpVer == PGP_5) + { + /* Its sad but true: pgp-5.0 returns also an exit value of 0 */ + /* when it finds a BAD signature. So instead we have to use */ + /* the text output. */ + res = RPMSIG_BAD; + } /* Write out the signature */ { const char *tmppath = rpmGetPath("%{_tmppath}", NULL); sigfile = tempnam(tmppath, "rpmsig"); @@ -581,7 +562,7 @@ static int verifyPGPSignature(const char if (pgp_path && *pgp_path != '%') dosetenv("PGPPATH", pgp_path, 1); - if (usingPGP5) { + if (pgpVer == PGP_5) { /* Some output (in particular "This signature applies to */ /* another message") is _always_ written to stderr; we */ /* want to catch that output, so dup stdout to stderr: */ @@ -717,7 +698,6 @@ char *rpmGetPassPhrase(const char *promp } break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: { const char *name = rpmExpand("%{_pgp_name}", NULL); aok = (name && *name != '%'); xfree(name); @@ -787,22 +767,22 @@ static int checkPassPhrase(const char *p _exit(RPMERR_EXEC); } break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL); const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL); const char *path; + int pgpVer; dosetenv("PGPPASSFD", "3", 1); if (pgp_path && *pgp_path != '%') dosetenv("PGPPATH", pgp_path, 1); - if ((path = rpmDetectPGPVersion(sigTag)) != NULL) { - switch(sigTag) { - case RPMSIGTAG_PGP: + if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { + switch(pgpVer) { + case PGP_2: execlp(path, "pgp", "+batchmode=on", "+verbose=0", name, "-sf", NULL); break; - case RPMSIGTAG_PGP5: + case PGP_5: execlp(path,"pgps", "+batchmode=on", "+verbose=0", name, "-f", NULL); break; --- checksig.c~ Fri Jun 25 12:03:15 1999 +++ checksig.c Tue Aug 24 12:26:37 1999 @@ -216,7 +216,7 @@ int doCheckSig(int flags, const char **a sigIter = headerInitIterator(sig); while (headerNextIterator(sigIter, &tag, &type, &ptr, &count)) { - if ((tag == RPMSIGTAG_PGP || tag == RPMSIGTAG_PGP5) + if ((tag == RPMSIGTAG_PGP) && !(flags & CHECKSIG_PGP)) continue; if ((tag == RPMSIGTAG_GPG) && !(flags & CHECKSIG_GPG)) @@ -246,7 +246,6 @@ int doCheckSig(int flags, const char **a res2 = 1; break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: if (res3 == RPMSIG_NOKEY || res3 == RPMSIG_NOTTRUSTED) { /* Do not consider these a failure */ int offset = 7; @@ -302,7 +301,6 @@ int doCheckSig(int flags, const char **a strcat(buffer, "md5 "); break; case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: strcat(buffer, "pgp "); break; case RPMSIGTAG_GPG: --- rpm.c~ Wed Jun 30 23:10:31 1999 +++ rpm.c Tue Aug 24 12:26:39 1999 @@ -1139,25 +1139,9 @@ int main(int argc, char ** argv) break; case RPMSIGTAG_GPG: case RPMSIGTAG_PGP: - case RPMSIGTAG_PGP5: if (sigTag == RPMSIGTAG_PGP - && !rpmDetectPGPVersion(RPMSIGTAG_PGP)) { + && !rpmDetectPGPVersion(NULL)) { fprintf(stderr, _("pgp not found: ")); - if (rpmDetectPGPVersion(RPMSIGTAG_PGP5)) { - fprintf(stderr, - _("Use `%%_signature pgp5' instead of `%%_signature pgp' in macro file.\n")); - exit(EXIT_FAILURE); - } - /* Fall through to default: */ - } - else if (sigTag == RPMSIGTAG_PGP5 - && !rpmDetectPGPVersion(RPMSIGTAG_PGP5)) { - fprintf(stderr, _("pgp version 5 not found: ")); - if (rpmDetectPGPVersion(RPMSIGTAG_PGP)) { - fprintf(stderr, - _("Use `%%_signature pgp' instead of `%%_signature pgp5' in macro file.\n")); - exit(EXIT_FAILURE); - } /* Fall through to default:*/ } else if (!(passPhrase =
I just checked in this patch -- thank you! Next to come is associating algorithms with executables that understand same. That doesn't look too bad ...