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

lib/signature.c

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

Generated on Wed Sep 4 12:49:53 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002