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
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 
00587         unsetenv("MALLOC_CHECK_");
00588         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
00589         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00590 /*@-boundsread@*/
00591         if (!rc)
00592             rc = execve(av[0], av+1, environ);
00593 /*@=boundsread@*/
00594 
00595         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00596                         strerror(errno));
00597         _exit(RPMERR_EXEC);
00598     }
00599 
00600     delMacro(NULL, "__plaintext_filename");
00601     delMacro(NULL, "__signature_filename");
00602 
00603     fpipe = fdopen(inpipe[1], "w");
00604     (void) close(inpipe[0]);
00605     if (fpipe) {
00606         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
00607         (void) fclose(fpipe);
00608     }
00609 
00610     (void) waitpid(pid, &status, 0);
00611     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00612         rpmError(RPMERR_SIGGEN, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
00613         return 1;
00614     }
00615 
00616     if (stat(sigfile, &st)) {
00617         /* GPG failed to write signature */
00618         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00619         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
00620         return 1;
00621     }
00622 
00623 /*@-boundswrite@*/
00624     *pktlenp = st.st_size;
00625     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlenp);
00626     *pktp = xmalloc(*pktlenp);
00627 /*@=boundswrite@*/
00628 
00629 /*@-boundsread@*/
00630     {   FD_t fd;
00631 
00632         rc = 0;
00633         fd = Fopen(sigfile, "r.fdio");
00634         if (fd != NULL && !Ferror(fd)) {
00635             rc = timedRead(fd, *pktp, *pktlenp);
00636             if (sigfile) (void) unlink(sigfile);
00637             (void) Fclose(fd);
00638         }
00639         if (rc != *pktlenp) {
00640 /*@-boundswrite@*/
00641             *pktp = _free(*pktp);
00642 /*@=boundswrite@*/
00643             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00644             return 1;
00645         }
00646     }
00647 
00648     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlenp);
00649 /*@=boundsread@*/
00650 
00651     /* Parse the signature, change signature tag as appropriate. */
00652     dig = pgpNewDig();
00653 
00654     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00655     sigp = &dig->signature;
00656 
00657     switch (*sigTagp) {
00658     case RPMSIGTAG_SIZE:
00659     case RPMSIGTAG_MD5:
00660     case RPMSIGTAG_SHA1:
00661         break;
00662     case RPMSIGTAG_GPG:
00663         /* XXX check MD5 hash too? */
00664         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00665             *sigTagp = RPMSIGTAG_PGP;
00666         break;
00667     case RPMSIGTAG_PGP5:        /* XXX legacy */
00668     case RPMSIGTAG_PGP:
00669         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00670             *sigTagp = RPMSIGTAG_GPG;
00671         break;
00672     case RPMSIGTAG_DSA:
00673         /* XXX check MD5 hash too? */
00674         if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
00675             *sigTagp = RPMSIGTAG_RSA;
00676         break;
00677     case RPMSIGTAG_RSA:
00678         if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
00679             *sigTagp = RPMSIGTAG_DSA;
00680         break;
00681     }
00682 
00683     dig = pgpFreeDig(dig);
00684 
00685     return 0;
00686 }
00687 
00696 static int makeHDRSignature(Header sigh, const char * file, int_32 sigTag,
00697                 /*@null@*/ const char * passPhrase)
00698         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00699         /*@modifies sigh, rpmGlobalMacroContext, fileSystem, internalState @*/
00700 {
00701     Header h = NULL;
00702     FD_t fd = NULL;
00703     byte * pkt;
00704     int_32 pktlen;
00705     const char * fn = NULL;
00706     const char * SHA1 = NULL;
00707     int ret = -1;       /* assume failure. */
00708 
00709     switch (sigTag) {
00710     case RPMSIGTAG_SIZE:
00711     case RPMSIGTAG_MD5:
00712     case RPMSIGTAG_PGP5:        /* XXX legacy */
00713     case RPMSIGTAG_PGP:
00714     case RPMSIGTAG_GPG:
00715         goto exit;
00716         /*@notreached@*/ break;
00717     case RPMSIGTAG_SHA1:
00718         fd = Fopen(file, "r.fdio");
00719         if (fd == NULL || Ferror(fd))
00720             goto exit;
00721         h = headerRead(fd, HEADER_MAGIC_YES);
00722         if (h == NULL)
00723             goto exit;
00724         (void) Fclose(fd);      fd = NULL;
00725 
00726         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
00727             DIGEST_CTX ctx;
00728             void * uh;
00729             int_32 uht, uhc;
00730         
00731             if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
00732              ||  uh == NULL)
00733             {
00734                 h = headerFree(h);
00735                 goto exit;
00736             }
00737             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00738             (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
00739             (void) rpmDigestUpdate(ctx, uh, uhc);
00740             (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
00741             uh = headerFreeData(uh, uht);
00742         }
00743         h = headerFree(h);
00744 
00745         if (SHA1 == NULL)
00746             goto exit;
00747         if (!headerAddEntry(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
00748             goto exit;
00749         ret = 0;
00750         break;
00751     case RPMSIGTAG_DSA:
00752         fd = Fopen(file, "r.fdio");
00753         if (fd == NULL || Ferror(fd))
00754             goto exit;
00755         h = headerRead(fd, HEADER_MAGIC_YES);
00756         if (h == NULL)
00757             goto exit;
00758         (void) Fclose(fd);      fd = NULL;
00759         if (makeTempFile(NULL, &fn, &fd))
00760             goto exit;
00761         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00762             goto exit;
00763         (void) Fclose(fd);      fd = NULL;
00764         if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00765          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00766             goto exit;
00767         ret = 0;
00768         break;
00769     case RPMSIGTAG_RSA:
00770         fd = Fopen(file, "r.fdio");
00771         if (fd == NULL || Ferror(fd))
00772             goto exit;
00773         h = headerRead(fd, HEADER_MAGIC_YES);
00774         if (h == NULL)
00775             goto exit;
00776         (void) Fclose(fd);      fd = NULL;
00777         if (makeTempFile(NULL, &fn, &fd))
00778             goto exit;
00779         if (headerWrite(fd, h, HEADER_MAGIC_YES))
00780             goto exit;
00781         (void) Fclose(fd);      fd = NULL;
00782         if (makePGPSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
00783          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00784             goto exit;
00785         ret = 0;
00786         break;
00787     }
00788 
00789 exit:
00790     if (fn) {
00791         (void) unlink(fn);
00792         fn = _free(fn);
00793     }
00794     SHA1 = _free(SHA1);
00795     h = headerFree(h);
00796     if (fd != NULL) (void) Fclose(fd);
00797     return ret;
00798 }
00799 
00800 int rpmAddSignature(Header sigh, const char * file, int_32 sigTag,
00801                 const char * passPhrase)
00802 {
00803     struct stat st;
00804     byte * pkt;
00805     int_32 pktlen;
00806     int ret = -1;       /* assume failure. */
00807 
00808     switch (sigTag) {
00809     case RPMSIGTAG_SIZE:
00810         if (stat(file, &st) != 0)
00811             break;
00812         pktlen = st.st_size;
00813         if (!headerAddEntry(sigh, sigTag, RPM_INT32_TYPE, &pktlen, 1))
00814             break;
00815         ret = 0;
00816         break;
00817     case RPMSIGTAG_MD5:
00818         pktlen = 16;
00819         pkt = memset(alloca(pktlen), 0, pktlen);
00820         if (domd5(file, pkt, 0, NULL)
00821          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00822             break;
00823         ret = 0;
00824         break;
00825     case RPMSIGTAG_PGP5:        /* XXX legacy */
00826     case RPMSIGTAG_PGP:
00827         if (makePGPSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00828          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00829             break;
00830 #ifdef  NOTYET  /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
00831         /* XXX Piggyback a header-only RSA signature as well. */
00832         ret = makeHDRSignature(sigh, file, RPMSIGTAG_RSA, passPhrase);
00833 #endif
00834         ret = 0;
00835         break;
00836     case RPMSIGTAG_GPG:
00837         if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
00838          || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
00839             break;
00840         /* XXX Piggyback a header-only DSA signature as well. */
00841         ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
00842         break;
00843     case RPMSIGTAG_RSA:
00844     case RPMSIGTAG_DSA:
00845     case RPMSIGTAG_SHA1:
00846         ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
00847         break;
00848     }
00849 
00850     return ret;
00851 }
00852 
00853 static int checkPassPhrase(const char * passPhrase, const int sigTag)
00854         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00855         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00856 {
00857     int passPhrasePipe[2];
00858     int pid, status;
00859     int rc;
00860     int xx;
00861 
00862     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00863 /*@-boundsread@*/
00864     xx = pipe(passPhrasePipe);
00865 /*@=boundsread@*/
00866     if (!(pid = fork())) {
00867         const char * cmd;
00868         char *const *av;
00869         int fdno;
00870 
00871         xx = close(STDIN_FILENO);
00872         xx = close(STDOUT_FILENO);
00873         xx = close(passPhrasePipe[1]);
00874         if (! rpmIsVerbose())
00875             xx = close(STDERR_FILENO);
00876         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00877             xx = dup2(fdno, STDIN_FILENO);
00878             xx = close(fdno);
00879         }
00880         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00881             xx = dup2(fdno, STDOUT_FILENO);
00882             xx = close(fdno);
00883         }
00884         xx = dup2(passPhrasePipe[0], 3);
00885 
00886         unsetenv("MALLOC_CHECK_");
00887         switch (sigTag) {
00888         case RPMSIGTAG_DSA:
00889         case RPMSIGTAG_GPG:
00890         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00891 
00892 /*@-boundsread@*/
00893             if (gpg_path && *gpg_path != '\0')
00894                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
00895 /*@=boundsread@*/
00896 
00897             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00898             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00899 /*@-boundsread@*/
00900             if (!rc)
00901                 rc = execve(av[0], av+1, environ);
00902 /*@=boundsread@*/
00903 
00904             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00905                         strerror(errno));
00906         }   /*@notreached@*/ break;
00907         case RPMSIGTAG_RSA:
00908         case RPMSIGTAG_PGP5:    /* XXX legacy */
00909         case RPMSIGTAG_PGP:
00910         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00911             const char *path;
00912             pgpVersion pgpVer;
00913 
00914             (void) dosetenv("PGPPASSFD", "3", 1);
00915 /*@-boundsread@*/
00916             if (pgp_path && *pgp_path != '\0')
00917                 xx = dosetenv("PGPPATH", pgp_path, 1);
00918 /*@=boundsread@*/
00919 
00920             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00921                 switch(pgpVer) {
00922                 case PGP_2:
00923                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
00924                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00925 /*@-boundsread@*/
00926                     if (!rc)
00927                         rc = execve(av[0], av+1, environ);
00928 /*@=boundsread@*/
00929                     /*@innerbreak@*/ break;
00930                 case PGP_5:     /* XXX legacy */
00931                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
00932                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00933 /*@-boundsread@*/
00934                     if (!rc)
00935                         rc = execve(av[0], av+1, environ);
00936 /*@=boundsread@*/
00937                     /*@innerbreak@*/ break;
00938                 case PGP_UNKNOWN:
00939                 case PGP_NOTDETECTED:
00940                     /*@innerbreak@*/ break;
00941                 }
00942             }
00943             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00944                         strerror(errno));
00945             _exit(RPMERR_EXEC);
00946         }   /*@notreached@*/ break;
00947         default: /* This case should have been screened out long ago. */
00948             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00949             _exit(RPMERR_SIGGEN);
00950             /*@notreached@*/ break;
00951         }
00952     }
00953 
00954     xx = close(passPhrasePipe[0]);
00955     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00956     xx = write(passPhrasePipe[1], "\n", 1);
00957     xx = close(passPhrasePipe[1]);
00958 
00959     (void) waitpid(pid, &status, 0);
00960 
00961     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
00962 }
00963 
00964 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
00965 {
00966     char *pass = NULL;
00967     int aok = 0;
00968 
00969     switch (sigTag) {
00970     case RPMSIGTAG_DSA:
00971     case RPMSIGTAG_GPG:
00972 /*@-boundsread@*/
00973       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
00974         aok = (name && *name != '\0');
00975         name = _free(name);
00976       }
00977 /*@=boundsread@*/
00978         if (aok)
00979             break;
00980         rpmError(RPMERR_SIGGEN,
00981                 _("You must set \"%%_gpg_name\" in your macro file\n"));
00982         break;
00983     case RPMSIGTAG_RSA:
00984     case RPMSIGTAG_PGP5:        /* XXX legacy */
00985     case RPMSIGTAG_PGP:
00986 /*@-boundsread@*/
00987       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
00988         aok = (name && *name != '\0');
00989         name = _free(name);
00990       }
00991 /*@=boundsread@*/
00992         if (aok)
00993             break;
00994         rpmError(RPMERR_SIGGEN,
00995                 _("You must set \"%%_pgp_name\" in your macro file\n"));
00996         break;
00997     default:
00998         /* Currently the calling function (rpm.c:main) is checking this and
00999          * doing a better job.  This section should never be accessed.
01000          */
01001         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
01002         break;
01003     }
01004 
01005     if (aok) {
01006 /*@-moduncon -nullpass -unrecog @*/
01007         pass = getpass( (prompt ? prompt : "") );
01008 /*@=moduncon =nullpass =unrecog @*/
01009 
01010         if (checkPassPhrase(pass, sigTag))
01011             pass = NULL;
01012     }
01013 
01014     return pass;
01015 }
01016 
01017 static /*@observer@*/ const char * rpmSigString(rpmRC res)
01018         /*@*/
01019 {
01020     const char * str;
01021     switch (res) {
01022     case RPMRC_OK:              str = "OK";             break;
01023     case RPMRC_FAIL:            str = "BAD";            break;
01024     case RPMRC_NOKEY:           str = "NOKEY";          break;
01025     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
01026     default:
01027     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
01028     }
01029     return str;
01030 }
01031 
01032 /*@-boundswrite@*/
01033 static rpmRC
01034 verifySizeSignature(const rpmts ts, /*@out@*/ char * t)
01035         /*@modifies *t @*/
01036 {
01037     const void * sig = rpmtsSig(ts);
01038     pgpDig dig = rpmtsDig(ts);
01039     rpmRC res;
01040     int_32 size = 0x7fffffff;
01041 
01042     *t = '\0';
01043     t = stpcpy(t, _("Header+Payload size: "));
01044 
01045     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
01046         res = RPMRC_NOKEY;
01047         t = stpcpy(t, rpmSigString(res));
01048         goto exit;
01049     }
01050 
01051     memcpy(&size, sig, sizeof(size));
01052 
01053     if (size != dig->nbytes) {
01054         res = RPMRC_FAIL;
01055         t = stpcpy(t, rpmSigString(res));
01056         sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes);
01057     } else {
01058         res = RPMRC_OK;
01059         t = stpcpy(t, rpmSigString(res));
01060         sprintf(t, " (%d)", (int)dig->nbytes);
01061     }
01062 
01063 exit:
01064     t = stpcpy(t, "\n");
01065     return res;
01066 }
01067 /*@=boundswrite@*/
01068 
01069 /*@-boundswrite@*/
01070 static rpmRC
01071 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t,
01072                 /*@null@*/ DIGEST_CTX md5ctx)
01073         /*@globals internalState @*/
01074         /*@modifies *t, internalState @*/
01075 {
01076     const void * sig = rpmtsSig(ts);
01077     int_32 siglen = rpmtsSiglen(ts);
01078     pgpDig dig = rpmtsDig(ts);
01079     rpmRC res;
01080     byte * md5sum = NULL;
01081     size_t md5len = 0;
01082 
01083     *t = '\0';
01084     t = stpcpy(t, _("MD5 digest: "));
01085 
01086     if (md5ctx == NULL || sig == NULL || dig == NULL) {
01087         res = RPMRC_NOKEY;
01088         t = stpcpy(t, rpmSigString(res));
01089         goto exit;
01090     }
01091 
01092     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01093     (void) rpmDigestFinal(rpmDigestDup(md5ctx),
01094                 (void **)&md5sum, &md5len, 0);
01095     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01096     rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
01097 
01098     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
01099         res = RPMRC_FAIL;
01100         t = stpcpy(t, rpmSigString(res));
01101         t = stpcpy(t, " Expected(");
01102         (void) pgpHexCvt(t, sig, siglen);
01103         t += strlen(t);
01104         t = stpcpy(t, ") != (");
01105     } else {
01106         res = RPMRC_OK;
01107         t = stpcpy(t, rpmSigString(res));
01108         t = stpcpy(t, " (");
01109     }
01110     (void) pgpHexCvt(t, md5sum, md5len);
01111     t += strlen(t);
01112     t = stpcpy(t, ")");
01113 
01114 exit:
01115     md5sum = _free(md5sum);
01116     t = stpcpy(t, "\n");
01117     return res;
01118 }
01119 /*@=boundswrite@*/
01120 
01121 /*@-boundswrite@*/
01129 static rpmRC
01130 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t,
01131                 /*@null@*/ DIGEST_CTX sha1ctx)
01132         /*@globals internalState @*/
01133         /*@modifies *t, internalState @*/
01134 {
01135     const void * sig = rpmtsSig(ts);
01136 #ifdef  NOTYET
01137     int_32 siglen = rpmtsSiglen(ts);
01138 #endif
01139     pgpDig dig = rpmtsDig(ts);
01140     rpmRC res;
01141     const char * SHA1 = NULL;
01142 
01143     *t = '\0';
01144     t = stpcpy(t, _("Header SHA1 digest: "));
01145 
01146     if (sha1ctx == NULL || sig == NULL || dig == NULL) {
01147         res = RPMRC_NOKEY;
01148         t = stpcpy(t, rpmSigString(res));
01149         goto exit;
01150     }
01151 
01152     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01153     (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
01154                 (void **)&SHA1, NULL, 1);
01155     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01156 
01157     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
01158         res = RPMRC_FAIL;
01159         t = stpcpy(t, rpmSigString(res));
01160         t = stpcpy(t, " Expected(");
01161         t = stpcpy(t, sig);
01162         t = stpcpy(t, ") != (");
01163     } else {
01164         res = RPMRC_OK;
01165         t = stpcpy(t, rpmSigString(res));
01166         t = stpcpy(t, " (");
01167     }
01168     if (SHA1)
01169         t = stpcpy(t, SHA1);
01170     t = stpcpy(t, ")");
01171 
01172 exit:
01173     SHA1 = _free(SHA1);
01174     t = stpcpy(t, "\n");
01175     return res;
01176 }
01177 /*@=boundswrite@*/
01178 
01184 static inline unsigned char nibble(char c)
01185         /*@*/
01186 {
01187     if (c >= '0' && c <= '9')
01188         return (c - '0');
01189     if (c >= 'A' && c <= 'F')
01190         return (c - 'A') + 10;
01191     if (c >= 'a' && c <= 'f')
01192         return (c - 'a') + 10;
01193     return 0;
01194 }
01195 
01196 /*@-boundswrite@*/
01204 static rpmRC
01205 verifyRSASignature(rpmts ts, /*@out@*/ char * t,
01206                 /*@null@*/ DIGEST_CTX md5ctx)
01207         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01208         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01209 {
01210     const void * sig = rpmtsSig(ts);
01211 #ifdef  NOTYET
01212     int_32 siglen = rpmtsSiglen(ts);
01213 #endif
01214     int_32 sigtag = rpmtsSigtag(ts);
01215     pgpDig dig = rpmtsDig(ts);
01216     pgpDigParams sigp = rpmtsSignature(ts);
01217     const char * prefix = NULL;
01218     rpmRC res = RPMRC_OK;
01219     int xx;
01220 
01221     *t = '\0';
01222     if (dig != NULL && dig->hdrmd5ctx == md5ctx)
01223         t = stpcpy(t, _("Header "));
01224     *t++ = 'V';
01225     switch (sigp->version) {
01226     case 3:     *t++ = '3';     break;
01227     case 4:     *t++ = '4';     break;
01228     }
01229 
01230     if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01231         res = RPMRC_NOKEY;
01232     }
01233 
01234     /* Verify the desired signature match. */
01235     switch (sigp->pubkey_algo) {
01236     case PGPPUBKEYALGO_RSA:
01237         if (sigtag == RPMSIGTAG_PGP || sigtag == RPMSIGTAG_PGP5 || sigtag == RPMSIGTAG_RSA)
01238             break;
01239         /*@fallthrough@*/
01240     default:
01241         res = RPMRC_NOKEY;
01242         break;
01243     }
01244 
01245     /* Verify the desired hash match. */
01246     /* XXX Values from PKCS#1 v2.1 (aka RFC-3447) */
01247     switch (sigp->hash_algo) {
01248     case PGPHASHALGO_MD5:
01249         t = stpcpy(t, " RSA/MD5");
01250         prefix = "3020300c06082a864886f70d020505000410";
01251         break;
01252     case PGPHASHALGO_SHA1:
01253         t = stpcpy(t, " RSA/SHA1");
01254         prefix = "3021300906052b0e03021a05000414";
01255         break;
01256     case PGPHASHALGO_RIPEMD160:
01257         res = RPMRC_NOKEY;
01258         prefix = NULL;
01259         break;
01260     case PGPHASHALGO_MD2:
01261         t = stpcpy(t, " RSA/MD2");
01262         prefix = "3020300c06082a864886f70d020205000410";
01263         break;
01264     case PGPHASHALGO_TIGER192:
01265         res = RPMRC_NOKEY;
01266         prefix = NULL;
01267         break;
01268     case PGPHASHALGO_HAVAL_5_160:
01269         res = RPMRC_NOKEY;
01270         prefix = NULL;
01271         break;
01272     case PGPHASHALGO_SHA256:
01273         t = stpcpy(t, " RSA/SHA256");
01274         prefix = "3031300d060960864801650304020105000420";
01275         break;
01276     case PGPHASHALGO_SHA384:
01277         t = stpcpy(t, " RSA/SHA384");
01278         prefix = "3041300d060960864801650304020205000430";
01279         break;
01280     case PGPHASHALGO_SHA512:
01281         t = stpcpy(t, " RSA/SHA512");
01282         prefix = "3051300d060960864801650304020305000440";
01283         break;
01284     default:
01285         res = RPMRC_NOKEY;
01286         prefix = NULL;
01287         break;
01288     }
01289 
01290     t = stpcpy(t, _(" signature: "));
01291     if (res != RPMRC_OK) {
01292         goto exit;
01293     }
01294 
01295     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01296     {   DIGEST_CTX ctx = rpmDigestDup(md5ctx);
01297         byte signhash16[2];
01298         const char * s;
01299 
01300         if (sigp->hash != NULL)
01301             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01302 
01303 #ifdef  NOTYET  /* XXX not for binary/text signatures as in packages. */
01304         if (!(sigp->sigtype == PGPSIGTYPE_BINARY || sigp->sigtype == PGP_SIGTYPE_TEXT)) {
01305             int nb = dig->nbytes + sigp->hashlen;
01306             byte trailer[6];
01307             nb = htonl(nb);
01308             trailer[0] = 0x4;
01309             trailer[1] = 0xff;
01310             memcpy(trailer+2, &nb, sizeof(nb));
01311             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01312         }
01313 #endif
01314 
01315         xx = rpmDigestFinal(ctx, (void **)&dig->md5, &dig->md5len, 1);
01316         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01317         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01318 
01319         /* Compare leading 16 bits of digest for quick check. */
01320         s = dig->md5;
01321         signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]);
01322         signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]);
01323         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
01324             res = RPMRC_FAIL;
01325             goto exit;
01326         }
01327     }
01328 
01329     /* Generate RSA modulus parameter. */
01330     {   unsigned int nbits = MP_WORDS_TO_BITS(dig->c.size);
01331         unsigned int nb = (nbits + 7) >> 3;
01332         const char * hexstr;
01333         char * tt;
01334 
01335 assert(prefix != NULL);
01336         hexstr = tt = xmalloc(2 * nb + 1);
01337         memset(tt, 'f', (2 * nb));
01338         tt[0] = '0'; tt[1] = '0';
01339         tt[2] = '0'; tt[3] = '1';
01340         tt += (2 * nb) - strlen(prefix) - strlen(dig->md5) - 2;
01341         *tt++ = '0'; *tt++ = '0';
01342         tt = stpcpy(tt, prefix);
01343         tt = stpcpy(tt, dig->md5);
01344 
01345         mpnzero(&dig->rsahm);   (void) mpnsethex(&dig->rsahm, hexstr);
01346 
01347         hexstr = _free(hexstr);
01348 
01349     }
01350 
01351     /* Retrieve the matching public key. */
01352     res = rpmtsFindPubkey(ts);
01353     if (res != RPMRC_OK)
01354         goto exit;
01355 
01356     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01357 #if HAVE_BEECRYPT_API_H
01358     xx = rsavrfy(&dig->rsa_pk.n, &dig->rsa_pk.e, &dig->c, &dig->rsahm);
01359 #else
01360     xx = rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c);
01361 #endif
01362     if (xx)
01363         res = RPMRC_OK;
01364     else
01365         res = RPMRC_FAIL;
01366     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01367 
01368 exit:
01369     t = stpcpy(t, rpmSigString(res));
01370     if (sigp != NULL) {
01371         t = stpcpy(t, ", key ID ");
01372         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01373         t += strlen(t);
01374     }
01375     t = stpcpy(t, "\n");
01376     return res;
01377 }
01378 /*@=boundswrite@*/
01379 
01387 /*@-boundswrite@*/
01388 static rpmRC
01389 verifyDSASignature(rpmts ts, /*@out@*/ char * t,
01390                 /*@null@*/ DIGEST_CTX sha1ctx)
01391         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01392         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01393 {
01394     const void * sig = rpmtsSig(ts);
01395 #ifdef  NOTYET
01396     int_32 siglen = rpmtsSiglen(ts);
01397 #endif
01398     int_32 sigtag = rpmtsSigtag(ts);
01399     pgpDig dig = rpmtsDig(ts);
01400     pgpDigParams sigp = rpmtsSignature(ts);
01401     rpmRC res;
01402     int xx;
01403 
01404     *t = '\0';
01405     if (dig != NULL && dig->hdrsha1ctx == sha1ctx)
01406         t = stpcpy(t, _("Header "));
01407     *t++ = 'V';
01408     switch (sigp->version) {
01409     case 3:    *t++ = '3';     break;
01410     case 4:    *t++ = '4';     break;
01411     }
01412     t = stpcpy(t, _(" DSA signature: "));
01413 
01414     if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01415         res = RPMRC_NOKEY;
01416         goto exit;
01417     }
01418 
01419     /* XXX sanity check on sigtag and signature agreement. */
01420     if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA)
01421         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
01422         && sigp->hash_algo == PGPHASHALGO_SHA1))
01423     {
01424         res = RPMRC_NOKEY;
01425         goto exit;
01426     }
01427 
01428     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01429     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
01430         byte signhash16[2];
01431 
01432         if (sigp->hash != NULL)
01433             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01434 
01435         if (sigp->version == 4) {
01436             int nb = sigp->hashlen;
01437             byte trailer[6];
01438             nb = htonl(nb);
01439             trailer[0] = sigp->version;
01440             trailer[1] = 0xff;
01441             memcpy(trailer+2, &nb, sizeof(nb));
01442             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01443         }
01444         xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 1);
01445         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01446         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01447 
01448         mpnzero(&dig->hm);      (void) mpnsethex(&dig->hm, dig->sha1);
01449 
01450         /* Compare leading 16 bits of digest for quick check. */
01451         signhash16[0] = (*dig->hm.data >> 24) & 0xff;
01452         signhash16[1] = (*dig->hm.data >> 16) & 0xff;
01453         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
01454             res = RPMRC_FAIL;
01455             goto exit;
01456         }
01457     }
01458 
01459     /* Retrieve the matching public key. */
01460     res = rpmtsFindPubkey(ts);
01461     if (res != RPMRC_OK)
01462         goto exit;
01463 
01464     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01465     if (dsavrfy(&dig->p, &dig->q, &dig->g,
01466                 &dig->hm, &dig->y, &dig->r, &dig->s))
01467         res = RPMRC_OK;
01468     else
01469         res = RPMRC_FAIL;
01470     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01471 
01472 exit:
01473     t = stpcpy(t, rpmSigString(res));
01474     if (sigp != NULL) {
01475         t = stpcpy(t, ", key ID ");
01476         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01477         t += strlen(t);
01478     }
01479     t = stpcpy(t, "\n");
01480     return res;
01481 }
01482 /*@=boundswrite@*/
01483 
01484 rpmRC
01485 rpmVerifySignature(const rpmts ts, char * result)
01486 {
01487     const void * sig = rpmtsSig(ts);
01488     int_32 siglen = rpmtsSiglen(ts);
01489     int_32 sigtag = rpmtsSigtag(ts);
01490     pgpDig dig = rpmtsDig(ts);
01491     rpmRC res;
01492 
01493     if (sig == NULL || siglen <= 0 || dig == NULL) {
01494         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
01495         return RPMRC_NOTFOUND;
01496     }
01497 
01498     switch (sigtag) {
01499     case RPMSIGTAG_SIZE:
01500         res = verifySizeSignature(ts, result);
01501         break;
01502     case RPMSIGTAG_MD5:
01503         res = verifyMD5Signature(ts, result, dig->md5ctx);
01504         break;
01505     case RPMSIGTAG_SHA1:
01506         res = verifySHA1Signature(ts, result, dig->hdrsha1ctx);
01507         break;
01508     case RPMSIGTAG_RSA:
01509         res = verifyRSASignature(ts, result, dig->hdrmd5ctx);
01510         break;
01511     case RPMSIGTAG_PGP5:        /* XXX legacy */
01512     case RPMSIGTAG_PGP:
01513         res = verifyRSASignature(ts, result,
01514                 ((dig->signature.hash_algo == PGPHASHALGO_MD5)
01515                         ? dig->md5ctx : dig->sha1ctx));
01516         break;
01517     case RPMSIGTAG_DSA:
01518         res = verifyDSASignature(ts, result, dig->hdrsha1ctx);
01519         break;
01520     case RPMSIGTAG_GPG:
01521         res = verifyDSASignature(ts, result, dig->sha1ctx);
01522         break;
01523     case RPMSIGTAG_LEMD5_1:
01524     case RPMSIGTAG_LEMD5_2:
01525         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
01526         res = RPMRC_NOTFOUND;
01527         break;
01528     default:
01529         sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag);
01530         res = RPMRC_NOTFOUND;
01531         break;
01532     }
01533     return res;
01534 }

Generated on Wed Jan 28 12:45:24 2009 for rpm by  doxygen 1.4.7