lib/signature.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmio_internal.h"
00008 #include <rpmlib.h>
00009 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
00010 #include "rpmdb.h"
00011 
00012 #include "rpmts.h"
00013 
00014 #include "misc.h"       /* XXX for dosetenv() and makeTempFile() */
00015 #include "legacy.h"     /* XXX for mdbinfile() */
00016 #include "rpmlead.h"
00017 #include "signature.h"
00018 #include "header_internal.h"
00019 #include "debug.h"
00020 
00021 /*@access FD_t@*/               /* XXX ufdio->read arg1 is void ptr */
00022 /*@access Header@*/             /* XXX compared with NULL */
00023 /*@access entryInfo @*/         /* XXX rpmReadSignature */
00024 /*@access indexEntry @*/        /* XXX rpmReadSignature */
00025 /*@access DIGEST_CTX@*/         /* XXX compared with NULL */
00026 /*@access pgpDig@*/
00027 /*@access pgpDigParams@*/
00028 
00029 #if !defined(__GLIBC__) && !defined(__APPLE__)
00030 char ** environ = NULL;
00031 #endif
00032 
00033 int rpmLookupSignatureType(int action)
00034 {
00035     /*@unchecked@*/
00036     static int disabled = 0;
00037     int rc = 0;
00038 
00039     switch (action) {
00040     case RPMLOOKUPSIG_DISABLE:
00041         disabled = -2;
00042         break;
00043     case RPMLOOKUPSIG_ENABLE:
00044         disabled = 0;
00045         /*@fallthrough@*/
00046     case RPMLOOKUPSIG_QUERY:
00047         if (disabled)
00048             break;      /* Disabled */
00049 /*@-boundsread@*/
00050       { const char *name = rpmExpand("%{?_signature}", NULL);
00051         if (!(name && *name != '\0'))
00052             rc = 0;
00053         else if (!xstrcasecmp(name, "none"))
00054             rc = 0;
00055         else if (!xstrcasecmp(name, "pgp"))
00056             rc = RPMSIGTAG_PGP;
00057         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
00058             rc = RPMSIGTAG_PGP;
00059         else if (!xstrcasecmp(name, "gpg"))
00060             rc = RPMSIGTAG_GPG;
00061         else
00062             rc = -1;    /* Invalid %_signature spec in macro file */
00063         name = _free(name);
00064       } break;
00065 /*@=boundsread@*/
00066     }
00067     return rc;
00068 }
00069 
00070 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
00071 /* executable of the requested version, or NULL when none found. */
00072 
00073 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
00074 {
00075     /* Actually this should support having more then one pgp version. */
00076     /* At the moment only one version is possible since we only       */
00077     /* have one %_pgpbin and one %_pgp_path.                          */
00078 
00079     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
00080     const char *pgpbin = rpmGetPath("%{?_pgpbin}", NULL);
00081 
00082     if (saved_pgp_version == PGP_UNKNOWN) {
00083         char *pgpvbin;
00084         struct stat st;
00085 
00086 /*@-boundsread@*/
00087         if (!(pgpbin && pgpbin[0] != '\0')) {
00088             pgpbin = _free(pgpbin);
00089             saved_pgp_version = -1;
00090             return NULL;
00091         }
00092 /*@=boundsread@*/
00093 /*@-boundswrite@*/
00094         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
00095         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
00096 /*@=boundswrite@*/
00097 
00098         if (stat(pgpvbin, &st) == 0)
00099             saved_pgp_version = PGP_5;
00100         else if (stat(pgpbin, &st) == 0)
00101             saved_pgp_version = PGP_2;
00102         else
00103             saved_pgp_version = PGP_NOTDETECTED;
00104     }
00105 
00106 /*@-boundswrite@*/
00107     if (pgpVer && pgpbin)
00108         *pgpVer = saved_pgp_version;
00109 /*@=boundswrite@*/
00110     return pgpbin;
00111 }
00112 
00122 static inline rpmRC printSize(FD_t fd, int siglen, int pad, int datalen)
00123         /*@globals fileSystem @*/
00124         /*@modifies fileSystem @*/
00125 {
00126     struct stat st;
00127     int fdno = Fileno(fd);
00128 
00129     /* HACK: workaround for davRead wiring. */
00130     if (fdno == 123456789) {
00131         st.st_size = 0;
00132 /*@-sizeoftype@*/
00133         st.st_size -= sizeof(struct rpmlead)+siglen+pad+datalen;
00134 /*@=sizeoftype@*/
00135     } else if (fstat(fdno, &st) < 0)
00136         return RPMRC_FAIL;
00137 
00138 /*@-sizeoftype@*/
00139     rpmMessage(RPMMESS_DEBUG,
00140         _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
00141                 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
00142                 (int)sizeof(struct rpmlead), siglen, pad, datalen);
00143 /*@=sizeoftype@*/
00144     rpmMessage(RPMMESS_DEBUG,
00145         _("  Actual size: %12d\n"), (int)st.st_size);
00146 
00147     return RPMRC_OK;
00148 }
00149 
00150 /*@unchecked@*/
00151 static unsigned char header_magic[8] = {
00152     0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00153 };
00154 
00155 rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type,
00156                 const char ** msg)
00157 {
00158     char buf[BUFSIZ];
00159     int_32 block[4];
00160     int_32 il;
00161     int_32 dl;
00162     int_32 * ei = NULL;
00163     entryInfo pe;
00164     size_t nb;
00165     int_32 ril = 0;
00166     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
00167     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
00168     unsigned char * dataStart;
00169     unsigned char * dataEnd = NULL;
00170     Header sigh = NULL;
00171     rpmRC rc = RPMRC_FAIL;              /* assume failure */
00172     int xx;
00173     int i;
00174 
00175 /*@-boundswrite@*/
00176     if (sighp)
00177         *sighp = NULL;
00178 
00179     buf[0] = '\0';
00180 /*@=boundswrite@*/
00181 
00182     if (sig_type != RPMSIGTYPE_HEADERSIG)
00183         goto exit;
00184 
00185     memset(block, 0, sizeof(block));
00186     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
00187         (void) snprintf(buf, sizeof(buf),
00188                 _("sigh size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
00189         goto exit;
00190     }
00191     if (memcmp(block, header_magic, sizeof(header_magic))) {
00192         (void) snprintf(buf, sizeof(buf),
00193                 _("sigh magic: BAD\n"));
00194         goto exit;
00195     }
00196 /*@-boundsread@*/
00197     il = ntohl(block[2]);
00198 /*@=boundsread@*/
00199     if (il < 0 || il > 32) {
00200         (void) snprintf(buf, sizeof(buf),
00201                 _("sigh tags: BAD, no. of tags(%d) out of range\n"), il);
00202         goto exit;
00203     }
00204 /*@-boundsread@*/
00205     dl = ntohl(block[3]);
00206 /*@=boundsread@*/
00207     if (dl < 0 || dl > 8192) {
00208         (void) snprintf(buf, sizeof(buf),
00209                 _("sigh data: BAD, no. of  bytes(%d) out of range\n"), dl);
00210         goto exit;
00211     }
00212 
00213 /*@-sizeoftype@*/
00214     nb = (il * sizeof(struct entryInfo_s)) + dl;
00215 /*@=sizeoftype@*/
00216     ei = xmalloc(sizeof(il) + sizeof(dl) + nb);
00217 /*@-bounds@*/
00218     ei[0] = block[2];
00219     ei[1] = block[3];
00220     pe = (entryInfo) &ei[2];
00221 /*@=bounds@*/
00222     dataStart = (unsigned char *) (pe + il);
00223     if ((xx = timedRead(fd, (char *)pe, nb)) != nb) {
00224         (void) snprintf(buf, sizeof(buf),
00225                 _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
00226         goto exit;
00227     }
00228     
00229     /* Check (and convert) the 1st tag element. */
00230     xx = headerVerifyInfo(1, dl, pe, &entry->info, 0);
00231     if (xx != -1) {
00232         (void) snprintf(buf, sizeof(buf),
00233                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00234                 0, entry->info.tag, entry->info.type,
00235                 entry->info.offset, entry->info.count);
00236         goto exit;
00237     }
00238 
00239     /* Is there an immutable header region tag? */
00240     if (entry->info.tag == RPMTAG_HEADERSIGNATURES) {
00241         /* Is the region tag sane? */
00242         if (!(entry->info.type == REGION_TAG_TYPE &&
00243               entry->info.count == REGION_TAG_COUNT)) {
00244             (void) snprintf(buf, sizeof(buf),
00245                     _("region tag: BAD, tag %d type %d offset %d count %d\n"),
00246                     entry->info.tag, entry->info.type,
00247                     entry->info.offset, entry->info.count);
00248             goto exit;
00249         }
00250 
00251         if (entry->info.offset + REGION_TAG_COUNT > dl) {
00252             (void) snprintf(buf, sizeof(buf),
00253                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00254                 entry->info.tag, entry->info.type,
00255                 entry->info.offset, entry->info.count);
00256             goto exit;
00257         }
00258 
00259         /* Is there an immutable header region tag trailer? */
00260         dataEnd = dataStart + entry->info.offset;
00261 /*@-sizeoftype@*/
00262 /*@-bounds@*/
00263         (void) memcpy(info, dataEnd, REGION_TAG_COUNT);
00264         /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
00265         if (info->tag == htonl(RPMTAG_HEADERIMAGE)) {
00266             int_32 stag = htonl(RPMTAG_HEADERSIGNATURES);
00267             info->tag = stag;
00268             memcpy(dataEnd, &stag, sizeof(stag));
00269         }
00270 /*@=bounds@*/
00271         dataEnd += REGION_TAG_COUNT;
00272 
00273         xx = headerVerifyInfo(1, il * sizeof(*pe), info, &entry->info, 1);
00274         if (xx != -1 ||
00275             !((entry->info.tag == RPMTAG_HEADERSIGNATURES || entry->info.tag == RPMTAG_HEADERIMAGE)
00276            && entry->info.type == REGION_TAG_TYPE
00277            && entry->info.count == REGION_TAG_COUNT))
00278         {
00279             (void) snprintf(buf, sizeof(buf),
00280                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00281                 entry->info.tag, entry->info.type,
00282                 entry->info.offset, entry->info.count);
00283             goto exit;
00284         }
00285 /*@=sizeoftype@*/
00286 /*@-boundswrite@*/
00287         memset(info, 0, sizeof(*info));
00288 /*@=boundswrite@*/
00289 
00290         /* Is the no. of tags in the region less than the total no. of tags? */
00291         ril = entry->info.offset/sizeof(*pe);
00292         if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00293             (void) snprintf(buf, sizeof(buf),
00294                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00295             goto exit;
00296         }
00297     }
00298 
00299     /* Sanity check signature tags */
00300 /*@-boundswrite@*/
00301     memset(info, 0, sizeof(*info));
00302 /*@=boundswrite@*/
00303     for (i = 1; i < il; i++) {
00304         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00305         if (xx != -1) {
00306             (void) snprintf(buf, sizeof(buf),
00307                 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00308                 i, entry->info.tag, entry->info.type,
00309                 entry->info.offset, entry->info.count);
00310             goto exit;
00311         }
00312     }
00313 
00314     /* OK, blob looks sane, load the header. */
00315     sigh = headerLoad(ei);
00316     if (sigh == NULL) {
00317         (void) snprintf(buf, sizeof(buf), _("sigh load: BAD\n"));
00318         goto exit;
00319     }
00320     sigh->flags |= HEADERFLAG_ALLOCATED;
00321 
00322     {   int sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
00323         int pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
00324         int_32 * archSize = NULL;
00325 
00326         /* Position at beginning of header. */
00327         if (pad && (xx = timedRead(fd, (char *)block, pad)) != pad) {
00328             (void) snprintf(buf, sizeof(buf),
00329                 _("sigh pad(%d): BAD, read %d bytes\n"), pad, xx);
00330             goto exit;
00331         }
00332 
00333         /* Print package component sizes. */
00334         if (headerGetEntry(sigh, RPMSIGTAG_SIZE, NULL,(void **)&archSize, NULL)) {
00335             rc = printSize(fd, sigSize, pad, *archSize);
00336             if (rc != RPMRC_OK)
00337                 (void) snprintf(buf, sizeof(buf),
00338                         _("sigh sigSize(%d): BAD, fstat(2) failed\n"), sigSize);
00339         }
00340     }
00341 
00342 exit:
00343 /*@-boundswrite@*/
00344     if (sighp && sigh && rc == RPMRC_OK)
00345         *sighp = headerLink(sigh);
00346     sigh = headerFree(sigh);
00347 
00348     if (msg != NULL) {
00349         buf[sizeof(buf)-1] = '\0';
00350         *msg = xstrdup(buf);
00351     }
00352 /*@=boundswrite@*/
00353 
00354     return rc;
00355 }
00356 
00357 int rpmWriteSignature(FD_t fd, Header sigh)
00358 {
00359     static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
00360     int sigSize, pad;
00361     int rc;
00362 
00363     rc = headerWrite(fd, sigh, HEADER_MAGIC_YES);
00364     if (rc)
00365         return rc;
00366 
00367     sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
00368     pad = (8 - (sigSize % 8)) % 8;
00369     if (pad) {
00370 /*@-boundswrite@*/
00371         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
00372             rc = 1;
00373 /*@=boundswrite@*/
00374     }
00375     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
00376     return rc;
00377 }
00378 
00379 Header rpmNewSignature(void)
00380 {
00381     Header sigh = headerNew();
00382     return sigh;
00383 }
00384 
00385 Header rpmFreeSignature(Header sigh)
00386 {
00387     return headerFree(sigh);
00388 }
00389 
00399 static int makePGPSignature(const char * file, int_32 * sigTagp,
00400                 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp,
00401                 /*@null@*/ const char * passPhrase)
00402         /*@globals errno, rpmGlobalMacroContext, h_errno,
00403                 fileSystem, internalState @*/
00404         /*@modifies errno, *pktp, *pktlenp, rpmGlobalMacroContext,
00405                 fileSystem, internalState @*/
00406 {
00407     char * sigfile = alloca(1024);
00408     int pid, status;
00409     int inpipe[2];
00410     struct stat st;
00411     const char * cmd;
00412     char *const *av;
00413     pgpDig dig = NULL;
00414     pgpDigParams sigp = NULL;
00415     int rc;
00416 
00417 /*@-boundswrite@*/
00418     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00419 /*@=boundswrite@*/
00420 
00421     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00422     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00423 
00424     inpipe[0] = inpipe[1] = 0;
00425 /*@-boundsread@*/
00426     (void) pipe(inpipe);
00427 /*@=boundsread@*/
00428 
00429     if (!(pid = fork())) {
00430         const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00431         const char *path;
00432         pgpVersion pgpVer;
00433 
00434         (void) close(STDIN_FILENO);
00435         (void) dup2(inpipe[0], 3);
00436         (void) close(inpipe[1]);
00437 
00438         (void) dosetenv("PGPPASSFD", "3", 1);
00439 /*@-boundsread@*/
00440         if (pgp_path && *pgp_path != '\0')
00441             (void) dosetenv("PGPPATH", pgp_path, 1);
00442 /*@=boundsread@*/
00443 
00444         /* dosetenv("PGPPASS", passPhrase, 1); */
00445 
00446         unsetenv("MALLOC_CHECK_");
00447         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00448             switch(pgpVer) {
00449             case PGP_2:
00450                 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
00451                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00452 /*@-boundsread@*/
00453                 if (!rc)
00454                     rc = execve(av[0], av+1, environ);
00455 /*@=boundsread@*/
00456                 break;
00457             case PGP_5:
00458                 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
00459                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00460 /*@-boundsread@*/
00461                 if (!rc)
00462                     rc = execve(av[0], av+1, environ);
00463 /*@=boundsread@*/
00464                 break;
00465             case PGP_UNKNOWN:
00466             case PGP_NOTDETECTED:
00467                 errno = ENOENT;
00468                 break;
00469             }
00470         }
00471         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00472                         strerror(errno));
00473         _exit(RPMERR_EXEC);
00474     }
00475 
00476     delMacro(NULL, "__plaintext_filename");
00477     delMacro(NULL, "__signature_filename");
00478 
00479     (void) close(inpipe[0]);
00480     if (passPhrase)
00481         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
00482     (void) write(inpipe[1], "\n", 1);
00483     (void) close(inpipe[1]);
00484 
00485     (void)waitpid(pid, &status, 0);
00486     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00487         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
00488         return 1;
00489     }
00490 
00491     if (stat(sigfile, &st)) {
00492         /* PGP failed to write signature */
00493         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00494         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
00495         return 1;
00496     }
00497 
00498 /*@-boundswrite@*/
00499     *pktlenp = st.st_size;
00500     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *pktlenp);
00501     *pktp = xmalloc(*pktlenp);
00502 /*@=boundswrite@*/
00503 
00504 /*@-boundsread@*/
00505     {   FD_t fd;
00506 
00507         rc = 0;
00508         fd = Fopen(sigfile, "r.fdio");
00509         if (fd != NULL && !Ferror(fd)) {
00510             rc = timedRead(fd, *pktp, *pktlenp);
00511             if (sigfile) (void) unlink(sigfile);
00512             (void) Fclose(fd);
00513         }
00514         if (rc != *pktlenp) {
00515 /*@-boundswrite@*/
00516             *pktp = _free(*pktp);
00517 /*@=boundswrite@*/
00518             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00519             return 1;
00520         }
00521     }
00522 
00523     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *pktlenp);
00524 /*@=boundsread@*/
00525 
00526 #ifdef  NOTYET
00527     /* Parse the signature, change signature tag as appropriate. */
00528     dig = pgpNewDig();
00529 
00530     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00531     sigp = &dig->signature;
00532 
00533     dig = pgpFreeDig(dig);
00534 #endif
00535 
00536     return 0;
00537 }
00538 
00548 static int makeGPGSignature(const char * file, int_32 * sigTagp,
00549                 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp,
00550                 /*@null@*/ const char * passPhrase)
00551         /*@globals rpmGlobalMacroContext, h_errno,
00552                 fileSystem, internalState @*/
00553         /*@modifies *pktp, *pktlenp, rpmGlobalMacroContext,
00554                 fileSystem, internalState @*/
00555 {
00556     char * sigfile = alloca(strlen(file)+sizeof(".sig"));
00557     int pid, status;
00558     int inpipe[2];
00559     FILE * fpipe;
00560     struct stat st;
00561     const char * cmd;
00562     char *const *av;
00563     pgpDig dig = NULL;
00564     pgpDigParams sigp = NULL;
00565     int rc;
00566 
00567 /*@-boundswrite@*/
00568     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00569 /*@=boundswrite@*/
00570 
00571     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00572     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00573 
00574     inpipe[0] = inpipe[1] = 0;
00575 /*@-boundsread@*/
00576     (void) pipe(inpipe);
00577 /*@=boundsread@*/
00578 
00579     if (!(pid = fork())) {
00580         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00581 
00582         (void) close(STDIN_FILENO);
00583         (void) dup2(inpipe[0], 3);
00584         (void) close(inpipe[1]);
00585 
00586 /*@-boundsread@*/
00587         if (gpg_path && *gpg_path != '\0')
00588             (void) dosetenv("GNUPGHOME", gpg_path, 1);
00589 /*@=boundsread@*/
00590         (void) dosetenv("LC_ALL", "C", 1);
00591 
00592         unsetenv("MALLOC_CHECK_");
00593         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
00594         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00595 /*@-boundsread@*/
00596         if (!rc)
00597             rc = execve(av[0], av+1, environ);
00598 /*@=boundsread@*/
00599 
00600         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00601                         strerror(errno));
00602         _exit(RPMERR_EXEC);
00603     }
00604 
00605     delMacro(NULL, "__plaintext_filename");
00606     delMacro(NULL, "__signature_filename");
00607 
00608     fpipe = fdopen(inpipe[1], "w");
00609     (void) close(inpipe[0]);
00610     if (fpipe) {
00611         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
00612         (void) fclose(fpipe);
00613     }
00614 
00615     (void) waitpid(pid, &status, 0);
00616     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00617         rpmError(RPMERR_SIGGEN, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
00618         return 1;
00619     }
00620 
00621     if (stat(sigfile, &st)) {
00622         /* GPG failed to write signature */
00623         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00624         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
00625         return 1;
00626     }
00627 
00628 /*@-boundswrite@*/
00629     *pktlenp = st.st_size;
00630     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlenp);
00631     *pktp = xmalloc(*pktlenp);
00632 /*@=boundswrite@*/
00633 
00634 /*@-boundsread@*/
00635     {   FD_t fd;
00636 
00637         rc = 0;
00638         fd = Fopen(sigfile, "r.fdio");
00639         if (fd != NULL && !Ferror(fd)) {
00640             rc = timedRead(fd, *pktp, *pktlenp);
00641             if (sigfile) (void) unlink(sigfile);
00642             (void) Fclose(fd);
00643         }
00644         if (rc != *pktlenp) {
00645 /*@-boundswrite@*/
00646             *pktp = _free(*pktp);
00647 /*@=boundswrite@*/
00648             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00649             return 1;
00650         }
00651     }
00652 
00653     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlenp);
00654 /*@=boundsread@*/
00655 
00656     /* Parse the signature, change signature tag as appropriate. */
00657     dig = pgpNewDig();
00658 
00659     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00660     sigp = &dig->signature;
00661 
00662     switch (*sigTagp) {
00663     case RPMSIGTAG_SIZE:
00664     case RPMSIGTAG_MD5:
00665     case RPMSIGTAG_SHA1:
00666         break;
00667     case RPMSIGTAG_GPG:
00668         /* XXX check MD5 hash too? */
00669         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00670             *sigTagp = RPMSIGTAG_PGP;
00671         break;
00672     case RPMSIGTAG_PGP5:        /* XXX legacy */
00673     case RPMSIGTAG_PGP:
00674         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00675             *sigTagp = RPMSIGTAG_GPG;
00676         break;
00677     case RPMSIGTAG_DSA:
00678         /* XXX check MD5 hash too? */
00679         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00680             *sigTagp = RPMSIGTAG_RSA;
00681         break;
00682     case RPMSIGTAG_RSA:
00683         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00684             *sigTagp = RPMSIGTAG_DSA;
00685         break;
00686     }
00687 
00688     dig = pgpFreeDig(dig);
00689 
00690     return 0;
00691 }
00692 
00701 static int makeHDRSignature(Header sigh, const char * file, int_32 sigTag,
00702                 /*@null@*/ const char * passPhrase)
00703         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00704         /*@modifies sigh, rpmGlobalMacroContext, fileSystem, internalState @*/
00705 {
00706     Header h = NULL;
00707     FD_t fd = NULL;
00708     byte * pkt;
00709     int_32 pktlen;
00710     const char * fn = NULL;
00711     const char * SHA1 = NULL;
00712     int ret = -1;       /* assume failure. */
00713 
00714     switch (sigTag) {
00715     case RPMSIGTAG_SIZE:
00716     case RPMSIGTAG_MD5:
00717     case RPMSIGTAG_PGP5:        /* XXX legacy */
00718     case RPMSIGTAG_PGP:
00719     case RPMSIGTAG_GPG:
00720         goto exit;
00721         /*@notreached@*/ break;
00722     case RPMSIGTAG_SHA1:
00723         fd = Fopen(file, "r.fdio");
00724         if (fd == NULL || Ferror(fd))
00725             goto exit;
00726         h = headerRead(fd, HEADER_MAGIC_YES);
00727         if (h == NULL)
00728             goto exit;
00729         (void) Fclose(fd);      fd = NULL;
00730 
00731         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
00732             DIGEST_CTX ctx;
00733             void * uh;
00734             int_32 uht, uhc;
00735         
00736             if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
00737              ||  uh == NULL)
00738             {
00739                 h = headerFree(h);
00740                 goto exit;
00741             }
00742             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00743             (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
00744             (void) rpmDigestUpdate(ctx, uh, uhc);
00745             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
00746             uh = headerFreeData(uh, uht);
00747         }
00748         h = headerFree(h);
00749 
00750         if (SHA1 == NULL)
00751             goto exit;
00752         if (!headerAddEntry(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
00753             goto exit;
00754         ret = 0;
00755         break;
00756     case RPMSIGTAG_DSA:
00757         fd = Fopen(file, "r.fdio");
00758         if (fd == NULL || Ferror(fd))
00759             goto exit;
00760         h = headerRead(fd, HEADER_MAGIC_YES);
00761         if (h == NULL)
00762             goto exit;
00763         (void) Fclose(fd);      fd = NULL;
00764         if (makeTempFile(NULL, &fn, &fd))
00765             goto exit;
00766         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00767             goto exit;
00768         (void) Fclose(fd);      fd = NULL;
00769         if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00770          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00771             goto exit;
00772         ret = 0;
00773         break;
00774     case RPMSIGTAG_RSA:
00775         fd = Fopen(file, "r.fdio");
00776         if (fd == NULL || Ferror(fd))
00777             goto exit;
00778         h = headerRead(fd, HEADER_MAGIC_YES);
00779         if (h == NULL)
00780             goto exit;
00781         (void) Fclose(fd);      fd = NULL;
00782         if (makeTempFile(NULL, &fn, &fd))
00783             goto exit;
00784         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00785             goto exit;
00786         (void) Fclose(fd);      fd = NULL;
00787         if (makePGPSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00788          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00789             goto exit;
00790         ret = 0;
00791         break;
00792     }
00793 
00794 exit:
00795     if (fn) {
00796         (void) unlink(fn);
00797         fn = _free(fn);
00798     }
00799     SHA1 = _free(SHA1);
00800     h = headerFree(h);
00801     if (fd != NULL) (void) Fclose(fd);
00802     return ret;
00803 }
00804 
00805 int rpmAddSignature(Header sigh, const char * file, int_32 sigTag,
00806                 const char * passPhrase)
00807 {
00808     struct stat st;
00809     byte * pkt;
00810     int_32 pktlen;
00811     int ret = -1;       /* assume failure. */
00812 
00813     switch (sigTag) {
00814     case RPMSIGTAG_SIZE:
00815         if (stat(file, &st) != 0)
00816             break;
00817         pktlen = st.st_size;
00818         if (!headerAddEntry(sigh, sigTag, RPM_INT32_TYPE, &pktlen, 1))
00819             break;
00820         ret = 0;
00821         break;
00822     case RPMSIGTAG_MD5:
00823         pktlen = 16;
00824         pkt = memset(alloca(pktlen), 0, pktlen);
00825         if (domd5(file, pkt, 0, NULL)
00826          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00827             break;
00828         ret = 0;
00829         break;
00830     case RPMSIGTAG_PGP5:        /* XXX legacy */
00831     case RPMSIGTAG_PGP:
00832         if (makePGPSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00833          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00834             break;
00835 #ifdef  NOTYET  /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
00836         /* XXX Piggyback a header-only RSA signature as well. */
00837         ret = makeHDRSignature(sigh, file, RPMSIGTAG_RSA, passPhrase);
00838 #endif
00839         ret = 0;
00840         break;
00841     case RPMSIGTAG_GPG:
00842         if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00843          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00844             break;
00845         /* XXX Piggyback a header-only DSA signature as well. */
00846         ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
00847         break;
00848     case RPMSIGTAG_RSA:
00849     case RPMSIGTAG_DSA:
00850     case RPMSIGTAG_SHA1:
00851         ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
00852         break;
00853     }
00854 
00855     return ret;
00856 }
00857 
00858 static int checkPassPhrase(const char * passPhrase, const int sigTag)
00859         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00860         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00861 {
00862     int passPhrasePipe[2];
00863     int pid, status;
00864     int rc;
00865     int xx;
00866 
00867     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00868 /*@-boundsread@*/
00869     xx = pipe(passPhrasePipe);
00870 /*@=boundsread@*/
00871     if (!(pid = fork())) {
00872         const char * cmd;
00873         char *const *av;
00874         int fdno;
00875 
00876         xx = close(STDIN_FILENO);
00877         xx = close(STDOUT_FILENO);
00878         xx = close(passPhrasePipe[1]);
00879         if (! rpmIsVerbose())
00880             xx = close(STDERR_FILENO);
00881         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00882             xx = dup2(fdno, STDIN_FILENO);
00883             xx = close(fdno);
00884         }
00885         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00886             xx = dup2(fdno, STDOUT_FILENO);
00887             xx = close(fdno);
00888         }
00889         xx = dup2(passPhrasePipe[0], 3);
00890 
00891         unsetenv("MALLOC_CHECK_");
00892         switch (sigTag) {
00893         case RPMSIGTAG_DSA:
00894         case RPMSIGTAG_GPG:
00895         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00896 
00897 /*@-boundsread@*/
00898             if (gpg_path && *gpg_path != '\0')
00899                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
00900 /*@=boundsread@*/
00901 
00902             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00903             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00904 /*@-boundsread@*/
00905             if (!rc)
00906                 rc = execve(av[0], av+1, environ);
00907 /*@=boundsread@*/
00908 
00909             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00910                         strerror(errno));
00911         }   /*@notreached@*/ break;
00912         case RPMSIGTAG_RSA:
00913         case RPMSIGTAG_PGP5:    /* XXX legacy */
00914         case RPMSIGTAG_PGP:
00915         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00916             const char *path;
00917             pgpVersion pgpVer;
00918 
00919             (void) dosetenv("PGPPASSFD", "3", 1);
00920 /*@-boundsread@*/
00921             if (pgp_path && *pgp_path != '\0')
00922                 xx = dosetenv("PGPPATH", pgp_path, 1);
00923 /*@=boundsread@*/
00924 
00925             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00926                 switch(pgpVer) {
00927                 case PGP_2:
00928                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
00929                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00930 /*@-boundsread@*/
00931                     if (!rc)
00932                         rc = execve(av[0], av+1, environ);
00933 /*@=boundsread@*/
00934                     /*@innerbreak@*/ break;
00935                 case PGP_5:     /* XXX legacy */
00936                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
00937                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00938 /*@-boundsread@*/
00939                     if (!rc)
00940                         rc = execve(av[0], av+1, environ);
00941 /*@=boundsread@*/
00942                     /*@innerbreak@*/ break;
00943                 case PGP_UNKNOWN:
00944                 case PGP_NOTDETECTED:
00945                     /*@innerbreak@*/ break;
00946                 }
00947             }
00948             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00949                         strerror(errno));
00950             _exit(RPMERR_EXEC);
00951         }   /*@notreached@*/ break;
00952         default: /* This case should have been screened out long ago. */
00953             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00954             _exit(RPMERR_SIGGEN);
00955             /*@notreached@*/ break;
00956         }
00957     }
00958 
00959     xx = close(passPhrasePipe[0]);
00960     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00961     xx = write(passPhrasePipe[1], "\n", 1);
00962     xx = close(passPhrasePipe[1]);
00963 
00964     (void) waitpid(pid, &status, 0);
00965 
00966     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
00967 }
00968 
00969 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
00970 {
00971     char *pass = NULL;
00972     int aok = 0;
00973 
00974     switch (sigTag) {
00975     case RPMSIGTAG_DSA:
00976     case RPMSIGTAG_GPG:
00977 /*@-boundsread@*/
00978       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
00979         aok = (name && *name != '\0');
00980         name = _free(name);
00981       }
00982 /*@=boundsread@*/
00983         if (aok)
00984             break;
00985         rpmError(RPMERR_SIGGEN,
00986                 _("You must set \"%%_gpg_name\" in your macro file\n"));
00987         break;
00988     case RPMSIGTAG_RSA:
00989     case RPMSIGTAG_PGP5:        /* XXX legacy */
00990     case RPMSIGTAG_PGP:
00991 /*@-boundsread@*/
00992       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
00993         aok = (name && *name != '\0');
00994         name = _free(name);
00995       }
00996 /*@=boundsread@*/
00997         if (aok)
00998             break;
00999         rpmError(RPMERR_SIGGEN,
01000                 _("You must set \"%%_pgp_name\" in your macro file\n"));
01001         break;
01002     default:
01003         /* Currently the calling function (rpm.c:main) is checking this and
01004          * doing a better job.  This section should never be accessed.
01005          */
01006         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
01007         break;
01008     }
01009 
01010     if (aok) {
01011 /*@-moduncon -nullpass -unrecog @*/
01012         pass = getpass( (prompt ? prompt : "") );
01013 /*@=moduncon =nullpass =unrecog @*/
01014 
01015         if (checkPassPhrase(pass, sigTag))
01016             pass = NULL;
01017     }
01018 
01019     return pass;
01020 }
01021 
01022 static /*@observer@*/ const char * rpmSigString(rpmRC res)
01023         /*@*/
01024 {
01025     const char * str;
01026     switch (res) {
01027     case RPMRC_OK:              str = "OK";             break;
01028     case RPMRC_FAIL:            str = "BAD";            break;
01029     case RPMRC_NOKEY:           str = "NOKEY";          break;
01030     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
01031     default:
01032     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
01033     }
01034     return str;
01035 }
01036 
01037 /*@-boundswrite@*/
01038 static rpmRC
01039 verifySizeSignature(const rpmts ts, /*@out@*/ char * t)
01040         /*@modifies *t @*/
01041 {
01042     const void * sig = rpmtsSig(ts);
01043     pgpDig dig = rpmtsDig(ts);
01044     rpmRC res;
01045     int_32 size = 0x7fffffff;
01046 
01047     *t = '\0';
01048     t = stpcpy(t, _("Header+Payload size: "));
01049 
01050     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
01051         res = RPMRC_NOKEY;
01052         t = stpcpy(t, rpmSigString(res));
01053         goto exit;
01054     }
01055 
01056     memcpy(&size, sig, sizeof(size));
01057 
01058     if (size != dig->nbytes) {
01059         res = RPMRC_FAIL;
01060         t = stpcpy(t, rpmSigString(res));
01061         sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes);
01062     } else {
01063         res = RPMRC_OK;
01064         t = stpcpy(t, rpmSigString(res));
01065         sprintf(t, " (%d)", (int)dig->nbytes);
01066     }
01067 
01068 exit:
01069     t = stpcpy(t, "\n");
01070     return res;
01071 }
01072 /*@=boundswrite@*/
01073 
01074 /*@-boundswrite@*/
01075 static rpmRC
01076 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t,
01077                 /*@null@*/ DIGEST_CTX md5ctx)
01078         /*@globals internalState @*/
01079         /*@modifies *t, internalState @*/
01080 {
01081     const void * sig = rpmtsSig(ts);
01082     int_32 siglen = rpmtsSiglen(ts);
01083     pgpDig dig = rpmtsDig(ts);
01084     rpmRC res;
01085     byte * md5sum = NULL;
01086     size_t md5len = 0;
01087 
01088     *t = '\0';
01089     t = stpcpy(t, _("MD5 digest: "));
01090 
01091     if (md5ctx == NULL || sig == NULL || dig == NULL) {
01092         res = RPMRC_NOKEY;
01093         t = stpcpy(t, rpmSigString(res));
01094         goto exit;
01095     }
01096 
01097     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01098     (void) rpmDigestFinal(rpmDigestDup(md5ctx),
01099                 (void **)&md5sum, &md5len, 0);
01100     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01101     rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
01102 
01103     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
01104         res = RPMRC_FAIL;
01105         t = stpcpy(t, rpmSigString(res));
01106         t = stpcpy(t, " Expected(");
01107         (void) pgpHexCvt(t, sig, siglen);
01108         t += strlen(t);
01109         t = stpcpy(t, ") != (");
01110     } else {
01111         res = RPMRC_OK;
01112         t = stpcpy(t, rpmSigString(res));
01113         t = stpcpy(t, " (");
01114     }
01115     (void) pgpHexCvt(t, md5sum, md5len);
01116     t += strlen(t);
01117     t = stpcpy(t, ")");
01118 
01119 exit:
01120     md5sum = _free(md5sum);
01121     t = stpcpy(t, "\n");
01122     return res;
01123 }
01124 /*@=boundswrite@*/
01125 
01126 /*@-boundswrite@*/
01134 static rpmRC
01135 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t,
01136                 /*@null@*/ DIGEST_CTX sha1ctx)
01137         /*@globals internalState @*/
01138         /*@modifies *t, internalState @*/
01139 {
01140     const void * sig = rpmtsSig(ts);
01141 #ifdef  NOTYET
01142     int_32 siglen = rpmtsSiglen(ts);
01143 #endif
01144     pgpDig dig = rpmtsDig(ts);
01145     rpmRC res;
01146     const char * SHA1 = NULL;
01147 
01148     *t = '\0';
01149     t = stpcpy(t, _("Header SHA1 digest: "));
01150 
01151     if (sha1ctx == NULL || sig == NULL || dig == NULL) {
01152         res = RPMRC_NOKEY;
01153         t = stpcpy(t, rpmSigString(res));
01154         goto exit;
01155     }
01156 
01157     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01158     (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
01159                 (void **)&SHA1, NULL, 1);
01160     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01161 
01162     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
01163         res = RPMRC_FAIL;
01164         t = stpcpy(t, rpmSigString(res));
01165         t = stpcpy(t, " Expected(");
01166         t = stpcpy(t, sig);
01167         t = stpcpy(t, ") != (");
01168     } else {
01169         res = RPMRC_OK;
01170         t = stpcpy(t, rpmSigString(res));
01171         t = stpcpy(t, " (");
01172     }
01173     if (SHA1)
01174         t = stpcpy(t, SHA1);
01175     t = stpcpy(t, ")");
01176 
01177 exit:
01178     SHA1 = _free(SHA1);
01179     t = stpcpy(t, "\n");
01180     return res;
01181 }
01182 /*@=boundswrite@*/
01183 
01189 static inline unsigned char nibble(char c)
01190         /*@*/
01191 {
01192     if (c >= '0' && c <= '9')
01193         return (c - '0');
01194     if (c >= 'A' && c <= 'F')
01195         return (c - 'A') + 10;
01196     if (c >= 'a' && c <= 'f')
01197         return (c - 'a') + 10;
01198     return 0;
01199 }
01200 
01201 /*@-boundswrite@*/
01209 static rpmRC
01210 verifyRSASignature(rpmts ts, /*@out@*/ char * t,
01211                 /*@null@*/ DIGEST_CTX md5ctx)
01212         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01213         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01214 {
01215     const void * sig = rpmtsSig(ts);
01216 #ifdef  NOTYET
01217     int_32 siglen = rpmtsSiglen(ts);
01218 #endif
01219     int_32 sigtag = rpmtsSigtag(ts);
01220     pgpDig dig = rpmtsDig(ts);
01221     pgpDigParams sigp = rpmtsSignature(ts);
01222     SECOidTag sigalg;
01223     rpmRC res = RPMRC_OK;
01224     int xx;
01225     SECItem digest;
01226 
01227     *t = '\0';
01228     if (dig != NULL && dig->hdrmd5ctx == md5ctx)
01229         t = stpcpy(t, _("Header "));
01230     *t++ = 'V';
01231     switch (sigp->version) {
01232     case 3:     *t++ = '3';     break;
01233     case 4:     *t++ = '4';     break;
01234     }
01235 
01236     if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01237         res = RPMRC_NOKEY;
01238     }
01239 
01240     /* Verify the desired signature match. */
01241     switch (sigp->pubkey_algo) {
01242     case PGPPUBKEYALGO_RSA:
01243         if (sigtag == RPMSIGTAG_PGP || sigtag == RPMSIGTAG_PGP5 || sigtag == RPMSIGTAG_RSA)
01244             break;
01245         /*@fallthrough@*/
01246     default:
01247         res = RPMRC_NOKEY;
01248         break;
01249     }
01250 
01251     /* Verify the desired hash match. */
01252     /* XXX Values from PKCS#1 v2.1 (aka RFC-3447) */
01253     switch (sigp->hash_algo) {
01254     case PGPHASHALGO_MD5:
01255         t = stpcpy(t, " RSA/MD5");
01256         sigalg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
01257         break;
01258     case PGPHASHALGO_SHA1:
01259         t = stpcpy(t, " RSA/SHA1");
01260         sigalg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
01261         break;
01262     case PGPHASHALGO_RIPEMD160:
01263         res = RPMRC_NOKEY;
01264         break;
01265     case PGPHASHALGO_MD2:
01266         t = stpcpy(t, " RSA/MD2");
01267         sigalg = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
01268         break;
01269     case PGPHASHALGO_TIGER192:
01270         res = RPMRC_NOKEY;
01271         break;
01272     case PGPHASHALGO_HAVAL_5_160:
01273         res = RPMRC_NOKEY;
01274         break;
01275     case PGPHASHALGO_SHA256:
01276         t = stpcpy(t, " RSA/SHA256");
01277         sigalg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
01278         break;
01279     case PGPHASHALGO_SHA384:
01280         t = stpcpy(t, " RSA/SHA384");
01281         sigalg = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
01282         break;
01283     case PGPHASHALGO_SHA512:
01284         t = stpcpy(t, " RSA/SHA512");
01285         sigalg = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
01286         break;
01287     default:
01288         res = RPMRC_NOKEY;
01289         sigalg = SEC_OID_UNKNOWN;
01290         break;
01291     }
01292 
01293     t = stpcpy(t, _(" signature: "));
01294     if (res != RPMRC_OK) {
01295         goto exit;
01296     }
01297 
01298     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01299     {   DIGEST_CTX ctx = rpmDigestDup(md5ctx);
01300 
01301         if (sigp->hash != NULL)
01302             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01303 
01304 #ifdef  NOTYET  /* XXX not for binary/text signatures as in packages. */
01305         if (!(sigp->sigtype == PGPSIGTYPE_BINARY || sigp->sigtype == PGP_SIGTYPE_TEXT)) {
01306             int nb = dig->nbytes + sigp->hashlen;
01307             byte trailer[6];
01308             nb = htonl(nb);
01309             trailer[0] = 0x4;
01310             trailer[1] = 0xff;
01311             memcpy(trailer+2, &nb, sizeof(nb));
01312             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01313         }
01314 #endif
01315 
01316         xx = rpmDigestFinal(ctx, (void **)&dig->md5, &dig->md5len, 0);
01317         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01318         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01319 
01320         /* Compare leading 16 bits of digest for quick check. */
01321         if (memcmp(dig->md5, sigp->signhash16, 2)) {
01322             res = RPMRC_FAIL;
01323             goto exit;
01324         }
01325         digest.type = siBuffer;
01326         digest.data = dig->md5;
01327         digest.len = dig->md5len;
01328     }
01329 
01330     /* Retrieve the matching public key. */
01331     res = rpmtsFindPubkey(ts);
01332     if (res != RPMRC_OK)
01333         goto exit;
01334 
01335     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01336     {   SECItem *sig = dig->rsasig;
01337         size_t siglen = SECKEY_SignatureLen(dig->rsa);
01338 
01339         /* Zero-pad signature data up to expected size if necessary */
01340         if (siglen > sig->len) {
01341             size_t pad = siglen - sig->len;
01342             if ((sig = SECITEM_AllocItem(NULL, NULL, siglen)) == NULL) {
01343                 res = RPMRC_FAIL;
01344                 goto exit;
01345             }
01346             memset(sig->data, 0, pad);
01347             memcpy(sig->data+pad, dig->rsasig->data, dig->rsasig->len);
01348         }
01349             
01350         if (VFY_VerifyDigest(&digest, dig->rsa, sig, sigalg, NULL) == SECSuccess)
01351             res = RPMRC_OK;
01352         else
01353             res = RPMRC_FAIL;
01354 
01355         if (sig != dig->rsasig) {
01356             SECITEM_ZfreeItem(sig, 1);
01357         }
01358     }
01359     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01360 
01361 exit:
01362     t = stpcpy(t, rpmSigString(res));
01363     if (sigp != NULL) {
01364         t = stpcpy(t, ", key ID ");
01365         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01366         t += strlen(t);
01367     }
01368     t = stpcpy(t, "\n");
01369     return res;
01370 }
01371 /*@=boundswrite@*/
01372 
01380 /*@-boundswrite@*/
01381 static rpmRC
01382 verifyDSASignature(rpmts ts, /*@out@*/ char * t,
01383                 /*@null@*/ DIGEST_CTX sha1ctx)
01384         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01385         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01386 {
01387     const void * sig = rpmtsSig(ts);
01388 #ifdef  NOTYET
01389     int_32 siglen = rpmtsSiglen(ts);
01390 #endif
01391     int_32 sigtag = rpmtsSigtag(ts);
01392     pgpDig dig = rpmtsDig(ts);
01393     pgpDigParams sigp = rpmtsSignature(ts);
01394     rpmRC res;
01395     int xx;
01396     SECItem digest;
01397 
01398     *t = '\0';
01399     if (dig != NULL && dig->hdrsha1ctx == sha1ctx)
01400         t = stpcpy(t, _("Header "));
01401     *t++ = 'V';
01402     switch (sigp->version) {
01403     case 3:    *t++ = '3';     break;
01404     case 4:    *t++ = '4';     break;
01405     }
01406     t = stpcpy(t, _(" DSA signature: "));
01407 
01408     if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01409         res = RPMRC_NOKEY;
01410         goto exit;
01411     }
01412 
01413     /* XXX sanity check on sigtag and signature agreement. */
01414     if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA)
01415         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
01416         && sigp->hash_algo == PGPHASHALGO_SHA1))
01417     {
01418         res = RPMRC_NOKEY;
01419         goto exit;
01420     }
01421 
01422     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01423     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
01424 
01425         if (sigp->hash != NULL)
01426             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01427 
01428         if (sigp->version == 4) {
01429             int nb = sigp->hashlen;
01430             byte trailer[6];
01431             nb = htonl(nb);
01432             trailer[0] = sigp->version;
01433             trailer[1] = 0xff;
01434             memcpy(trailer+2, &nb, sizeof(nb));
01435             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01436         }
01437         xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 0);
01438         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01439         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01440 
01441         /* Compare leading 16 bits of digest for quick check. */
01442         if (memcmp(dig->sha1, sigp->signhash16, 2)) {
01443             res = RPMRC_FAIL;
01444             goto exit;
01445         }
01446         digest.type = siBuffer;
01447         digest.data = dig->sha1;
01448         digest.len = dig->sha1len;
01449     }
01450 
01451     /* Retrieve the matching public key. */
01452     res = rpmtsFindPubkey(ts);
01453     if (res != RPMRC_OK)
01454         goto exit;
01455 
01456     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01457     if (VFY_VerifyDigest(&digest, dig->dsa, dig->dsasig,
01458                 SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST, NULL) == SECSuccess)
01459         res = RPMRC_OK;
01460     else
01461         res = RPMRC_FAIL;
01462     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01463 
01464 exit:
01465     t = stpcpy(t, rpmSigString(res));
01466     if (sigp != NULL) {
01467         t = stpcpy(t, ", key ID ");
01468         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01469         t += strlen(t);
01470     }
01471     t = stpcpy(t, "\n");
01472     return res;
01473 }
01474 /*@=boundswrite@*/
01475 
01476 rpmRC
01477 rpmVerifySignature(const rpmts ts, char * result)
01478 {
01479     const void * sig = rpmtsSig(ts);
01480     int_32 siglen = rpmtsSiglen(ts);
01481     int_32 sigtag = rpmtsSigtag(ts);
01482     pgpDig dig = rpmtsDig(ts);
01483     rpmRC res;
01484 
01485     if (sig == NULL || siglen <= 0 || dig == NULL) {
01486         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
01487         return RPMRC_NOTFOUND;
01488     }
01489 
01490     switch (sigtag) {
01491     case RPMSIGTAG_SIZE:
01492         res = verifySizeSignature(ts, result);
01493         break;
01494     case RPMSIGTAG_MD5:
01495         res = verifyMD5Signature(ts, result, dig->md5ctx);
01496         break;
01497     case RPMSIGTAG_SHA1:
01498         res = verifySHA1Signature(ts, result, dig->hdrsha1ctx);
01499         break;
01500     case RPMSIGTAG_RSA:
01501         res = verifyRSASignature(ts, result, dig->hdrmd5ctx);
01502         break;
01503     case RPMSIGTAG_PGP5:        /* XXX legacy */
01504     case RPMSIGTAG_PGP:
01505         res = verifyRSASignature(ts, result,
01506                 ((dig->signature.hash_algo == PGPHASHALGO_MD5)
01507                         ? dig->md5ctx : dig->sha1ctx));
01508         break;
01509     case RPMSIGTAG_DSA:
01510         res = verifyDSASignature(ts, result, dig->hdrsha1ctx);
01511         break;
01512     case RPMSIGTAG_GPG:
01513         res = verifyDSASignature(ts, result, dig->sha1ctx);
01514         break;
01515     case RPMSIGTAG_LEMD5_1:
01516     case RPMSIGTAG_LEMD5_2:
01517         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
01518         res = RPMRC_NOTFOUND;
01519         break;
01520     default:
01521         sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag);
01522         res = RPMRC_NOTFOUND;
01523         break;
01524     }
01525     return res;
01526 }

Generated on Mon Feb 25 17:14:22 2013 for rpm by  doxygen 1.4.7