rpm  5.4.4
rpmdb/signature.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmurl.h>
00009 #include <rpmcb.h>      /* XXX rpmIsVerbose() */
00010 #define _RPMPGP_INTERNAL
00011 #include <rpmpgp.h>
00012 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
00013 #include <rpmhkp.h>
00014 #include <rpmku.h>
00015 
00016 #include <rpmtag.h>
00017 #include "rpmdb.h"
00018 #include <pkgio.h>      /* XXX expects <rpmts.h> */
00019 #include "legacy.h"     /* XXX for dodogest() */
00020 #include "signature.h"
00021 
00022 #include "debug.h"
00023 
00024 /*@access FD_t@*/               /* XXX ufdio->read arg1 is void ptr */
00025 /*@access Header@*/             /* XXX compared with NULL */
00026 /*@access DIGEST_CTX@*/         /* XXX compared with NULL */
00027 /*@access pgpDig@*/
00028 /*@access pgpDigParams@*/
00029 
00030 int rpmTempFile(const char * prefix, const char ** fnptr, void * fdptr)
00031 {
00032     const char * tpmacro = "%{?_tmppath}%{!?_tmppath:/var/tmp/}";
00033     const char * tempfn = NULL;
00034     const char * tfn = NULL;
00035     static int _initialized = 0;
00036     int temput;
00037     FD_t fd = NULL;
00038     unsigned int ran;
00039 
00040     if (!prefix) prefix = "";
00041 
00042     /* Create the temp directory if it doesn't already exist. */
00043     if (!_initialized) {
00044         _initialized = 1;
00045         tempfn = rpmGenPath(prefix, tpmacro, NULL);
00046         if (rpmioMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
00047             goto errxit;
00048     }
00049 
00050     /* XXX should probably use mkstemp here */
00051     ran = (unsigned) time(NULL);
00052     srand(ran);
00053     ran = rand() % 100000;
00054 
00055     /* maybe this should use link/stat? */
00056 
00057     do {
00058         char tfnbuf[64];
00059 #ifndef NOTYET
00060         sprintf(tfnbuf, "rpm-tmp.%u", ran++);
00061         tempfn = _free(tempfn);
00062         tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
00063 #else
00064         strcpy(tfnbuf, "rpm-tmp.XXXXXX");
00065         tempfn = _free(tempfn);
00066         tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
00067 #endif
00068 
00069         temput = urlPath(tempfn, &tfn);
00070         if (*tfn == '\0') goto errxit;
00071 
00072         switch (temput) {
00073         case URL_IS_DASH:
00074         case URL_IS_HKP:
00075         case URL_IS_MONGO:      /* XXX FIXME */
00076             goto errxit;
00077             /*@notreached@*/ /*@switchbreak@*/ break;
00078         case URL_IS_HTTPS:
00079         case URL_IS_HTTP:
00080         case URL_IS_FTP:
00081         default:
00082             /*@switchbreak@*/ break;
00083         }
00084 
00085         fd = Fopen(tempfn, "w+x.fdio");
00086         /* XXX FIXME: errno may not be correct for ufdio */
00087     } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
00088 
00089     if (fd == NULL || Ferror(fd)) {
00090         rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tempfn);
00091         goto errxit;
00092     }
00093 
00094     switch(temput) {
00095     case URL_IS_PATH:
00096     case URL_IS_UNKNOWN:
00097       { struct stat sb, sb2;
00098         if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
00099             rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00100             goto errxit;
00101         }
00102 
00103         if (sb.st_nlink != 1) {
00104             rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00105             goto errxit;
00106         }
00107 
00108         if (fstat(Fileno(fd), &sb2) == 0) {
00109             if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
00110                 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00111                 goto errxit;
00112             }
00113         }
00114       } break;
00115     default:
00116         break;
00117     }
00118 
00119     if (fnptr)
00120         *fnptr = tempfn;
00121     else 
00122         tempfn = _free(tempfn);
00123     if (fdptr)
00124         *(FD_t *)fdptr = fd;
00125 
00126     return 0;
00127 
00128 errxit:
00129     tempfn = _free(tempfn);
00130     if (fnptr)
00131         *fnptr = NULL;
00132     /*@-usereleased@*/
00133     if (fd != NULL) (void) Fclose(fd);
00134     /*@=usereleased@*/
00135     return 1;
00136 }
00137 
00138 
00148 static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
00149                 /*@out@*/ rpmuint8_t ** pktp, /*@out@*/ rpmuint32_t * pktlenp,
00150                 /*@null@*/ const char * passPhrase)
00151         /*@globals rpmGlobalMacroContext, h_errno,
00152                 fileSystem, internalState @*/
00153         /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext,
00154                 fileSystem, internalState @*/
00155 {
00156     char * sigfile = alloca(strlen(file)+sizeof(".sig"));
00157     pid_t pid;
00158     int status;
00159     int inpipe[2];
00160     FILE * fpipe;
00161     struct stat st;
00162     const char * cmd;
00163     char *const *av;
00164     pgpDig dig = NULL;
00165     pgpDigParams sigp = NULL;
00166     const char * pw = NULL;
00167     int rc;
00168 
00169     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00170 
00171     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00172     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00173 
00174     inpipe[0] = inpipe[1] = 0;
00175     if (pipe(inpipe) < 0) {
00176         rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
00177         return 1;
00178     }
00179 
00180     if (!(pid = fork())) {
00181         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00182 
00183         (void) dup2(inpipe[0], 3);
00184         (void) close(inpipe[1]);
00185 
00186         if (gpg_path && *gpg_path != '\0')
00187             (void) setenv("GNUPGHOME", gpg_path, 1);
00188 
00189         unsetenv("MALLOC_CHECK_");
00190         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
00191         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00192         if (!rc)
00193             rc = execve(av[0], av+1, environ);
00194 
00195         rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
00196                         strerror(errno));
00197         _exit(EXIT_FAILURE);
00198     }
00199 
00200     delMacro(NULL, "__plaintext_filename");
00201     delMacro(NULL, "__signature_filename");
00202 
00203     pw = rpmkuPassPhrase(passPhrase);
00204     if (pw == NULL) {
00205         rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
00206                         strerror(errno));
00207         return 1;
00208     }
00209 
00210     fpipe = fdopen(inpipe[1], "w");
00211     (void) close(inpipe[0]);
00212     if (fpipe) {
00213         fprintf(fpipe, "%s\n", (pw ? pw : ""));
00214         (void) fclose(fpipe);
00215     }
00216 
00217     if (pw != NULL) {
00218         (void) memset((void *)pw, 0, strlen(pw));
00219         pw = _free(pw);
00220     }
00221 
00222 /*@+longunsignedintegral@*/
00223     (void) waitpid(pid, &status, 0);
00224 /*@=longunsignedintegral@*/
00225     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00226         rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
00227         return 1;
00228     }
00229 
00230     if (Stat(sigfile, &st)) {
00231         /* GPG failed to write signature */
00232         if (sigfile) (void) Unlink(sigfile);  /* Just in case */
00233         rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
00234         return 1;
00235     }
00236 
00237     *pktlenp = (rpmuint32_t)st.st_size;
00238     rpmlog(RPMLOG_DEBUG, D_("GPG sig size: %u\n"), (unsigned)*pktlenp);
00239     *pktp = xmalloc(*pktlenp);
00240 
00241     {   FD_t fd;
00242 
00243         rc = 0;
00244         fd = Fopen(sigfile, "r.ufdio");
00245         if (fd != NULL && !Ferror(fd)) {
00246             rc = (int) Fread(*pktp, sizeof((*pktp)[0]), *pktlenp, fd);
00247             if (sigfile) (void) Unlink(sigfile);
00248             (void) Fclose(fd);
00249         }
00250         if ((rpmuint32_t)rc != *pktlenp) {
00251             *pktp = _free(*pktp);
00252             rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
00253             return 1;
00254         }
00255     }
00256 
00257     rpmlog(RPMLOG_DEBUG, D_("Got %u bytes of GPG sig\n"), (unsigned)*pktlenp);
00258 
00259     /* Parse the signature, change signature tag as appropriate. */
00260     dig = pgpDigNew(RPMVSF_DEFAULT, 0);
00261 
00262     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00263     sigp = pgpGetSignature(dig);
00264 
00265     /* Identify the type of signature being returned. */
00266     switch (*sigTagp) {
00267     default:
00268 assert(0);      /* XXX never happens. */
00269         /*@notreached@*/ break;
00270     case RPMSIGTAG_SIZE:
00271     case RPMSIGTAG_MD5:
00272     case RPMSIGTAG_SHA1:
00273         break;
00274     case RPMSIGTAG_DSA:
00275         /* XXX check hash algorithm too? */
00276         if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA)
00277             *sigTagp = RPMSIGTAG_RSA;
00278         break;
00279     case RPMSIGTAG_RSA:
00280         if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA)
00281             *sigTagp = RPMSIGTAG_DSA;
00282         break;
00283     }
00284 
00285     dig = pgpDigFree(dig);
00286 
00287     return 0;
00288 }
00289 
00298 /*@-mustmod@*/ /* sigh is modified */
00299 static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
00300                 /*@null@*/ const char * passPhrase)
00301         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00302         /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/
00303 {
00304     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00305     Header h = NULL;
00306     FD_t fd = NULL;
00307     rpmuint8_t * pkt;
00308     rpmuint32_t pktlen;
00309     const char * fn = NULL;
00310     const char * msg;
00311     rpmRC rc;
00312     int ret = -1;       /* assume failure. */
00313     int xx;
00314 
00315     switch (sigTag) {
00316     default:
00317 assert(0);      /* XXX never happens. */
00318         /*@notreached@*/ break;
00319     case RPMSIGTAG_SIZE:
00320     case RPMSIGTAG_MD5:
00321     case RPMSIGTAG_PGP5:        /* XXX legacy */
00322     case RPMSIGTAG_PGP:
00323     case RPMSIGTAG_GPG:
00324         goto exit;
00325         /*@notreached@*/ break;
00326     case RPMSIGTAG_SHA1:
00327     {   const char * SHA1 = NULL;
00328         fd = Fopen(file, "r.fdio");
00329         if (fd == NULL || Ferror(fd))
00330             goto exit;
00331         {   const char item[] = "Header";
00332             msg = NULL;
00333             rc = rpmpkgRead(item, fd, &h, &msg);
00334             if (rc != RPMRC_OK) {
00335                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00336                 msg = _free(msg);
00337                 goto exit;
00338             }
00339             msg = _free(msg);
00340         }
00341         (void) Fclose(fd);      fd = NULL;
00342 
00343         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
00344             unsigned char * hmagic = NULL;
00345             size_t nmagic = 0;
00346             DIGEST_CTX ctx;
00347         
00348             he->tag = RPMTAG_HEADERIMMUTABLE;
00349             if (!headerGet(h, he, 0) || he->p.ptr == NULL)
00350             {
00351                 (void)headerFree(h);
00352                 h = NULL;
00353                 goto exit;
00354             }
00355             (void) headerGetMagic(NULL, &hmagic, &nmagic);
00356             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00357             if (hmagic && nmagic > 0)
00358                 (void) rpmDigestUpdate(ctx, hmagic, nmagic);
00359             (void) rpmDigestUpdate(ctx, he->p.ptr, he->c);
00360             (void) rpmDigestFinal(ctx, &SHA1, NULL, 1);
00361             he->p.ptr = _free(he->p.ptr);
00362         }
00363         (void)headerFree(h);
00364         h = NULL;
00365 
00366         if (SHA1 == NULL)
00367             goto exit;
00368         he->tag = (rpmTag) RPMSIGTAG_SHA1;
00369         he->t = RPM_STRING_TYPE;
00370         he->p.str = SHA1;
00371         he->c = 1;
00372         xx = headerPut(sigh, he, 0);
00373         SHA1 = _free(SHA1);
00374         if (!xx)
00375             goto exit;
00376         ret = 0;
00377    }    break;
00378    case RPMSIGTAG_DSA:
00379         fd = Fopen(file, "r.fdio");
00380         if (fd == NULL || Ferror(fd))
00381             goto exit;
00382         {   const char item[] = "Header";
00383             msg = NULL;
00384             rc = rpmpkgRead(item, fd, &h, &msg);
00385             if (rc != RPMRC_OK) {
00386                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00387                 msg = _free(msg);
00388                 goto exit;
00389             }
00390             msg = _free(msg);
00391         }
00392         (void) Fclose(fd);      fd = NULL;
00393 
00394         if (rpmTempFile(NULL, &fn, &fd))
00395             goto exit;
00396         {   const char item[] = "Header";
00397             msg = NULL;
00398             rc = rpmpkgWrite(item, fd, h, &msg);
00399             if (rc != RPMRC_OK) {
00400                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00401                 msg = _free(msg);
00402                 goto exit;
00403             }
00404             msg = _free(msg);
00405         }
00406         (void) Fclose(fd);      fd = NULL;
00407 
00408         if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase))
00409             goto exit;
00410         he->tag = (rpmTag) sigTag;
00411         he->t = RPM_BIN_TYPE;
00412         he->p.ptr = pkt;
00413         he->c = pktlen;
00414         xx = headerPut(sigh, he, 0);
00415         if (!xx)
00416             goto exit;
00417         ret = 0;
00418         break;
00419     }
00420 
00421 exit:
00422     if (fn) {
00423         (void) Unlink(fn);
00424         fn = _free(fn);
00425     }
00426     (void)headerFree(h);
00427     h = NULL;
00428     if (fd != NULL) (void) Fclose(fd);
00429     return ret;
00430 }
00431 /*@=mustmod@*/
00432 
00433 int rpmAddSignature(Header sigh, const char * file, rpmSigTag sigTag,
00434                 const char * passPhrase)
00435 {
00436     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00437     struct stat st;
00438     rpmuint8_t * pkt;
00439     rpmuint32_t pktlen;
00440     int ret = -1;       /* assume failure. */
00441     int xx;
00442 
00443     switch (sigTag) {
00444     default:
00445 assert(0);      /* XXX never happens. */
00446         /*@notreached@*/ break;
00447     case RPMSIGTAG_SIZE:
00448         if (Stat(file, &st) != 0)
00449             break;
00450         pktlen = (rpmuint32_t)st.st_size;
00451         he->tag = (rpmTag) sigTag;
00452         he->t = RPM_UINT32_TYPE;
00453         he->p.ui32p = &pktlen;
00454         he->c = 1;
00455 /*@-compmempass@*/
00456         xx = headerPut(sigh, he, 0);
00457 /*@=compmempass@*/
00458         if (!xx)
00459             break;
00460         ret = 0;
00461         break;
00462     case RPMSIGTAG_MD5:
00463         pktlen = 128/8;
00464         pkt = memset(alloca(pktlen), 0, pktlen);
00465         if (dodigest(PGPHASHALGO_MD5, file, (unsigned char *)pkt, 0, NULL))
00466             break;
00467         he->tag = (rpmTag) sigTag;
00468         he->t = RPM_BIN_TYPE;
00469         he->p.ptr = pkt;
00470         he->c = pktlen;
00471         xx = headerPut(sigh, he, 0);
00472         if (!xx)
00473             break;
00474         ret = 0;
00475         break;
00476     case RPMSIGTAG_GPG:
00477         ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
00478         break;
00479     case RPMSIGTAG_RSA:
00480     case RPMSIGTAG_DSA:
00481     case RPMSIGTAG_SHA1:
00482         ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
00483         break;
00484     }
00485 
00486     return ret;
00487 }
00488 
00489 int rpmCheckPassPhrase(const char * passPhrase)
00490 {
00491     const char *pw;
00492     int p[2];
00493     pid_t pid;
00494     int status;
00495     int rc;
00496     int xx;
00497 
00498     if (!(passPhrase && passPhrase[0]))
00499         return 0;
00500 
00501     p[0] = p[1] = 0;
00502     xx = pipe(p);
00503 
00504     if (!(pid = fork())) {
00505         const char * cmd;
00506         char *const *av;
00507         int fdno;
00508 
00509         xx = close(STDIN_FILENO);
00510         xx = close(STDOUT_FILENO);
00511         xx = close(p[1]);
00512         if (!rpmIsVerbose())
00513             xx = close(STDERR_FILENO);
00514         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00515             xx = dup2(fdno, STDIN_FILENO);
00516             xx = close(fdno);
00517         }
00518         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00519             xx = dup2(fdno, STDOUT_FILENO);
00520             xx = close(fdno);
00521         }
00522         xx = dup2(p[0], 3);
00523 
00524         unsetenv("MALLOC_CHECK_");
00525         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00526 
00527             if (gpg_path && *gpg_path != '\0')
00528                 (void) setenv("GNUPGHOME", gpg_path, 1);
00529 
00530             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00531             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00532             if (!rc)
00533                 rc = execve(av[0], av+1, environ);
00534 
00535             rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
00536                         strerror(errno));
00537         }
00538     }
00539 
00540     pw = rpmkuPassPhrase(passPhrase);
00541     if (pw == NULL) {
00542         rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
00543                         strerror(errno));
00544         return 1;
00545     }
00546 
00547     xx = close(p[0]);
00548     xx = (int) write(p[1], pw, strlen(pw));
00549     xx = (int) write(p[1], "\n", 1);
00550     xx = close(p[1]);
00551 
00552     if (pw != NULL) {
00553         (void) memset((void *)pw, 0, strlen(pw));
00554         pw = _free(pw);
00555     }
00556 
00557 /*@+longunsignedintegral@*/
00558     (void) waitpid(pid, &status, 0);
00559 /*@=longunsignedintegral@*/
00560 
00561     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
00562 }
00563 
00564 static /*@observer@*/ const char * rpmSigString(rpmRC res)
00565         /*@*/
00566 {
00567     const char * str;
00568     switch (res) {
00569     case RPMRC_OK:              str = "OK";             break;
00570     case RPMRC_FAIL:            str = "BAD";            break;
00571     case RPMRC_NOKEY:           str = "NOKEY";          break;
00572     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
00573     default:
00574     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
00575     }
00576     return str;
00577 }
00578 
00579 static rpmRC
00580 verifySize(const pgpDig dig, /*@out@*/ char * t)
00581         /*@modifies *t @*/
00582 {
00583     const void * sig = pgpGetSig(dig);
00584     rpmRC res;
00585     rpmuint32_t size = 0xffffffff;
00586 
00587     *t = '\0';
00588     t = stpcpy(t, _("Header+Payload size: "));
00589 
00590     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
00591         res = RPMRC_NOKEY;
00592         t = stpcpy(t, rpmSigString(res));
00593         goto exit;
00594     }
00595 
00596     memcpy(&size, sig, sizeof(size));
00597 
00598     if (size !=(rpmuint32_t) dig->nbytes) {
00599         res = RPMRC_FAIL;
00600         t = stpcpy(t, rpmSigString(res));
00601         sprintf(t, " Expected(%u) != (%u)\n", (unsigned)size, (unsigned)dig->nbytes);
00602     } else {
00603         res = RPMRC_OK;
00604         t = stpcpy(t, rpmSigString(res));
00605         sprintf(t, " (%u)", (unsigned)dig->nbytes);
00606     }
00607 
00608 exit:
00609     return res;
00610 }
00611 
00612 static rpmRC
00613 verifyMD5(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX md5ctx)
00614         /*@globals internalState @*/
00615         /*@modifies *t, internalState @*/
00616 {
00617     const void * sig = pgpGetSig(dig);
00618     rpmuint32_t siglen = pgpGetSiglen(dig);
00619     rpmRC res;
00620     rpmuint8_t * md5sum = NULL;
00621     size_t md5len = 0;
00622 
00623 assert(dig != NULL);
00624 assert(md5ctx != NULL);
00625 assert(sig != NULL);
00626 
00627     *t = '\0';
00628 
00629     /* Identify the hash. */
00630     t = stpcpy(t, rpmDigestName(md5ctx));
00631     t = stpcpy(t, _(" digest: "));
00632 
00633     if (sig == NULL) {          /* XXX can't happen, DYING */
00634         res = RPMRC_NOKEY;
00635         t = stpcpy(t, rpmSigString(res));
00636         goto exit;
00637     }
00638 
00639     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00640         (void) rpmswEnter(op, 0);
00641         (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0);
00642         (void) rpmswExit(op, 0);
00643         if (op != NULL) op->count--;    /* XXX one too many */
00644     }
00645 
00646     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
00647         res = RPMRC_FAIL;
00648         t = stpcpy(t, rpmSigString(res));
00649         t = stpcpy(t, " Expected(");
00650         (void) pgpHexCvt(t, sig, siglen);
00651         t += strlen(t);
00652         t = stpcpy(t, ") != (");
00653     } else {
00654         res = RPMRC_OK;
00655         t = stpcpy(t, rpmSigString(res));
00656         t = stpcpy(t, " (");
00657     }
00658     (void) pgpHexCvt(t, md5sum, md5len);
00659     t += strlen(t);
00660     t = stpcpy(t, ")");
00661 
00662 exit:
00663     md5sum = _free(md5sum);
00664     return res;
00665 }
00666 
00674 static rpmRC
00675 verifySHA1(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX shactx)
00676         /*@globals internalState @*/
00677         /*@modifies *t, internalState @*/
00678 {
00679     const void * sig = pgpGetSig(dig);
00680 #ifdef  NOTYET
00681     rpmuint32_t siglen = pgpGetSiglen(dig);
00682 #endif
00683     rpmRC res;
00684     const char * SHA1 = NULL;
00685 
00686 assert(dig != NULL);
00687 assert(shactx != NULL);
00688 assert(sig != NULL);
00689 
00690     *t = '\0';
00691     t = stpcpy(t, _("Header "));
00692 
00693     /* Identify the hash. */
00694     t = stpcpy(t, rpmDigestName(shactx));
00695     t = stpcpy(t, _(" digest: "));
00696 
00697     if (sig == NULL) {          /* XXX can't happen, DYING */
00698         res = RPMRC_NOKEY;
00699         t = stpcpy(t, rpmSigString(res));
00700         goto exit;
00701     }
00702 
00703     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00704         (void) rpmswEnter(op, 0);
00705         (void) rpmDigestFinal(rpmDigestDup(shactx), &SHA1, NULL, 1);
00706         (void) rpmswExit(op, 0);
00707     }
00708 
00709     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
00710         res = RPMRC_FAIL;
00711         t = stpcpy(t, rpmSigString(res));
00712         t = stpcpy(t, " Expected(");
00713         t = stpcpy(t, sig);
00714         t = stpcpy(t, ") != (");
00715     } else {
00716         res = RPMRC_OK;
00717         t = stpcpy(t, rpmSigString(res));
00718         t = stpcpy(t, " (");
00719     }
00720     if (SHA1)
00721         t = stpcpy(t, SHA1);
00722     t = stpcpy(t, ")");
00723 
00724 exit:
00725     SHA1 = _free(SHA1);
00726     return res;
00727 }
00728 
00736 static rpmRC
00737 verifyRSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX rsactx)
00738         /*@globals internalState @*/
00739         /*@modifies dig, *t, internalState */
00740 {
00741     const void * sig = pgpGetSig(dig);
00742 #ifdef  NOTYET
00743     rpmuint32_t siglen = pgpGetSiglen(dig);
00744 #endif
00745     pgpDigParams sigp = pgpGetSignature(dig);
00746     rpmRC res = RPMRC_OK;
00747     int xx;
00748 
00749 if (_rpmhkp_debug)
00750 fprintf(stderr, "--> %s(%p,%p,%p) sig %p sigp %p\n", __FUNCTION__, dig, t, rsactx, sig, sigp);
00751 
00752 assert(dig != NULL);
00753 assert(rsactx != NULL);
00754 assert(sigp != NULL);
00755 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA);
00756 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(rsactx));
00757 assert(pgpGetSigtag(dig) == RPMSIGTAG_RSA);
00758 assert(sig != NULL);
00759 
00760     *t = '\0';
00761     if (dig->hdrctx == rsactx)
00762         t = stpcpy(t, _("Header "));
00763 
00764     /* Identify the signature version. */
00765     *t++ = 'V';
00766     switch (sigp->version) {
00767     case 3:     *t++ = '3';     break;
00768     case 4:     *t++ = '4';     break;
00769     }
00770 
00771     /* Identify the RSA/hash. */
00772     {   const char * hashname = rpmDigestName(rsactx);
00773         t = stpcpy(t, " RSA");
00774         if (strcmp(hashname, "UNKNOWN")) {
00775             *t++ = '/';
00776             t = stpcpy(t, hashname);
00777         }
00778     }
00779     t = stpcpy(t, _(" signature: "));
00780 
00781     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00782         DIGEST_CTX ctx = rpmDigestDup(rsactx);
00783 
00784         (void) rpmswEnter(op, 0);
00785         if (sigp->hash != NULL)
00786             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
00787 
00788         if (sigp->version == (rpmuint8_t) 4) {
00789             rpmuint8_t trailer[6];
00790             trailer[0] = sigp->version;
00791             trailer[1] = (rpmuint8_t)0xff;
00792             trailer[2] = (sigp->hashlen >> 24);
00793             trailer[3] = (sigp->hashlen >> 16);
00794             trailer[4] = (sigp->hashlen >>  8);
00795             trailer[5] = (sigp->hashlen      );
00796             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
00797         }
00798         (void) rpmswExit(op, sigp->hashlen);
00799         if (op != NULL) op->count--;    /* XXX one too many */
00800 
00801         if ((xx = pgpImplSetRSA(ctx, dig, sigp)) != 0) {
00802             res = RPMRC_FAIL;
00803             goto exit;
00804         }
00805     }
00806 
00807     /* Retrieve the matching public key. */
00808     res = pgpFindPubkey(dig);
00809     if (res != RPMRC_OK)
00810         goto exit;
00811 
00812     /* Verify the RSA signature. */
00813     {   rpmop op = pgpStatsAccumulator(dig, 11);        /* RPMTS_OP_SIGNATURE */
00814         (void) rpmswEnter(op, 0);
00815         xx = pgpImplVerify(dig);
00816         (void) rpmswExit(op, 0);
00817         res = (xx ? RPMRC_OK : RPMRC_FAIL);
00818     }
00819 
00820 exit:
00821     /* Identify the pubkey fingerprint. */
00822     t = stpcpy(t, rpmSigString(res));
00823     if (sigp != NULL) {
00824         t = stpcpy(t, ", key ID ");
00825         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
00826         t += strlen(t);
00827     }
00828     return res;
00829 }
00830 
00838 static rpmRC
00839 verifyDSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX dsactx)
00840         /*@globals internalState @*/
00841         /*@modifies dig, *t, internalState */
00842 {
00843     const void * sig = pgpGetSig(dig);
00844 #ifdef  NOTYET
00845     rpmuint32_t siglen = pgpGetSiglen(dig);
00846 #endif
00847     pgpDigParams sigp = pgpGetSignature(dig);
00848     rpmRC res;
00849     int xx;
00850 
00851 if (_rpmhkp_debug)
00852 fprintf(stderr, "--> %s(%p,%p,%p) sig %p sigp %p\n", __FUNCTION__, dig, t, dsactx, sig, sigp);
00853 
00854 assert(dig != NULL);
00855 assert(dsactx != NULL);
00856 assert(sigp != NULL);
00857 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA);
00858 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(dsactx));
00859 assert(pgpGetSigtag(dig) == RPMSIGTAG_DSA);
00860 assert(sig != NULL);
00861 
00862     *t = '\0';
00863     if (dig != NULL && dig->hdrsha1ctx == dsactx)
00864         t = stpcpy(t, _("Header "));
00865 
00866     /* Identify the signature version. */
00867     *t++ = 'V';
00868     switch (sigp->version) {
00869     case 3:    *t++ = '3';     break;
00870     case 4:    *t++ = '4';     break;
00871     }
00872 
00873     /* Identify the DSA/hash. */
00874     {   const char * hashname = rpmDigestName(dsactx);
00875         t = stpcpy(t, " DSA");
00876         if (strcmp(hashname, "UNKNOWN") && strcmp(hashname, "SHA1")) {
00877             *t++ = '/';
00878             t = stpcpy(t, hashname);
00879         }
00880     }
00881     t = stpcpy(t, _(" signature: "));
00882 
00883     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00884         DIGEST_CTX ctx = rpmDigestDup(dsactx);
00885 
00886         (void) rpmswEnter(op, 0);
00887         if (sigp->hash != NULL)
00888             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
00889 
00890         if (sigp->version == (rpmuint8_t) 4) {
00891             rpmuint8_t trailer[6];
00892             trailer[0] = sigp->version;
00893             trailer[1] = (rpmuint8_t)0xff;
00894             trailer[2] = (sigp->hashlen >> 24);
00895             trailer[3] = (sigp->hashlen >> 16);
00896             trailer[4] = (sigp->hashlen >>  8);
00897             trailer[5] = (sigp->hashlen      );
00898             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
00899         }
00900         (void) rpmswExit(op, sigp->hashlen);
00901         if (op != NULL) op->count--;    /* XXX one too many */
00902 
00903         if (pgpImplSetDSA(ctx, dig, sigp)) {
00904             res = RPMRC_FAIL;
00905             goto exit;
00906         }
00907     }
00908 
00909     /* Retrieve the matching public key. */
00910     res = pgpFindPubkey(dig);
00911     if (res != RPMRC_OK)
00912         goto exit;
00913 
00914     /* Verify the DSA signature. */
00915     {   rpmop op = pgpStatsAccumulator(dig, 11);        /* RPMTS_OP_SIGNATURE */
00916         (void) rpmswEnter(op, 0);
00917         xx = pgpImplVerify(dig);
00918         res = (xx ? RPMRC_OK : RPMRC_FAIL);
00919         (void) rpmswExit(op, 0);
00920     }
00921 
00922 exit:
00923     /* Identify the pubkey fingerprint. */
00924     t = stpcpy(t, rpmSigString(res));
00925     if (sigp != NULL) {
00926         t = stpcpy(t, ", key ID ");
00927         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
00928         t += strlen(t);
00929     }
00930 
00931 if (_rpmhkp_debug)
00932 fprintf(stderr, "<-- %s(%p,%p,%p) res %d %s\n", __FUNCTION__, dig, t, dsactx, res, t);
00933 
00934     return res;
00935 }
00936 
00937 rpmRC
00938 rpmVerifySignature(void * _dig, char * result)
00939 {
00940     pgpDig dig = _dig;
00941     const void * sig = pgpGetSig(dig);
00942     rpmuint32_t siglen = pgpGetSiglen(dig);
00943     rpmSigTag sigtag = pgpGetSigtag(dig);
00944     rpmRC res;
00945 
00946 if (_rpmhkp_debug)
00947 fprintf(stderr, "--> %s(%p,%p) sig %p[%u]\n", __FUNCTION__, _dig, result, sig, siglen);
00948 
00949     if (dig == NULL || sig == NULL || siglen == 0) {
00950         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
00951         res = RPMRC_NOTFOUND;
00952         goto exit;
00953     }
00954 
00955     switch (sigtag) {
00956     case RPMSIGTAG_SIZE:
00957         res = verifySize(dig, result);
00958         break;
00959     case RPMSIGTAG_MD5:
00960         res = verifyMD5(dig, result, dig->md5ctx);
00961         break;
00962     case RPMSIGTAG_SHA1:
00963         res = verifySHA1(dig, result, dig->hdrsha1ctx);
00964         break;
00965     case RPMSIGTAG_RSA:
00966         res = verifyRSA(dig, result, dig->hdrctx);
00967         break;
00968     case RPMSIGTAG_DSA:
00969         res = verifyDSA(dig, result, dig->hdrsha1ctx);
00970         break;
00971     default:
00972         sprintf(result, _("Signature: UNKNOWN (%u)\n"), (unsigned)sigtag);
00973         res = RPMRC_NOTFOUND;
00974         break;
00975     }
00976 
00977 exit:
00978 if (_rpmhkp_debug)
00979 fprintf(stderr, "<-- %s(%p,%p) res %d %s\n", __FUNCTION__, _dig, result, res, result);
00980 
00981     return res;
00982 }