Main Page Modules Data Structures File List Data Fields Globals Related Pages

# 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 Header@*/             /* XXX compared with NULL */
    00022 /*@access FD_t@*/               /* XXX compared with NULL */
    00023 /*@access DIGEST_CTX@*/         /* XXX compared with NULL */
    00024 /*@access pgpDig@*/
    00025 /*@access pgpDigParams@*/
    00026
    00027 #if !defined(__GLIBC__)
    00028 char ** environ = NULL;
    00029 #endif
    00030
    00031 int rpmLookupSignatureType(int action)
    00032 {
    00033     /*@unchecked@*/
    00034     static int disabled = 0;
    00035     int rc = 0;
    00036
    00037     switch (action) {
    00038     case RPMLOOKUPSIG_DISABLE:
    00039         disabled = -2;
    00040         break;
    00041     case RPMLOOKUPSIG_ENABLE:
    00042         disabled = 0;
    00043         /*@fallthrough@*/
    00044     case RPMLOOKUPSIG_QUERY:
    00045         if (disabled)
    00046             break;      /* Disabled */
    00047 /*@-boundsread@*/
    00048       { const char *name = rpmExpand("%{?_signature}", NULL);
    00049         if (!(name && *name != '\0'))
    00050             rc = 0;
    00051         else if (!xstrcasecmp(name, "none"))
    00052             rc = 0;
    00053         else if (!xstrcasecmp(name, "pgp"))
    00054             rc = RPMSIGTAG_PGP;
    00055         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
    00056             rc = RPMSIGTAG_PGP;
    00057         else if (!xstrcasecmp(name, "gpg"))
    00058             rc = RPMSIGTAG_GPG;
    00059         else
    00060             rc = -1;    /* Invalid %_signature spec in macro file */
    00061         name = _free(name);
    00062       } break;
    00063 /*@=boundsread@*/
    00064     }
    00065     return rc;
    00066 }
    00067
    00068 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
    00069 /* executable of the requested version, or NULL when none found. */
    00070
    00071 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
    00072 {
    00073     /* Actually this should support having more then one pgp version. */
    00074     /* At the moment only one version is possible since we only       */
    00075     /* have one %_pgpbin and one %_pgp_path.                          */
    00076
    00077     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
    00078     const char *pgpbin = rpmGetPath("%{?_pgpbin}", NULL);
    00079
    00080     if (saved_pgp_version == PGP_UNKNOWN) {
    00081         char *pgpvbin;
    00082         struct stat st;
    00083
    00084 /*@-boundsread@*/
    00085         if (!(pgpbin && pgpbin[0] != '\0')) {
    00086             pgpbin = _free(pgpbin);
    00087             saved_pgp_version = -1;
    00088             return NULL;
    00089         }
    00090 /*@=boundsread@*/
    00091 /*@-boundswrite@*/
    00092         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
    00093         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
    00094 /*@=boundswrite@*/
    00095
    00096         if (stat(pgpvbin, &st) == 0)
    00097             saved_pgp_version = PGP_5;
    00098         else if (stat(pgpbin, &st) == 0)
    00099             saved_pgp_version = PGP_2;
    00100         else
    00101             saved_pgp_version = PGP_NOTDETECTED;
    00102     }
    00103
    00104 /*@-boundswrite@*/
    00105     if (pgpVer && pgpbin)
    00106         *pgpVer = saved_pgp_version;
    00107 /*@=boundswrite@*/
    00108     return pgpbin;
    00109 }
    00110
    00120 static inline rpmRC printSize(FD_t fd, int siglen, int pad, int datalen)
    00121         /*@globals fileSystem @*/
    00122         /*@modifies fileSystem @*/
    00123 {
    00124     struct stat st;
    00125
    00126     if (fstat(Fileno(fd), &st) < 0)
    00127         return RPMRC_FAIL;
    00128
    00129     /*@-sizeoftype@*/
    00130     rpmMessage(RPMMESS_DEBUG,
    00131         _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
    00132                 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
    00133                 (int)sizeof(struct rpmlead), siglen, pad, datalen);
    00134     /*@=sizeoftype@*/
    00135     rpmMessage(RPMMESS_DEBUG,
    00136         _("  Actual size: %12d\n"), (int)st.st_size);
    00137
    00138     return RPMRC_OK;
    00139 }
    00140
    00141 /*@unchecked@*/
    00142 static unsigned char header_magic[8] = {
    00143     0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
    00144 };
    00145
    00146 rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type)
    00147 {
    00148     int_32 block[4];
    00149     int_32 il;
    00150     int_32 dl;
    00151     int_32 * ei = NULL;
    00152     entryInfo pe;
    00153     int_32 nb;
    00154     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
    00155     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
    00156     Header sigh = NULL;
    00157     rpmRC rc = RPMRC_FAIL;              /* assume failure */
    00158     int xx;
    00159     int i;
    00160
    00161     if (sighp)
    00162         *sighp = NULL;
    00163
    00164     if (sig_type != RPMSIGTYPE_HEADERSIG)
    00165         goto exit;
    00166
    00167     if (timedRead(fd, (char *)block, sizeof(block)) != sizeof(block))
    00168         goto exit;
    00169     if (memcmp(block, header_magic, sizeof(header_magic)))
    00170         goto exit;
    00171     il = ntohl(block[2]);
    00172     if (il < 0 || il > 32)
    00173         goto exit;
    00174     dl = ntohl(block[3]);
    00175     if (dl < 0 || dl > 8192)
    00176         goto exit;
    00177
    00178     nb = (il * sizeof(struct entryInfo_s)) + dl;
    00179     ei = xmalloc(sizeof(il) + sizeof(dl) + nb);
    00180     ei[0] = htonl(il);
    00181     ei[1] = htonl(dl);
    00182     pe = (entryInfo) &ei[2];
    00183     if (timedRead(fd, (char *)pe, nb) != nb)
    00184         goto exit;
    00185
    00186     /* Sanity check signature tags */
    00187     memset(info, 0, sizeof(*info));
    00188     for (i = 0; i < il; i++) {
    00189         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
    00190         if (xx != -1)
    00191             goto exit;
    00192     }
    00193
    00194     /* OK, blob looks sane, load the header. */
    00195     sigh = headerLoad(ei);
    00196     if (sigh == NULL)
    00197         goto exit;
    00198     sigh->flags |= HEADERFLAG_ALLOCATED;
    00199
    00200     {   int sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
    00201         int pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
    00202         int_32 * archSize = NULL;
    00203
    00204         /* Position at beginning of header. */
    00205         if (pad && timedRead(fd, (char *)block, pad) != pad)
    00206             goto exit;
    00207
    00208         /* Print package component sizes. */
    00209         if (headerGetEntry(sigh, RPMSIGTAG_SIZE, NULL,(void **)&archSize, NULL))
    00210             rc = printSize(fd, sigSize, pad, *archSize);
    00211     }
    00212
    00213 exit:
    00214     if (rc == RPMRC_OK && sighp && sigh)
    00215         *sighp = headerLink(sigh);
    00216     sigh = headerFree(sigh);
    00217     return rc;
    00218 }
    00219
    00220 int rpmWriteSignature(FD_t fd, Header h)
    00221 {
    00222     static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    00223     int sigSize, pad;
    00224     int rc;
    00225
    00226     rc = headerWrite(fd, h, HEADER_MAGIC_YES);
    00227     if (rc)
    00228         return rc;
    00229
    00230     sigSize = headerSizeof(h, HEADER_MAGIC_YES);
    00231     pad = (8 - (sigSize % 8)) % 8;
    00232     if (pad) {
    00233 /*@-boundswrite@*/
    00234         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
    00235             rc = 1;
    00236 /*@=boundswrite@*/
    00237     }
    00238     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
    00239     return rc;
    00240 }
    00241
    00242 Header rpmNewSignature(void)
    00243 {
    00244     Header h = headerNew();
    00245     return h;
    00246 }
    00247
    00248 Header rpmFreeSignature(Header h)
    00249 {
    00250     return headerFree(h);
    00251 }
    00252
    00261 static int makePGPSignature(const char * file, /*@out@*/ byte ** pkt,
    00262                 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
    00263         /*@globals errno, rpmGlobalMacroContext,
    00264                 fileSystem, internalState @*/
    00265         /*@modifies errno, *pkt, *pktlen, rpmGlobalMacroContext,
    00266                 fileSystem, internalState @*/
    00267 {
    00268     char * sigfile = alloca(1024);
    00269     int pid, status;
    00270     int inpipe[2];
    00271     struct stat st;
    00272     const char * cmd;
    00273     char *const *av;
    00274     int rc;
    00275
    00276 /*@-boundswrite@*/
    00277     (void) stpcpy( stpcpy(sigfile, file), ".sig");
    00278 /*@=boundswrite@*/
    00279
    00280     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
    00281     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
    00282
    00283     inpipe[0] = inpipe[1] = 0;
    00284 /*@-boundsread@*/
    00285     (void) pipe(inpipe);
    00286 /*@=boundsread@*/
    00287
    00288     if (!(pid = fork())) {
    00289         const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
    00290         const char *path;
    00291         pgpVersion pgpVer;
    00292
    00293         (void) close(STDIN_FILENO);
    00294         (void) dup2(inpipe[0], 3);
    00295         (void) close(inpipe[1]);
    00296
    00297         (void) dosetenv("PGPPASSFD", "3", 1);
    00298 /*@-boundsread@*/
    00299         if (pgp_path && *pgp_path != '\0')
    00300             (void) dosetenv("PGPPATH", pgp_path, 1);
    00301 /*@=boundsread@*/
    00302
    00303         /* dosetenv("PGPPASS", passPhrase, 1); */
    00304
    00305         unsetenv("MALLOC_CHECK_");
    00306         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
    00307             switch(pgpVer) {
    00308             case PGP_2:
    00309                 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
    00310                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00311 /*@-boundsread@*/
    00312                 if (!rc)
    00313                     rc = execve(av[0], av+1, environ);
    00314 /*@=boundsread@*/
    00315                 break;
    00316             case PGP_5:
    00317                 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
    00318                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00319 /*@-boundsread@*/
    00320                 if (!rc)
    00321                     rc = execve(av[0], av+1, environ);
    00322 /*@=boundsread@*/
    00323                 break;
    00324             case PGP_UNKNOWN:
    00325             case PGP_NOTDETECTED:
    00326                 errno = ENOENT;
    00327                 break;
    00328             }
    00329         }
    00330         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
    00331                         strerror(errno));
    00332         _exit(RPMERR_EXEC);
    00333     }
    00334
    00335     delMacro(NULL, "__plaintext_filename");
    00336     delMacro(NULL, "__signature_filename");
    00337
    00338     (void) close(inpipe[0]);
    00339     if (passPhrase)
    00340         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
    00341     (void) write(inpipe[1], "\n", 1);
    00342     (void) close(inpipe[1]);
    00343
    00344     (void)waitpid(pid, &status, 0);
    00345     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
    00346         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
    00347         return 1;
    00348     }
    00349
    00350     if (stat(sigfile, &st)) {
    00351         /* PGP failed to write signature */
    00352         if (sigfile) (void) unlink(sigfile);  /* Just in case */
    00353         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
    00354         return 1;
    00355     }
    00356
    00357 /*@-boundswrite@*/
    00358     *pktlen = st.st_size;
    00359     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *pktlen);
    00360     *pkt = xmalloc(*pktlen);
    00361 /*@=boundswrite@*/
    00362
    00363 /*@-boundsread@*/
    00364     {   FD_t fd;
    00365
    00366         rc = 0;
    00367         fd = Fopen(sigfile, "r.fdio");
    00368         if (fd != NULL && !Ferror(fd)) {
    00369             rc = timedRead(fd, *pkt, *pktlen);
    00370             if (sigfile) (void) unlink(sigfile);
    00371             (void) Fclose(fd);
    00372         }
    00373         if (rc != *pktlen) {
    00374 /*@-boundswrite@*/
    00375             *pkt = _free(*pkt);
    00376 /*@=boundswrite@*/
    00377             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
    00378             return 1;
    00379         }
    00380     }
    00381
    00382     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *pktlen);
    00383 /*@=boundsread@*/
    00384
    00385     return 0;
    00386 }
    00387
    00396 static int makeGPGSignature(const char * file, /*@out@*/ byte ** pkt,
    00397                 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
    00398         /*@globals rpmGlobalMacroContext,
    00399                 fileSystem, internalState @*/
    00400         /*@modifies *pkt, *pktlen, rpmGlobalMacroContext,
    00401                 fileSystem, internalState @*/
    00402 {
    00403     char * sigfile = alloca(1024);
    00404     int pid, status;
    00405     int inpipe[2];
    00406     FILE * fpipe;
    00407     struct stat st;
    00408     const char * cmd;
    00409     char *const *av;
    00410     int rc;
    00411
    00412 /*@-boundswrite@*/
    00413     (void) stpcpy( stpcpy(sigfile, file), ".sig");
    00414 /*@=boundswrite@*/
    00415
    00416     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
    00417     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
    00418
    00419     inpipe[0] = inpipe[1] = 0;
    00420 /*@-boundsread@*/
    00421     (void) pipe(inpipe);
    00422 /*@=boundsread@*/
    00423
    00424     if (!(pid = fork())) {
    00425         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
    00426
    00427         (void) close(STDIN_FILENO);
    00428         (void) dup2(inpipe[0], 3);
    00429         (void) close(inpipe[1]);
    00430
    00431 /*@-boundsread@*/
    00432         if (gpg_path && *gpg_path != '\0')
    00433             (void) dosetenv("GNUPGHOME", gpg_path, 1);
    00434 /*@=boundsread@*/
    00435
    00436         unsetenv("MALLOC_CHECK_");
    00437         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
    00438         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00439 /*@-boundsread@*/
    00440         if (!rc)
    00441             rc = execve(av[0], av+1, environ);
    00442 /*@=boundsread@*/
    00443
    00444         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
    00445                         strerror(errno));
    00446         _exit(RPMERR_EXEC);
    00447     }
    00448
    00449     delMacro(NULL, "__plaintext_filename");
    00450     delMacro(NULL, "__signature_filename");
    00451
    00452     fpipe = fdopen(inpipe[1], "w");
    00453     (void) close(inpipe[0]);
    00454     if (fpipe) {
    00455         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
    00456         (void) fclose(fpipe);
    00457     }
    00458
    00459     (void) waitpid(pid, &status, 0);
    00460     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
    00461         rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
    00462         return 1;
    00463     }
    00464
    00465     if (stat(sigfile, &st)) {
    00466         /* GPG failed to write signature */
    00467         if (sigfile) (void) unlink(sigfile);  /* Just in case */
    00468         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
    00469         return 1;
    00470     }
    00471
    00472 /*@-boundswrite@*/
    00473     *pktlen = st.st_size;
    00474     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlen);
    00475     *pkt = xmalloc(*pktlen);
    00476 /*@=boundswrite@*/
    00477
    00478 /*@-boundsread@*/
    00479     {   FD_t fd;
    00480
    00481         rc = 0;
    00482         fd = Fopen(sigfile, "r.fdio");
    00483         if (fd != NULL && !Ferror(fd)) {
    00484             rc = timedRead(fd, *pkt, *pktlen);
    00485             if (sigfile) (void) unlink(sigfile);
    00486             (void) Fclose(fd);
    00487         }
    00488         if (rc != *pktlen) {
    00489 /*@-boundswrite@*/
    00490             *pkt = _free(*pkt);
    00491 /*@=boundswrite@*/
    00492             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
    00493             return 1;
    00494         }
    00495     }
    00496
    00497     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlen);
    00498 /*@=boundsread@*/
    00499
    00500     return 0;
    00501 }
    00502
    00511 static int makeHDRSignature(Header sig, const char * file, int_32 sigTag,
    00512                 /*@null@*/ const char * passPhrase)
    00513         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00514         /*@modifies sig, rpmGlobalMacroContext, fileSystem, internalState @*/
    00515 {
    00516     Header h = NULL;
    00517     FD_t fd = NULL;
    00518     byte * pkt;
    00519     int_32 pktlen;
    00520     const char * fn = NULL;
    00521     const char * SHA1 = NULL;
    00522     int ret = -1;       /* assume failure. */
    00523
    00524     switch (sigTag) {
    00525     case RPMSIGTAG_SIZE:
    00526     case RPMSIGTAG_MD5:
    00527     case RPMSIGTAG_PGP5:        /* XXX legacy */
    00528     case RPMSIGTAG_PGP:
    00529     case RPMSIGTAG_GPG:
    00530         goto exit;
    00531         /*@notreached@*/ break;
    00532     case RPMSIGTAG_SHA1:
    00533         fd = Fopen(file, "r.fdio");
    00534         if (fd == NULL || Ferror(fd))
    00535             goto exit;
    00536         h = headerRead(fd, HEADER_MAGIC_YES);
    00537         if (h == NULL)
    00538             goto exit;
    00539         (void) Fclose(fd);      fd = NULL;
    00540
    00541         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
    00542             DIGEST_CTX ctx;
    00543             void * uh;
    00544             int_32 uht, uhc;
    00545
    00546             if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
    00547              ||  uh == NULL)
    00548             {
    00549                 h = headerFree(h);
    00550                 goto exit;
    00551             }
    00552             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
    00553             (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
    00554             (void) rpmDigestUpdate(ctx, uh, uhc);
    00555             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
    00556             uh = headerFreeData(uh, uht);
    00557         }
    00558         h = headerFree(h);
    00559
    00560         if (SHA1 == NULL)
    00561             goto exit;
    00562         if (!headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
    00563             goto exit;
    00564         ret = 0;
    00565         break;
    00566     case RPMSIGTAG_DSA:
    00567         fd = Fopen(file, "r.fdio");
    00568         if (fd == NULL || Ferror(fd))
    00569             goto exit;
    00570         h = headerRead(fd, HEADER_MAGIC_YES);
    00571         if (h == NULL)
    00572             goto exit;
    00573         (void) Fclose(fd);      fd = NULL;
    00574         if (makeTempFile(NULL, &fn, &fd))
    00575             goto exit;
    00576         if (headerWrite(fd, h, HEADER_MAGIC_YES))
    00577             goto exit;
    00578         (void) Fclose(fd);      fd = NULL;
    00579         if (makeGPGSignature(fn, &pkt, &pktlen, passPhrase)
    00580          || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
    00581             goto exit;
    00582         ret = 0;
    00583         break;
    00584     case RPMSIGTAG_RSA:
    00585         fd = Fopen(file, "r.fdio");
    00586         if (fd == NULL || Ferror(fd))
    00587             goto exit;
    00588         h = headerRead(fd, HEADER_MAGIC_YES);
    00589         if (h == NULL)
    00590             goto exit;
    00591         (void) Fclose(fd);      fd = NULL;
    00592         if (makeTempFile(NULL, &fn, &fd))
    00593             goto exit;
    00594         if (headerWrite(fd, h, HEADER_MAGIC_YES))
    00595             goto exit;
    00596         (void) Fclose(fd);      fd = NULL;
    00597         if (makePGPSignature(fn, &pkt, &pktlen, passPhrase)
    00598          || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
    00599             goto exit;
    00600         ret = 0;
    00601         break;
    00602     }
    00603
    00604 exit:
    00605     if (fn) {
    00606         (void) unlink(fn);
    00607         fn = _free(fn);
    00608     }
    00609     SHA1 = _free(SHA1);
    00610     h = headerFree(h);
    00611     if (fd) (void) Fclose(fd);
    00612     return ret;
    00613 }
    00614
    00615 int rpmAddSignature(Header sig, const char * file, int_32 sigTag,
    00616                 const char * passPhrase)
    00617 {
    00618     struct stat st;
    00619     byte * pkt;
    00620     int_32 pktlen;
    00621     int ret = -1;       /* assume failure. */
    00622
    00623     switch (sigTag) {
    00624     case RPMSIGTAG_SIZE:
    00625         if (stat(file, &st) != 0)
    00626             break;
    00627         pktlen = st.st_size;
    00628         if (!headerAddEntry(sig, sigTag, RPM_INT32_TYPE, &pktlen, 1))
    00629             break;
    00630         ret = 0;
    00631         break;
    00632     case RPMSIGTAG_MD5:
    00633         pktlen = 16;
    00634         pkt = xcalloc(1, pktlen);
    00635         if (domd5(file, pkt, 0, NULL)
    00636          || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
    00637             break;
    00638         ret = 0;
    00639         break;
    00640     case RPMSIGTAG_PGP5:        /* XXX legacy */
    00641     case RPMSIGTAG_PGP:
    00642         if (makePGPSignature(file, &pkt, &pktlen, passPhrase)
    00643          || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
    00644             break;
    00645 #ifdef  NOTYET  /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
    00646         /* XXX Piggyback a header-only RSA signature as well. */
    00647         ret = makeHDRSignature(sig, file, RPMSIGTAG_RSA, passPhrase);
    00648 #endif
    00649         ret = 0;
    00650         break;
    00651     case RPMSIGTAG_GPG:
    00652         if (makeGPGSignature(file, &pkt, &pktlen, passPhrase)
    00653          || !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
    00654             break;
    00655         /* XXX Piggyback a header-only DSA signature as well. */
    00656         ret = makeHDRSignature(sig, file, RPMSIGTAG_DSA, passPhrase);
    00657         break;
    00658     case RPMSIGTAG_RSA:
    00659     case RPMSIGTAG_DSA:
    00660     case RPMSIGTAG_SHA1:
    00661         ret = makeHDRSignature(sig, file, sigTag, passPhrase);
    00662         break;
    00663     }
    00664
    00665     return ret;
    00666 }
    00667
    00668 static int checkPassPhrase(const char * passPhrase, const int sigTag)
    00669         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00670         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
    00671 {
    00672     int passPhrasePipe[2];
    00673     int pid, status;
    00674     int rc;
    00675     int xx;
    00676
    00677     passPhrasePipe[0] = passPhrasePipe[1] = 0;
    00678 /*@-boundsread@*/
    00679     xx = pipe(passPhrasePipe);
    00680 /*@=boundsread@*/
    00681     if (!(pid = fork())) {
    00682         const char * cmd;
    00683         char *const *av;
    00684         int fdno;
    00685
    00686         xx = close(STDIN_FILENO);
    00687         xx = close(STDOUT_FILENO);
    00688         xx = close(passPhrasePipe[1]);
    00689         if (! rpmIsVerbose())
    00690             xx = close(STDERR_FILENO);
    00691         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
    00692             xx = dup2(fdno, STDIN_FILENO);
    00693             xx = close(fdno);
    00694         }
    00695         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
    00696             xx = dup2(fdno, STDOUT_FILENO);
    00697             xx = close(fdno);
    00698         }
    00699         xx = dup2(passPhrasePipe[0], 3);
    00700
    00701         unsetenv("MALLOC_CHECK_");
    00702         switch (sigTag) {
    00703         case RPMSIGTAG_DSA:
    00704         case RPMSIGTAG_GPG:
    00705         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
    00706
    00707 /*@-boundsread@*/
    00708             if (gpg_path && *gpg_path != '\0')
    00709                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
    00710 /*@=boundsread@*/
    00711
    00712             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
    00713             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00714 /*@-boundsread@*/
    00715             if (!rc)
    00716                 rc = execve(av[0], av+1, environ);
    00717 /*@=boundsread@*/
    00718
    00719             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
    00720                         strerror(errno));
    00721         }   /*@notreached@*/ break;
    00722         case RPMSIGTAG_RSA:
    00723         case RPMSIGTAG_PGP5:    /* XXX legacy */
    00724         case RPMSIGTAG_PGP:
    00725         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
    00726             const char *path;
    00727             pgpVersion pgpVer;
    00728
    00729             (void) dosetenv("PGPPASSFD", "3", 1);
    00730 /*@-boundsread@*/
    00731             if (pgp_path && *pgp_path != '\0')
    00732                 xx = dosetenv("PGPPATH", pgp_path, 1);
    00733 /*@=boundsread@*/
    00734
    00735             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
    00736                 switch(pgpVer) {
    00737                 case PGP_2:
    00738                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
    00739                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00740 /*@-boundsread@*/
    00741                     if (!rc)
    00742                         rc = execve(av[0], av+1, environ);
    00743 /*@=boundsread@*/
    00744                     /*@innerbreak@*/ break;
    00745                 case PGP_5:     /* XXX legacy */
    00746                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
    00747                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
    00748 /*@-boundsread@*/
    00749                     if (!rc)
    00750                         rc = execve(av[0], av+1, environ);
    00751 /*@=boundsread@*/
    00752                     /*@innerbreak@*/ break;
    00753                 case PGP_UNKNOWN:
    00754                 case PGP_NOTDETECTED:
    00755                     /*@innerbreak@*/ break;
    00756                 }
    00757             }
    00758             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
    00759                         strerror(errno));
    00760             _exit(RPMERR_EXEC);
    00761         }   /*@notreached@*/ break;
    00762         default: /* This case should have been screened out long ago. */
    00763             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
    00764             _exit(RPMERR_SIGGEN);
    00765             /*@notreached@*/ break;
    00766         }
    00767     }
    00768
    00769     xx = close(passPhrasePipe[0]);
    00770     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
    00771     xx = write(passPhrasePipe[1], "\n", 1);
    00772     xx = close(passPhrasePipe[1]);
    00773
    00774     (void) waitpid(pid, &status, 0);
    00775
    00776     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
    00777 }
    00778
    00779 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
    00780 {
    00781     char *pass;
    00782     int aok;
    00783
    00784     switch (sigTag) {
    00785     case RPMSIGTAG_DSA:
    00786     case RPMSIGTAG_GPG:
    00787 /*@-boundsread@*/
    00788       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
    00789         aok = (name && *name != '\0');
    00790         name = _free(name);
    00791       }
    00792 /*@=boundsread@*/
    00793         if (!aok) {
    00794             rpmError(RPMERR_SIGGEN,
    00795                 _("You must set \"%%_gpg_name\" in your macro file\n"));
    00796             return NULL;
    00797         }
    00798         break;
    00799     case RPMSIGTAG_RSA:
    00800     case RPMSIGTAG_PGP5:        /* XXX legacy */
    00801     case RPMSIGTAG_PGP:
    00802 /*@-boundsread@*/
    00803       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
    00804         aok = (name && *name != '\0');
    00805         name = _free(name);
    00806       }
    00807 /*@=boundsread@*/
    00808         if (!aok) {
    00809             rpmError(RPMERR_SIGGEN,
    00810                 _("You must set \"%%_pgp_name\" in your macro file\n"));
    00811             return NULL;
    00812         }
    00813         break;
    00814     default:
    00815         /* Currently the calling function (rpm.c:main) is checking this and
    00816          * doing a better job.  This section should never be accessed.
    00817          */
    00818         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
    00819         return NULL;
    00820         /*@notreached@*/ break;
    00821     }
    00822
    00823 /*@-moduncon -nullpass @*/
    00824     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
    00825 /*@=moduncon -nullpass @*/
    00826
    00827     if (checkPassPhrase(pass, sigTag))
    00828         return NULL;
    00829
    00830     return pass;
    00831 }
    00832
    00833 static /*@observer@*/ const char * rpmSigString(rpmRC res)
    00834         /*@*/
    00835 {
    00836     const char * str;
    00837     switch (res) {
    00838     case RPMRC_OK:              str = "OK";             break;
    00839     case RPMRC_FAIL:            str = "BAD";            break;
    00840     case RPMRC_NOKEY:           str = "NOKEY";          break;
    00841     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
    00842     default:
    00843     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
    00844     }
    00845     return str;
    00846 }
    00847
    00848 /*@-boundswrite@*/
    00849 static rpmRC
    00850 verifySizeSignature(const rpmts ts, /*@out@*/ char * t)
    00851         /*@modifies *t @*/
    00852 {
    00853     const void * sig = rpmtsSig(ts);
    00854     pgpDig dig = rpmtsDig(ts);
    00855     rpmRC res;
    00856     int_32 size = 0x7fffffff;
    00857
    00858     *t = '\0';
    00859     t = stpcpy(t, _("Header+Payload size: "));
    00860
    00861     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
    00862         res = RPMRC_NOKEY;
    00863         t = stpcpy(t, rpmSigString(res));
    00864         goto exit;
    00865     }
    00866
    00867     memcpy(&size, sig, sizeof(size));
    00868
    00869     if (size != dig->nbytes) {
    00870         res = RPMRC_FAIL;
    00871         t = stpcpy(t, rpmSigString(res));
    00872         sprintf(t, " Expected(%d) != (%d)\n", size, dig->nbytes);
    00873     } else {
    00874         res = RPMRC_OK;
    00875         t = stpcpy(t, rpmSigString(res));
    00876         sprintf(t, " (%d)", dig->nbytes);
    00877     }
    00878
    00879 exit:
    00880     t = stpcpy(t, "\n");
    00881     return res;
    00882 }
    00883 /*@=boundswrite@*/
    00884
    00885 /*@-boundswrite@*/
    00886 static rpmRC
    00887 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t,
    00888                 /*@null@*/ DIGEST_CTX md5ctx)
    00889         /*@modifies *t @*/
    00890 {
    00891     const void * sig = rpmtsSig(ts);
    00892     int_32 siglen = rpmtsSiglen(ts);
    00893     pgpDig dig = rpmtsDig(ts);
    00894     rpmRC res;
    00895     byte * md5sum = NULL;
    00896     size_t md5len = 0;
    00897
    00898     *t = '\0';
    00899     t = stpcpy(t, _("MD5 digest: "));
    00900
    00901     if (md5ctx == NULL || sig == NULL || dig == NULL) {
    00902         res = RPMRC_NOKEY;
    00903         t = stpcpy(t, rpmSigString(res));
    00904         goto exit;
    00905     }
    00906
    00907     (void) rpmDigestFinal(rpmDigestDup(md5ctx),
    00908                 (void **)&md5sum, &md5len, 0);
    00909
    00910     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
    00911         res = RPMRC_FAIL;
    00912         t = stpcpy(t, rpmSigString(res));
    00913         t = stpcpy(t, " Expected(");
    00914         (void) pgpHexCvt(t, sig, siglen);
    00915         t += strlen(t);
    00916         t = stpcpy(t, ") != (");
    00917     } else {
    00918         res = RPMRC_OK;
    00919         t = stpcpy(t, rpmSigString(res));
    00920         t = stpcpy(t, " (");
    00921     }
    00922     (void) pgpHexCvt(t, md5sum, md5len);
    00923     t += strlen(t);
    00924     t = stpcpy(t, ")");
    00925
    00926 exit:
    00927     md5sum = _free(md5sum);
    00928     t = stpcpy(t, "\n");
    00929     return res;
    00930 }
    00931 /*@=boundswrite@*/
    00932
    00933 /*@-boundswrite@*/
    00941 static rpmRC
    00942 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t,
    00943                 /*@null@*/ DIGEST_CTX sha1ctx)
    00944         /*@modifies *t @*/
    00945 {
    00946     const void * sig = rpmtsSig(ts);
    00947 #ifdef  NOTYET
    00948     int_32 siglen = rpmtsSiglen(ts);
    00949 #endif
    00950     pgpDig dig = rpmtsDig(ts);
    00951     rpmRC res;
    00952     const char * SHA1 = NULL;
    00953
    00954     *t = '\0';
    00955     t = stpcpy(t, _("Header SHA1 digest: "));
    00956
    00957     if (sha1ctx == NULL || sig == NULL || dig == NULL) {
    00958         res = RPMRC_NOKEY;
    00959         t = stpcpy(t, rpmSigString(res));
    00960         goto exit;
    00961     }
    00962
    00963     (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
    00964                 (void **)&SHA1, NULL, 1);
    00965
    00966     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
    00967         res = RPMRC_FAIL;
    00968         t = stpcpy(t, rpmSigString(res));
    00969         t = stpcpy(t, " Expected(");
    00970         t = stpcpy(t, sig);
    00971         t = stpcpy(t, ") != (");
    00972     } else {
    00973         res = RPMRC_OK;
    00974         t = stpcpy(t, rpmSigString(res));
    00975         t = stpcpy(t, " (");
    00976     }
    00977     if (SHA1)
    00978         t = stpcpy(t, SHA1);
    00979     t = stpcpy(t, ")");
    00980
    00981 exit:
    00982     SHA1 = _free(SHA1);
    00983     t = stpcpy(t, "\n");
    00984     return res;
    00985 }
    00986 /*@=boundswrite@*/
    00987
    00993 static inline unsigned char nibble(char c)
    00994         /*@*/
    00995 {
    00996     if (c >= '0' && c <= '9')
    00997         return (c - '0');
    00998     if (c >= 'A' && c <= 'F')
    00999         return (c - 'A') + 10;
    01000     if (c >= 'a' && c <= 'f')
    01001         return (c - 'a') + 10;
    01002     return 0;
    01003 }
    01004
    01005 /*@-boundswrite@*/
    01013 static rpmRC
    01014 verifyPGPSignature(rpmts ts, /*@out@*/ char * t,
    01015                 /*@null@*/ DIGEST_CTX md5ctx)
    01016         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    01017         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
    01018 {
    01019     const void * sig = rpmtsSig(ts);
    01020 #ifdef  NOTYET
    01021     int_32 siglen = rpmtsSiglen(ts);
    01022 #endif
    01023     int_32 sigtag = rpmtsSigtag(ts);
    01024     pgpDig dig = rpmtsDig(ts);
    01025     pgpDigParams sigp = rpmtsSignature(ts);
    01026     rpmRC res;
    01027     int xx;
    01028
    01029     *t = '\0';
    01030     t = stpcpy(t, _("V3 RSA/MD5 signature: "));
    01031
    01032     if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
    01033         res = RPMRC_NOKEY;
    01034         goto exit;
    01035     }
    01036
    01037     /* XXX sanity check on sigtag and signature agreement. */
    01038     if (!(sigtag == RPMSIGTAG_PGP
    01039         && sigp->pubkey_algo == PGPPUBKEYALGO_RSA
    01040         && sigp->hash_algo == PGPHASHALGO_MD5))
    01041     {
    01042         res = RPMRC_NOKEY;
    01043         goto exit;
    01044     }
    01045
    01046     {   DIGEST_CTX ctx = rpmDigestDup(md5ctx);
    01047         byte signhash16[2];
    01048         const char * s;
    01049
    01050         if (sigp->hash != NULL)
    01051             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
    01052
    01053 #ifdef  NOTYET  /* XXX not for binary/text document signatures. */
    01054         if (sigp->sigtype == 4) {
    01055             int nb = dig->nbytes + sigp->hashlen;
    01056             byte trailer[6];
    01057             nb = htonl(nb);
    01058             trailer[0] = 0x4;
    01059             trailer[1] = 0xff;
    01060             memcpy(trailer+2, &nb, sizeof(nb));
    01061             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
    01062         }
    01063 #endif
    01064
    01065         xx = rpmDigestFinal(ctx, (void **)&dig->md5, &dig->md5len, 1);
    01066
    01067         /* Compare leading 16 bits of digest for quick check. */
    01068         s = dig->md5;
    01069         signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]);
    01070         signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]);
    01071         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
    01072             res = RPMRC_FAIL;
    01073             goto exit;
    01074         }
    01075
    01076     }
    01077
    01078     {   const char * prefix = "3020300c06082a864886f70d020505000410";
    01079         unsigned int nbits = 1024;
    01080         unsigned int nb = (nbits + 7) >> 3;
    01081         const char * hexstr;
    01082         char * tt;
    01083
    01084         hexstr = tt = xmalloc(2 * nb + 1);
    01085         memset(tt, 'f', (2 * nb));
    01086         tt[0] = '0'; tt[1] = '0';
    01087         tt[2] = '0'; tt[3] = '1';
    01088         tt += (2 * nb) - strlen(prefix) - strlen(dig->md5) - 2;
    01089         *tt++ = '0'; *tt++ = '0';
    01090         tt = stpcpy(tt, prefix);
    01091         tt = stpcpy(tt, dig->md5);
    01092
    01093         mp32nzero(&dig->rsahm); mp32nsethex(&dig->rsahm, hexstr);
    01094
    01095         hexstr = _free(hexstr);
    01096
    01097     }
    01098
    01099     /* Retrieve the matching public key. */
    01100     res = rpmtsFindPubkey(ts);
    01101     if (res != RPMRC_OK)
    01102         goto exit;
    01103
    01104     if (rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c))
    01105         res = RPMRC_OK;
    01106     else
    01107         res = RPMRC_FAIL;
    01108
    01109 exit:
    01110     t = stpcpy(t, rpmSigString(res));
    01111     if (sigp != NULL) {
    01112         t = stpcpy(t, ", key ID ");
    01113         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
    01114         t += strlen(t);
    01115     }
    01116     t = stpcpy(t, "\n");
    01117     return res;
    01118 }
    01119 /*@=boundswrite@*/
    01120
    01128 /*@-boundswrite@*/
    01129 static rpmRC
    01130 verifyGPGSignature(rpmts ts, /*@out@*/ char * t,
    01131                 /*@null@*/ DIGEST_CTX sha1ctx)
    01132         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    01133         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
    01134 {
    01135     const void * sig = rpmtsSig(ts);
    01136 #ifdef  NOTYET
    01137     int_32 siglen = rpmtsSiglen(ts);
    01138 #endif
    01139     int_32 sigtag = rpmtsSigtag(ts);
    01140     pgpDig dig = rpmtsDig(ts);
    01141     pgpDigParams sigp = rpmtsSignature(ts);
    01142     rpmRC res;
    01143     int xx;
    01144
    01145     *t = '\0';
    01146     if (dig != NULL && dig->hdrsha1ctx == sha1ctx)
    01147         t = stpcpy(t, _("Header "));
    01148     t = stpcpy(t, _("V3 DSA signature: "));
    01149
    01150     if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
    01151         res = RPMRC_NOKEY;
    01152         goto exit;
    01153     }
    01154
    01155     /* XXX sanity check on sigtag and signature agreement. */
    01156     if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA)
    01157         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
    01158         && sigp->hash_algo == PGPHASHALGO_SHA1))
    01159     {
    01160         res = RPMRC_NOKEY;
    01161         goto exit;
    01162     }
    01163
    01164     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
    01165         byte signhash16[2];
    01166
    01167         if (sigp->hash != NULL)
    01168             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
    01169
    01170 #ifdef  NOTYET  /* XXX not for binary/text document signatures. */
    01171         if (sigp->sigtype == 4) {
    01172             int nb = dig->nbytes + sigp->hashlen;
    01173             byte trailer[6];
    01174             nb = htonl(nb);
    01175             trailer[0] = 0x4;
    01176             trailer[1] = 0xff;
    01177             memcpy(trailer+2, &nb, sizeof(nb));
    01178             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
    01179         }
    01180 #endif
    01181         xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 1);
    01182
    01183         mp32nzero(&dig->hm);    mp32nsethex(&dig->hm, dig->sha1);
    01184
    01185         /* Compare leading 16 bits of digest for quick check. */
    01186         signhash16[0] = (*dig->hm.data >> 24) & 0xff;
    01187         signhash16[1] = (*dig->hm.data >> 16) & 0xff;
    01188         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
    01189             res = RPMRC_FAIL;
    01190             goto exit;
    01191         }
    01192     }
    01193
    01194     /* Retrieve the matching public key. */
    01195     res = rpmtsFindPubkey(ts);
    01196     if (res != RPMRC_OK)
    01197         goto exit;
    01198
    01199     if (dsavrfy(&dig->p, &dig->q, &dig->g,
    01200                 &dig->hm, &dig->y, &dig->r, &dig->s))
    01201         res = RPMRC_OK;
    01202     else
    01203         res = RPMRC_FAIL;
    01204
    01205 exit:
    01206     t = stpcpy(t, rpmSigString(res));
    01207     if (sigp != NULL) {
    01208         t = stpcpy(t, ", key ID ");
    01209         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
    01210         t += strlen(t);
    01211     }
    01212     t = stpcpy(t, "\n");
    01213     return res;
    01214 }
    01215 /*@=boundswrite@*/
    01216
    01217 rpmRC
    01218 rpmVerifySignature(const rpmts ts, char * result)
    01219 {
    01220     const void * sig = rpmtsSig(ts);
    01221     int_32 siglen = rpmtsSiglen(ts);
    01222     int_32 sigtag = rpmtsSigtag(ts);
    01223     pgpDig dig = rpmtsDig(ts);
    01224     rpmRC res;
    01225
    01226     if (sig == NULL || siglen <= 0 || dig == NULL) {
    01227         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
    01228         return RPMRC_NOTFOUND;
    01229     }
    01230
    01231     switch (sigtag) {
    01232     case RPMSIGTAG_SIZE:
    01233         res = verifySizeSignature(ts, result);
    01234         break;
    01235     case RPMSIGTAG_MD5:
    01236         res = verifyMD5Signature(ts, result, dig->md5ctx);
    01237         break;
    01238     case RPMSIGTAG_SHA1:
    01239         res = verifySHA1Signature(ts, result, dig->hdrsha1ctx);
    01240         break;
    01241     case RPMSIGTAG_RSA:
    01242     case RPMSIGTAG_PGP5:        /* XXX legacy */
    01243     case RPMSIGTAG_PGP:
    01244         res = verifyPGPSignature(ts, result, dig->md5ctx);
    01245         break;
    01246     case RPMSIGTAG_DSA:
    01247         res = verifyGPGSignature(ts, result, dig->hdrsha1ctx);
    01248         break;
    01249     case RPMSIGTAG_GPG:
    01250         res = verifyGPGSignature(ts, result, dig->sha1ctx);
    01251         break;
    01252     case RPMSIGTAG_LEMD5_1:
    01253     case RPMSIGTAG_LEMD5_2:
    01254         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
    01255         res = RPMRC_NOTFOUND;
    01256         break;
    01257     default:
    01258         sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag);
    01259         res = RPMRC_NOTFOUND;
    01260         break;
    01261     }
    01262     return res;
    01263 }