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

lib/signature.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmio_internal.h"
00008 #include <rpmlib.h>
00009 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
00010 #include "rpmdb.h"
00011 
00012 #include "rpmts.h"
00013 
00014 #include "misc.h"       /* XXX for dosetenv() and makeTempFile() */
00015 #include "legacy.h"     /* XXX for mdbinfile() */
00016 #include "rpmlead.h"
00017 #include "signature.h"
00018 #include "header_internal.h"
00019 #include "debug.h"
00020 
00021 /*@access 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 int rpmLookupSignatureType(int action)
00030 {
00031     /*@unchecked@*/
00032     static int disabled = 0;
00033     int rc = 0;
00034 
00035     switch (action) {
00036     case RPMLOOKUPSIG_DISABLE:
00037         disabled = -2;
00038         break;
00039     case RPMLOOKUPSIG_ENABLE:
00040         disabled = 0;
00041         /*@fallthrough@*/
00042     case RPMLOOKUPSIG_QUERY:
00043         if (disabled)
00044             break;      /* Disabled */
00045 /*@-boundsread@*/
00046       { const char *name = rpmExpand("%{?_signature}", NULL);
00047         if (!(name && *name != '\0'))
00048             rc = 0;
00049         else if (!xstrcasecmp(name, "none"))
00050             rc = 0;
00051         else if (!xstrcasecmp(name, "pgp"))
00052             rc = RPMSIGTAG_PGP;
00053         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
00054             rc = RPMSIGTAG_PGP;
00055         else if (!xstrcasecmp(name, "gpg"))
00056             rc = RPMSIGTAG_GPG;
00057         else
00058             rc = -1;    /* Invalid %_signature spec in macro file */
00059         name = _free(name);
00060       } break;
00061 /*@=boundsread@*/
00062     }
00063     return rc;
00064 }
00065 
00066 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
00067 /* executable of the requested version, or NULL when none found. */
00068 
00069 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
00070 {
00071     /* Actually this should support having more then one pgp version. */
00072     /* At the moment only one version is possible since we only       */
00073     /* have one %__pgp and one %_pgp_path.                          */
00074 
00075     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
00076     const char *pgpbin = rpmGetPath("%{?__pgp}", NULL);
00077 
00078     if (saved_pgp_version == PGP_UNKNOWN) {
00079         char *pgpvbin;
00080         struct stat st;
00081 
00082 /*@-boundsread@*/
00083         if (!(pgpbin && pgpbin[0] != '\0')) {
00084             pgpbin = _free(pgpbin);
00085             saved_pgp_version = -1;
00086             return NULL;
00087         }
00088 /*@=boundsread@*/
00089 /*@-boundswrite@*/
00090         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
00091         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
00092 /*@=boundswrite@*/
00093 
00094         if (stat(pgpvbin, &st) == 0)
00095             saved_pgp_version = PGP_5;
00096         else if (stat(pgpbin, &st) == 0)
00097             saved_pgp_version = PGP_2;
00098         else
00099             saved_pgp_version = PGP_NOTDETECTED;
00100     }
00101 
00102 /*@-boundswrite@*/
00103     if (pgpVer && pgpbin)
00104         *pgpVer = saved_pgp_version;
00105 /*@=boundswrite@*/
00106     return pgpbin;
00107 }
00108 
00118 static inline rpmRC printSize(FD_t fd, int siglen, int pad, size_t datalen)
00119         /*@globals fileSystem @*/
00120         /*@modifies fileSystem @*/
00121 {
00122     int fdno = Fileno(fd);
00123     struct stat st;
00124     size_t expected;
00125 
00126     /* HACK: workaround for davRead wiring. */
00127     if (fdno == 123456789) {
00128         st.st_size = 0;
00129 /*@-sizeoftype@*/
00130         st.st_size -= sizeof(struct rpmlead)+siglen+pad+datalen;
00131 /*@=sizeoftype@*/
00132     } else if (fstat(fdno, &st) < 0)
00133         return RPMRC_FAIL;
00134 
00135 /*@-sizeoftype@*/
00136     expected = sizeof(struct rpmlead) + siglen + pad;
00137     expected += datalen,
00138     rpmMessage(RPMMESS_DEBUG,
00139         D_("Expected size: %12lu = lead(%d)+sigs(%d)+pad(%d)+data(%lu)\n"),
00140                 (unsigned long)expected,
00141                 (int)sizeof(struct rpmlead), siglen, pad, (unsigned long)datalen);
00142 /*@=sizeoftype@*/
00143     rpmMessage(RPMMESS_DEBUG,
00144         D_("  Actual size: %12lu\n"), (unsigned long)st.st_size);
00145 
00146     return RPMRC_OK;
00147 }
00148 
00149 /*@unchecked@*/
00150 static unsigned char header_magic[8] = {
00151     0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00152 };
00153 
00154 rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type,
00155                 const char ** msg)
00156 {
00157     char buf[BUFSIZ];
00158     int_32 block[4];
00159     int_32 il;
00160     int_32 dl;
00161     int_32 * ei = NULL;
00162     entryInfo pe;
00163     size_t nb;
00164     int_32 ril = 0;
00165     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
00166     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
00167     unsigned char * dataStart;
00168     unsigned char * dataEnd = NULL;
00169     Header sigh = NULL;
00170     rpmRC rc = RPMRC_FAIL;              /* assume failure */
00171     int xx;
00172     int i;
00173 
00174 /*@-boundswrite@*/
00175     if (sighp)
00176         *sighp = NULL;
00177 
00178     buf[0] = '\0';
00179 /*@=boundswrite@*/
00180 
00181     if (sig_type != RPMSIGTYPE_HEADERSIG)
00182         goto exit;
00183 
00184     memset(block, 0, sizeof(block));
00185     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
00186         (void) snprintf(buf, sizeof(buf),
00187                 _("sigh size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
00188         goto exit;
00189     }
00190     if (memcmp(block, header_magic, sizeof(header_magic))) {
00191         (void) snprintf(buf, sizeof(buf),
00192                 _("sigh magic: BAD\n"));
00193         goto exit;
00194     }
00195 /*@-boundsread@*/
00196     il = ntohl(block[2]);
00197 /*@=boundsread@*/
00198     if (il < 0 || il > 32) {
00199         (void) snprintf(buf, sizeof(buf),
00200                 _("sigh tags: BAD, no. of tags(%d) out of range\n"), il);
00201         goto exit;
00202     }
00203 /*@-boundsread@*/
00204     dl = ntohl(block[3]);
00205 /*@=boundsread@*/
00206     if (dl < 0 || dl > 8192) {
00207         (void) snprintf(buf, sizeof(buf),
00208                 _("sigh data: BAD, no. of  bytes(%d) out of range\n"), dl);
00209         goto exit;
00210     }
00211 
00212 /*@-sizeoftype@*/
00213     nb = (il * sizeof(struct entryInfo_s)) + dl;
00214 /*@=sizeoftype@*/
00215     ei = xmalloc(sizeof(il) + sizeof(dl) + nb);
00216 /*@-bounds@*/
00217     ei[0] = block[2];
00218     ei[1] = block[3];
00219     pe = (entryInfo) &ei[2];
00220 /*@=bounds@*/
00221     dataStart = (unsigned char *) (pe + il);
00222     if ((xx = timedRead(fd, (char *)pe, nb)) != nb) {
00223         (void) snprintf(buf, sizeof(buf),
00224                 _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
00225         goto exit;
00226     }
00227     
00228     /* Check (and convert) the 1st tag element. */
00229     xx = headerVerifyInfo(1, dl, pe, &entry->info, 0);
00230     if (xx != -1) {
00231         (void) snprintf(buf, sizeof(buf),
00232                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00233                 0, entry->info.tag, entry->info.type,
00234                 entry->info.offset, entry->info.count);
00235         goto exit;
00236     }
00237 
00238     /* Is there an immutable header region tag? */
00239 /*@-sizeoftype@*/
00240     if (entry->info.tag == RPMTAG_HEADERSIGNATURES
00241        && entry->info.type == RPM_BIN_TYPE
00242        && entry->info.count == REGION_TAG_COUNT)
00243     {
00244 /*@=sizeoftype@*/
00245 
00246         if (entry->info.offset >= dl) {
00247             (void) snprintf(buf, sizeof(buf),
00248                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00249                 entry->info.tag, entry->info.type,
00250                 entry->info.offset, entry->info.count);
00251             goto exit;
00252         }
00253 
00254         /* Is there an immutable header region tag trailer? */
00255         dataEnd = dataStart + entry->info.offset;
00256 /*@-sizeoftype@*/
00257 /*@-bounds@*/
00258         (void) memcpy(info, dataEnd, REGION_TAG_COUNT);
00259         /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */
00260         if (info->tag == htonl(RPMTAG_HEADERIMAGE)) {
00261             int_32 stag = htonl(RPMTAG_HEADERSIGNATURES);
00262             info->tag = stag;
00263             memcpy(dataEnd, &stag, sizeof(stag));
00264         }
00265 /*@=bounds@*/
00266         dataEnd += REGION_TAG_COUNT;
00267 
00268         xx = headerVerifyInfo(1, dl, info, &entry->info, 1);
00269         if (xx != -1 ||
00270             !(entry->info.tag == RPMTAG_HEADERSIGNATURES
00271            && entry->info.type == RPM_BIN_TYPE
00272            && entry->info.count == REGION_TAG_COUNT))
00273         {
00274             (void) snprintf(buf, sizeof(buf),
00275                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00276                 entry->info.tag, entry->info.type,
00277                 entry->info.offset, entry->info.count);
00278             goto exit;
00279         }
00280 /*@=sizeoftype@*/
00281 /*@-boundswrite@*/
00282         memset(info, 0, sizeof(*info));
00283 /*@=boundswrite@*/
00284 
00285         /* Is the no. of tags in the region less than the total no. of tags? */
00286         ril = entry->info.offset/sizeof(*pe);
00287         if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00288             (void) snprintf(buf, sizeof(buf),
00289                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00290             goto exit;
00291         }
00292     }
00293 
00294     /* Sanity check signature tags */
00295 /*@-boundswrite@*/
00296     memset(info, 0, sizeof(*info));
00297 /*@=boundswrite@*/
00298     for (i = 1; i < il; i++) {
00299         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00300         if (xx != -1) {
00301             (void) snprintf(buf, sizeof(buf),
00302                 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00303                 i, entry->info.tag, entry->info.type,
00304                 entry->info.offset, entry->info.count);
00305             goto exit;
00306         }
00307     }
00308 
00309     /* OK, blob looks sane, load the header. */
00310     sigh = headerLoad(ei);
00311     if (sigh == NULL) {
00312         (void) snprintf(buf, sizeof(buf), _("sigh load: BAD\n"));
00313         goto exit;
00314     }
00315     sigh->flags |= HEADERFLAG_ALLOCATED;
00316 
00317     {   int sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
00318         int pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
00319         int_32 * archSize = NULL;
00320 
00321         /* Position at beginning of header. */
00322         if (pad && (xx = timedRead(fd, (char *)block, pad)) != pad) {
00323             (void) snprintf(buf, sizeof(buf),
00324                 _("sigh pad(%d): BAD, read %d bytes\n"), pad, xx);
00325             goto exit;
00326         }
00327 
00328         /* Print package component sizes. */
00329         if (headerGetEntry(sigh, RPMSIGTAG_SIZE, NULL, &archSize, NULL)) {
00330             size_t datasize = *(uint_32 *)archSize;
00331             rc = printSize(fd, sigSize, pad, datasize);
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, D_("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, /*@unused@*/ 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 #ifdef  NOTYET
00410     pgpDig dig = NULL;
00411     pgpDigParams sigp = NULL;
00412 #endif
00413     int rc;
00414 
00415 /*@-boundswrite@*/
00416     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00417 /*@=boundswrite@*/
00418 
00419     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00420     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00421 
00422     inpipe[0] = inpipe[1] = 0;
00423 /*@-boundsread@*/
00424     (void) pipe(inpipe);
00425 /*@=boundsread@*/
00426 
00427     if (!(pid = fork())) {
00428         const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00429         const char *path;
00430         pgpVersion pgpVer;
00431 
00432         (void) dup2(inpipe[0], 3);
00433         (void) close(inpipe[1]);
00434 
00435         (void) dosetenv("PGPPASSFD", "3", 1);
00436 /*@-boundsread@*/
00437         if (pgp_path && *pgp_path != '\0')
00438             (void) dosetenv("PGPPATH", pgp_path, 1);
00439 /*@=boundsread@*/
00440 
00441         /* dosetenv("PGPPASS", passPhrase, 1); */
00442 
00443         unsetenv("MALLOC_CHECK_");
00444         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00445             switch(pgpVer) {
00446             case PGP_2:
00447                 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
00448                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00449 /*@-boundsread@*/
00450                 if (!rc)
00451                     rc = execve(av[0], av+1, environ);
00452 /*@=boundsread@*/
00453                 break;
00454             case PGP_5:
00455                 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
00456                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00457 /*@-boundsread@*/
00458                 if (!rc)
00459                     rc = execve(av[0], av+1, environ);
00460 /*@=boundsread@*/
00461                 break;
00462             case PGP_UNKNOWN:
00463             case PGP_NOTDETECTED:
00464                 errno = ENOENT;
00465                 break;
00466             }
00467         }
00468         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00469                         strerror(errno));
00470         _exit(RPMERR_EXEC);
00471     }
00472 
00473     delMacro(NULL, "__plaintext_filename");
00474     delMacro(NULL, "__signature_filename");
00475 
00476     (void) close(inpipe[0]);
00477     if (passPhrase)
00478         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
00479     (void) write(inpipe[1], "\n", 1);
00480     (void) close(inpipe[1]);
00481 
00482     (void)waitpid(pid, &status, 0);
00483     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00484         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
00485         return 1;
00486     }
00487 
00488     if (stat(sigfile, &st)) {
00489         /* PGP failed to write signature */
00490         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00491         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
00492         return 1;
00493     }
00494 
00495 /*@-boundswrite@*/
00496     *pktlenp = st.st_size;
00497     rpmMessage(RPMMESS_DEBUG, D_("PGP sig size: %d\n"), *pktlenp);
00498     *pktp = xmalloc(*pktlenp);
00499 /*@=boundswrite@*/
00500 
00501 /*@-boundsread@*/
00502     {   FD_t fd;
00503 
00504         rc = 0;
00505         fd = Fopen(sigfile, "r.fdio");
00506         if (fd != NULL && !Ferror(fd)) {
00507             rc = timedRead(fd, *pktp, *pktlenp);
00508             if (sigfile) (void) unlink(sigfile);
00509             (void) Fclose(fd);
00510         }
00511         if (rc != *pktlenp) {
00512 /*@-boundswrite@*/
00513             *pktp = _free(*pktp);
00514 /*@=boundswrite@*/
00515             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00516             return 1;
00517         }
00518     }
00519 
00520     rpmMessage(RPMMESS_DEBUG, D_("Got %d bytes of PGP sig\n"), *pktlenp);
00521 /*@=boundsread@*/
00522 
00523 #ifdef  NOTYET
00524     /* Parse the signature, change signature tag as appropriate. */
00525     dig = pgpNewDig();
00526 
00527     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00528     sigp = &dig->signature;
00529 
00530     dig = pgpFreeDig(dig);
00531 #endif
00532 
00533     return 0;
00534 }
00535 
00545 static int makeGPGSignature(const char * file, int_32 * sigTagp,
00546                 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp,
00547                 /*@null@*/ const char * passPhrase)
00548         /*@globals rpmGlobalMacroContext, h_errno,
00549                 fileSystem, internalState @*/
00550         /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext,
00551                 fileSystem, internalState @*/
00552 {
00553     char * sigfile = alloca(strlen(file)+sizeof(".sig"));
00554     int pid, status;
00555     int inpipe[2];
00556     FILE * fpipe;
00557     struct stat st;
00558     const char * cmd;
00559     char *const *av;
00560     pgpDig dig = NULL;
00561     pgpDigParams sigp = NULL;
00562     int rc;
00563 
00564 /*@-boundswrite@*/
00565     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00566 /*@=boundswrite@*/
00567 
00568     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00569     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00570 
00571     inpipe[0] = inpipe[1] = 0;
00572 /*@-boundsread@*/
00573     (void) pipe(inpipe);
00574 /*@=boundsread@*/
00575 
00576     if (!(pid = fork())) {
00577         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00578 
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, D_("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, D_("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, sigTag, 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, &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 (dodigest(PGPHASHALGO_MD5, 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         pass = Getpass(prompt);
01007 
01008         if (pass != NULL && checkPassPhrase(pass, sigTag))
01009             pass = NULL;
01010     }
01011 
01012     return pass;
01013 }
01014 
01015 static /*@observer@*/ const char * rpmSigString(rpmRC res)
01016         /*@*/
01017 {
01018     const char * str;
01019     switch (res) {
01020     case RPMRC_OK:              str = "OK";             break;
01021     case RPMRC_FAIL:            str = "BAD";            break;
01022     case RPMRC_NOKEY:           str = "NOKEY";          break;
01023     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
01024     default:
01025     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
01026     }
01027     return str;
01028 }
01029 
01030 /*@-boundswrite@*/
01031 static rpmRC
01032 verifySizeSignature(const rpmts ts, /*@out@*/ char * t)
01033         /*@modifies *t @*/
01034 {
01035     const void * sig = rpmtsSig(ts);
01036     pgpDig dig = rpmtsDig(ts);
01037     rpmRC res;
01038     int_32 size = 0x7fffffff;
01039 
01040     *t = '\0';
01041     t = stpcpy(t, _("Header+Payload size: "));
01042 
01043     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
01044         res = RPMRC_NOKEY;
01045         t = stpcpy(t, rpmSigString(res));
01046         goto exit;
01047     }
01048 
01049     memcpy(&size, sig, sizeof(size));
01050 
01051     if (size != dig->nbytes) {
01052         res = RPMRC_FAIL;
01053         t = stpcpy(t, rpmSigString(res));
01054         sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes);
01055     } else {
01056         res = RPMRC_OK;
01057         t = stpcpy(t, rpmSigString(res));
01058         sprintf(t, " (%d)", (int)dig->nbytes);
01059     }
01060 
01061 exit:
01062     t = stpcpy(t, "\n");
01063     return res;
01064 }
01065 /*@=boundswrite@*/
01066 
01067 /*@-boundswrite@*/
01068 static rpmRC
01069 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t,
01070                 /*@null@*/ DIGEST_CTX md5ctx)
01071         /*@globals internalState @*/
01072         /*@modifies *t, internalState @*/
01073 {
01074     const void * sig = rpmtsSig(ts);
01075     int_32 siglen = rpmtsSiglen(ts);
01076     pgpDig dig = rpmtsDig(ts);
01077     rpmRC res;
01078     byte * md5sum = NULL;
01079     size_t md5len = 0;
01080 
01081     *t = '\0';
01082     t = stpcpy(t, _("MD5 digest: "));
01083 
01084     if (md5ctx == NULL || sig == NULL || dig == NULL) {
01085         res = RPMRC_NOKEY;
01086         t = stpcpy(t, rpmSigString(res));
01087         goto exit;
01088     }
01089 
01090     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01091     (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0);
01092     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01093     rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
01094 
01095     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
01096         res = RPMRC_FAIL;
01097         t = stpcpy(t, rpmSigString(res));
01098         t = stpcpy(t, " Expected(");
01099         (void) pgpHexCvt(t, sig, siglen);
01100         t += strlen(t);
01101         t = stpcpy(t, ") != (");
01102     } else {
01103         res = RPMRC_OK;
01104         t = stpcpy(t, rpmSigString(res));
01105         t = stpcpy(t, " (");
01106     }
01107     (void) pgpHexCvt(t, md5sum, md5len);
01108     t += strlen(t);
01109     t = stpcpy(t, ")");
01110 
01111 exit:
01112     md5sum = _free(md5sum);
01113     t = stpcpy(t, "\n");
01114     return res;
01115 }
01116 /*@=boundswrite@*/
01117 
01118 /*@-boundswrite@*/
01126 static rpmRC
01127 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t,
01128                 /*@null@*/ DIGEST_CTX sha1ctx)
01129         /*@globals internalState @*/
01130         /*@modifies *t, internalState @*/
01131 {
01132     const void * sig = rpmtsSig(ts);
01133 #ifdef  NOTYET
01134     int_32 siglen = rpmtsSiglen(ts);
01135 #endif
01136     pgpDig dig = rpmtsDig(ts);
01137     rpmRC res;
01138     const char * SHA1 = NULL;
01139 
01140     *t = '\0';
01141     t = stpcpy(t, _("Header SHA1 digest: "));
01142 
01143     if (sha1ctx == NULL || sig == NULL || dig == NULL) {
01144         res = RPMRC_NOKEY;
01145         t = stpcpy(t, rpmSigString(res));
01146         goto exit;
01147     }
01148 
01149     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01150     (void) rpmDigestFinal(rpmDigestDup(sha1ctx), &SHA1, NULL, 1);
01151     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01152 
01153     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
01154         res = RPMRC_FAIL;
01155         t = stpcpy(t, rpmSigString(res));
01156         t = stpcpy(t, " Expected(");
01157         t = stpcpy(t, sig);
01158         t = stpcpy(t, ") != (");
01159     } else {
01160         res = RPMRC_OK;
01161         t = stpcpy(t, rpmSigString(res));
01162         t = stpcpy(t, " (");
01163     }
01164     if (SHA1)
01165         t = stpcpy(t, SHA1);
01166     t = stpcpy(t, ")");
01167 
01168 exit:
01169     SHA1 = _free(SHA1);
01170     t = stpcpy(t, "\n");
01171     return res;
01172 }
01173 /*@=boundswrite@*/
01174 
01180 static inline unsigned char nibble(char c)
01181         /*@*/
01182 {
01183     if (c >= '0' && c <= '9')
01184         return (c - '0');
01185     if (c >= 'A' && c <= 'F')
01186         return (c - 'A') + 10;
01187     if (c >= 'a' && c <= 'f')
01188         return (c - 'a') + 10;
01189     return 0;
01190 }
01191 
01192 /*@-boundswrite@*/
01200 static rpmRC
01201 verifyRSASignature(rpmts ts, /*@out@*/ char * t,
01202                 /*@null@*/ DIGEST_CTX md5ctx)
01203         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01204         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01205 {
01206     const void * sig = rpmtsSig(ts);
01207 #ifdef  NOTYET
01208     int_32 siglen = rpmtsSiglen(ts);
01209 #endif
01210     int_32 sigtag = rpmtsSigtag(ts);
01211     pgpDig dig = rpmtsDig(ts);
01212     pgpDigParams sigp = rpmtsSignature(ts);
01213     const char * prefix = NULL;
01214     rpmRC res = RPMRC_OK;
01215     int xx;
01216 
01217 assert(dig != NULL);
01218 assert(sigp != NULL);
01219     *t = '\0';
01220     if (dig != NULL && dig->hdrmd5ctx == md5ctx)
01221         t = stpcpy(t, _("Header "));
01222     *t++ = 'V';
01223     switch (sigp->version) {
01224     case 3:     *t++ = '3';     break;
01225     case 4:     *t++ = '4';     break;
01226     }
01227 
01228     if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01229         res = RPMRC_NOKEY;
01230     }
01231 
01232     /* Verify the desired signature match. */
01233     switch (sigp->pubkey_algo) {
01234     case PGPPUBKEYALGO_RSA:
01235         if (sigtag == RPMSIGTAG_PGP || sigtag == RPMSIGTAG_PGP5 || sigtag == RPMSIGTAG_RSA)
01236             break;
01237         /*@fallthrough@*/
01238     default:
01239         res = RPMRC_NOKEY;
01240         break;
01241     }
01242 
01243     /* Verify the desired hash match. */
01244     /* XXX Values from PKCS#1 v2.1 (aka RFC-3447) */
01245 /*@-branchstate@*/
01246     switch (sigp->hash_algo) {
01247     case PGPHASHALGO_MD5:
01248         t = stpcpy(t, " RSA/MD5");
01249         prefix = "3020300c06082a864886f70d020505000410";
01250         break;
01251     case PGPHASHALGO_SHA1:
01252         t = stpcpy(t, " RSA/SHA1");
01253         prefix = "3021300906052b0e03021a05000414";
01254         break;
01255     case PGPHASHALGO_RIPEMD160:
01256         t = stpcpy(t, " RSA/RIPEMD160");
01257         prefix = "3021300906052b2403020105000414";
01258         break;
01259     case PGPHASHALGO_MD2:
01260         t = stpcpy(t, " RSA/MD2");
01261         prefix = "3020300c06082a864886f70d020205000410";
01262         break;
01263     case PGPHASHALGO_TIGER192:
01264         t = stpcpy(t, " RSA/TIGER192");
01265         prefix = "3029300d06092b06010401da470c0205000418";
01266         break;
01267     case PGPHASHALGO_HAVAL_5_160:
01268         res = RPMRC_NOKEY;
01269         prefix = NULL;
01270         break;
01271     case PGPHASHALGO_SHA256:
01272         t = stpcpy(t, " RSA/SHA256");
01273         prefix = "3031300d060960864801650304020105000420";
01274         break;
01275     case PGPHASHALGO_SHA384:
01276         t = stpcpy(t, " RSA/SHA384");
01277         prefix = "3041300d060960864801650304020205000430";
01278         break;
01279     case PGPHASHALGO_SHA512:
01280         t = stpcpy(t, " RSA/SHA512");
01281         prefix = "3051300d060960864801650304020305000440";
01282         break;
01283     default:
01284         res = RPMRC_NOKEY;
01285         prefix = NULL;
01286         break;
01287     }
01288 /*@=branchstate@*/
01289 
01290     t = stpcpy(t, _(" signature: "));
01291     if (res != RPMRC_OK) {
01292         goto exit;
01293     }
01294 
01295 assert(md5ctx != NULL); /* XXX can't happen. */
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, &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 /*@-type@*/     /* XXX FIX: avoid beecrypt API incompatibility. */
01359 #if HAVE_BEECRYPT_API_H
01360     xx = rsavrfy(&dig->rsa_pk.n, &dig->rsa_pk.e, &dig->c, &dig->rsahm);
01361 #else
01362     xx = rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c);
01363 #endif
01364 /*@=type@*/
01365     if (xx)
01366         res = RPMRC_OK;
01367     else
01368         res = RPMRC_FAIL;
01369     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01370 
01371 exit:
01372     t = stpcpy(t, rpmSigString(res));
01373     if (sigp != NULL) {
01374         t = stpcpy(t, ", key ID ");
01375         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01376         t += strlen(t);
01377     }
01378     t = stpcpy(t, "\n");
01379     return res;
01380 }
01381 /*@=boundswrite@*/
01382 
01390 /*@-boundswrite@*/
01391 static rpmRC
01392 verifyDSASignature(rpmts ts, /*@out@*/ char * t,
01393                 /*@null@*/ DIGEST_CTX sha1ctx)
01394         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01395         /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */
01396 {
01397     const void * sig = rpmtsSig(ts);
01398 #ifdef  NOTYET
01399     int_32 siglen = rpmtsSiglen(ts);
01400 #endif
01401     int_32 sigtag = rpmtsSigtag(ts);
01402     pgpDig dig = rpmtsDig(ts);
01403     pgpDigParams sigp = rpmtsSignature(ts);
01404     rpmRC res;
01405     int xx;
01406 
01407 assert(dig != NULL);
01408 assert(sigp != NULL);
01409     *t = '\0';
01410     if (dig != NULL && dig->hdrsha1ctx == sha1ctx)
01411         t = stpcpy(t, _("Header "));
01412     *t++ = 'V';
01413     switch (sigp->version) {
01414     case 3:    *t++ = '3';     break;
01415     case 4:    *t++ = '4';     break;
01416     }
01417     t = stpcpy(t, _(" DSA signature: "));
01418 
01419     if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) {
01420         res = RPMRC_NOKEY;
01421         goto exit;
01422     }
01423 
01424     /* XXX sanity check on sigtag and signature agreement. */
01425     if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA)
01426         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
01427         && sigp->hash_algo == PGPHASHALGO_SHA1))
01428     {
01429         res = RPMRC_NOKEY;
01430         goto exit;
01431     }
01432 
01433     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01434     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
01435         byte signhash16[2];
01436 
01437         if (sigp->hash != NULL)
01438             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
01439 
01440         if (sigp->version == 4) {
01441             int nb = sigp->hashlen;
01442             byte trailer[6];
01443             nb = htonl(nb);
01444             trailer[0] = sigp->version;
01445             trailer[1] = 0xff;
01446             memcpy(trailer+2, &nb, sizeof(nb));
01447             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
01448         }
01449         xx = rpmDigestFinal(ctx, &dig->sha1, &dig->sha1len, 1);
01450         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen);
01451         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01452 
01453         mpnzero(&dig->hm);      (void) mpnsethex(&dig->hm, dig->sha1);
01454 
01455         /* Compare leading 16 bits of digest for quick check. */
01456         signhash16[0] = (*dig->hm.data >> 24) & 0xff;
01457         signhash16[1] = (*dig->hm.data >> 16) & 0xff;
01458         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
01459             res = RPMRC_FAIL;
01460             goto exit;
01461         }
01462     }
01463 
01464     /* Retrieve the matching public key. */
01465     res = rpmtsFindPubkey(ts);
01466     if (res != RPMRC_OK)
01467         goto exit;
01468 
01469     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01470     if (dsavrfy(&dig->p, &dig->q, &dig->g,
01471                 &dig->hm, &dig->y, &dig->r, &dig->s))
01472         res = RPMRC_OK;
01473     else
01474         res = RPMRC_FAIL;
01475     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0);
01476 
01477 exit:
01478     t = stpcpy(t, rpmSigString(res));
01479     if (sigp != NULL) {
01480         t = stpcpy(t, ", key ID ");
01481         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
01482         t += strlen(t);
01483     }
01484     t = stpcpy(t, "\n");
01485     return res;
01486 }
01487 /*@=boundswrite@*/
01488 
01489 rpmRC
01490 rpmVerifySignature(const rpmts ts, char * result)
01491 {
01492     const void * sig = rpmtsSig(ts);
01493     int_32 siglen = rpmtsSiglen(ts);
01494     int_32 sigtag = rpmtsSigtag(ts);
01495     pgpDig dig = rpmtsDig(ts);
01496     rpmRC res;
01497 
01498     if (sig == NULL || siglen <= 0 || dig == NULL) {
01499         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
01500         return RPMRC_NOTFOUND;
01501     }
01502 
01503     switch (sigtag) {
01504     case RPMSIGTAG_SIZE:
01505         res = verifySizeSignature(ts, result);
01506         break;
01507     case RPMSIGTAG_MD5:
01508         res = verifyMD5Signature(ts, result, dig->md5ctx);
01509         break;
01510     case RPMSIGTAG_SHA1:
01511         res = verifySHA1Signature(ts, result, dig->hdrsha1ctx);
01512         break;
01513     case RPMSIGTAG_RSA:
01514         res = verifyRSASignature(ts, result, dig->hdrmd5ctx);
01515         break;
01516     case RPMSIGTAG_PGP5:        /* XXX legacy */
01517     case RPMSIGTAG_PGP:
01518         res = verifyRSASignature(ts, result,
01519                 ((dig->signature.hash_algo == PGPHASHALGO_MD5)
01520                         ? dig->md5ctx : dig->sha1ctx));
01521         break;
01522     case RPMSIGTAG_DSA:
01523         res = verifyDSASignature(ts, result, dig->hdrsha1ctx);
01524         break;
01525     case RPMSIGTAG_GPG:
01526         res = verifyDSASignature(ts, result, dig->sha1ctx);
01527         break;
01528     case RPMSIGTAG_LEMD5_1:
01529     case RPMSIGTAG_LEMD5_2:
01530         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
01531         res = RPMRC_NOTFOUND;
01532         break;
01533     default:
01534         sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag);
01535         res = RPMRC_NOTFOUND;
01536         break;
01537     }
01538     return res;
01539 }

Generated on Mon Aug 23 10:18:25 2010 for rpm by  doxygen 1.4.4