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 /*@-sizeoftype@*/
00241     if (entry->info.tag == RPMTAG_HEADERSIGNATURES
00242        && entry->info.type == RPM_BIN_TYPE
00243        && entry->info.count == REGION_TAG_COUNT)
00244     {
00245 /*@=sizeoftype@*/
00246 
00247         if (entry->info.offset >= dl) {
00248             (void) snprintf(buf, sizeof(buf),
00249                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00250                 entry->info.tag, entry->info.type,
00251                 entry->info.offset, entry->info.count);
00252             goto exit;
00253         }
00254 
00255         /* Is there an immutable header region tag trailer? */
00256         dataEnd = dataStart + entry->info.offset;
00257 /*@-sizeoftype@*/
00258 /*@-bounds@*/
00259         (void) memcpy(info, dataEnd, REGION_TAG_COUNT);
00260         /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
00261         if (info->tag == htonl(RPMTAG_HEADERIMAGE)) {
00262             int_32 stag = htonl(RPMTAG_HEADERSIGNATURES);
00263             info->tag = stag;
00264             memcpy(dataEnd, &stag, sizeof(stag));
00265         }
00266 /*@=bounds@*/
00267         dataEnd += REGION_TAG_COUNT;
00268 
00269         xx = headerVerifyInfo(1, dl, info, &entry->info, 1);
00270         if (xx != -1 ||
00271             !((entry->info.tag == RPMTAG_HEADERSIGNATURES || entry->info.tag == RPMTAG_HEADERIMAGE)
00272            && entry->info.type == RPM_BIN_TYPE
00273            && entry->info.count == REGION_TAG_COUNT))
00274         {
00275             (void) snprintf(buf, sizeof(buf),
00276                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00277                 entry->info.tag, entry->info.type,
00278                 entry->info.offset, entry->info.count);
00279             goto exit;
00280         }
00281 /*@=sizeoftype@*/
00282 /*@-boundswrite@*/
00283         memset(info, 0, sizeof(*info));
00284 /*@=boundswrite@*/
00285 
00286         /* Is the no. of tags in the region less than the total no. of tags? */
00287         ril = entry->info.offset/sizeof(*pe);
00288         if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00289             (void) snprintf(buf, sizeof(buf),
00290                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00291             goto exit;
00292         }
00293     }
00294 
00295     /* Sanity check signature tags */
00296 /*@-boundswrite@*/
00297     memset(info, 0, sizeof(*info));
00298 /*@=boundswrite@*/
00299     for (i = 1; i < il; i++) {
00300         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00301         if (xx != -1) {
00302             (void) snprintf(buf, sizeof(buf),
00303                 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00304                 i, entry->info.tag, entry->info.type,
00305                 entry->info.offset, entry->info.count);
00306             goto exit;
00307         }
00308     }
00309 
00310     /* OK, blob looks sane, load the header. */
00311     sigh = headerLoad(ei);
00312     if (sigh == NULL) {
00313         (void) snprintf(buf, sizeof(buf), _("sigh load: BAD\n"));
00314         goto exit;
00315     }
00316     sigh->flags |= HEADERFLAG_ALLOCATED;
00317 
00318     {   int sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
00319         int pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
00320         int_32 * archSize = NULL;
00321 
00322         /* Position at beginning of header. */
00323         if (pad && (xx = timedRead(fd, (char *)block, pad)) != pad) {
00324             (void) snprintf(buf, sizeof(buf),
00325                 _("sigh pad(%d): BAD, read %d bytes\n"), pad, xx);
00326             goto exit;
00327         }
00328 
00329         /* Print package component sizes. */
00330         if (headerGetEntry(sigh, RPMSIGTAG_SIZE, NULL,(void **)&archSize, NULL)) {
00331             rc = printSize(fd, sigSize, pad, *archSize);
00332             if (rc != RPMRC_OK)
00333                 (void) snprintf(buf, sizeof(buf),
00334                         _("sigh sigSize(%d): BAD, fstat(2) failed\n"), sigSize);
00335         }
00336     }
00337 
00338 exit:
00339 /*@-boundswrite@*/
00340     if (sighp && sigh && rc == RPMRC_OK)
00341         *sighp = headerLink(sigh);
00342     sigh = headerFree(sigh);
00343 
00344     if (msg != NULL) {
00345         buf[sizeof(buf)-1] = '\0';
00346         *msg = xstrdup(buf);
00347     }
00348 /*@=boundswrite@*/
00349 
00350     return rc;
00351 }
00352 
00353 int rpmWriteSignature(FD_t fd, Header sigh)
00354 {
00355     static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
00356     int sigSize, pad;
00357     int rc;
00358 
00359     rc = headerWrite(fd, sigh, HEADER_MAGIC_YES);
00360     if (rc)
00361         return rc;
00362 
00363     sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
00364     pad = (8 - (sigSize % 8)) % 8;
00365     if (pad) {
00366 /*@-boundswrite@*/
00367         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
00368             rc = 1;
00369 /*@=boundswrite@*/
00370     }
00371     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
00372     return rc;
00373 }
00374 
00375 Header rpmNewSignature(void)
00376 {
00377     Header sigh = headerNew();
00378     return sigh;
00379 }
00380 
00381 Header rpmFreeSignature(Header sigh)
00382 {
00383     return headerFree(sigh);
00384 }
00385 
00395 static int makePGPSignature(const char * file, int_32 * sigTagp,
00396                 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp,
00397                 /*@null@*/ const char * passPhrase)
00398         /*@globals errno, rpmGlobalMacroContext, h_errno,
00399                 fileSystem, internalState @*/
00400         /*@modifies errno, *pktp, *pktlenp, rpmGlobalMacroContext,
00401                 fileSystem, internalState @*/
00402 {
00403     char * sigfile = alloca(1024);
00404     int pid, status;
00405     int inpipe[2];
00406     struct stat st;
00407     const char * cmd;
00408     char *const *av;
00409     pgpDig dig = NULL;
00410     pgpDigParams sigp = NULL;
00411     int rc;
00412 
00413 /*@-boundswrite@*/
00414     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00415 /*@=boundswrite@*/
00416 
00417     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00418     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00419 
00420     inpipe[0] = inpipe[1] = 0;
00421 /*@-boundsread@*/
00422     (void) pipe(inpipe);
00423 /*@=boundsread@*/
00424 
00425     if (!(pid = fork())) {
00426         const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00427         const char *path;
00428         pgpVersion pgpVer;
00429 
00430         (void) close(STDIN_FILENO);
00431         (void) dup2(inpipe[0], 3);
00432         (void) close(inpipe[1]);
00433 
00434         (void) dosetenv("PGPPASSFD", "3", 1);
00435 /*@-boundsread@*/
00436         if (pgp_path && *pgp_path != '\0')
00437             (void) dosetenv("PGPPATH", pgp_path, 1);
00438 /*@=boundsread@*/
00439 
00440         /* dosetenv("PGPPASS", passPhrase, 1); */
00441 
00442         unsetenv("MALLOC_CHECK_");
00443         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00444             switch(pgpVer) {
00445             case PGP_2:
00446                 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
00447                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00448 /*@-boundsread@*/
00449                 if (!rc)
00450                     rc = execve(av[0], av+1, environ);
00451 /*@=boundsread@*/
00452                 break;
00453             case PGP_5:
00454                 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
00455                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00456 /*@-boundsread@*/
00457                 if (!rc)
00458                     rc = execve(av[0], av+1, environ);
00459 /*@=boundsread@*/
00460                 break;
00461             case PGP_UNKNOWN:
00462             case PGP_NOTDETECTED:
00463                 errno = ENOENT;
00464                 break;
00465             }
00466         }
00467         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00468                         strerror(errno));
00469         _exit(RPMERR_EXEC);
00470     }
00471 
00472     delMacro(NULL, "__plaintext_filename");
00473     delMacro(NULL, "__signature_filename");
00474 
00475     (void) close(inpipe[0]);
00476     if (passPhrase)
00477         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
00478     (void) write(inpipe[1], "\n", 1);
00479     (void) close(inpipe[1]);
00480 
00481     (void)waitpid(pid, &status, 0);
00482     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00483         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
00484         return 1;
00485     }
00486 
00487     if (stat(sigfile, &st)) {
00488         /* PGP failed to write signature */
00489         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00490         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
00491         return 1;
00492     }
00493 
00494 /*@-boundswrite@*/
00495     *pktlenp = st.st_size;
00496     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *pktlenp);
00497     *pktp = xmalloc(*pktlenp);
00498 /*@=boundswrite@*/
00499 
00500 /*@-boundsread@*/
00501     {   FD_t fd;
00502 
00503         rc = 0;
00504         fd = Fopen(sigfile, "r.fdio");
00505         if (fd != NULL && !Ferror(fd)) {
00506             rc = timedRead(fd, *pktp, *pktlenp);
00507             if (sigfile) (void) unlink(sigfile);
00508             (void) Fclose(fd);
00509         }
00510         if (rc != *pktlenp) {
00511 /*@-boundswrite@*/
00512             *pktp = _free(*pktp);
00513 /*@=boundswrite@*/
00514             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00515             return 1;
00516         }
00517     }
00518 
00519     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *pktlenp);
00520 /*@=boundsread@*/
00521 
00522 #ifdef  NOTYET
00523     /* Parse the signature, change signature tag as appropriate. */
00524     dig = pgpNewDig();
00525 
00526     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00527     sigp = &dig->signature;
00528 
00529     dig = pgpFreeDig(dig);
00530 #endif
00531 
00532     return 0;
00533 }
00534 
00544 static int makeGPGSignature(const char * file, int_32 * sigTagp,
00545                 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp,
00546                 /*@null@*/ const char * passPhrase)
00547         /*@globals rpmGlobalMacroContext, h_errno,
00548                 fileSystem, internalState @*/
00549         /*@modifies *pktp, *pktlenp, rpmGlobalMacroContext,
00550                 fileSystem, internalState @*/
00551 {
00552     char * sigfile = alloca(strlen(file)+sizeof(".sig"));
00553     int pid, status;
00554     int inpipe[2];
00555     FILE * fpipe;
00556     struct stat st;
00557     const char * cmd;
00558     char *const *av;
00559     pgpDig dig = NULL;
00560     pgpDigParams sigp = NULL;
00561     int rc;
00562 
00563 /*@-boundswrite@*/
00564     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00565 /*@=boundswrite@*/
00566 
00567     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00568     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00569 
00570     inpipe[0] = inpipe[1] = 0;
00571 /*@-boundsread@*/
00572     (void) pipe(inpipe);
00573 /*@=boundsread@*/
00574 
00575     if (!(pid = fork())) {
00576         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00577 
00578         (void) close(STDIN_FILENO);
00579         (void) dup2(inpipe[0], 3);
00580         (void) close(inpipe[1]);
00581 
00582 /*@-boundsread@*/
00583         if (gpg_path && *gpg_path != '\0')
00584             (void) dosetenv("GNUPGHOME", gpg_path, 1);
00585 /*@=boundsread@*/
00586         (void) dosetenv("LC_ALL", "C", 1);
00587 
00588         unsetenv("MALLOC_CHECK_");
00589         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
00590         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00591 /*@-boundsread@*/
00592         if (!rc)
00593             rc = execve(av[0], av+1, environ);
00594 /*@=boundsread@*/
00595 
00596         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00597                         strerror(errno));
00598         _exit(RPMERR_EXEC);
00599     }
00600 
00601     delMacro(NULL, "__plaintext_filename");
00602     delMacro(NULL, "__signature_filename");
00603 
00604     fpipe = fdopen(inpipe[1], "w");
00605     (void) close(inpipe[0]);
00606     if (fpipe) {
00607         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
00608         (void) fclose(fpipe);
00609     }
00610 
00611     (void) waitpid(pid, &status, 0);
00612     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00613         rpmError(RPMERR_SIGGEN, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
00614         return 1;
00615     }
00616 
00617     if (stat(sigfile, &st)) {
00618         /* GPG failed to write signature */
00619         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00620         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
00621         return 1;
00622     }
00623 
00624 /*@-boundswrite@*/
00625     *pktlenp = st.st_size;
00626     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlenp);
00627     *pktp = xmalloc(*pktlenp);
00628 /*@=boundswrite@*/
00629 
00630 /*@-boundsread@*/
00631     {   FD_t fd;
00632 
00633         rc = 0;
00634         fd = Fopen(sigfile, "r.fdio");
00635         if (fd != NULL && !Ferror(fd)) {
00636             rc = timedRead(fd, *pktp, *pktlenp);
00637             if (sigfile) (void) unlink(sigfile);
00638             (void) Fclose(fd);
00639         }
00640         if (rc != *pktlenp) {
00641 /*@-boundswrite@*/
00642             *pktp = _free(*pktp);
00643 /*@=boundswrite@*/
00644             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00645             return 1;
00646         }
00647     }
00648 
00649     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlenp);
00650 /*@=boundsread@*/
00651 
00652     /* Parse the signature, change signature tag as appropriate. */
00653     dig = pgpNewDig();
00654 
00655     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00656     sigp = &dig->signature;
00657 
00658     switch (*sigTagp) {
00659     case RPMSIGTAG_SIZE:
00660     case RPMSIGTAG_MD5:
00661     case RPMSIGTAG_SHA1:
00662         break;
00663     case RPMSIGTAG_GPG:
00664         /* XXX check MD5 hash too? */
00665         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00666             *sigTagp = RPMSIGTAG_PGP;
00667         break;
00668     case RPMSIGTAG_PGP5:        /* XXX legacy */
00669     case RPMSIGTAG_PGP:
00670         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00671             *sigTagp = RPMSIGTAG_GPG;
00672         break;
00673     case RPMSIGTAG_DSA:
00674         /* XXX check MD5 hash too? */
00675         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00676             *sigTagp = RPMSIGTAG_RSA;
00677         break;
00678     case RPMSIGTAG_RSA:
00679         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00680             *sigTagp = RPMSIGTAG_DSA;
00681         break;
00682     }
00683 
00684     dig = pgpFreeDig(dig);
00685 
00686     return 0;
00687 }
00688 
00697 static int makeHDRSignature(Header sigh, const char * file, int_32 sigTag,
00698                 /*@null@*/ const char * passPhrase)
00699         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00700         /*@modifies sigh, rpmGlobalMacroContext, fileSystem, internalState @*/
00701 {
00702     Header h = NULL;
00703     FD_t fd = NULL;
00704     byte * pkt;
00705     int_32 pktlen;
00706     const char * fn = NULL;
00707     const char * SHA1 = NULL;
00708     int ret = -1;       /* assume failure. */
00709 
00710     switch (sigTag) {
00711     case RPMSIGTAG_SIZE:
00712     case RPMSIGTAG_MD5:
00713     case RPMSIGTAG_PGP5:        /* XXX legacy */
00714     case RPMSIGTAG_PGP:
00715     case RPMSIGTAG_GPG:
00716         goto exit;
00717         /*@notreached@*/ break;
00718     case RPMSIGTAG_SHA1:
00719         fd = Fopen(file, "r.fdio");
00720         if (fd == NULL || Ferror(fd))
00721             goto exit;
00722         h = headerRead(fd, HEADER_MAGIC_YES);
00723         if (h == NULL)
00724             goto exit;
00725         (void) Fclose(fd);      fd = NULL;
00726 
00727         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
00728             DIGEST_CTX ctx;
00729             void * uh;
00730             int_32 uht, uhc;
00731         
00732             if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
00733              ||  uh == NULL)
00734             {
00735                 h = headerFree(h);
00736                 goto exit;
00737             }
00738             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00739             (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
00740             (void) rpmDigestUpdate(ctx, uh, uhc);
00741             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
00742             uh = headerFreeData(uh, uht);
00743         }
00744         h = headerFree(h);
00745 
00746         if (SHA1 == NULL)
00747             goto exit;
00748         if (!headerAddEntry(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
00749             goto exit;
00750         ret = 0;
00751         break;
00752     case RPMSIGTAG_DSA:
00753         fd = Fopen(file, "r.fdio");
00754         if (fd == NULL || Ferror(fd))
00755             goto exit;
00756         h = headerRead(fd, HEADER_MAGIC_YES);
00757         if (h == NULL)
00758             goto exit;
00759         (void) Fclose(fd);      fd = NULL;
00760         if (makeTempFile(NULL, &fn, &fd))
00761             goto exit;
00762         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00763             goto exit;
00764         (void) Fclose(fd);      fd = NULL;
00765         if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00766          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00767             goto exit;
00768         ret = 0;
00769         break;
00770     case RPMSIGTAG_RSA:
00771         fd = Fopen(file, "r.fdio");
00772         if (fd == NULL || Ferror(fd))
00773             goto exit;
00774         h = headerRead(fd, HEADER_MAGIC_YES);
00775         if (h == NULL)
00776             goto exit;
00777         (void) Fclose(fd);      fd = NULL;
00778         if (makeTempFile(NULL, &fn, &fd))
00779             goto exit;
00780         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00781             goto exit;
00782         (void) Fclose(fd);      fd = NULL;
00783         if (makePGPSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00784          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00785             goto exit;
00786         ret = 0;
00787         break;
00788     }
00789 
00790 exit:
00791     if (fn) {
00792         (void) unlink(fn);
00793         fn = _free(fn);
00794     }
00795     SHA1 = _free(SHA1);
00796     h = headerFree(h);
00797     if (fd != NULL) (void) Fclose(fd);
00798     return ret;
00799 }
00800 
00801 int rpmAddSignature(Header sigh, const char * file, int_32 sigTag,
00802                 const char * passPhrase)
00803 {
00804     struct stat st;
00805     byte * pkt;
00806     int_32 pktlen;
00807     int ret = -1;       /* assume failure. */
00808 
00809     switch (sigTag) {
00810     case RPMSIGTAG_SIZE:
00811         if (stat(file, &st) != 0)
00812             break;
00813         pktlen = st.st_size;
00814         if (!headerAddEntry(sigh, sigTag, RPM_INT32_TYPE, &pktlen, 1))
00815             break;
00816         ret = 0;
00817         break;
00818     case RPMSIGTAG_MD5:
00819         pktlen = 16;
00820         pkt = memset(alloca(pktlen), 0, pktlen);
00821         if (domd5(file, pkt, 0, NULL)
00822          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00823             break;
00824         ret = 0;
00825         break;
00826     case RPMSIGTAG_PGP5:        /* XXX legacy */
00827     case RPMSIGTAG_PGP:
00828         if (makePGPSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00829          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00830             break;
00831 #ifdef  NOTYET  /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
00832         /* XXX Piggyback a header-only RSA signature as well. */
00833         ret = makeHDRSignature(sigh, file, RPMSIGTAG_RSA, passPhrase);
00834 #endif
00835         ret = 0;
00836         break;
00837     case RPMSIGTAG_GPG:
00838         if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00839          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00840             break;
00841         /* XXX Piggyback a header-only DSA signature as well. */
00842         ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
00843         break;
00844     case RPMSIGTAG_RSA:
00845     case RPMSIGTAG_DSA:
00846     case RPMSIGTAG_SHA1:
00847         ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
00848         break;
00849     }
00850 
00851     return ret;
00852 }
00853 
00854 static int checkPassPhrase(const char * passPhrase, const int sigTag)
00855         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00856         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00857 {
00858     int passPhrasePipe[2];
00859     int pid, status;
00860     int rc;
00861     int xx;
00862 
00863     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00864 /*@-boundsread@*/
00865     xx = pipe(passPhrasePipe);
00866 /*@=boundsread@*/
00867     if (!(pid = fork())) {
00868         const char * cmd;
00869         char *const *av;
00870         int fdno;
00871 
00872         xx = close(STDIN_FILENO);
00873         xx = close(STDOUT_FILENO);
00874         xx = close(passPhrasePipe[1]);
00875         if (! rpmIsVerbose())
00876             xx = close(STDERR_FILENO);
00877         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00878             xx = dup2(fdno, STDIN_FILENO);
00879             xx = close(fdno);
00880         }
00881         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00882             xx = dup2(fdno, STDOUT_FILENO);
00883             xx = close(fdno);
00884         }
00885         xx = dup2(passPhrasePipe[0], 3);
00886 
00887         unsetenv("MALLOC_CHECK_");
00888         switch (sigTag) {
00889         case RPMSIGTAG_DSA:
00890         case RPMSIGTAG_GPG:
00891         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00892 
00893 /*@-boundsread@*/
00894             if (gpg_path && *gpg_path != '\0')
00895                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
00896 /*@=boundsread@*/
00897 
00898             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00899             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00900 /*@-boundsread@*/
00901             if (!rc)
00902                 rc = execve(av[0], av+1, environ);
00903 /*@=boundsread@*/
00904 
00905             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00906                         strerror(errno));
00907         }   /*@notreached@*/ break;
00908         case RPMSIGTAG_RSA:
00909         case RPMSIGTAG_PGP5:    /* XXX legacy */
00910         case RPMSIGTAG_PGP:
00911         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00912             const char *path;
00913             pgpVersion pgpVer;
00914 
00915             (void) dosetenv("PGPPASSFD", "3", 1);
00916 /*@-boundsread@*/
00917             if (pgp_path && *pgp_path != '\0')
00918                 xx = dosetenv("PGPPATH", pgp_path, 1);
00919 /*@=boundsread@*/
00920 
00921             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00922                 switch(pgpVer) {
00923                 case PGP_2:
00924                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
00925                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00926 /*@-boundsread@*/
00927                     if (!rc)
00928                         rc = execve(av[0], av+1, environ);
00929 /*@=boundsread@*/
00930                     /*@innerbreak@*/ break;
00931                 case PGP_5:     /* XXX legacy */
00932                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
00933                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00934 /*@-boundsread@*/
00935                     if (!rc)
00936                         rc = execve(av[0], av+1, environ);
00937 /*@=boundsread@*/
00938                     /*@innerbreak@*/ break;
00939                 case PGP_UNKNOWN:
00940                 case PGP_NOTDETECTED:
00941                     /*@innerbreak@*/ break;
00942                 }
00943             }
00944             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00945                         strerror(errno));
00946             _exit(RPMERR_EXEC);
00947         }   /*@notreached@*/ break;
00948         default: /* This case should have been screened out long ago. */
00949             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00950             _exit(RPMERR_SIGGEN);
00951             /*@notreached@*/ break;
00952         }
00953     }
00954 
00955     xx = close(passPhrasePipe[0]);
00956     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00957     xx = write(passPhrasePipe[1], "\n", 1);
00958     xx = close(passPhrasePipe[1]);
00959 
00960     (void) waitpid(pid, &status, 0);
00961 
00962     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
00963 }
00964 
00965 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
00966 {
00967     char *pass = NULL;
00968     int aok = 0;
00969 
00970     switch (sigTag) {
00971     case RPMSIGTAG_DSA:
00972     case RPMSIGTAG_GPG:
00973 /*@-boundsread@*/
00974       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
00975         aok = (name && *name != '\0');
00976         name = _free(name);
00977       }
00978 /*@=boundsread@*/
00979         if (aok)
00980             break;
00981         rpmError(RPMERR_SIGGEN,
00982                 _("You must set \"%%_gpg_name\" in your macro file\n"));
00983         break;
00984     case RPMSIGTAG_RSA:
00985     case RPMSIGTAG_PGP5:        /* XXX legacy */
00986     case RPMSIGTAG_PGP:
00987 /*@-boundsread@*/
00988       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
00989         aok = (name && *name != '\0');
00990         name = _free(name);
00991       }
00992 /*@=boundsread@*/
00993         if (aok)
00994             break;
00995         rpmError(RPMERR_SIGGEN,
00996                 _("You must set \"%%_pgp_name\" in your macro file\n"));
00997         break;
00998     default:
00999         /* Currently the calling function (rpm.c:main) is checking this and
01000          * doing a better job.  This section should never be accessed.
01001          */
01002         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
01003         break;
01004     }
01005 
01006     if (aok) {
01007 /*@-moduncon -nullpass -unrecog @*/
01008         pass = getpass( (prompt ? prompt : "") );
01009 /*@=moduncon =nullpass =unrecog @*/
01010 
01011         if (checkPassPhrase(pass, sigTag))
01012             pass = NULL;
01013     }
01014 
01015     return pass;
01016 }
01017 
01018 static /*@observer@*/ const char * rpmSigString(rpmRC res)
01019         /*@*/
01020 {
01021     const char * str;
01022     switch (res) {
01023     case RPMRC_OK:              str = "OK";             break;
01024     case RPMRC_FAIL:            str = "BAD";            break;
01025     case RPMRC_NOKEY:           str = "NOKEY";          break;
01026     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
01027     default:
01028     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
01029     }
01030     return str;
01031 }
01032 
01033 /*@-boundswrite@*/
01034 static rpmRC
01035 verifySizeSignature(const rpmts ts, /*@out@*/ char * t)
01036         /*@modifies *t @*/
01037 {
01038     const void * sig = rpmtsSig(ts);
01039     pgpDig dig = rpmtsDig(ts);
01040     rpmRC res;
01041     int_32 size = 0x7fffffff;
01042 
01043     *t = '\0';
01044     t = stpcpy(t, _("Header+Payload size: "));
01045 
01046     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
01047         res = RPMRC_NOKEY;
01048         t = stpcpy(t, rpmSigString(res));
01049         goto exit;
01050     }
01051 
01052     memcpy(&size, sig, sizeof(size));
01053 
01054     if (size != dig->nbytes) {
01055         res = RPMRC_FAIL;
01056         t = stpcpy(t, rpmSigString(res));
01057         sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes);
01058     } else {
01059         res = RPMRC_OK;
01060         t = stpcpy(t, rpmSigString(res));
01061         sprintf(t, " (%d)", (int)dig->nbytes);
01062     }
01063 
01064 exit:
01065     t = stpcpy(t, "\n");
01066     return res;
01067 }
01068 /*@=boundswrite@*/
01069 
01070 /*@-boundswrite@*/
01071 static rpmRC
01072 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t,
01073                 /*@null@*/ DIGEST_CTX md5ctx)
01074         /*@globals internalState @*/
01075         /*@modifies *t, internalState @*/
01076 {
01077     const void * sig = rpmtsSig(ts);
01078     int_32 siglen = rpmtsSiglen(ts);
01079     pgpDig dig = rpmtsDig(ts);
01080     rpmRC res;
01081     byte * md5sum = NULL;
01082     size_t md5len = 0;
01083 
01084     *t = '\0';
01085     t = stpcpy(t, _("MD5 digest: "));
01086 
01087     if (md5ctx == NULL || sig == NULL || dig == NULL) {
01088         res = RPMRC_NOKEY;
01089         t = stpcpy(t, rpmSigString(res));
01090         goto exit;
01091     }
01092 
01093     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01094     (void) rpmDigestFinal(rpmDigestDup(md5ctx),
01095                 (void **)&md5sum, &md5len, 0);
01096     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01097     rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
01098 
01099     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
01100         res = RPMRC_FAIL;
01101         t = stpcpy(t, rpmSigString(res));
01102         t = stpcpy(t, " Expected(");
01103         (void) pgpHexCvt(t, sig, siglen);
01104         t += strlen(t);
01105         t = stpcpy(t, ") != (");
01106     } else {
01107         res = RPMRC_OK;
01108         t = stpcpy(t, rpmSigString(res));
01109         t = stpcpy(t, " (");
01110     }
01111     (void) pgpHexCvt(t, md5sum, md5len);
01112     t += strlen(t);
01113     t = stpcpy(t, ")");
01114 
01115 exit:
01116     md5sum = _free(md5sum);
01117     t = stpcpy(t, "\n");
01118     return res;
01119 }
01120 /*@=boundswrite@*/
01121 
01122 /*@-boundswrite@*/
01130 static rpmRC
01131 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t,
01132                 /*@null@*/ DIGEST_CTX sha1ctx)
01133         /*@globals internalState @*/
01134         /*@modifies *t, internalState @*/
01135 {
01136     const void * sig = rpmtsSig(ts);
01137 #ifdef  NOTYET
01138     int_32 siglen = rpmtsSiglen(ts);
01139 #endif
01140     pgpDig dig = rpmtsDig(ts);
01141     rpmRC res;
01142     const char * SHA1 = NULL;
01143 
01144     *t = '\0';
01145     t = stpcpy(t, _("Header SHA1 digest: "));
01146 
01147     if (sha1ctx == NULL || sig == NULL || dig == NULL) {
01148         res = RPMRC_NOKEY;
01149         t = stpcpy(t, rpmSigString(res));
01150         goto exit;
01151     }
01152 
01153     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01154     (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
01155                 (void **)&SHA1, NULL, 1);
01156     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01157 
01158     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
01159         res = RPMRC_FAIL;
01160         t = stpcpy(t, rpmSigString(res));
01161         t = stpcpy(t, " Expected(");
01162         t = stpcpy(t, sig);
01163         t = stpcpy(t, ") != (");
01164     } else {
01165         res = RPMRC_OK;
01166         t = stpcpy(t, rpmSigString(res));
01167         t = stpcpy(t, " (");
01168     }
01169     if (SHA1)
01170         t = stpcpy(t, SHA1);
01171     t = stpcpy(t, ")");
01172 
01173 exit:
01174     SHA1 = _free(SHA1);
01175     t = stpcpy(t, "\n");
01176     return res;
01177 }
01178 /*@=boundswrite@*/
01179 
01185 static inline unsigned char nibble(char c)
01186         /*@*/
01187 {
01188     if (c >= '0' && c <= '9')
01189         return (c - '0');
01190     if (c >= 'A' && c <= 'F')
01191         return (c - 'A') + 10;
01192     if (c >= 'a' && c <= 'f')
01193         return (c - 'a') + 10;
01194     return 0;
01195 }
01196 
01197 /*@-boundswrite@*/
01205 static rpmRC
01206 verifyRSASignature(rpmts ts, /*@out@*/ char * t,
01207                 /*@null@*/ DIGEST_CTX md5ctx)
01208         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01209         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01210 {
01211     const void * sig = rpmtsSig(ts);
01212 #ifdef  NOTYET
01213     int_32 siglen = rpmtsSiglen(ts);
01214 #endif
01215     int_32 sigtag = rpmtsSigtag(ts);
01216     pgpDig dig = rpmtsDig(ts);
01217     pgpDigParams sigp = rpmtsSignature(ts);
01218     const char * prefix = NULL;
01219     rpmRC res = RPMRC_OK;
01220     int xx;
01221 
01222     *t = '\0';
01223     if (dig != NULL && dig->hdrmd5ctx == md5ctx)
01224         t = stpcpy(t, _("Header "));
01225     *t++ = 'V';
01226     switch (sigp->version) {
01227     case 3:     *t++ = '3';     break;
01228     case 4:     *t++ = '4';     break;
01229     }
01230 
01231     if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01232         res = RPMRC_NOKEY;
01233     }
01234 
01235     /* Verify the desired signature match. */
01236     switch (sigp->pubkey_algo) {
01237     case PGPPUBKEYALGO_RSA:
01238         if (sigtag == RPMSIGTAG_PGP || sigtag == RPMSIGTAG_PGP5 || sigtag == RPMSIGTAG_RSA)
01239             break;
01240         /*@fallthrough@*/
01241     default:
01242         res = RPMRC_NOKEY;
01243         break;
01244     }
01245 
01246     /* Verify the desired hash match. */
01247     /* XXX Values from PKCS#1 v2.1 (aka RFC-3447) */
01248     switch (sigp->hash_algo) {
01249     case PGPHASHALGO_MD5:
01250         t = stpcpy(t, " RSA/MD5");
01251         prefix = "3020300c06082a864886f70d020505000410";
01252         break;
01253     case PGPHASHALGO_SHA1:
01254         t = stpcpy(t, " RSA/SHA1");
01255         prefix = "3021300906052b0e03021a05000414";
01256         break;
01257     case PGPHASHALGO_RIPEMD160:
01258         res = RPMRC_NOKEY;
01259         prefix = NULL;
01260         break;
01261     case PGPHASHALGO_MD2:
01262         t = stpcpy(t, " RSA/MD2");
01263         prefix = "3020300c06082a864886f70d020205000410";
01264         break;
01265     case PGPHASHALGO_TIGER192:
01266         res = RPMRC_NOKEY;
01267         prefix = NULL;
01268         break;
01269     case PGPHASHALGO_HAVAL_5_160:
01270         res = RPMRC_NOKEY;
01271         prefix = NULL;
01272         break;
01273     case PGPHASHALGO_SHA256:
01274         t = stpcpy(t, " RSA/SHA256");
01275         prefix = "3031300d060960864801650304020105000420";
01276         break;
01277     case PGPHASHALGO_SHA384:
01278         t = stpcpy(t, " RSA/SHA384");
01279         prefix = "3041300d060960864801650304020205000430";
01280         break;
01281     case PGPHASHALGO_SHA512:
01282         t = stpcpy(t, " RSA/SHA512");
01283         prefix = "3051300d060960864801650304020305000440";
01284         break;
01285     default:
01286         res = RPMRC_NOKEY;
01287         prefix = NULL;
01288         break;
01289     }
01290 
01291     t = stpcpy(t, _(" signature: "));
01292     if (res != RPMRC_OK) {
01293         goto exit;
01294     }
01295 
01296     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01297     {   DIGEST_CTX ctx = rpmDigestDup(md5ctx);
01298         byte signhash16[2];
01299         const char * s;
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, 1);
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         s = dig->md5;
01322         signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]);
01323         signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]);
01324         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
01325             res = RPMRC_FAIL;
01326             goto exit;
01327         }
01328     }
01329 
01330     /* Generate RSA modulus parameter. */
01331     {   unsigned int nbits = MP_WORDS_TO_BITS(dig->c.size);
01332         unsigned int nb = (nbits + 7) >> 3;
01333         const char * hexstr;
01334         char * tt;
01335 
01336 assert(prefix != NULL);
01337         hexstr = tt = xmalloc(2 * nb + 1);
01338         memset(tt, 'f', (2 * nb));
01339         tt[0] = '0'; tt[1] = '0';
01340         tt[2] = '0'; tt[3] = '1';
01341         tt += (2 * nb) - strlen(prefix) - strlen(dig->md5) - 2;
01342         *tt++ = '0'; *tt++ = '0';
01343         tt = stpcpy(tt, prefix);
01344         tt = stpcpy(tt, dig->md5);
01345 
01346         mpnzero(&dig->rsahm);   (void) mpnsethex(&dig->rsahm, hexstr);
01347 
01348         hexstr = _free(hexstr);
01349 
01350     }
01351 
01352     /* Retrieve the matching public key. */
01353     res = rpmtsFindPubkey(ts);
01354     if (res != RPMRC_OK)
01355         goto exit;
01356 
01357     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01358 #if HAVE_BEECRYPT_API_H
01359     xx = rsavrfy(&dig->rsa_pk.n, &dig->rsa_pk.e, &dig->c, &dig->rsahm);
01360 #else
01361     xx = rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c);
01362 #endif
01363     if (xx)
01364         res = RPMRC_OK;
01365     else
01366         res = RPMRC_FAIL;
01367     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01368 
01369 exit:
01370     t = stpcpy(t, rpmSigString(res));
01371     if (sigp != NULL) {
01372         t = stpcpy(t, ", key ID ");
01373         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01374         t += strlen(t);
01375     }
01376     t = stpcpy(t, "\n");
01377     return res;
01378 }
01379 /*@=boundswrite@*/
01380 
01388 /*@-boundswrite@*/
01389 static rpmRC
01390 verifyDSASignature(rpmts ts, /*@out@*/ char * t,
01391                 /*@null@*/ DIGEST_CTX sha1ctx)
01392         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01393         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01394 {
01395     const void * sig = rpmtsSig(ts);
01396 #ifdef  NOTYET
01397     int_32 siglen = rpmtsSiglen(ts);
01398 #endif
01399     int_32 sigtag = rpmtsSigtag(ts);
01400     pgpDig dig = rpmtsDig(ts);
01401     pgpDigParams sigp = rpmtsSignature(ts);
01402     rpmRC res;
01403     int xx;
01404 
01405     *t = '\0';
01406     if (dig != NULL && dig->hdrsha1ctx == sha1ctx)
01407         t = stpcpy(t, _("Header "));
01408     *t++ = 'V';
01409     switch (sigp->version) {
01410     case 3:    *t++ = '3';     break;
01411     case 4:    *t++ = '4';     break;
01412     }
01413     t = stpcpy(t, _(" DSA signature: "));
01414 
01415     if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01416         res = RPMRC_NOKEY;
01417         goto exit;
01418     }
01419 
01420     /* XXX sanity check on sigtag and signature agreement. */
01421     if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA)
01422         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
01423         && sigp->hash_algo == PGPHASHALGO_SHA1))
01424     {
01425         res = RPMRC_NOKEY;
01426         goto exit;
01427     }
01428 
01429     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01430     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
01431         byte signhash16[2];
01432 
01433         if (sigp->hash != NULL)
01434             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01435 
01436         if (sigp->version == 4) {
01437             int nb = sigp->hashlen;
01438             byte trailer[6];
01439             nb = htonl(nb);
01440             trailer[0] = sigp->version;
01441             trailer[1] = 0xff;
01442             memcpy(trailer+2, &nb, sizeof(nb));
01443             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01444         }
01445         xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 1);
01446         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01447         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01448 
01449         mpnzero(&dig->hm);      (void) mpnsethex(&dig->hm, dig->sha1);
01450 
01451         /* Compare leading 16 bits of digest for quick check. */
01452         signhash16[0] = (*dig->hm.data >> 24) & 0xff;
01453         signhash16[1] = (*dig->hm.data >> 16) & 0xff;
01454         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
01455             res = RPMRC_FAIL;
01456             goto exit;
01457         }
01458     }
01459 
01460     /* Retrieve the matching public key. */
01461     res = rpmtsFindPubkey(ts);
01462     if (res != RPMRC_OK)
01463         goto exit;
01464 
01465     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01466     if (dsavrfy(&dig->p, &dig->q, &dig->g,
01467                 &dig->hm, &dig->y, &dig->r, &dig->s))
01468         res = RPMRC_OK;
01469     else
01470         res = RPMRC_FAIL;
01471     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01472 
01473 exit:
01474     t = stpcpy(t, rpmSigString(res));
01475     if (sigp != NULL) {
01476         t = stpcpy(t, ", key ID ");
01477         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01478         t += strlen(t);
01479     }
01480     t = stpcpy(t, "\n");
01481     return res;
01482 }
01483 /*@=boundswrite@*/
01484 
01485 rpmRC
01486 rpmVerifySignature(const rpmts ts, char * result)
01487 {
01488     const void * sig = rpmtsSig(ts);
01489     int_32 siglen = rpmtsSiglen(ts);
01490     int_32 sigtag = rpmtsSigtag(ts);
01491     pgpDig dig = rpmtsDig(ts);
01492     rpmRC res;
01493 
01494     if (sig == NULL || siglen <= 0 || dig == NULL) {
01495         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
01496         return RPMRC_NOTFOUND;
01497     }
01498 
01499     switch (sigtag) {
01500     case RPMSIGTAG_SIZE:
01501         res = verifySizeSignature(ts, result);
01502         break;
01503     case RPMSIGTAG_MD5:
01504         res = verifyMD5Signature(ts, result, dig->md5ctx);
01505         break;
01506     case RPMSIGTAG_SHA1:
01507         res = verifySHA1Signature(ts, result, dig->hdrsha1ctx);
01508         break;
01509     case RPMSIGTAG_RSA:
01510         res = verifyRSASignature(ts, result, dig->hdrmd5ctx);
01511         break;
01512     case RPMSIGTAG_PGP5:        /* XXX legacy */
01513     case RPMSIGTAG_PGP:
01514         res = verifyRSASignature(ts, result,
01515                 ((dig->signature.hash_algo == PGPHASHALGO_MD5)
01516                         ? dig->md5ctx : dig->sha1ctx));
01517         break;
01518     case RPMSIGTAG_DSA:
01519         res = verifyDSASignature(ts, result, dig->hdrsha1ctx);
01520         break;
01521     case RPMSIGTAG_GPG:
01522         res = verifyDSASignature(ts, result, dig->sha1ctx);
01523         break;
01524     case RPMSIGTAG_LEMD5_1:
01525     case RPMSIGTAG_LEMD5_2:
01526         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
01527         res = RPMRC_NOTFOUND;
01528         break;
01529     default:
01530         sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag);
01531         res = RPMRC_NOTFOUND;
01532         break;
01533     }
01534     return res;
01535 }

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2