rpm 5.3.7

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